forked from Minki/linux
[SCSI] mvsas: add support for Task collector mode and fixed relative bugs
1. Add support for Task collector mode. 2. Fixed relative collector mode bug: - I/O failed when disks is on two ports - system hang when hotplug disk - system hang when unplug disk during run IO 3. Unlock ap->lock within .lldd_execute_task for direct mode to improve performance Signed-off-by: Xiangliang Yu <yuxiangl@marvell.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
parent
8214028344
commit
0b15fb1fdf
@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2007 Red Hat, Inc.
|
# Copyright 2007 Red Hat, Inc.
|
||||||
# Copyright 2008 Marvell. <kewei@marvell.com>
|
# Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
# Copyright 2009-20011 Marvell. <yuxiangl@marvell.com>
|
||||||
#
|
#
|
||||||
# This file is licensed under GPLv2.
|
# This file is licensed under GPLv2.
|
||||||
#
|
#
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2007 Red Hat, Inc.
|
# Copyright 2007 Red Hat, Inc.
|
||||||
# Copyright 2008 Marvell. <kewei@marvell.com>
|
# Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
# Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
|
||||||
#
|
#
|
||||||
# This file is licensed under GPLv2.
|
# This file is licensed under GPLv2.
|
||||||
#
|
#
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2007 Red Hat, Inc.
|
* Copyright 2007 Red Hat, Inc.
|
||||||
* Copyright 2008 Marvell. <kewei@marvell.com>
|
* Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under GPLv2.
|
* This file is licensed under GPLv2.
|
||||||
*
|
*
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2007 Red Hat, Inc.
|
* Copyright 2007 Red Hat, Inc.
|
||||||
* Copyright 2008 Marvell. <kewei@marvell.com>
|
* Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under GPLv2.
|
* This file is licensed under GPLv2.
|
||||||
*
|
*
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2007 Red Hat, Inc.
|
* Copyright 2007 Red Hat, Inc.
|
||||||
* Copyright 2008 Marvell. <kewei@marvell.com>
|
* Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under GPLv2.
|
* This file is licensed under GPLv2.
|
||||||
*
|
*
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2007 Red Hat, Inc.
|
* Copyright 2007 Red Hat, Inc.
|
||||||
* Copyright 2008 Marvell. <kewei@marvell.com>
|
* Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under GPLv2.
|
* This file is licensed under GPLv2.
|
||||||
*
|
*
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2007 Red Hat, Inc.
|
* Copyright 2007 Red Hat, Inc.
|
||||||
* Copyright 2008 Marvell. <kewei@marvell.com>
|
* Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under GPLv2.
|
* This file is licensed under GPLv2.
|
||||||
*
|
*
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2007 Red Hat, Inc.
|
* Copyright 2007 Red Hat, Inc.
|
||||||
* Copyright 2008 Marvell. <kewei@marvell.com>
|
* Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under GPLv2.
|
* This file is licensed under GPLv2.
|
||||||
*
|
*
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2007 Red Hat, Inc.
|
* Copyright 2007 Red Hat, Inc.
|
||||||
* Copyright 2008 Marvell. <kewei@marvell.com>
|
* Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under GPLv2.
|
* This file is licensed under GPLv2.
|
||||||
*
|
*
|
||||||
@ -25,7 +26,16 @@
|
|||||||
|
|
||||||
#include "mv_sas.h"
|
#include "mv_sas.h"
|
||||||
|
|
||||||
|
static int lldd_max_execute_num = 1;
|
||||||
|
module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
|
||||||
|
MODULE_PARM_DESC(collector, "\n"
|
||||||
|
"\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
|
||||||
|
"\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
|
||||||
|
"\tThe mvsas SAS LLDD supports both modes.\n"
|
||||||
|
"\tDefault: 1 (Direct Mode).\n");
|
||||||
|
|
||||||
static struct scsi_transport_template *mvs_stt;
|
static struct scsi_transport_template *mvs_stt;
|
||||||
|
struct kmem_cache *mvs_task_list_cache;
|
||||||
static const struct mvs_chip_info mvs_chips[] = {
|
static const struct mvs_chip_info mvs_chips[] = {
|
||||||
[chip_6320] = { 1, 2, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
|
[chip_6320] = { 1, 2, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
|
||||||
[chip_6440] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
|
[chip_6440] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
|
||||||
@ -109,7 +119,6 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
|
|||||||
|
|
||||||
static void mvs_free(struct mvs_info *mvi)
|
static void mvs_free(struct mvs_info *mvi)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
struct mvs_wq *mwq;
|
struct mvs_wq *mwq;
|
||||||
int slot_nr;
|
int slot_nr;
|
||||||
|
|
||||||
@ -121,12 +130,8 @@ static void mvs_free(struct mvs_info *mvi)
|
|||||||
else
|
else
|
||||||
slot_nr = MVS_SLOTS;
|
slot_nr = MVS_SLOTS;
|
||||||
|
|
||||||
for (i = 0; i < mvi->tags_num; i++) {
|
if (mvi->dma_pool)
|
||||||
struct mvs_slot_info *slot = &mvi->slot_info[i];
|
pci_pool_destroy(mvi->dma_pool);
|
||||||
if (slot->buf)
|
|
||||||
dma_free_coherent(mvi->dev, MVS_SLOT_BUF_SZ,
|
|
||||||
slot->buf, slot->buf_dma);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mvi->tx)
|
if (mvi->tx)
|
||||||
dma_free_coherent(mvi->dev,
|
dma_free_coherent(mvi->dev,
|
||||||
@ -215,6 +220,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
|
|||||||
static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
|
static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
|
||||||
{
|
{
|
||||||
int i = 0, slot_nr;
|
int i = 0, slot_nr;
|
||||||
|
char pool_name[32];
|
||||||
|
|
||||||
if (mvi->flags & MVF_FLAG_SOC)
|
if (mvi->flags & MVF_FLAG_SOC)
|
||||||
slot_nr = MVS_SOC_SLOTS;
|
slot_nr = MVS_SOC_SLOTS;
|
||||||
@ -274,18 +280,14 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
|
|||||||
if (!mvi->bulk_buffer)
|
if (!mvi->bulk_buffer)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
#endif
|
#endif
|
||||||
for (i = 0; i < slot_nr; i++) {
|
sprintf(pool_name, "%s%d", "mvs_dma_pool", mvi->id);
|
||||||
struct mvs_slot_info *slot = &mvi->slot_info[i];
|
mvi->dma_pool = pci_pool_create(pool_name, mvi->pdev, MVS_SLOT_BUF_SZ, 16, 0);
|
||||||
|
if (!mvi->dma_pool) {
|
||||||
slot->buf = dma_alloc_coherent(mvi->dev, MVS_SLOT_BUF_SZ,
|
printk(KERN_DEBUG "failed to create dma pool %s.\n", pool_name);
|
||||||
&slot->buf_dma, GFP_KERNEL);
|
|
||||||
if (!slot->buf) {
|
|
||||||
printk(KERN_DEBUG"failed to allocate slot->buf.\n");
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
|
||||||
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
|
|
||||||
++mvi->tags_num;
|
|
||||||
}
|
}
|
||||||
|
mvi->tags_num = slot_nr;
|
||||||
|
|
||||||
/* Initialize tags */
|
/* Initialize tags */
|
||||||
mvs_tag_init(mvi);
|
mvs_tag_init(mvi);
|
||||||
return 0;
|
return 0;
|
||||||
@ -486,7 +488,7 @@ static void __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost,
|
|||||||
|
|
||||||
sha->num_phys = nr_core * chip_info->n_phy;
|
sha->num_phys = nr_core * chip_info->n_phy;
|
||||||
|
|
||||||
sha->lldd_max_execute_num = 1;
|
sha->lldd_max_execute_num = lldd_max_execute_num;
|
||||||
|
|
||||||
if (mvi->flags & MVF_FLAG_SOC)
|
if (mvi->flags & MVF_FLAG_SOC)
|
||||||
can_queue = MVS_SOC_CAN_QUEUE;
|
can_queue = MVS_SOC_CAN_QUEUE;
|
||||||
@ -710,6 +712,14 @@ static int __init mvs_init(void)
|
|||||||
if (!mvs_stt)
|
if (!mvs_stt)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mvs_task_list_cache = kmem_cache_create("mvs_task_list", sizeof(struct mvs_task_list),
|
||||||
|
0, SLAB_HWCACHE_ALIGN, NULL);
|
||||||
|
if (!mvs_task_list_cache) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
mv_printk("%s: mvs_task_list_cache alloc failed! \n", __func__);
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
rc = pci_register_driver(&mvs_pci_driver);
|
rc = pci_register_driver(&mvs_pci_driver);
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -726,6 +736,7 @@ static void __exit mvs_exit(void)
|
|||||||
{
|
{
|
||||||
pci_unregister_driver(&mvs_pci_driver);
|
pci_unregister_driver(&mvs_pci_driver);
|
||||||
sas_release_transport(mvs_stt);
|
sas_release_transport(mvs_stt);
|
||||||
|
kmem_cache_destroy(mvs_task_list_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(mvs_init);
|
module_init(mvs_init);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2007 Red Hat, Inc.
|
* Copyright 2007 Red Hat, Inc.
|
||||||
* Copyright 2008 Marvell. <kewei@marvell.com>
|
* Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under GPLv2.
|
* This file is licensed under GPLv2.
|
||||||
*
|
*
|
||||||
@ -862,178 +863,286 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE)))
|
#define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE)))
|
||||||
static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
|
static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf,
|
||||||
struct completion *completion,int is_tmf,
|
struct mvs_tmf_task *tmf, int *pass)
|
||||||
struct mvs_tmf_task *tmf)
|
|
||||||
{
|
{
|
||||||
struct domain_device *dev = task->dev;
|
struct domain_device *dev = task->dev;
|
||||||
struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
|
struct mvs_device *mvi_dev = dev->lldd_dev;
|
||||||
struct mvs_info *mvi = mvi_dev->mvi_info;
|
|
||||||
struct mvs_task_exec_info tei;
|
struct mvs_task_exec_info tei;
|
||||||
struct sas_task *t = task;
|
|
||||||
struct mvs_slot_info *slot;
|
struct mvs_slot_info *slot;
|
||||||
u32 tag = 0xdeadbeef, rc, n_elem = 0;
|
u32 tag = 0xdeadbeef, n_elem = 0;
|
||||||
u32 n = num, pass = 0;
|
int rc = 0;
|
||||||
unsigned long flags = 0, flags_libsas = 0;
|
|
||||||
|
|
||||||
if (!dev->port) {
|
if (!dev->port) {
|
||||||
struct task_status_struct *tsm = &t->task_status;
|
struct task_status_struct *tsm = &task->task_status;
|
||||||
|
|
||||||
tsm->resp = SAS_TASK_UNDELIVERED;
|
tsm->resp = SAS_TASK_UNDELIVERED;
|
||||||
tsm->stat = SAS_PHY_DOWN;
|
tsm->stat = SAS_PHY_DOWN;
|
||||||
|
/*
|
||||||
|
* libsas will use dev->port, should
|
||||||
|
* not call task_done for sata
|
||||||
|
*/
|
||||||
if (dev->dev_type != SATA_DEV)
|
if (dev->dev_type != SATA_DEV)
|
||||||
t->task_done(t);
|
task->task_done(task);
|
||||||
return 0;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&mvi->lock, flags);
|
if (DEV_IS_GONE(mvi_dev)) {
|
||||||
do {
|
if (mvi_dev)
|
||||||
dev = t->dev;
|
mv_dprintk("device %d not ready.\n",
|
||||||
mvi_dev = dev->lldd_dev;
|
mvi_dev->device_id);
|
||||||
if (DEV_IS_GONE(mvi_dev)) {
|
else
|
||||||
if (mvi_dev)
|
mv_dprintk("device %016llx not ready.\n",
|
||||||
mv_dprintk("device %d not ready.\n",
|
SAS_ADDR(dev->sas_addr));
|
||||||
mvi_dev->device_id);
|
|
||||||
else
|
|
||||||
mv_dprintk("device %016llx not ready.\n",
|
|
||||||
SAS_ADDR(dev->sas_addr));
|
|
||||||
|
|
||||||
rc = SAS_PHY_DOWN;
|
rc = SAS_PHY_DOWN;
|
||||||
goto out_done;
|
return rc;
|
||||||
}
|
}
|
||||||
|
tei.port = dev->port->lldd_port;
|
||||||
|
if (tei.port && !tei.port->port_attached && !tmf) {
|
||||||
|
if (sas_protocol_ata(task->task_proto)) {
|
||||||
|
struct task_status_struct *ts = &task->task_status;
|
||||||
|
mv_dprintk("SATA/STP port %d does not attach"
|
||||||
|
"device.\n", dev->port->id);
|
||||||
|
ts->resp = SAS_TASK_COMPLETE;
|
||||||
|
ts->stat = SAS_PHY_DOWN;
|
||||||
|
|
||||||
if (dev->port->id >= mvi->chip->n_phy)
|
task->task_done(task);
|
||||||
tei.port = &mvi->port[dev->port->id - mvi->chip->n_phy];
|
|
||||||
else
|
|
||||||
tei.port = &mvi->port[dev->port->id];
|
|
||||||
|
|
||||||
if (tei.port && !tei.port->port_attached) {
|
|
||||||
if (sas_protocol_ata(t->task_proto)) {
|
|
||||||
struct task_status_struct *ts = &t->task_status;
|
|
||||||
|
|
||||||
mv_dprintk("port %d does not"
|
|
||||||
"attached device.\n", dev->port->id);
|
|
||||||
ts->stat = SAS_PROTO_RESPONSE;
|
|
||||||
ts->stat = SAS_PHY_DOWN;
|
|
||||||
spin_unlock_irqrestore(dev->sata_dev.ap->lock,
|
|
||||||
flags_libsas);
|
|
||||||
spin_unlock_irqrestore(&mvi->lock, flags);
|
|
||||||
t->task_done(t);
|
|
||||||
spin_lock_irqsave(&mvi->lock, flags);
|
|
||||||
spin_lock_irqsave(dev->sata_dev.ap->lock,
|
|
||||||
flags_libsas);
|
|
||||||
if (n > 1)
|
|
||||||
t = list_entry(t->list.next,
|
|
||||||
struct sas_task, list);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
struct task_status_struct *ts = &t->task_status;
|
|
||||||
ts->resp = SAS_TASK_UNDELIVERED;
|
|
||||||
ts->stat = SAS_PHY_DOWN;
|
|
||||||
t->task_done(t);
|
|
||||||
if (n > 1)
|
|
||||||
t = list_entry(t->list.next,
|
|
||||||
struct sas_task, list);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sas_protocol_ata(t->task_proto)) {
|
|
||||||
if (t->num_scatter) {
|
|
||||||
n_elem = dma_map_sg(mvi->dev,
|
|
||||||
t->scatter,
|
|
||||||
t->num_scatter,
|
|
||||||
t->data_dir);
|
|
||||||
if (!n_elem) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
n_elem = t->num_scatter;
|
struct task_status_struct *ts = &task->task_status;
|
||||||
|
mv_dprintk("SAS port %d does not attach"
|
||||||
|
"device.\n", dev->port->id);
|
||||||
|
ts->resp = SAS_TASK_UNDELIVERED;
|
||||||
|
ts->stat = SAS_PHY_DOWN;
|
||||||
|
task->task_done(task);
|
||||||
}
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
rc = mvs_tag_alloc(mvi, &tag);
|
if (!sas_protocol_ata(task->task_proto)) {
|
||||||
if (rc)
|
if (task->num_scatter) {
|
||||||
goto err_out;
|
n_elem = dma_map_sg(mvi->dev,
|
||||||
|
task->scatter,
|
||||||
slot = &mvi->slot_info[tag];
|
task->num_scatter,
|
||||||
|
task->data_dir);
|
||||||
|
if (!n_elem) {
|
||||||
t->lldd_task = NULL;
|
rc = -ENOMEM;
|
||||||
slot->n_elem = n_elem;
|
goto prep_out;
|
||||||
slot->slot_tag = tag;
|
}
|
||||||
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
|
|
||||||
|
|
||||||
tei.task = t;
|
|
||||||
tei.hdr = &mvi->slot[tag];
|
|
||||||
tei.tag = tag;
|
|
||||||
tei.n_elem = n_elem;
|
|
||||||
switch (t->task_proto) {
|
|
||||||
case SAS_PROTOCOL_SMP:
|
|
||||||
rc = mvs_task_prep_smp(mvi, &tei);
|
|
||||||
break;
|
|
||||||
case SAS_PROTOCOL_SSP:
|
|
||||||
rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf);
|
|
||||||
break;
|
|
||||||
case SAS_PROTOCOL_SATA:
|
|
||||||
case SAS_PROTOCOL_STP:
|
|
||||||
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
|
|
||||||
rc = mvs_task_prep_ata(mvi, &tei);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dev_printk(KERN_ERR, mvi->dev,
|
|
||||||
"unknown sas_task proto: 0x%x\n",
|
|
||||||
t->task_proto);
|
|
||||||
rc = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
n_elem = task->num_scatter;
|
||||||
|
}
|
||||||
|
|
||||||
if (rc) {
|
rc = mvs_tag_alloc(mvi, &tag);
|
||||||
mv_dprintk("rc is %x\n", rc);
|
if (rc)
|
||||||
goto err_out_tag;
|
goto err_out;
|
||||||
}
|
|
||||||
slot->task = t;
|
|
||||||
slot->port = tei.port;
|
|
||||||
t->lldd_task = slot;
|
|
||||||
list_add_tail(&slot->entry, &tei.port->list);
|
|
||||||
/* TODO: select normal or high priority */
|
|
||||||
spin_lock(&t->task_state_lock);
|
|
||||||
t->task_state_flags |= SAS_TASK_AT_INITIATOR;
|
|
||||||
spin_unlock(&t->task_state_lock);
|
|
||||||
|
|
||||||
mvs_hba_memory_dump(mvi, tag, t->task_proto);
|
slot = &mvi->slot_info[tag];
|
||||||
mvi_dev->running_req++;
|
|
||||||
++pass;
|
|
||||||
mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
|
|
||||||
if (n > 1)
|
|
||||||
t = list_entry(t->list.next, struct sas_task, list);
|
|
||||||
if (likely(pass))
|
|
||||||
MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) &
|
|
||||||
(MVS_CHIP_SLOT_SZ - 1));
|
|
||||||
|
|
||||||
} while (--n);
|
task->lldd_task = NULL;
|
||||||
rc = 0;
|
slot->n_elem = n_elem;
|
||||||
goto out_done;
|
slot->slot_tag = tag;
|
||||||
|
|
||||||
|
slot->buf = pci_pool_alloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma);
|
||||||
|
if (!slot->buf)
|
||||||
|
goto err_out_tag;
|
||||||
|
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
|
||||||
|
|
||||||
|
tei.task = task;
|
||||||
|
tei.hdr = &mvi->slot[tag];
|
||||||
|
tei.tag = tag;
|
||||||
|
tei.n_elem = n_elem;
|
||||||
|
switch (task->task_proto) {
|
||||||
|
case SAS_PROTOCOL_SMP:
|
||||||
|
rc = mvs_task_prep_smp(mvi, &tei);
|
||||||
|
break;
|
||||||
|
case SAS_PROTOCOL_SSP:
|
||||||
|
rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf);
|
||||||
|
break;
|
||||||
|
case SAS_PROTOCOL_SATA:
|
||||||
|
case SAS_PROTOCOL_STP:
|
||||||
|
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
|
||||||
|
rc = mvs_task_prep_ata(mvi, &tei);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_printk(KERN_ERR, mvi->dev,
|
||||||
|
"unknown sas_task proto: 0x%x\n",
|
||||||
|
task->task_proto);
|
||||||
|
rc = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
mv_dprintk("rc is %x\n", rc);
|
||||||
|
goto err_out_slot_buf;
|
||||||
|
}
|
||||||
|
slot->task = task;
|
||||||
|
slot->port = tei.port;
|
||||||
|
task->lldd_task = slot;
|
||||||
|
list_add_tail(&slot->entry, &tei.port->list);
|
||||||
|
spin_lock(&task->task_state_lock);
|
||||||
|
task->task_state_flags |= SAS_TASK_AT_INITIATOR;
|
||||||
|
spin_unlock(&task->task_state_lock);
|
||||||
|
|
||||||
|
mvs_hba_memory_dump(mvi, tag, task->task_proto);
|
||||||
|
mvi_dev->running_req++;
|
||||||
|
++(*pass);
|
||||||
|
mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
err_out_slot_buf:
|
||||||
|
pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma);
|
||||||
err_out_tag:
|
err_out_tag:
|
||||||
mvs_tag_free(mvi, tag);
|
mvs_tag_free(mvi, tag);
|
||||||
err_out:
|
err_out:
|
||||||
|
|
||||||
dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
|
dev_printk(KERN_ERR, mvi->dev, "mvsas prep failed[%d]!\n", rc);
|
||||||
if (!sas_protocol_ata(t->task_proto))
|
if (!sas_protocol_ata(task->task_proto))
|
||||||
if (n_elem)
|
if (n_elem)
|
||||||
dma_unmap_sg(mvi->dev, t->scatter, n_elem,
|
dma_unmap_sg(mvi->dev, task->scatter, n_elem,
|
||||||
t->data_dir);
|
task->data_dir);
|
||||||
out_done:
|
prep_out:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mvs_task_list *mvs_task_alloc_list(int *num, gfp_t gfp_flags)
|
||||||
|
{
|
||||||
|
struct mvs_task_list *first = NULL;
|
||||||
|
|
||||||
|
for (; *num > 0; --*num) {
|
||||||
|
struct mvs_task_list *mvs_list = kmem_cache_zalloc(mvs_task_list_cache, gfp_flags);
|
||||||
|
|
||||||
|
if (!mvs_list)
|
||||||
|
break;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&mvs_list->list);
|
||||||
|
if (!first)
|
||||||
|
first = mvs_list;
|
||||||
|
else
|
||||||
|
list_add_tail(&mvs_list->list, &first->list);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mvs_task_free_list(struct mvs_task_list *mvs_list)
|
||||||
|
{
|
||||||
|
LIST_HEAD(list);
|
||||||
|
struct list_head *pos, *a;
|
||||||
|
struct mvs_task_list *mlist = NULL;
|
||||||
|
|
||||||
|
__list_add(&list, mvs_list->list.prev, &mvs_list->list);
|
||||||
|
|
||||||
|
list_for_each_safe(pos, a, &list) {
|
||||||
|
list_del_init(pos);
|
||||||
|
mlist = list_entry(pos, struct mvs_task_list, list);
|
||||||
|
kmem_cache_free(mvs_task_list_cache, mlist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
|
||||||
|
struct completion *completion, int is_tmf,
|
||||||
|
struct mvs_tmf_task *tmf)
|
||||||
|
{
|
||||||
|
struct domain_device *dev = task->dev;
|
||||||
|
struct mvs_info *mvi = NULL;
|
||||||
|
u32 rc = 0;
|
||||||
|
u32 pass = 0;
|
||||||
|
unsigned long flags = 0;
|
||||||
|
|
||||||
|
mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info;
|
||||||
|
|
||||||
|
if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
|
||||||
|
spin_unlock_irq(dev->sata_dev.ap->lock);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&mvi->lock, flags);
|
||||||
|
rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass);
|
||||||
|
if (rc)
|
||||||
|
dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
|
||||||
|
|
||||||
|
if (likely(pass))
|
||||||
|
MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) &
|
||||||
|
(MVS_CHIP_SLOT_SZ - 1));
|
||||||
spin_unlock_irqrestore(&mvi->lock, flags);
|
spin_unlock_irqrestore(&mvi->lock, flags);
|
||||||
|
|
||||||
|
if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
|
||||||
|
spin_lock_irq(dev->sata_dev.ap->lock);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mvs_collector_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
|
||||||
|
struct completion *completion, int is_tmf,
|
||||||
|
struct mvs_tmf_task *tmf)
|
||||||
|
{
|
||||||
|
struct domain_device *dev = task->dev;
|
||||||
|
struct mvs_prv_info *mpi = dev->port->ha->lldd_ha;
|
||||||
|
struct mvs_info *mvi = NULL;
|
||||||
|
struct sas_task *t = task;
|
||||||
|
struct mvs_task_list *mvs_list = NULL, *a;
|
||||||
|
LIST_HEAD(q);
|
||||||
|
int pass[2] = {0};
|
||||||
|
u32 rc = 0;
|
||||||
|
u32 n = num;
|
||||||
|
unsigned long flags = 0;
|
||||||
|
|
||||||
|
mvs_list = mvs_task_alloc_list(&n, gfp_flags);
|
||||||
|
if (n) {
|
||||||
|
printk(KERN_ERR "%s: mvs alloc list failed.\n", __func__);
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto free_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
__list_add(&q, mvs_list->list.prev, &mvs_list->list);
|
||||||
|
|
||||||
|
list_for_each_entry(a, &q, list) {
|
||||||
|
a->task = t;
|
||||||
|
t = list_entry(t->list.next, struct sas_task, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(a, &q , list) {
|
||||||
|
|
||||||
|
t = a->task;
|
||||||
|
mvi = ((struct mvs_device *)t->dev->lldd_dev)->mvi_info;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&mvi->lock, flags);
|
||||||
|
rc = mvs_task_prep(t, mvi, is_tmf, tmf, &pass[mvi->id]);
|
||||||
|
if (rc)
|
||||||
|
dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
|
||||||
|
spin_unlock_irqrestore(&mvi->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (likely(pass[0]))
|
||||||
|
MVS_CHIP_DISP->start_delivery(mpi->mvi[0],
|
||||||
|
(mpi->mvi[0]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
|
||||||
|
|
||||||
|
if (likely(pass[1]))
|
||||||
|
MVS_CHIP_DISP->start_delivery(mpi->mvi[1],
|
||||||
|
(mpi->mvi[1]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
|
||||||
|
|
||||||
|
list_del_init(&q);
|
||||||
|
|
||||||
|
free_list:
|
||||||
|
if (mvs_list)
|
||||||
|
mvs_task_free_list(mvs_list);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mvs_queue_command(struct sas_task *task, const int num,
|
int mvs_queue_command(struct sas_task *task, const int num,
|
||||||
gfp_t gfp_flags)
|
gfp_t gfp_flags)
|
||||||
{
|
{
|
||||||
return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL);
|
struct mvs_device *mvi_dev = task->dev->lldd_dev;
|
||||||
|
struct sas_ha_struct *sas = mvi_dev->mvi_info->sas;
|
||||||
|
|
||||||
|
if (sas->lldd_max_execute_num < 2)
|
||||||
|
return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL);
|
||||||
|
else
|
||||||
|
return mvs_collector_task_exec(task, num, gfp_flags, NULL, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
|
static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
|
||||||
@ -1067,6 +1176,11 @@ static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
|
|||||||
/* do nothing */
|
/* do nothing */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (slot->buf) {
|
||||||
|
pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma);
|
||||||
|
slot->buf = NULL;
|
||||||
|
}
|
||||||
list_del_init(&slot->entry);
|
list_del_init(&slot->entry);
|
||||||
task->lldd_task = NULL;
|
task->lldd_task = NULL;
|
||||||
slot->task = NULL;
|
slot->task = NULL;
|
||||||
@ -1255,6 +1369,7 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
|
|||||||
spin_lock_irqsave(&mvi->lock, flags);
|
spin_lock_irqsave(&mvi->lock, flags);
|
||||||
port->port_attached = 1;
|
port->port_attached = 1;
|
||||||
phy->port = port;
|
phy->port = port;
|
||||||
|
sas_port->lldd_port = port;
|
||||||
if (phy->phy_type & PORT_TYPE_SAS) {
|
if (phy->phy_type & PORT_TYPE_SAS) {
|
||||||
port->wide_port_phymap = sas_port->phy_mask;
|
port->wide_port_phymap = sas_port->phy_mask;
|
||||||
mv_printk("set wide port phy map %x\n", sas_port->phy_mask);
|
mv_printk("set wide port phy map %x\n", sas_port->phy_mask);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2007 Red Hat, Inc.
|
* Copyright 2007 Red Hat, Inc.
|
||||||
* Copyright 2008 Marvell. <kewei@marvell.com>
|
* Copyright 2008 Marvell. <kewei@marvell.com>
|
||||||
|
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under GPLv2.
|
* This file is licensed under GPLv2.
|
||||||
*
|
*
|
||||||
@ -67,6 +68,7 @@ extern struct mvs_tgt_initiator mvs_tgt;
|
|||||||
extern struct mvs_info *tgt_mvi;
|
extern struct mvs_info *tgt_mvi;
|
||||||
extern const struct mvs_dispatch mvs_64xx_dispatch;
|
extern const struct mvs_dispatch mvs_64xx_dispatch;
|
||||||
extern const struct mvs_dispatch mvs_94xx_dispatch;
|
extern const struct mvs_dispatch mvs_94xx_dispatch;
|
||||||
|
extern struct kmem_cache *mvs_task_list_cache;
|
||||||
|
|
||||||
#define DEV_IS_EXPANDER(type) \
|
#define DEV_IS_EXPANDER(type) \
|
||||||
((type == EDGE_DEV) || (type == FANOUT_DEV))
|
((type == EDGE_DEV) || (type == FANOUT_DEV))
|
||||||
@ -341,6 +343,7 @@ struct mvs_info {
|
|||||||
dma_addr_t bulk_buffer_dma;
|
dma_addr_t bulk_buffer_dma;
|
||||||
#define TRASH_BUCKET_SIZE 0x20000
|
#define TRASH_BUCKET_SIZE 0x20000
|
||||||
#endif
|
#endif
|
||||||
|
void *dma_pool;
|
||||||
struct mvs_slot_info slot_info[0];
|
struct mvs_slot_info slot_info[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -367,6 +370,11 @@ struct mvs_task_exec_info {
|
|||||||
int n_elem;
|
int n_elem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mvs_task_list {
|
||||||
|
struct sas_task *task;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/******************** function prototype *********************/
|
/******************** function prototype *********************/
|
||||||
void mvs_get_sas_addr(void *buf, u32 buflen);
|
void mvs_get_sas_addr(void *buf, u32 buflen);
|
||||||
|
Loading…
Reference in New Issue
Block a user