aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2017-05-30 13:42:09 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2017-05-30 13:42:09 +1000
commit55277d058c9139f8ddc384c0bd5ee1b7c9191ae2 (patch)
tree22d299af4cb9c1bcffceecc35cb29bc95b04ea5b
parent12e1adb5c3cdb925da16a92d6bd4b33107a51c5a (diff)
parent35f07119477d3782812bf26ea885e302f83ab2ac (diff)
Merge remote-tracking branch 'scsi/for-next'
-rw-r--r--drivers/hv/channel_mgmt.c1
-rw-r--r--drivers/scsi/aacraid/aachba.c17
-rw-r--r--drivers/scsi/aacraid/aacraid.h22
-rw-r--r--drivers/scsi/aacraid/commctrl.c15
-rw-r--r--drivers/scsi/aacraid/comminit.c18
-rw-r--r--drivers/scsi/aacraid/commsup.c78
-rw-r--r--drivers/scsi/aacraid/linit.c232
-rw-r--r--drivers/scsi/aacraid/src.c136
-rw-r--r--drivers/scsi/csiostor/csio_hw.c79
-rw-r--r--drivers/scsi/csiostor/csio_hw_chip.h14
-rw-r--r--drivers/scsi/csiostor/csio_hw_t5.c29
-rw-r--r--drivers/scsi/csiostor/csio_init.c6
-rw-r--r--drivers/scsi/csiostor/csio_lnode.c43
-rw-r--r--drivers/scsi/csiostor/csio_wr.c4
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c25
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.h16
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c10
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c2
-rw-r--r--drivers/scsi/hpsa.c849
-rw-r--r--drivers/scsi/hpsa.h4
-rw-r--r--drivers/scsi/hpsa_cmd.h20
-rw-r--r--drivers/scsi/libiscsi.c4
-rw-r--r--drivers/scsi/qedi/qedi.h3
-rw-r--r--drivers/scsi/qedi/qedi_fw.c2
-rw-r--r--drivers/scsi/qedi/qedi_iscsi.c7
-rw-r--r--drivers/scsi/qedi/qedi_main.c25
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h1
-rw-r--r--drivers/scsi/smartpqi/smartpqi.h194
-rw-r--r--drivers/scsi/smartpqi/smartpqi_init.c2325
-rw-r--r--drivers/scsi/smartpqi/smartpqi_sas_transport.c2
-rw-r--r--drivers/scsi/smartpqi/smartpqi_sis.c100
-rw-r--r--drivers/scsi/smartpqi/smartpqi_sis.h7
-rw-r--r--drivers/scsi/storvsc_drv.c52
-rw-r--r--include/linux/hyperv.h1
34 files changed, 2678 insertions, 1665 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 0fabd410efd9..4bbb8dea4727 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -332,7 +332,6 @@ static struct vmbus_channel *alloc_channel(void)
if (!channel)
return NULL;
- spin_lock_init(&channel->inbound_lock);
spin_lock_init(&channel->lock);
INIT_LIST_HEAD(&channel->sc_list);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 43d88389e899..707ee2f5954d 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -2071,20 +2071,15 @@ int aac_get_adapter_info(struct aac_dev* dev)
expose_physicals = 0;
}
- if(dev->dac_support != 0) {
- if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(64)) &&
- !pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(64))) {
+ if (dev->dac_support) {
+ if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(64))) {
if (!dev->in_reset)
- printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
- dev->name, dev->id);
- } else if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(32)) &&
- !pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32))) {
- printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n",
- dev->name, dev->id);
+ dev_info(&dev->pdev->dev, "64 Bit DAC enabled\n");
+ } else if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(32))) {
+ dev_info(&dev->pdev->dev, "DMA mask set failed, 64 Bit DAC disabled\n");
dev->dac_support = 0;
} else {
- printk(KERN_WARNING"%s%d: No suitable DMA available.\n",
- dev->name, dev->id);
+ dev_info(&dev->pdev->dev, "No suitable DMA available\n");
rcode = -ENOMEM;
}
}
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index d281492009fb..d31a9bc2ba69 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -97,7 +97,7 @@ enum {
#define PMC_GLOBAL_INT_BIT0 0x00000001
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 50792
+# define AAC_DRIVER_BUILD 50834
# define AAC_DRIVER_BRANCH "-custom"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -415,6 +415,7 @@ struct aac_ciss_identify_pd {
* These macros convert from physical channels to virtual channels
*/
#define CONTAINER_CHANNEL (0)
+#define NATIVE_CHANNEL (1)
#define CONTAINER_TO_CHANNEL(cont) (CONTAINER_CHANNEL)
#define CONTAINER_TO_ID(cont) (cont)
#define CONTAINER_TO_LUN(cont) (0)
@@ -423,7 +424,6 @@ struct aac_ciss_identify_pd {
#define PMC_DEVICE_S6 0x28b
#define PMC_DEVICE_S7 0x28c
#define PMC_DEVICE_S8 0x28d
-#define PMC_DEVICE_S9 0x28f
#define aac_phys_to_logical(x) ((x)+1)
#define aac_logical_to_phys(x) ((x)?(x)-1:0)
@@ -2377,6 +2377,7 @@ struct revision
#define SOFT_RESET_TIME 60
+
struct aac_common
{
/*
@@ -2487,7 +2488,9 @@ struct aac_hba_info {
#define IOP_RESET_FW_FIB_DUMP 0x00000034
#define IOP_RESET 0x00001000
#define IOP_RESET_ALWAYS 0x00001001
-#define RE_INIT_ADAPTER 0x000000ee
+#define RE_INIT_ADAPTER 0x000000ee
+
+#define IOP_SRC_RESET_MASK 0x00000100
/*
* Adapter Status Register
@@ -2512,6 +2515,7 @@ struct aac_hba_info {
#define SELF_TEST_FAILED 0x00000004
#define MONITOR_PANIC 0x00000020
+#define KERNEL_BOOTING 0x00000040
#define KERNEL_UP_AND_RUNNING 0x00000080
#define KERNEL_PANIC 0x00000100
#define FLASH_UPD_PENDING 0x00002000
@@ -2684,6 +2688,18 @@ int aac_probe_container(struct aac_dev *dev, int cid);
int _aac_rx_init(struct aac_dev *dev);
int aac_rx_select_comm(struct aac_dev *dev, int comm);
int aac_rx_deliver_producer(struct fib * fib);
+
+static inline int aac_is_src(struct aac_dev *dev)
+{
+ u16 device = dev->pdev->device;
+
+ if (device == PMC_DEVICE_S6 ||
+ device == PMC_DEVICE_S7 ||
+ device == PMC_DEVICE_S8)
+ return 1;
+ return 0;
+}
+
char * get_container_type(unsigned type);
extern int numacb;
extern char aac_driver_version[];
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index d2f8d5954840..106b9332f718 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -668,7 +668,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
goto cleanup;
}
- p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA);
+ p = kmalloc(sg_count[i], GFP_KERNEL);
if (!p) {
rcode = -ENOMEM;
goto cleanup;
@@ -732,8 +732,8 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode = -EINVAL;
goto cleanup;
}
- /* Does this really need to be GFP_DMA? */
- p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA);
+
+ p = kmalloc(sg_count[i], GFP_KERNEL);
if(!p) {
dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
sg_count[i], i, upsg->count));
@@ -788,8 +788,8 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode = -EINVAL;
goto cleanup;
}
- /* Does this really need to be GFP_DMA? */
- p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA);
+
+ p = kmalloc(sg_count[i], GFP_KERNEL);
if(!p) {
dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
sg_count[i], i, usg->count));
@@ -845,8 +845,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode = -EINVAL;
goto cleanup;
}
- /* Does this really need to be GFP_DMA? */
- p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA);
+ p = kmalloc(sg_count[i], GFP_KERNEL|GFP_DMA32);
if (!p) {
dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
sg_count[i], i, usg->count));
@@ -887,7 +886,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode = -EINVAL;
goto cleanup;
}
- p = kmalloc(sg_count[i], GFP_KERNEL);
+ p = kmalloc(sg_count[i], GFP_KERNEL|GFP_DMA32);
if (!p) {
dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
sg_count[i], i, upsg->count));
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 1151505853cf..9ee025b1d0e0 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -53,11 +53,8 @@ static inline int aac_is_msix_mode(struct aac_dev *dev)
{
u32 status = 0;
- if (dev->pdev->device == PMC_DEVICE_S6 ||
- dev->pdev->device == PMC_DEVICE_S7 ||
- dev->pdev->device == PMC_DEVICE_S8) {
+ if (aac_is_src(dev))
status = src_readl(dev, MUnit.OMR);
- }
return (status & AAC_INT_MODE_MSIX);
}
@@ -325,9 +322,7 @@ int aac_send_shutdown(struct aac_dev * dev)
/* FIB should be freed only after getting the response from the F/W */
if (status != -ERESTARTSYS)
aac_fib_free(fibctx);
- if ((dev->pdev->device == PMC_DEVICE_S7 ||
- dev->pdev->device == PMC_DEVICE_S8 ||
- dev->pdev->device == PMC_DEVICE_S9) &&
+ if (aac_is_src(dev) &&
dev->msi_enabled)
aac_set_intx_mode(dev);
return status;
@@ -583,9 +578,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
dev->max_fib_size = status[1] & 0xFFE0;
host->sg_tablesize = status[2] >> 16;
dev->sg_tablesize = status[2] & 0xFFFF;
- if (dev->pdev->device == PMC_DEVICE_S7 ||
- dev->pdev->device == PMC_DEVICE_S8 ||
- dev->pdev->device == PMC_DEVICE_S9) {
+ if (aac_is_src(dev)) {
if (host->can_queue > (status[3] >> 16) -
AAC_NUM_MGT_FIB)
host->can_queue = (status[3] >> 16) -
@@ -604,10 +597,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
pr_warn("numacb=%d ignored\n", numacb);
}
- if (dev->pdev->device == PMC_DEVICE_S6 ||
- dev->pdev->device == PMC_DEVICE_S7 ||
- dev->pdev->device == PMC_DEVICE_S8 ||
- dev->pdev->device == PMC_DEVICE_S9)
+ if (aac_is_src(dev))
aac_define_int_mode(dev);
/*
* Ok now init the communication subsystem
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 7a1b8a2ce658..1c617ccfaf12 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -803,11 +803,11 @@ int aac_hba_send(u8 command, struct fib *fibptr, fib_callback callback,
if (aac_check_eeh_failure(dev))
return -EFAULT;
- /* Only set for first known interruptable command */
- if (down_interruptible(&fibptr->event_wait)) {
+ fibptr->flags |= FIB_CONTEXT_FLAG_WAIT;
+ if (down_interruptible(&fibptr->event_wait))
fibptr->done = 2;
- up(&fibptr->event_wait);
- }
+ fibptr->flags &= ~(FIB_CONTEXT_FLAG_WAIT);
+
spin_lock_irqsave(&fibptr->event_lock, flags);
if ((fibptr->done == 0) || (fibptr->done == 2)) {
fibptr->done = 2; /* Tell interrupt we aborted */
@@ -1513,6 +1513,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type)
struct scsi_cmnd *command_list;
int jafo = 0;
int bled;
+ u64 dmamask;
+ int num_of_fibs = 0;
/*
* Assumptions:
@@ -1546,10 +1548,20 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type)
/*
* Loop through the fibs, close the synchronous FIBS
*/
- for (retval = 1, index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) {
+ retval = 1;
+ num_of_fibs = aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB;
+ for (index = 0; index < num_of_fibs; index++) {
+
struct fib *fib = &aac->fibs[index];
- if (!(fib->hw_fib_va->header.XferState & cpu_to_le32(NoResponseExpected | Async)) &&
- (fib->hw_fib_va->header.XferState & cpu_to_le32(ResponseExpected))) {
+ __le32 XferState = fib->hw_fib_va->header.XferState;
+ bool is_response_expected = false;
+
+ if (!(XferState & cpu_to_le32(NoResponseExpected | Async)) &&
+ (XferState & cpu_to_le32(ResponseExpected)))
+ is_response_expected = true;
+
+ if (is_response_expected
+ || fib->flags & FIB_CONTEXT_FLAG_WAIT) {
unsigned long flagv;
spin_lock_irqsave(&fib->event_lock, flagv);
up(&fib->event_wait);
@@ -1580,21 +1592,27 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type)
aac_free_irq(aac);
kfree(aac->fsa_dev);
aac->fsa_dev = NULL;
+
+ dmamask = DMA_BIT_MASK(32);
quirks = aac_get_driver_ident(index)->quirks;
- if (quirks & AAC_QUIRK_31BIT) {
- if (((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(31)))) ||
- ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_BIT_MASK(31)))))
- goto out;
- } else {
- if (((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(32)))) ||
- ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_BIT_MASK(32)))))
- goto out;
+ if (quirks & AAC_QUIRK_31BIT)
+ retval = pci_set_dma_mask(aac->pdev, dmamask);
+ else if (!(quirks & AAC_QUIRK_SRC))
+ retval = pci_set_dma_mask(aac->pdev, dmamask);
+ else
+ retval = pci_set_consistent_dma_mask(aac->pdev, dmamask);
+
+ if (quirks & AAC_QUIRK_31BIT && !retval) {
+ dmamask = DMA_BIT_MASK(31);
+ retval = pci_set_consistent_dma_mask(aac->pdev, dmamask);
}
+
+ if (retval)
+ goto out;
+
if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
goto out;
- if (quirks & AAC_QUIRK_31BIT)
- if ((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(32))))
- goto out;
+
if (jafo) {
aac->thread = kthread_run(aac_command_thread, aac, "%s",
aac->name);
@@ -1768,8 +1786,6 @@ int aac_check_health(struct aac_dev * aac)
int BlinkLED;
unsigned long time_now, flagv = 0;
struct list_head * entry;
- struct Scsi_Host * host;
- int bled;
/* Extending the scope of fib_lock slightly to protect aac->in_reset */
if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
@@ -1881,19 +1897,6 @@ int aac_check_health(struct aac_dev * aac)
printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
- if (!aac_check_reset || ((aac_check_reset == 1) &&
- (aac->supplement_adapter_info.supported_options2 &
- AAC_OPTION_IGNORE_RESET)))
- goto out;
- host = aac->scsi_host_ptr;
- if (aac->thread->pid != current->pid)
- spin_lock_irqsave(host->host_lock, flagv);
- bled = aac_check_reset != 1 ? 1 : 0;
- _aac_reset_adapter(aac, bled, IOP_HWSOFT_RESET);
- if (aac->thread->pid != current->pid)
- spin_unlock_irqrestore(host->host_lock, flagv);
- return BlinkLED;
-
out:
aac->in_reset = 0;
return BlinkLED;
@@ -2483,7 +2486,7 @@ int aac_command_thread(void *data)
if ((time_before(next_check_jiffies,next_jiffies))
&& ((difference = next_check_jiffies - jiffies) <= 0)) {
next_check_jiffies = next_jiffies;
- if (aac_check_health(dev) == 0) {
+ if (aac_adapter_check_health(dev) == 0) {
difference = ((long)(unsigned)check_interval)
* HZ;
next_check_jiffies = jiffies + difference;
@@ -2496,7 +2499,7 @@ int aac_command_thread(void *data)
int ret;
/* Don't even try to talk to adapter if its sick */
- ret = aac_check_health(dev);
+ ret = aac_adapter_check_health(dev);
if (ret || !dev->queues)
break;
next_check_jiffies = jiffies
@@ -2588,10 +2591,7 @@ void aac_free_irq(struct aac_dev *dev)
int cpu;
cpu = cpumask_first(cpu_online_mask);
- if (dev->pdev->device == PMC_DEVICE_S6 ||
- dev->pdev->device == PMC_DEVICE_S7 ||
- dev->pdev->device == PMC_DEVICE_S8 ||
- dev->pdev->device == PMC_DEVICE_S9) {
+ if (aac_is_src(dev)) {
if (dev->max_msix > 1) {
for (i = 0; i < dev->max_msix; i++)
free_irq(pci_irq_vector(dev->pdev, i),
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 372a07533026..0f277df73af0 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -405,17 +405,23 @@ static int aac_slave_configure(struct scsi_device *sdev)
int chn, tid;
unsigned int depth = 0;
unsigned int set_timeout = 0;
+ bool set_qd_dev_type = false;
+ u8 devtype = 0;
chn = aac_logical_to_phys(sdev_channel(sdev));
tid = sdev_id(sdev);
- if (chn < AAC_MAX_BUSES && tid < AAC_MAX_TARGETS &&
- aac->hba_map[chn][tid].devtype == AAC_DEVTYPE_NATIVE_RAW) {
- depth = aac->hba_map[chn][tid].qd_limit;
+ if (chn < AAC_MAX_BUSES && tid < AAC_MAX_TARGETS && aac->sa_firmware) {
+ devtype = aac->hba_map[chn][tid].devtype;
+
+ if (devtype == AAC_DEVTYPE_NATIVE_RAW)
+ depth = aac->hba_map[chn][tid].qd_limit;
+ else if (devtype == AAC_DEVTYPE_ARC_RAW)
+ set_qd_dev_type = true;
+
set_timeout = 1;
goto common_config;
}
-
if (aac->jbod && (sdev->type == TYPE_DISK))
sdev->removable = 1;
@@ -466,9 +472,26 @@ static int aac_slave_configure(struct scsi_device *sdev)
++num_lsu;
depth = (host->can_queue - num_one) / num_lsu;
+
+ if (sdev_channel(sdev) != NATIVE_CHANNEL)
+ goto common_config;
+
+ set_qd_dev_type = true;
+
}
common_config:
+
+ /*
+ * Check if SATA drive
+ */
+ if (set_qd_dev_type) {
+ if (strncmp(sdev->vendor, "ATA", 3) == 0)
+ depth = 32;
+ else
+ depth = 64;
+ }
+
/*
* Firmware has an individual device recovery time typically
* of 35 seconds, give us a margin.
@@ -601,6 +624,56 @@ static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
return aac_do_ioctl(dev, cmd, arg);
}
+static int get_num_of_incomplete_fibs(struct aac_dev *aac)
+{
+
+ unsigned long flags;
+ struct scsi_device *sdev = NULL;
+ struct Scsi_Host *shost = aac->scsi_host_ptr;
+ struct scsi_cmnd *scmnd = NULL;
+ struct device *ctrl_dev;
+
+ int mlcnt = 0;
+ int llcnt = 0;
+ int ehcnt = 0;
+ int fwcnt = 0;
+ int krlcnt = 0;
+
+ __shost_for_each_device(sdev, shost) {
+ spin_lock_irqsave(&sdev->list_lock, flags);
+ list_for_each_entry(scmnd, &sdev->cmd_list, list) {
+ switch (scmnd->SCp.phase) {
+ case AAC_OWNER_FIRMWARE:
+ fwcnt++;
+ break;
+ case AAC_OWNER_ERROR_HANDLER:
+ ehcnt++;
+ break;
+ case AAC_OWNER_LOWLEVEL:
+ llcnt++;
+ break;
+ case AAC_OWNER_MIDLEVEL:
+ mlcnt++;
+ break;
+ default:
+ krlcnt++;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&sdev->list_lock, flags);
+ }
+
+ ctrl_dev = &aac->pdev->dev;
+
+ dev_info(ctrl_dev, "outstanding cmd: midlevel-%d\n", mlcnt);
+ dev_info(ctrl_dev, "outstanding cmd: lowlevel-%d\n", llcnt);
+ dev_info(ctrl_dev, "outstanding cmd: error handler-%d\n", ehcnt);
+ dev_info(ctrl_dev, "outstanding cmd: firmware-%d\n", fwcnt);
+ dev_info(ctrl_dev, "outstanding cmd: kernel-%d\n", krlcnt);
+
+ return mlcnt + llcnt + ehcnt + fwcnt;
+}
+
static int aac_eh_abort(struct scsi_cmnd* cmd)
{
struct scsi_device * dev = cmd->device;
@@ -661,8 +734,8 @@ static int aac_eh_abort(struct scsi_cmnd* cmd)
(fib_callback) aac_hba_callback,
(void *) cmd);
- /* Wait up to 2 minutes for completion */
- for (count = 0; count < 120; ++count) {
+ /* Wait up to 15 secs for completion */
+ for (count = 0; count < 15; ++count) {
if (cmd->SCp.sent_command) {
ret = SUCCESS;
break;
@@ -754,6 +827,12 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
int count;
u32 bus, cid;
int ret = FAILED;
+ int status = 0;
+ __le32 supported_options2 = 0;
+ bool is_mu_reset;
+ bool is_ignore_reset;
+ bool is_doorbell_reset;
+
bus = aac_logical_to_phys(scmd_channel(cmd));
cid = scmd_id(cmd);
@@ -817,8 +896,8 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
(fib_callback) aac_hba_callback,
(void *) cmd);
- /* Wait up to 2 minutes for completion */
- for (count = 0; count < 120; ++count) {
+ /* Wait up to 15 seconds for completion */
+ for (count = 0; count < 15; ++count) {
if (cmd->SCp.sent_command) {
ret = SUCCESS;
break;
@@ -826,12 +905,10 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
msleep(1000);
}
- if (ret != SUCCESS)
- pr_err("%s: Host adapter reset request timed out\n",
- AAC_DRIVERNAME);
+ if (ret == SUCCESS)
+ goto out;
+
} else {
- struct scsi_cmnd *command;
- unsigned long flags;
/* Mark the assoc. FIB to not complete, eh handler does this */
for (count = 0;
@@ -846,68 +923,42 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
}
}
+ }
- pr_err("%s: Host adapter reset request. SCSI hang ?\n",
- AAC_DRIVERNAME);
-
- count = aac_check_health(aac);
- if (count)
- return count;
- /*
- * Wait for all commands to complete to this specific
- * target (block maximum 60 seconds).
- */
- for (count = 60; count; --count) {
- int active = aac->in_reset;
-
- if (active == 0)
- __shost_for_each_device(dev, host) {
- spin_lock_irqsave(&dev->list_lock, flags);
- list_for_each_entry(command, &dev->cmd_list,
- list) {
- if ((command != cmd) &&
- (command->SCp.phase ==
- AAC_OWNER_FIRMWARE)) {
- active++;
- break;
- }
- }
- spin_unlock_irqrestore(&dev->list_lock, flags);
- if (active)
- break;
+ pr_err("%s: Host adapter reset request. SCSI hang ?\n", AAC_DRIVERNAME);
- }
- /*
- * We can exit If all the commands are complete
- */
- if (active == 0)
- return SUCCESS;
- ssleep(1);
- }
- pr_err("%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
+ /*
+ * Check the health of the controller
+ */
+ status = aac_adapter_check_health(aac);
+ if (status)
+ dev_err(&aac->pdev->dev, "Adapter health - %d\n", status);
- /*
- * This adapter needs a blind reset, only do so for
- * Adapters that support a register, instead of a commanded,
- * reset.
- */
- if (((aac->supplement_adapter_info.supported_options2 &
- AAC_OPTION_MU_RESET) ||
- (aac->supplement_adapter_info.supported_options2 &
- AAC_OPTION_DOORBELL_RESET)) &&
- aac_check_reset &&
- ((aac_check_reset != 1) ||
- !(aac->supplement_adapter_info.supported_options2 &
- AAC_OPTION_IGNORE_RESET))) {
- /* Bypass wait for command quiesce */
- aac_reset_adapter(aac, 2, IOP_HWSOFT_RESET);
- }
- ret = SUCCESS;
- }
+ count = get_num_of_incomplete_fibs(aac);
+ if (count == 0)
+ return SUCCESS;
+
+ /*
+ * Check if reset is supported by the firmware
+ */
+ supported_options2 = aac->supplement_adapter_info.supported_options2;
+ is_mu_reset = supported_options2 & AAC_OPTION_MU_RESET;
+ is_doorbell_reset = supported_options2 & AAC_OPTION_DOORBELL_RESET;
+ is_ignore_reset = supported_options2 & AAC_OPTION_IGNORE_RESET;
/*
- * Cause an immediate retry of the command with a ten second delay
- * after successful tur
+ * This adapter needs a blind reset, only do so for
+ * Adapters that support a register, instead of a commanded,
+ * reset.
*/
+ if ((is_mu_reset || is_doorbell_reset)
+ && aac_check_reset
+ && (aac_check_reset != -1 || !is_ignore_reset)) {
+ /* Bypass wait for command quiesce */
+ aac_reset_adapter(aac, 2, IOP_HWSOFT_RESET);
+ }
+ ret = SUCCESS;
+
+out:
return ret;
}
@@ -1365,10 +1416,7 @@ static void __aac_shutdown(struct aac_dev * aac)
kthread_stop(aac->thread);
}
aac_adapter_disable_int(aac);
- if (aac->pdev->device == PMC_DEVICE_S6 ||
- aac->pdev->device == PMC_DEVICE_S7 ||
- aac->pdev->device == PMC_DEVICE_S8 ||
- aac->pdev->device == PMC_DEVICE_S9) {
+ if (aac_is_src(aac)) {
if (aac->max_msix > 1) {
for (i = 0; i < aac->max_msix; i++) {
free_irq(pci_irq_vector(aac->pdev, i),
@@ -1403,6 +1451,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
int error = -ENODEV;
int unique_id = 0;
u64 dmamask;
+ int mask_bits = 0;
extern int aac_sync_mode;
/*
@@ -1426,18 +1475,32 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto out;
error = -ENODEV;
+ if (!(aac_drivers[index].quirks & AAC_QUIRK_SRC)) {
+ error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (error) {
+ dev_err(&pdev->dev, "PCI 32 BIT dma mask set failed");
+ goto out_disable_pdev;
+ }
+ }
+
/*
* If the quirk31 bit is set, the adapter needs adapter
* to driver communication memory to be allocated below 2gig
*/
- if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
+ if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) {
dmamask = DMA_BIT_MASK(31);
- else
+ mask_bits = 31;
+ } else {
dmamask = DMA_BIT_MASK(32);
+ mask_bits = 32;
+ }
- if (pci_set_dma_mask(pdev, dmamask) ||
- pci_set_consistent_dma_mask(pdev, dmamask))
+ error = pci_set_consistent_dma_mask(pdev, dmamask);
+ if (error) {
+ dev_err(&pdev->dev, "PCI %d B consistent dma mask set failed\n"
+ , mask_bits);
goto out_disable_pdev;
+ }
pci_set_master(pdev);
@@ -1501,15 +1564,6 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_deinit;
}
- /*
- * If we had set a smaller DMA mask earlier, set it to 4gig
- * now since the adapter can dma data to at least a 4gig
- * address space.
- */
- if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
- goto out_deinit;
-
aac->maximum_num_channels = aac_drivers[index].channels;
error = aac_get_adapter_info(aac);
if (error < 0)
@@ -1627,9 +1681,7 @@ static int aac_acquire_resources(struct aac_dev *dev)
aac_adapter_enable_int(dev);
- if ((dev->pdev->device == PMC_DEVICE_S7 ||
- dev->pdev->device == PMC_DEVICE_S8 ||
- dev->pdev->device == PMC_DEVICE_S9))
+ if (aac_is_src(dev))
aac_define_int_mode(dev);
if (dev->msi_enabled)
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index 7b0410e0f569..48c2b2b34b72 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -694,33 +694,52 @@ static void aac_dump_fw_fib_iop_reset(struct aac_dev *dev)
0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
}
-static void aac_send_iop_reset(struct aac_dev *dev, int bled)
+static bool aac_is_ctrl_up_and_running(struct aac_dev *dev)
{
- u32 var, reset_mask;
+ bool ctrl_up = true;
+ unsigned long status, start;
+ bool is_up = false;
- aac_dump_fw_fib_iop_reset(dev);
+ start = jiffies;
+ do {
+ schedule();
+ status = src_readl(dev, MUnit.OMR);
- bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
- 0, 0, 0, 0, 0, 0, &var,
- &reset_mask, NULL, NULL, NULL);
+ if (status == 0xffffffff)
+ status = 0;
- if ((bled || var != 0x00000001) && !dev->doorbell_mask)
- bled = -EINVAL;
- else if (dev->doorbell_mask) {
- reset_mask = dev->doorbell_mask;
- bled = 0;
- var = 0x00000001;
- }
+ if (status & KERNEL_BOOTING) {
+ start = jiffies;
+ continue;
+ }
+
+ if (time_after(jiffies, start+HZ*SOFT_RESET_TIME)) {
+ ctrl_up = false;
+ break;
+ }
+
+ is_up = status & KERNEL_UP_AND_RUNNING;
+
+ } while (!is_up);
+
+ return ctrl_up;
+}
+
+static void aac_notify_fw_of_iop_reset(struct aac_dev *dev)
+{
+ aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, 0, 0, 0, 0, 0, 0, NULL,
+ NULL, NULL, NULL, NULL);
+}
+
+static void aac_send_iop_reset(struct aac_dev *dev)
+{
+ aac_dump_fw_fib_iop_reset(dev);
+
+ aac_notify_fw_of_iop_reset(dev);
aac_set_intx_mode(dev);
- if (!bled && (dev->supplement_adapter_info.supported_options2 &
- AAC_OPTION_DOORBELL_RESET)) {
- src_writel(dev, MUnit.IDR, reset_mask);
- } else {
- src_writel(dev, MUnit.IDR, 0x100);
- }
- msleep(30000);
+ src_writel(dev, MUnit.IDR, IOP_SRC_RESET_MASK);
}
static void aac_send_hardware_soft_reset(struct aac_dev *dev)
@@ -735,14 +754,14 @@ static void aac_send_hardware_soft_reset(struct aac_dev *dev)
static int aac_src_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type)
{
- unsigned long status, start;
+ bool is_ctrl_up;
+ int ret = 0;
if (bled < 0)
goto invalid_out;
if (bled)
- pr_err("%s%d: adapter kernel panic'd %x.\n",
- dev->name, dev->id, bled);
+ dev_err(&dev->pdev->dev, "adapter kernel panic'd %x.\n", bled);
/*
* When there is a BlinkLED, IOP_RESET has not effect
@@ -752,48 +771,55 @@ static int aac_src_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type)
dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
- switch (reset_type) {
- case IOP_HWSOFT_RESET:
- aac_send_iop_reset(dev, bled);
+ dev_err(&dev->pdev->dev, "Controller reset type is %d\n", reset_type);
+
+ if (reset_type & HW_IOP_RESET) {
+ dev_info(&dev->pdev->dev, "Issuing IOP reset\n");
+ aac_send_iop_reset(dev);
+
/*
- * Check to see if KERNEL_UP_AND_RUNNING
- * Wait for the adapter to be up and running.
- * If !KERNEL_UP_AND_RUNNING issue HW Soft Reset
+ * Creates a delay or wait till up and running comes thru
*/
- status = src_readl(dev, MUnit.OMR);
- if (dev->sa_firmware
- && !(status & KERNEL_UP_AND_RUNNING)) {
- start = jiffies;
- do {
- status = src_readl(dev, MUnit.OMR);
- if (time_after(jiffies,
- start+HZ*SOFT_RESET_TIME)) {
- aac_send_hardware_soft_reset(dev);
- start = jiffies;
- }
- } while (!(status & KERNEL_UP_AND_RUNNING));
+ is_ctrl_up = aac_is_ctrl_up_and_running(dev);
+ if (!is_ctrl_up)
+ dev_err(&dev->pdev->dev, "IOP reset failed\n");
+ else {
+ dev_info(&dev->pdev->dev, "IOP reset succeded\n");
+ goto set_startup;
}
- break;
- case HW_SOFT_RESET:
- if (dev->sa_firmware) {
- aac_send_hardware_soft_reset(dev);
- aac_set_intx_mode(dev);
- }
- break;
- default:
- aac_send_iop_reset(dev, bled);
- break;
}
-invalid_out:
+ if (!dev->sa_firmware) {
+ dev_err(&dev->pdev->dev, "ARC Reset attempt failed\n");
+ ret = -ENODEV;
+ goto out;
+ }
- if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC)
- return -ENODEV;
+ if (reset_type & HW_SOFT_RESET) {
+ dev_info(&dev->pdev->dev, "Issuing SOFT reset\n");
+ aac_send_hardware_soft_reset(dev);
+ dev->msi_enabled = 0;
+ is_ctrl_up = aac_is_ctrl_up_and_running(dev);
+ if (!is_ctrl_up) {
+ dev_err(&dev->pdev->dev, "SOFT reset failed\n");
+ ret = -ENODEV;
+ goto out;
+ } else
+ dev_info(&dev->pdev->dev, "SOFT reset succeded\n");
+ }
+
+set_startup:
if (startup_timeout < 300)
startup_timeout = 300;
- return 0;
+out:
+ return ret;
+
+invalid_out:
+ if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC)
+ ret = -ENODEV;
+goto out;
}
/**
diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c
index dab195f04da7..c6e18140759c 100644
--- a/drivers/scsi/csiostor/csio_hw.c
+++ b/drivers/scsi/csiostor/csio_hw.c
@@ -794,18 +794,24 @@ csio_hw_dev_ready(struct csio_hw *hw)
{
uint32_t reg;
int cnt = 6;
+ int src_pf;
while (((reg = csio_rd_reg32(hw, PL_WHOAMI_A)) == 0xFFFFFFFF) &&
(--cnt != 0))
mdelay(100);
- if ((cnt == 0) && (((int32_t)(SOURCEPF_G(reg)) < 0) ||
- (SOURCEPF_G(reg) >= CSIO_MAX_PFN))) {
+ if (csio_is_t5(hw->pdev->device & CSIO_HW_CHIP_MASK))
+ src_pf = SOURCEPF_G(reg);
+ else
+ src_pf = T6_SOURCEPF_G(reg);
+
+ if ((cnt == 0) && (((int32_t)(src_pf) < 0) ||
+ (src_pf >= CSIO_MAX_PFN))) {
csio_err(hw, "PL_WHOAMI returned 0x%x, cnt:%d\n", reg, cnt);
return -EIO;
}
- hw->pfn = SOURCEPF_G(reg);
+ hw->pfn = src_pf;
return 0;
}
@@ -1581,10 +1587,16 @@ csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path)
unsigned int mtype = 0, maddr = 0;
uint32_t *cfg_data;
int value_to_add = 0;
+ const char *fw_cfg_file;
+
+ if (csio_is_t5(pci_dev->device & CSIO_HW_CHIP_MASK))
+ fw_cfg_file = FW_CFG_NAME_T5;
+ else
+ fw_cfg_file = FW_CFG_NAME_T6;
- if (request_firmware(&cf, FW_CFG_NAME_T5, dev) < 0) {
+ if (request_firmware(&cf, fw_cfg_file, dev) < 0) {
csio_err(hw, "could not find config file %s, err: %d\n",
- FW_CFG_NAME_T5, ret);
+ fw_cfg_file, ret);
return -ENOENT;
}
@@ -1623,9 +1635,8 @@ csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path)
ret = csio_memory_write(hw, mtype, maddr + size, 4, &last.word);
}
if (ret == 0) {
- csio_info(hw, "config file upgraded to %s\n",
- FW_CFG_NAME_T5);
- snprintf(path, 64, "%s%s", "/lib/firmware/", FW_CFG_NAME_T5);
+ csio_info(hw, "config file upgraded to %s\n", fw_cfg_file);
+ snprintf(path, 64, "%s%s", "/lib/firmware/", fw_cfg_file);
}
leave:
@@ -1886,6 +1897,19 @@ static struct fw_info fw_info_array[] = {
.intfver_iscsi = FW_INTFVER(T5, ISCSI),
.intfver_fcoe = FW_INTFVER(T5, FCOE),
},
+ }, {
+ .chip = CHELSIO_T6,
+ .fs_name = FW_CFG_NAME_T6,
+ .fw_mod_name = FW_FNAME_T6,
+ .fw_hdr = {
+ .chip = FW_HDR_CHIP_T6,
+ .fw_ver = __cpu_to_be32(FW_VERSION(T6)),
+ .intfver_nic = FW_INTFVER(T6, NIC),
+ .intfver_vnic = FW_INTFVER(T6, VNIC),
+ .intfver_ri = FW_INTFVER(T6, RI),
+ .intfver_iscsi = FW_INTFVER(T6, ISCSI),
+ .intfver_fcoe = FW_INTFVER(T6, FCOE),
+ },
}
};
@@ -2002,6 +2026,7 @@ csio_hw_flash_fw(struct csio_hw *hw, int *reset)
struct device *dev = &pci_dev->dev ;
const u8 *fw_data = NULL;
unsigned int fw_size = 0;
+ const char *fw_bin_file;
/* This is the firmware whose headers the driver was compiled
* against
@@ -2014,9 +2039,14 @@ csio_hw_flash_fw(struct csio_hw *hw, int *reset)
return -EINVAL;
}
- if (request_firmware(&fw, FW_FNAME_T5, dev) < 0) {
+ if (csio_is_t5(pci_dev->device & CSIO_HW_CHIP_MASK))
+ fw_bin_file = FW_FNAME_T5;
+ else
+ fw_bin_file = FW_FNAME_T6;
+
+ if (request_firmware(&fw, fw_bin_file, dev) < 0) {
csio_err(hw, "could not find firmware image %s, err: %d\n",
- FW_FNAME_T5, ret);
+ fw_bin_file, ret);
} else {
fw_data = fw->data;
fw_size = fw->size;
@@ -2241,9 +2271,14 @@ static void
csio_hw_intr_enable(struct csio_hw *hw)
{
uint16_t vec = (uint16_t)csio_get_mb_intr_idx(csio_hw_to_mbm(hw));
- uint32_t pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A));
+ u32 pf = 0;
uint32_t pl = csio_rd_reg32(hw, PL_INT_ENABLE_A);
+ if (csio_is_t5(hw->pdev->device & CSIO_HW_CHIP_MASK))
+ pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A));
+ else
+ pf = T6_SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A));
+
/*
* Set aivec for MSI/MSIX. PCIE_PF_CFG.INTXType is set up
* by FW, so do nothing for INTX.
@@ -2293,7 +2328,12 @@ csio_hw_intr_enable(struct csio_hw *hw)
void
csio_hw_intr_disable(struct csio_hw *hw)
{
- uint32_t pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A));
+ u32 pf = 0;
+
+ if (csio_is_t5(hw->pdev->device & CSIO_HW_CHIP_MASK))
+ pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A));
+ else
+ pf = T6_SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A));
if (!(hw->flags & CSIO_HWF_HW_INTR_ENABLED))
return;
@@ -2918,6 +2958,8 @@ static void csio_cplsw_intr_handler(struct csio_hw *hw)
*/
static void csio_le_intr_handler(struct csio_hw *hw)
{
+ enum chip_type chip = CHELSIO_CHIP_VERSION(hw->chip_id);
+
static struct intr_info le_intr_info[] = {
{ LIPMISS_F, "LE LIP miss", -1, 0 },
{ LIP0_F, "LE 0 LIP error", -1, 0 },
@@ -2927,7 +2969,18 @@ static void csio_le_intr_handler(struct csio_hw *hw)
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, LE_DB_INT_CAUSE_A, le_intr_info))
+ static struct intr_info t6_le_intr_info[] = {
+ { T6_LIPMISS_F, "LE LIP miss", -1, 0 },
+ { T6_LIP0_F, "LE 0 LIP error", -1, 0 },
+ { TCAMINTPERR_F, "LE parity error", -1, 1 },
+ { T6_UNKNOWNCMD_F, "LE unknown command", -1, 1 },
+ { SSRAMINTPERR_F, "LE request queue parity error", -1, 1 },
+ { 0, NULL, 0, 0 }
+ };
+
+ if (csio_handle_intr_status(hw, LE_DB_INT_CAUSE_A,
+ (chip == CHELSIO_T5) ?
+ le_intr_info : t6_le_intr_info))
csio_hw_fatal_err(hw);
}
diff --git a/drivers/scsi/csiostor/csio_hw_chip.h b/drivers/scsi/csiostor/csio_hw_chip.h
index b56a11d817be..aaabdbe11d88 100644
--- a/drivers/scsi/csiostor/csio_hw_chip.h
+++ b/drivers/scsi/csiostor/csio_hw_chip.h
@@ -39,11 +39,15 @@
/* Define MACRO values */
#define CSIO_HW_T5 0x5000
#define CSIO_T5_FCOE_ASIC 0x5600
+#define CSIO_HW_T6 0x6000
+#define CSIO_T6_FCOE_ASIC 0x6600
#define CSIO_HW_CHIP_MASK 0xF000
#define T5_REGMAP_SIZE (332 * 1024)
#define FW_FNAME_T5 "cxgb4/t5fw.bin"
#define FW_CFG_NAME_T5 "cxgb4/t5-config.txt"
+#define FW_FNAME_T6 "cxgb4/t6fw.bin"
+#define FW_CFG_NAME_T6 "cxgb4/t6-config.txt"
#define CHELSIO_CHIP_CODE(version, revision) (((version) << 4) | (revision))
#define CHELSIO_CHIP_FPGA 0x100
@@ -51,12 +55,17 @@
#define CHELSIO_CHIP_RELEASE(code) ((code) & 0xf)
#define CHELSIO_T5 0x5
+#define CHELSIO_T6 0x6
enum chip_type {
T5_A0 = CHELSIO_CHIP_CODE(CHELSIO_T5, 0),
T5_A1 = CHELSIO_CHIP_CODE(CHELSIO_T5, 1),
T5_FIRST_REV = T5_A0,
T5_LAST_REV = T5_A1,
+
+ T6_A0 = CHELSIO_CHIP_CODE(CHELSIO_T6, 0),
+ T6_FIRST_REV = T6_A0,
+ T6_LAST_REV = T6_A0,
};
static inline int csio_is_t5(uint16_t chip)
@@ -64,6 +73,11 @@ static inline int csio_is_t5(uint16_t chip)
return (chip == CSIO_HW_T5);
}
+static inline int csio_is_t6(uint16_t chip)
+{
+ return (chip == CSIO_HW_T6);
+}
+
/* Define MACRO DEFINITIONS */
#define CSIO_DEVICE(devid, idx) \
{ PCI_VENDOR_ID_CHELSIO, (devid), PCI_ANY_ID, PCI_ANY_ID, 0, 0, (idx) }
diff --git a/drivers/scsi/csiostor/csio_hw_t5.c b/drivers/scsi/csiostor/csio_hw_t5.c
index 3267f4f627c9..f24def6c6fd1 100644
--- a/drivers/scsi/csiostor/csio_hw_t5.c
+++ b/drivers/scsi/csiostor/csio_hw_t5.c
@@ -71,27 +71,6 @@ csio_t5_set_mem_win(struct csio_hw *hw, uint32_t win)
static void
csio_t5_pcie_intr_handler(struct csio_hw *hw)
{
- static struct intr_info sysbus_intr_info[] = {
- { RNPP_F, "RXNP array parity error", -1, 1 },
- { RPCP_F, "RXPC array parity error", -1, 1 },
- { RCIP_F, "RXCIF array parity error", -1, 1 },
- { RCCP_F, "Rx completions control array parity error", -1, 1 },
- { RFTP_F, "RXFT array parity error", -1, 1 },
- { 0, NULL, 0, 0 }
- };
- static struct intr_info pcie_port_intr_info[] = {
- { TPCP_F, "TXPC array parity error", -1, 1 },
- { TNPP_F, "TXNP array parity error", -1, 1 },
- { TFTP_F, "TXFT array parity error", -1, 1 },
- { TCAP_F, "TXCA array parity error", -1, 1 },
- { TCIP_F, "TXCIF array parity error", -1, 1 },
- { RCAP_F, "RXCA array parity error", -1, 1 },
- { OTDD_F, "outbound request TLP discarded", -1, 1 },
- { RDPE_F, "Rx data parity error", -1, 1 },
- { TDUE_F, "Tx uncorrectable data error", -1, 1 },
- { 0, NULL, 0, 0 }
- };
-
static struct intr_info pcie_intr_info[] = {
{ MSTGRPPERR_F, "Master Response Read Queue parity error",
-1, 1 },
@@ -133,13 +112,7 @@ csio_t5_pcie_intr_handler(struct csio_hw *hw)
};
int fat;
- fat = csio_handle_intr_status(hw,
- PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A,
- sysbus_intr_info) +
- csio_handle_intr_status(hw,
- PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS_A,
- pcie_port_intr_info) +
- csio_handle_intr_status(hw, PCIE_INT_CAUSE_A, pcie_intr_info);
+ fat = csio_handle_intr_status(hw, PCIE_INT_CAUSE_A, pcie_intr_info);
if (fat)
csio_hw_fatal_err(hw);
}
diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c
index dbe416ff46c2..ea0c31086cc6 100644
--- a/drivers/scsi/csiostor/csio_init.c
+++ b/drivers/scsi/csiostor/csio_init.c
@@ -952,8 +952,9 @@ static int csio_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
struct csio_hw *hw;
struct csio_lnode *ln;
- /* probe only T5 cards */
- if (!csio_is_t5((pdev->device & CSIO_HW_CHIP_MASK)))
+ /* probe only T5 and T6 cards */
+ if (!csio_is_t5((pdev->device & CSIO_HW_CHIP_MASK)) &&
+ !csio_is_t6((pdev->device & CSIO_HW_CHIP_MASK)))
return -ENODEV;
rv = csio_pci_init(pdev, &bars);
@@ -1253,3 +1254,4 @@ MODULE_LICENSE(CSIO_DRV_LICENSE);
MODULE_DEVICE_TABLE(pci, csio_pci_tbl);
MODULE_VERSION(CSIO_DRV_VERSION);
MODULE_FIRMWARE(FW_FNAME_T5);
+MODULE_FIRMWARE(FW_FNAME_T6);
diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c
index c00b2ff72b55..be5ee2d37815 100644
--- a/drivers/scsi/csiostor/csio_lnode.c
+++ b/drivers/scsi/csiostor/csio_lnode.c
@@ -238,14 +238,23 @@ csio_osname(uint8_t *buf, size_t buf_len)
}
static inline void
-csio_append_attrib(uint8_t **ptr, uint16_t type, uint8_t *val, uint16_t len)
+csio_append_attrib(uint8_t **ptr, uint16_t type, void *val, size_t val_len)
{
+ uint16_t len;
struct fc_fdmi_attr_entry *ae = (struct fc_fdmi_attr_entry *)*ptr;
+
+ if (WARN_ON(val_len > U16_MAX))
+ return;
+
+ len = val_len;
+
ae->type = htons(type);
len += 4; /* includes attribute type and length */
len = (len + 3) & ~3; /* should be multiple of 4 bytes */
ae->len = htons(len);
- memcpy(ae->value, val, len);
+ memcpy(ae->value, val, val_len);
+ if (len > val_len)
+ memset(ae->value + val_len, 0, len - val_len);
*ptr += len;
}
@@ -335,7 +344,7 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
numattrs++;
val = htonl(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_SUPPORTEDSPEED,
- (uint8_t *)&val,
+ &val,
FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN);
numattrs++;
@@ -346,23 +355,22 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
else
val = htonl(CSIO_HBA_PORTSPEED_UNKNOWN);
csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED,
- (uint8_t *)&val,
- FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN);
+ &val, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN);
numattrs++;
mfs = ln->ln_sparm.csp.sp_bb_data;
csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_MAXFRAMESIZE,
- (uint8_t *)&mfs, FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN);
+ &mfs, sizeof(mfs));
numattrs++;
strcpy(buf, "csiostor");
csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_OSDEVICENAME, buf,
- (uint16_t)strlen(buf));
+ strlen(buf));
numattrs++;
if (!csio_hostname(buf, sizeof(buf))) {
csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_HOSTNAME,
- buf, (uint16_t)strlen(buf));
+ buf, strlen(buf));
numattrs++;
}
attrib_blk->numattrs = htonl(numattrs);
@@ -444,33 +452,32 @@ csio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
strcpy(buf, "Chelsio Communications");
csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MANUFACTURER, buf,
- (uint16_t)strlen(buf));
+ strlen(buf));
numattrs++;
csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_SERIALNUMBER,
- hw->vpd.sn, (uint16_t)sizeof(hw->vpd.sn));
+ hw->vpd.sn, sizeof(hw->vpd.sn));
numattrs++;
csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MODEL, hw->vpd.id,
- (uint16_t)sizeof(hw->vpd.id));
+ sizeof(hw->vpd.id));
numattrs++;
csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MODELDESCRIPTION,
- hw->model_desc, (uint16_t)strlen(hw->model_desc));
+ hw->model_desc, strlen(hw->model_desc));
numattrs++;
csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_HARDWAREVERSION,
- hw->hw_ver, (uint16_t)sizeof(hw->hw_ver));
+ hw->hw_ver, sizeof(hw->hw_ver));
numattrs++;
csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_FIRMWAREVERSION,
- hw->fwrev_str, (uint16_t)strlen(hw->fwrev_str));
+ hw->fwrev_str, strlen(hw->fwrev_str));
numattrs++;
if (!csio_osname(buf, sizeof(buf))) {
csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_OSNAMEVERSION,
- buf, (uint16_t)strlen(buf));
+ buf, strlen(buf));
numattrs++;
}
csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MAXCTPAYLOAD,
- (uint8_t *)&maxpayload,
- FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN);
+ &maxpayload, FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN);
len = (uint32_t)(pld - (uint8_t *)cmd);
numattrs++;
attrib_blk->numattrs = htonl(numattrs);
@@ -1794,6 +1801,8 @@ csio_ln_mgmt_submit_req(struct csio_ioreq *io_req,
struct csio_mgmtm *mgmtm = csio_hw_to_mgmtm(hw);
int rv;
+ BUG_ON(pld_len > pld->len);
+
io_req->io_cbfn = io_cbfn; /* Upper layer callback handler */
io_req->fw_handle = (uintptr_t) (io_req);
io_req->eq_idx = mgmtm->eq_idx;
diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c
index e8f18174f2e9..c0a17789752f 100644
--- a/drivers/scsi/csiostor/csio_wr.c
+++ b/drivers/scsi/csiostor/csio_wr.c
@@ -480,12 +480,14 @@ csio_wr_iq_create(struct csio_hw *hw, void *priv, int iq_idx,
flq_idx = csio_q_iq_flq_idx(hw, iq_idx);
if (flq_idx != -1) {
+ enum chip_type chip = CHELSIO_CHIP_VERSION(hw->chip_id);
struct csio_q *flq = hw->wrm.q_arr[flq_idx];
iqp.fl0paden = 1;
iqp.fl0packen = flq->un.fl.packen ? 1 : 0;
iqp.fl0fbmin = X_FETCHBURSTMIN_64B;
- iqp.fl0fbmax = X_FETCHBURSTMAX_512B;
+ iqp.fl0fbmax = ((chip == CHELSIO_T5) ?
+ X_FETCHBURSTMAX_512B : X_FETCHBURSTMAX_256B);
iqp.fl0size = csio_q_size(hw, flq_idx) / CSIO_QCREDIT_SZ;
iqp.fl0addr = csio_q_pstart(hw, flq_idx);
}
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index bd7d39ecbd24..fb06974c88c1 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -1873,6 +1873,11 @@ int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)
tcp_task->dd_data = tdata;
task->hdr = NULL;
+ if (tdata->skb) {
+ kfree_skb(tdata->skb);
+ tdata->skb = NULL;
+ }
+
if (SKB_MAX_HEAD(cdev->skb_tx_rsvd) > (512 * MAX_SKB_FRAGS) &&
(opcode == ISCSI_OP_SCSI_DATA_OUT ||
(opcode == ISCSI_OP_SCSI_CMD &&
@@ -1890,6 +1895,7 @@ int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)
return -ENOMEM;
}
+ skb_get(tdata->skb);
skb_reserve(tdata->skb, cdev->skb_tx_rsvd);
task->hdr = (struct iscsi_hdr *)tdata->skb->data;
task->hdr_max = SKB_TX_ISCSI_PDU_HEADER_MAX; /* BHS + AHS */
@@ -2035,9 +2041,9 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
unsigned int datalen;
int err;
- if (!skb) {
+ if (!skb || cxgbi_skcb_test_flag(skb, SKCBF_TX_DONE)) {
log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX,
- "task 0x%p, skb NULL.\n", task);
+ "task 0x%p, skb 0x%p\n", task, skb);
return 0;
}
@@ -2050,7 +2056,6 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
}
datalen = skb->data_len;
- tdata->skb = NULL;
/* write ppod first if using ofldq to write ppod */
if (ttinfo->flags & CXGBI_PPOD_INFO_FLAG_VALID) {
@@ -2078,6 +2083,7 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
pdulen += ISCSI_DIGEST_SIZE;
task->conn->txdata_octets += pdulen;
+ cxgbi_skcb_set_flag(skb, SKCBF_TX_DONE);
return 0;
}
@@ -2086,7 +2092,6 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
"task 0x%p, skb 0x%p, len %u/%u, %d EAGAIN.\n",
task, skb, skb->len, skb->data_len, err);
/* reset skb to send when we are called again */
- tdata->skb = skb;
return err;
}
@@ -2094,7 +2099,8 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
"itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n",
task->itt, skb, skb->len, skb->data_len, err);
- kfree_skb(skb);
+ __kfree_skb(tdata->skb);
+ tdata->skb = NULL;
iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err);
iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED);
@@ -2113,8 +2119,10 @@ void cxgbi_cleanup_task(struct iscsi_task *task)
tcp_task->dd_data = NULL;
/* never reached the xmit task callout */
- if (tdata->skb)
- __kfree_skb(tdata->skb);
+ if (tdata->skb) {
+ kfree_skb(tdata->skb);
+ tdata->skb = NULL;
+ }
task_release_itt(task, task->hdr_itt);
memset(tdata, 0, sizeof(*tdata));
@@ -2714,6 +2722,9 @@ EXPORT_SYMBOL_GPL(cxgbi_attr_is_visible);
static int __init libcxgbi_init_module(void)
{
pr_info("%s", version);
+
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, cb) <
+ sizeof(struct cxgbi_skb_cb));
return 0;
}
diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h
index 18e0ea83d361..239462a75760 100644
--- a/drivers/scsi/cxgbi/libcxgbi.h
+++ b/drivers/scsi/cxgbi/libcxgbi.h
@@ -195,7 +195,8 @@ struct cxgbi_skb_rx_cb {
};
struct cxgbi_skb_tx_cb {
- void *l2t;
+ void *handle;
+ void *arp_err_handler;
struct sk_buff *wr_next;
};
@@ -203,6 +204,7 @@ enum cxgbi_skcb_flags {
SKCBF_TX_NEED_HDR, /* packet needs a header */
SKCBF_TX_MEM_WRITE, /* memory write */
SKCBF_TX_FLAG_COMPL, /* wr completion flag */
+ SKCBF_TX_DONE, /* skb tx done */
SKCBF_RX_COALESCED, /* received whole pdu */
SKCBF_RX_HDR, /* received pdu header */
SKCBF_RX_DATA, /* received pdu payload */
@@ -215,13 +217,13 @@ enum cxgbi_skcb_flags {
};
struct cxgbi_skb_cb {
- unsigned char ulp_mode;
- unsigned long flags;
- unsigned int seq;
union {
struct cxgbi_skb_rx_cb rx;
struct cxgbi_skb_tx_cb tx;
};
+ unsigned char ulp_mode;
+ unsigned long flags;
+ unsigned int seq;
};
#define CXGBI_SKB_CB(skb) ((struct cxgbi_skb_cb *)&((skb)->cb[0]))
@@ -374,11 +376,9 @@ static inline void cxgbi_sock_enqueue_wr(struct cxgbi_sock *csk,
cxgbi_skcb_tx_wr_next(skb) = NULL;
/*
* We want to take an extra reference since both us and the driver
- * need to free the packet before it's really freed. We know there's
- * just one user currently so we use atomic_set rather than skb_get
- * to avoid the atomic op.
+ * need to free the packet before it's really freed.
*/
- atomic_set(&skb->users, 2);
+ skb_get(skb);
if (!csk->wr_pending_head)
csk->wr_pending_head = skb;
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 3cbab8710e58..2ceff585f189 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -265,18 +265,16 @@ static unsigned int rdac_failover_get(struct rdac_controller *ctlr,
struct list_head *list,
unsigned char *cdb)
{
- struct scsi_device *sdev = ctlr->ms_sdev;
- struct rdac_dh_data *h = sdev->handler_data;
struct rdac_mode_common *common;
unsigned data_size;
struct rdac_queue_data *qdata;
u8 *lun_table;
- if (h->ctlr->use_ms10) {
+ if (ctlr->use_ms10) {
struct rdac_pg_expanded *rdac_pg;
data_size = sizeof(struct rdac_pg_expanded);
- rdac_pg = &h->ctlr->mode_select.expanded;
+ rdac_pg = &ctlr->mode_select.expanded;
memset(rdac_pg, 0, data_size);
common = &rdac_pg->common;
rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER + 0x40;
@@ -288,7 +286,7 @@ static unsigned int rdac_failover_get(struct rdac_controller *ctlr,
struct rdac_pg_legacy *rdac_pg;
data_size = sizeof(struct rdac_pg_legacy);
- rdac_pg = &h->ctlr->mode_select.legacy;
+ rdac_pg = &ctlr->mode_select.legacy;
memset(rdac_pg, 0, data_size);
common = &rdac_pg->common;
rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER;
@@ -304,7 +302,7 @@ static unsigned int rdac_failover_get(struct rdac_controller *ctlr,
}
/* Prepare the command. */
- if (h->ctlr->use_ms10) {
+ if (ctlr->use_ms10) {
cdb[0] = MODE_SELECT_10;
cdb[7] = data_size >> 8;
cdb[8] = data_size & 0xff;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index d622db502ec9..f720d3ced851 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -963,7 +963,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
HISI_SAS_INT_ABT_DEV, 0);
rc = hisi_sas_softreset_ata_disk(device);
}
- } else if (task->task_proto & SAS_PROTOCOL_SMP) {
+ } else if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SMP) {
/* SMP */
struct hisi_sas_slot *slot = task->lldd_task;
u32 tag = slot->idx;
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 73daace478cb..9934947073e6 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -60,7 +60,7 @@
* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.'
* with an optional trailing '-' followed by a byte value (0-255).
*/
-#define HPSA_DRIVER_VERSION "3.4.18-0"
+#define HPSA_DRIVER_VERSION "3.4.20-0"
#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
#define HPSA "hpsa"
@@ -258,7 +258,6 @@ static int hpsa_scan_finished(struct Scsi_Host *sh,
static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth);
static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
-static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd);
static int hpsa_slave_alloc(struct scsi_device *sdev);
static int hpsa_slave_configure(struct scsi_device *sdev);
static void hpsa_slave_destroy(struct scsi_device *sdev);
@@ -326,7 +325,7 @@ static inline bool hpsa_is_cmd_idle(struct CommandList *c)
static inline bool hpsa_is_pending_event(struct CommandList *c)
{
- return c->abort_pending || c->reset_pending;
+ return c->reset_pending;
}
/* extract sense key, asc, and ascq from sense data. -1 means invalid. */
@@ -581,12 +580,6 @@ static u32 soft_unresettable_controller[] = {
0x409D0E11, /* Smart Array 6400 EM */
};
-static u32 needs_abort_tags_swizzled[] = {
- 0x323D103C, /* Smart Array P700m */
- 0x324a103C, /* Smart Array P712m */
- 0x324b103C, /* SmartArray P711m */
-};
-
static int board_id_in_array(u32 a[], int nelems, u32 board_id)
{
int i;
@@ -615,12 +608,6 @@ static int ctlr_is_resettable(u32 board_id)
ctlr_is_soft_resettable(board_id);
}
-static int ctlr_needs_abort_tags_swizzled(u32 board_id)
-{
- return board_id_in_array(needs_abort_tags_swizzled,
- ARRAY_SIZE(needs_abort_tags_swizzled), board_id);
-}
-
static ssize_t host_show_resettable(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -928,8 +915,8 @@ static struct device_attribute *hpsa_shost_attrs[] = {
NULL,
};
-#define HPSA_NRESERVED_CMDS (HPSA_CMDS_RESERVED_FOR_ABORTS + \
- HPSA_CMDS_RESERVED_FOR_DRIVER + HPSA_MAX_CONCURRENT_PASSTHRUS)
+#define HPSA_NRESERVED_CMDS (HPSA_CMDS_RESERVED_FOR_DRIVER +\
+ HPSA_MAX_CONCURRENT_PASSTHRUS)
static struct scsi_host_template hpsa_driver_template = {
.module = THIS_MODULE,
@@ -941,7 +928,6 @@ static struct scsi_host_template hpsa_driver_template = {
.change_queue_depth = hpsa_change_queue_depth,
.this_id = -1,
.use_clustering = ENABLE_CLUSTERING,
- .eh_abort_handler = hpsa_eh_abort_handler,
.eh_device_reset_handler = hpsa_eh_device_reset_handler,
.ioctl = hpsa_ioctl,
.slave_alloc = hpsa_slave_alloc,
@@ -1110,6 +1096,7 @@ static int is_firmware_flash_cmd(u8 *cdb)
*/
#define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ)
#define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ)
+#define HPSA_EVENT_MONITOR_INTERVAL (15 * HZ)
static void dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h,
struct CommandList *c)
{
@@ -1859,10 +1846,13 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h,
* A reset can cause a device status to change
* re-schedule the scan to see what happened.
*/
+ spin_lock_irqsave(&h->reset_lock, flags);
if (h->reset_in_progress) {
h->drv_req_rescan = 1;
+ spin_unlock_irqrestore(&h->reset_lock, flags);
return;
}
+ spin_unlock_irqrestore(&h->reset_lock, flags);
added = kzalloc(sizeof(*added) * HPSA_MAX_DEVICES, GFP_KERNEL);
removed = kzalloc(sizeof(*removed) * HPSA_MAX_DEVICES, GFP_KERNEL);
@@ -2066,10 +2056,13 @@ static int hpsa_slave_configure(struct scsi_device *sdev)
sd = sdev->hostdata;
sdev->no_uld_attach = !sd || !sd->expose_device;
- if (sd)
- queue_depth = sd->queue_depth != 0 ?
- sd->queue_depth : sdev->host->can_queue;
- else
+ if (sd) {
+ if (sd->external)
+ queue_depth = EXTERNAL_QD;
+ else
+ queue_depth = sd->queue_depth != 0 ?
+ sd->queue_depth : sdev->host->can_queue;
+ } else
queue_depth = sdev->host->can_queue;
scsi_change_queue_depth(sdev, queue_depth);
@@ -2354,26 +2347,12 @@ static void hpsa_cmd_resolve_events(struct ctlr_info *h,
bool do_wake = false;
/*
- * Prevent the following race in the abort handler:
- *
- * 1. LLD is requested to abort a SCSI command
- * 2. The SCSI command completes
- * 3. The struct CommandList associated with step 2 is made available
- * 4. New I/O request to LLD to another LUN re-uses struct CommandList
- * 5. Abort handler follows scsi_cmnd->host_scribble and
- * finds struct CommandList and tries to aborts it
- * Now we have aborted the wrong command.
- *
- * Reset c->scsi_cmd here so that the abort or reset handler will know
+ * Reset c->scsi_cmd here so that the reset handler will know
* this command has completed. Then, check to see if the handler is
* waiting for this command, and, if so, wake it.
*/
c->scsi_cmd = SCSI_CMD_IDLE;
mb(); /* Declare command idle before checking for pending events. */
- if (c->abort_pending) {
- do_wake = true;
- c->abort_pending = false;
- }
if (c->reset_pending) {
unsigned long flags;
struct hpsa_scsi_dev_t *dev;
@@ -2416,20 +2395,6 @@ static void hpsa_retry_cmd(struct ctlr_info *h, struct CommandList *c)
queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work);
}
-static void hpsa_set_scsi_cmd_aborted(struct scsi_cmnd *cmd)
-{
- cmd->result = DID_ABORT << 16;
-}
-
-static void hpsa_cmd_abort_and_free(struct ctlr_info *h, struct CommandList *c,
- struct scsi_cmnd *cmd)
-{
- hpsa_set_scsi_cmd_aborted(cmd);
- dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n",
- c->Request.CDB, c->err_info->ScsiStatus);
- hpsa_cmd_resolve_and_free(h, c);
-}
-
static void process_ioaccel2_completion(struct ctlr_info *h,
struct CommandList *c, struct scsi_cmnd *cmd,
struct hpsa_scsi_dev_t *dev)
@@ -2554,12 +2519,9 @@ static void complete_scsi_command(struct CommandList *cp)
return hpsa_cmd_free_and_done(h, cp, cmd);
}
- if ((unlikely(hpsa_is_pending_event(cp)))) {
+ if ((unlikely(hpsa_is_pending_event(cp))))
if (cp->reset_pending)
return hpsa_cmd_free_and_done(h, cp, cmd);
- if (cp->abort_pending)
- return hpsa_cmd_abort_and_free(h, cp, cmd);
- }
if (cp->cmd_type == CMD_IOACCEL2)
return process_ioaccel2_completion(h, cp, cmd, dev);
@@ -2679,8 +2641,8 @@ static void complete_scsi_command(struct CommandList *cp)
cp->Request.CDB);
break;
case CMD_ABORTED:
- /* Return now to avoid calling scsi_done(). */
- return hpsa_cmd_abort_and_free(h, cp, cmd);
+ cmd->result = DID_ABORT << 16;
+ break;
case CMD_ABORT_FAILED:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "CDB %16phN : abort failed\n",
@@ -3090,7 +3052,7 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
if (unlikely(rc))
atomic_set(&dev->reset_cmds_out, 0);
else
- wait_for_device_to_become_ready(h, scsi3addr, 0);
+ rc = wait_for_device_to_become_ready(h, scsi3addr, 0);
mutex_unlock(&h->reset_mutex);
return rc;
@@ -3353,6 +3315,11 @@ static void hpsa_get_enclosure_info(struct ctlr_info *h,
bmic_device_index = GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]);
+ if (encl_dev->target == -1 || encl_dev->lun == -1) {
+ rc = IO_OK;
+ goto out;
+ }
+
if (bmic_device_index == 0xFF00 || MASKED_DEVICE(&rle->lunid[0])) {
rc = IO_OK;
goto out;
@@ -3781,53 +3748,6 @@ static unsigned char hpsa_volume_offline(struct ctlr_info *h,
return HPSA_LV_OK;
}
-/*
- * Find out if a logical device supports aborts by simply trying one.
- * Smart Array may claim not to support aborts on logical drives, but
- * if a MSA2000 * is connected, the drives on that will be presented
- * by the Smart Array as logical drives, and aborts may be sent to
- * those devices successfully. So the simplest way to find out is
- * to simply try an abort and see how the device responds.
- */
-static int hpsa_device_supports_aborts(struct ctlr_info *h,
- unsigned char *scsi3addr)
-{
- struct CommandList *c;
- struct ErrorInfo *ei;
- int rc = 0;
-
- u64 tag = (u64) -1; /* bogus tag */
-
- /* Assume that physical devices support aborts */
- if (!is_logical_dev_addr_mode(scsi3addr))
- return 1;
-
- c = cmd_alloc(h);
-
- (void) fill_cmd(c, HPSA_ABORT_MSG, h, &tag, 0, 0, scsi3addr, TYPE_MSG);
- (void) hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
- DEFAULT_TIMEOUT);
- /* no unmap needed here because no data xfer. */
- ei = c->err_info;
- switch (ei->CommandStatus) {
- case CMD_INVALID:
- rc = 0;
- break;
- case CMD_UNABORTABLE:
- case CMD_ABORT_FAILED:
- rc = 1;
- break;
- case CMD_TMF_STATUS:
- rc = hpsa_evaluate_tmf_status(h, c);
- break;
- default:
- rc = 0;
- break;
- }
- cmd_free(h, c);
- return rc;
-}
-
static int hpsa_update_device_info(struct ctlr_info *h,
unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device,
unsigned char *is_OBDR_device)
@@ -3907,6 +3827,9 @@ static int hpsa_update_device_info(struct ctlr_info *h,
this_device->queue_depth = h->nr_cmds;
}
+ if (this_device->external)
+ this_device->queue_depth = EXTERNAL_QD;
+
if (is_OBDR_device) {
/* See if this is a One-Button-Disaster-Recovery device
* by looking for "$DR-10" at offset 43 in inquiry data.
@@ -3924,31 +3847,6 @@ bail_out:
return rc;
}
-static void hpsa_update_device_supports_aborts(struct ctlr_info *h,
- struct hpsa_scsi_dev_t *dev, u8 *scsi3addr)
-{
- unsigned long flags;
- int rc, entry;
- /*
- * See if this device supports aborts. If we already know
- * the device, we already know if it supports aborts, otherwise
- * we have to find out if it supports aborts by trying one.
- */
- spin_lock_irqsave(&h->devlock, flags);
- rc = hpsa_scsi_find_entry(dev, h->dev, h->ndevices, &entry);
- if ((rc == DEVICE_SAME || rc == DEVICE_UPDATED) &&
- entry >= 0 && entry < h->ndevices) {
- dev->supports_aborts = h->dev[entry]->supports_aborts;
- spin_unlock_irqrestore(&h->devlock, flags);
- } else {
- spin_unlock_irqrestore(&h->devlock, flags);
- dev->supports_aborts =
- hpsa_device_supports_aborts(h, scsi3addr);
- if (dev->supports_aborts < 0)
- dev->supports_aborts = 0;
- }
-}
-
/*
* Helper function to assign bus, target, lun mapping of devices.
* Logical drive target and lun are assigned at this time, but
@@ -3986,35 +3884,6 @@ static void figure_bus_target_lun(struct ctlr_info *h,
0, lunid & 0x3fff);
}
-
-/*
- * Get address of physical disk used for an ioaccel2 mode command:
- * 1. Extract ioaccel2 handle from the command.
- * 2. Find a matching ioaccel2 handle from list of physical disks.
- * 3. Return:
- * 1 and set scsi3addr to address of matching physical
- * 0 if no matching physical disk was found.
- */
-static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
- struct CommandList *ioaccel2_cmd_to_abort, unsigned char *scsi3addr)
-{
- struct io_accel2_cmd *c2 =
- &h->ioaccel2_cmd_pool[ioaccel2_cmd_to_abort->cmdindex];
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&h->devlock, flags);
- for (i = 0; i < h->ndevices; i++)
- if (h->dev[i]->ioaccel_handle == le32_to_cpu(c2->scsi_nexus)) {
- memcpy(scsi3addr, h->dev[i]->scsi3addr,
- sizeof(h->dev[i]->scsi3addr));
- spin_unlock_irqrestore(&h->devlock, flags);
- return 1;
- }
- spin_unlock_irqrestore(&h->devlock, flags);
- return 0;
-}
-
static int figure_external_status(struct ctlr_info *h, int raid_ctlr_position,
int i, int nphysicals, int nlocal_logicals)
{
@@ -4115,14 +3984,6 @@ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h,
int rc;
struct ext_report_lun_entry *rle;
- /*
- * external targets don't support BMIC
- */
- if (dev->external) {
- dev->queue_depth = 7;
- return;
- }
-
rle = &rlep->LUN[rle_index];
dev->ioaccel_handle = rle->ioaccel_handle;
@@ -4387,7 +4248,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
}
figure_bus_target_lun(h, lunaddrbytes, tmpdevice);
- hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes);
this_device = currentsd[ncurrent];
/* Turn on discovery_polling if there are ext target devices.
@@ -4584,7 +4444,55 @@ sglist_finished:
return 0;
}
-#define IO_ACCEL_INELIGIBLE (1)
+#define BUFLEN 128
+static inline void warn_zero_length_transfer(struct ctlr_info *h,
+ u8 *cdb, int cdb_len,
+ const char *func)
+{
+ char buf[BUFLEN];
+ int outlen;
+ int i;
+
+ outlen = scnprintf(buf, BUFLEN,
+ "%s: Blocking zero-length request: CDB:", func);
+ for (i = 0; i < cdb_len; i++)
+ outlen += scnprintf(buf+outlen, BUFLEN - outlen,
+ "%02hhx", cdb[i]);
+ dev_warn(&h->pdev->dev, "%s\n", buf);
+}
+
+#define IO_ACCEL_INELIGIBLE 1
+/* zero-length transfers trigger hardware errors. */
+static bool is_zero_length_transfer(u8 *cdb)
+{
+ u32 block_cnt;
+
+ /* Block zero-length transfer sizes on certain commands. */
+ switch (cdb[0]) {
+ case READ_10:
+ case WRITE_10:
+ case VERIFY: /* 0x2F */
+ case WRITE_VERIFY: /* 0x2E */
+ block_cnt = get_unaligned_be16(&cdb[7]);
+ break;
+ case READ_12:
+ case WRITE_12:
+ case VERIFY_12: /* 0xAF */
+ case WRITE_VERIFY_12: /* 0xAE */
+ block_cnt = get_unaligned_be32(&cdb[6]);
+ break;
+ case READ_16:
+ case WRITE_16:
+ case VERIFY_16: /* 0x8F */
+ block_cnt = get_unaligned_be32(&cdb[10]);
+ break;
+ default:
+ return false;
+ }
+
+ return block_cnt == 0;
+}
+
static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
{
int is_write = 0;
@@ -4651,6 +4559,12 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX);
+ if (is_zero_length_transfer(cdb)) {
+ warn_zero_length_transfer(h, cdb, cdb_len, __func__);
+ atomic_dec(&phys_disk->ioaccel_cmds_out);
+ return IO_ACCEL_INELIGIBLE;
+ }
+
if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
atomic_dec(&phys_disk->ioaccel_cmds_out);
return IO_ACCEL_INELIGIBLE;
@@ -4815,6 +4729,12 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
+ if (is_zero_length_transfer(cdb)) {
+ warn_zero_length_transfer(h, cdb, cdb_len, __func__);
+ atomic_dec(&phys_disk->ioaccel_cmds_out);
+ return IO_ACCEL_INELIGIBLE;
+ }
+
if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
atomic_dec(&phys_disk->ioaccel_cmds_out);
return IO_ACCEL_INELIGIBLE;
@@ -5460,9 +5380,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
return hpsa_cmd_free_and_done(c->h, c, cmd);
}
if (c->reset_pending)
- return hpsa_cmd_resolve_and_free(c->h, c);
- if (c->abort_pending)
- return hpsa_cmd_abort_and_free(c->h, c, cmd);
+ return hpsa_cmd_free_and_done(c->h, c, cmd);
if (c->cmd_type == CMD_IOACCEL2) {
struct ctlr_info *h = c->h;
struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
@@ -5613,10 +5531,14 @@ static void hpsa_scan_start(struct Scsi_Host *sh)
/*
* Do the scan after a reset completion
*/
+ spin_lock_irqsave(&h->reset_lock, flags);
if (h->reset_in_progress) {
h->drv_req_rescan = 1;
+ spin_unlock_irqrestore(&h->reset_lock, flags);
+ hpsa_scan_complete(h);
return;
}
+ spin_unlock_irqrestore(&h->reset_lock, flags);
hpsa_update_scsi_devices(h);
@@ -5828,24 +5750,37 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h,
*/
static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
{
- int rc;
+ int rc = SUCCESS;
struct ctlr_info *h;
struct hpsa_scsi_dev_t *dev;
u8 reset_type;
char msg[48];
+ unsigned long flags;
/* find the controller to which the command to be aborted was sent */
h = sdev_to_hba(scsicmd->device);
if (h == NULL) /* paranoia */
return FAILED;
- if (lockup_detected(h))
- return FAILED;
+ spin_lock_irqsave(&h->reset_lock, flags);
+ h->reset_in_progress = 1;
+ spin_unlock_irqrestore(&h->reset_lock, flags);
+
+ if (lockup_detected(h)) {
+ rc = FAILED;
+ goto return_reset_status;
+ }
dev = scsicmd->device->hostdata;
if (!dev) {
dev_err(&h->pdev->dev, "%s: device lookup failed\n", __func__);
- return FAILED;
+ rc = FAILED;
+ goto return_reset_status;
+ }
+
+ if (dev->devtype == TYPE_ENCLOSURE) {
+ rc = SUCCESS;
+ goto return_reset_status;
}
/* if controller locked up, we can guarantee command won't complete */
@@ -5854,7 +5789,8 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
"cmd %d RESET FAILED, lockup detected",
hpsa_get_cmd_index(scsicmd));
hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
- return FAILED;
+ rc = FAILED;
+ goto return_reset_status;
}
/* this reset request might be the result of a lockup; check */
@@ -5863,12 +5799,15 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
"cmd %d RESET FAILED, new lockup detected",
hpsa_get_cmd_index(scsicmd));
hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
- return FAILED;
+ rc = FAILED;
+ goto return_reset_status;
}
/* Do not attempt on controller */
- if (is_hba_lunid(dev->scsi3addr))
- return SUCCESS;
+ if (is_hba_lunid(dev->scsi3addr)) {
+ rc = SUCCESS;
+ goto return_reset_status;
+ }
if (is_logical_dev_addr_mode(dev->scsi3addr))
reset_type = HPSA_DEVICE_RESET_MSG;
@@ -5879,446 +5818,26 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ");
hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
- h->reset_in_progress = 1;
-
/* send a reset to the SCSI LUN which the command was sent to */
rc = hpsa_do_reset(h, dev, dev->scsi3addr, reset_type,
DEFAULT_REPLY_QUEUE);
+ if (rc == 0)
+ rc = SUCCESS;
+ else
+ rc = FAILED;
+
sprintf(msg, "reset %s %s",
reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ",
- rc == 0 ? "completed successfully" : "failed");
+ rc == SUCCESS ? "completed successfully" : "failed");
hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
- h->reset_in_progress = 0;
- return rc == 0 ? SUCCESS : FAILED;
-}
-
-static void swizzle_abort_tag(u8 *tag)
-{
- u8 original_tag[8];
-
- memcpy(original_tag, tag, 8);
- tag[0] = original_tag[3];
- tag[1] = original_tag[2];
- tag[2] = original_tag[1];
- tag[3] = original_tag[0];
- tag[4] = original_tag[7];
- tag[5] = original_tag[6];
- tag[6] = original_tag[5];
- tag[7] = original_tag[4];
-}
-
-static void hpsa_get_tag(struct ctlr_info *h,
- struct CommandList *c, __le32 *taglower, __le32 *tagupper)
-{
- u64 tag;
- if (c->cmd_type == CMD_IOACCEL1) {
- struct io_accel1_cmd *cm1 = (struct io_accel1_cmd *)
- &h->ioaccel_cmd_pool[c->cmdindex];
- tag = le64_to_cpu(cm1->tag);
- *tagupper = cpu_to_le32(tag >> 32);
- *taglower = cpu_to_le32(tag);
- return;
- }
- if (c->cmd_type == CMD_IOACCEL2) {
- struct io_accel2_cmd *cm2 = (struct io_accel2_cmd *)
- &h->ioaccel2_cmd_pool[c->cmdindex];
- /* upper tag not used in ioaccel2 mode */
- memset(tagupper, 0, sizeof(*tagupper));
- *taglower = cm2->Tag;
- return;
- }
- tag = le64_to_cpu(c->Header.tag);
- *tagupper = cpu_to_le32(tag >> 32);
- *taglower = cpu_to_le32(tag);
-}
-
-static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
- struct CommandList *abort, int reply_queue)
-{
- int rc = IO_OK;
- struct CommandList *c;
- struct ErrorInfo *ei;
- __le32 tagupper, taglower;
-
- c = cmd_alloc(h);
-
- /* fill_cmd can't fail here, no buffer to map */
- (void) fill_cmd(c, HPSA_ABORT_MSG, h, &abort->Header.tag,
- 0, 0, scsi3addr, TYPE_MSG);
- if (h->needs_abort_tags_swizzled)
- swizzle_abort_tag(&c->Request.CDB[4]);
- (void) hpsa_scsi_do_simple_cmd(h, c, reply_queue, DEFAULT_TIMEOUT);
- hpsa_get_tag(h, abort, &taglower, &tagupper);
- dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd(abort) completed.\n",
- __func__, tagupper, taglower);
- /* no unmap needed here because no data xfer. */
-
- ei = c->err_info;
- switch (ei->CommandStatus) {
- case CMD_SUCCESS:
- break;
- case CMD_TMF_STATUS:
- rc = hpsa_evaluate_tmf_status(h, c);
- break;
- case CMD_UNABORTABLE: /* Very common, don't make noise. */
- rc = -1;
- break;
- default:
- dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: interpreting error.\n",
- __func__, tagupper, taglower);
- hpsa_scsi_interpret_error(h, c);
- rc = -1;
- break;
- }
- cmd_free(h, c);
- dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n",
- __func__, tagupper, taglower);
- return rc;
-}
-
-static void setup_ioaccel2_abort_cmd(struct CommandList *c, struct ctlr_info *h,
- struct CommandList *command_to_abort, int reply_queue)
-{
- struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
- struct hpsa_tmf_struct *ac = (struct hpsa_tmf_struct *) c2;
- struct io_accel2_cmd *c2a =
- &h->ioaccel2_cmd_pool[command_to_abort->cmdindex];
- struct scsi_cmnd *scmd = command_to_abort->scsi_cmd;
- struct hpsa_scsi_dev_t *dev = scmd->device->hostdata;
- if (!dev)
- return;
-
- /*
- * We're overlaying struct hpsa_tmf_struct on top of something which
- * was allocated as a struct io_accel2_cmd, so we better be sure it
- * actually fits, and doesn't overrun the error info space.
- */
- BUILD_BUG_ON(sizeof(struct hpsa_tmf_struct) >
- sizeof(struct io_accel2_cmd));
- BUG_ON(offsetof(struct io_accel2_cmd, error_data) <
- offsetof(struct hpsa_tmf_struct, error_len) +
- sizeof(ac->error_len));
-
- c->cmd_type = IOACCEL2_TMF;
- c->scsi_cmd = SCSI_CMD_BUSY;
-
- /* Adjust the DMA address to point to the accelerated command buffer */
- c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle +
- (c->cmdindex * sizeof(struct io_accel2_cmd));
- BUG_ON(c->busaddr & 0x0000007F);
-
- memset(ac, 0, sizeof(*c2)); /* yes this is correct */
- ac->iu_type = IOACCEL2_IU_TMF_TYPE;
- ac->reply_queue = reply_queue;
- ac->tmf = IOACCEL2_TMF_ABORT;
- ac->it_nexus = cpu_to_le32(dev->ioaccel_handle);
- memset(ac->lun_id, 0, sizeof(ac->lun_id));
- ac->tag = cpu_to_le64(c->cmdindex << DIRECT_LOOKUP_SHIFT);
- ac->abort_tag = cpu_to_le64(le32_to_cpu(c2a->Tag));
- ac->error_ptr = cpu_to_le64(c->busaddr +
- offsetof(struct io_accel2_cmd, error_data));
- ac->error_len = cpu_to_le32(sizeof(c2->error_data));
-}
-
-/* ioaccel2 path firmware cannot handle abort task requests.
- * Change abort requests to physical target reset, and send to the
- * address of the physical disk used for the ioaccel 2 command.
- * Return 0 on success (IO_OK)
- * -1 on failure
- */
-
-static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
- unsigned char *scsi3addr, struct CommandList *abort, int reply_queue)
-{
- int rc = IO_OK;
- struct scsi_cmnd *scmd; /* scsi command within request being aborted */
- struct hpsa_scsi_dev_t *dev; /* device to which scsi cmd was sent */
- unsigned char phys_scsi3addr[8]; /* addr of phys disk with volume */
- unsigned char *psa = &phys_scsi3addr[0];
-
- /* Get a pointer to the hpsa logical device. */
- scmd = abort->scsi_cmd;
- dev = (struct hpsa_scsi_dev_t *)(scmd->device->hostdata);
- if (dev == NULL) {
- dev_warn(&h->pdev->dev,
- "Cannot abort: no device pointer for command.\n");
- return -1; /* not abortable */
- }
-
- if (h->raid_offload_debug > 0)
- dev_info(&h->pdev->dev,
- "scsi %d:%d:%d:%d %s scsi3addr 0x%8phN\n",
- h->scsi_host->host_no, dev->bus, dev->target, dev->lun,
- "Reset as abort", scsi3addr);
-
- if (!dev->offload_enabled) {
- dev_warn(&h->pdev->dev,
- "Can't abort: device is not operating in HP SSD Smart Path mode.\n");
- return -1; /* not abortable */
- }
-
- /* Incoming scsi3addr is logical addr. We need physical disk addr. */
- if (!hpsa_get_pdisk_of_ioaccel2(h, abort, psa)) {
- dev_warn(&h->pdev->dev, "Can't abort: Failed lookup of physical address.\n");
- return -1; /* not abortable */
- }
-
- /* send the reset */
- if (h->raid_offload_debug > 0)
- dev_info(&h->pdev->dev,
- "Reset as abort: Resetting physical device at scsi3addr 0x%8phN\n",
- psa);
- rc = hpsa_do_reset(h, dev, psa, HPSA_PHYS_TARGET_RESET, reply_queue);
- if (rc != 0) {
- dev_warn(&h->pdev->dev,
- "Reset as abort: Failed on physical device at scsi3addr 0x%8phN\n",
- psa);
- return rc; /* failed to reset */
- }
-
- /* wait for device to recover */
- if (wait_for_device_to_become_ready(h, psa, reply_queue) != 0) {
- dev_warn(&h->pdev->dev,
- "Reset as abort: Failed: Device never recovered from reset: 0x%8phN\n",
- psa);
- return -1; /* failed to recover */
- }
-
- /* device recovered */
- dev_info(&h->pdev->dev,
- "Reset as abort: Device recovered from reset: scsi3addr 0x%8phN\n",
- psa);
-
- return rc; /* success */
-}
-
-static int hpsa_send_abort_ioaccel2(struct ctlr_info *h,
- struct CommandList *abort, int reply_queue)
-{
- int rc = IO_OK;
- struct CommandList *c;
- __le32 taglower, tagupper;
- struct hpsa_scsi_dev_t *dev;
- struct io_accel2_cmd *c2;
-
- dev = abort->scsi_cmd->device->hostdata;
- if (!dev)
- return -1;
-
- if (!dev->offload_enabled && !dev->hba_ioaccel_enabled)
- return -1;
-
- c = cmd_alloc(h);
- setup_ioaccel2_abort_cmd(c, h, abort, reply_queue);
- c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
- (void) hpsa_scsi_do_simple_cmd(h, c, reply_queue, DEFAULT_TIMEOUT);
- hpsa_get_tag(h, abort, &taglower, &tagupper);
- dev_dbg(&h->pdev->dev,
- "%s: Tag:0x%08x:%08x: do_simple_cmd(ioaccel2 abort) completed.\n",
- __func__, tagupper, taglower);
- /* no unmap needed here because no data xfer. */
-
- dev_dbg(&h->pdev->dev,
- "%s: Tag:0x%08x:%08x: abort service response = 0x%02x.\n",
- __func__, tagupper, taglower, c2->error_data.serv_response);
- switch (c2->error_data.serv_response) {
- case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE:
- case IOACCEL2_SERV_RESPONSE_TMF_SUCCESS:
- rc = 0;
- break;
- case IOACCEL2_SERV_RESPONSE_TMF_REJECTED:
- case IOACCEL2_SERV_RESPONSE_FAILURE:
- case IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN:
- rc = -1;
- break;
- default:
- dev_warn(&h->pdev->dev,
- "%s: Tag:0x%08x:%08x: unknown abort service response 0x%02x\n",
- __func__, tagupper, taglower,
- c2->error_data.serv_response);
- rc = -1;
- }
- cmd_free(h, c);
- dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__,
- tagupper, taglower);
+return_reset_status:
+ spin_lock_irqsave(&h->reset_lock, flags);
+ h->reset_in_progress = 0;
+ spin_unlock_irqrestore(&h->reset_lock, flags);
return rc;
}
-static int hpsa_send_abort_both_ways(struct ctlr_info *h,
- struct hpsa_scsi_dev_t *dev, struct CommandList *abort, int reply_queue)
-{
- /*
- * ioccelerator mode 2 commands should be aborted via the
- * accelerated path, since RAID path is unaware of these commands,
- * but not all underlying firmware can handle abort TMF.
- * Change abort to physical device reset when abort TMF is unsupported.
- */
- if (abort->cmd_type == CMD_IOACCEL2) {
- if ((HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags) ||
- dev->physical_device)
- return hpsa_send_abort_ioaccel2(h, abort,
- reply_queue);
- else
- return hpsa_send_reset_as_abort_ioaccel2(h,
- dev->scsi3addr,
- abort, reply_queue);
- }
- return hpsa_send_abort(h, dev->scsi3addr, abort, reply_queue);
-}
-
-/* Find out which reply queue a command was meant to return on */
-static int hpsa_extract_reply_queue(struct ctlr_info *h,
- struct CommandList *c)
-{
- if (c->cmd_type == CMD_IOACCEL2)
- return h->ioaccel2_cmd_pool[c->cmdindex].reply_queue;
- return c->Header.ReplyQueue;
-}
-
-/*
- * Limit concurrency of abort commands to prevent
- * over-subscription of commands
- */
-static inline int wait_for_available_abort_cmd(struct ctlr_info *h)
-{
-#define ABORT_CMD_WAIT_MSECS 5000
- return !wait_event_timeout(h->abort_cmd_wait_queue,
- atomic_dec_if_positive(&h->abort_cmds_available) >= 0,
- msecs_to_jiffies(ABORT_CMD_WAIT_MSECS));
-}
-
-/* Send an abort for the specified command.
- * If the device and controller support it,
- * send a task abort request.
- */
-static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
-{
-
- int rc;
- struct ctlr_info *h;
- struct hpsa_scsi_dev_t *dev;
- struct CommandList *abort; /* pointer to command to be aborted */
- struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */
- char msg[256]; /* For debug messaging. */
- int ml = 0;
- __le32 tagupper, taglower;
- int refcount, reply_queue;
-
- if (sc == NULL)
- return FAILED;
-
- if (sc->device == NULL)
- return FAILED;
-
- /* Find the controller of the command to be aborted */
- h = sdev_to_hba(sc->device);
- if (h == NULL)
- return FAILED;
-
- /* Find the device of the command to be aborted */
- dev = sc->device->hostdata;
- if (!dev) {
- dev_err(&h->pdev->dev, "%s FAILED, Device lookup failed.\n",
- msg);
- return FAILED;
- }
-
- /* If controller locked up, we can guarantee command won't complete */
- if (lockup_detected(h)) {
- hpsa_show_dev_msg(KERN_WARNING, h, dev,
- "ABORT FAILED, lockup detected");
- return FAILED;
- }
-
- /* This is a good time to check if controller lockup has occurred */
- if (detect_controller_lockup(h)) {
- hpsa_show_dev_msg(KERN_WARNING, h, dev,
- "ABORT FAILED, new lockup detected");
- return FAILED;
- }
-
- /* Check that controller supports some kind of task abort */
- if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) &&
- !(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags))
- return FAILED;
-
- memset(msg, 0, sizeof(msg));
- ml += sprintf(msg+ml, "scsi %d:%d:%d:%llu %s %p",
- h->scsi_host->host_no, sc->device->channel,
- sc->device->id, sc->device->lun,
- "Aborting command", sc);
-
- /* Get SCSI command to be aborted */
- abort = (struct CommandList *) sc->host_scribble;
- if (abort == NULL) {
- /* This can happen if the command already completed. */
- return SUCCESS;
- }
- refcount = atomic_inc_return(&abort->refcount);
- if (refcount == 1) { /* Command is done already. */
- cmd_free(h, abort);
- return SUCCESS;
- }
-
- /* Don't bother trying the abort if we know it won't work. */
- if (abort->cmd_type != CMD_IOACCEL2 &&
- abort->cmd_type != CMD_IOACCEL1 && !dev->supports_aborts) {
- cmd_free(h, abort);
- return FAILED;
- }
-
- /*
- * Check that we're aborting the right command.
- * It's possible the CommandList already completed and got re-used.
- */
- if (abort->scsi_cmd != sc) {
- cmd_free(h, abort);
- return SUCCESS;
- }
-
- abort->abort_pending = true;
- hpsa_get_tag(h, abort, &taglower, &tagupper);
- reply_queue = hpsa_extract_reply_queue(h, abort);
- ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower);
- as = abort->scsi_cmd;
- if (as != NULL)
- ml += sprintf(msg+ml,
- "CDBLen: %d CDB: 0x%02x%02x... SN: 0x%lx ",
- as->cmd_len, as->cmnd[0], as->cmnd[1],
- as->serial_number);
- dev_warn(&h->pdev->dev, "%s BEING SENT\n", msg);
- hpsa_show_dev_msg(KERN_WARNING, h, dev, "Aborting command");
-
- /*
- * Command is in flight, or possibly already completed
- * by the firmware (but not to the scsi mid layer) but we can't
- * distinguish which. Send the abort down.
- */
- if (wait_for_available_abort_cmd(h)) {
- dev_warn(&h->pdev->dev,
- "%s FAILED, timeout waiting for an abort command to become available.\n",
- msg);
- cmd_free(h, abort);
- return FAILED;
- }
- rc = hpsa_send_abort_both_ways(h, dev, abort, reply_queue);
- atomic_inc(&h->abort_cmds_available);
- wake_up_all(&h->abort_cmd_wait_queue);
- if (rc != 0) {
- dev_warn(&h->pdev->dev, "%s SENT, FAILED\n", msg);
- hpsa_show_dev_msg(KERN_WARNING, h, dev,
- "FAILED to abort command");
- cmd_free(h, abort);
- return FAILED;
- }
- dev_info(&h->pdev->dev, "%s SENT, SUCCESS\n", msg);
- wait_event(h->event_sync_wait_queue,
- abort->scsi_cmd != sc || lockup_detected(h));
- cmd_free(h, abort);
- return !lockup_detected(h) ? SUCCESS : FAILED;
-}
-
/*
* For operations with an associated SCSI command, a command block is allocated
* at init, and managed by cmd_tagged_alloc() and cmd_tagged_free() using the
@@ -6364,9 +5883,7 @@ static void cmd_tagged_free(struct ctlr_info *h, struct CommandList *c)
{
/*
* Release our reference to the block. We don't need to do anything
- * else to free it, because it is accessed by index. (There's no point
- * in checking the result of the decrement, since we cannot guarantee
- * that there isn't a concurrent abort which is also accessing it.)
+ * else to free it, because it is accessed by index.
*/
(void)atomic_dec(&c->refcount);
}
@@ -6905,7 +6422,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
int cmd_type)
{
int pci_dir = XFER_NONE;
- u64 tag; /* for commands to be aborted */
c->cmd_type = CMD_IOCTL_PEND;
c->scsi_cmd = SCSI_CMD_BUSY;
@@ -7089,27 +6605,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[6] = 0x00;
c->Request.CDB[7] = 0x00;
break;
- case HPSA_ABORT_MSG:
- memcpy(&tag, buff, sizeof(tag));
- dev_dbg(&h->pdev->dev,
- "Abort Tag:0x%016llx using rqst Tag:0x%016llx",
- tag, c->Header.tag);
- c->Request.CDBLen = 16;
- c->Request.type_attr_dir =
- TYPE_ATTR_DIR(cmd_type,
- ATTR_SIMPLE, XFER_WRITE);
- c->Request.Timeout = 0; /* Don't time out */
- c->Request.CDB[0] = HPSA_TASK_MANAGEMENT;
- c->Request.CDB[1] = HPSA_TMF_ABORT_TASK;
- c->Request.CDB[2] = 0x00; /* reserved */
- c->Request.CDB[3] = 0x00; /* reserved */
- /* Tag to abort goes in CDB[4]-CDB[11] */
- memcpy(&c->Request.CDB[4], &tag, sizeof(tag));
- c->Request.CDB[12] = 0x00; /* reserved */
- c->Request.CDB[13] = 0x00; /* reserved */
- c->Request.CDB[14] = 0x00; /* reserved */
- c->Request.CDB[15] = 0x00; /* reserved */
- break;
default:
dev_warn(&h->pdev->dev, "unknown message type %d\n",
cmd);
@@ -8067,9 +7562,6 @@ static int hpsa_pci_init(struct ctlr_info *h)
h->product_name = products[prod_index].product_name;
h->access = *(products[prod_index].access);
- h->needs_abort_tags_swizzled =
- ctlr_needs_abort_tags_swizzled(h->board_id);
-
pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S |
PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
@@ -8627,41 +8119,79 @@ out:
return rc;
}
-static void hpsa_rescan_ctlr_worker(struct work_struct *work)
+static void hpsa_perform_rescan(struct ctlr_info *h)
{
+ struct Scsi_Host *sh = NULL;
unsigned long flags;
- struct ctlr_info *h = container_of(to_delayed_work(work),
- struct ctlr_info, rescan_ctlr_work);
-
-
- if (h->remove_in_progress)
- return;
/*
* Do the scan after the reset
*/
+ spin_lock_irqsave(&h->reset_lock, flags);
if (h->reset_in_progress) {
h->drv_req_rescan = 1;
+ spin_unlock_irqrestore(&h->reset_lock, flags);
return;
}
+ spin_unlock_irqrestore(&h->reset_lock, flags);
+
+ sh = scsi_host_get(h->scsi_host);
+ if (sh != NULL) {
+ hpsa_scan_start(sh);
+ scsi_host_put(sh);
+ h->drv_req_rescan = 0;
+ }
+}
+
+/*
+ * watch for controller events
+ */
+static void hpsa_event_monitor_worker(struct work_struct *work)
+{
+ struct ctlr_info *h = container_of(to_delayed_work(work),
+ struct ctlr_info, event_monitor_work);
+ unsigned long flags;
+
+ spin_lock_irqsave(&h->lock, flags);
+ if (h->remove_in_progress) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
- if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) {
- scsi_host_get(h->scsi_host);
+ if (hpsa_ctlr_needs_rescan(h)) {
hpsa_ack_ctlr_events(h);
- hpsa_scan_start(h->scsi_host);
- scsi_host_put(h->scsi_host);
+ hpsa_perform_rescan(h);
+ }
+
+ spin_lock_irqsave(&h->lock, flags);
+ if (!h->remove_in_progress)
+ schedule_delayed_work(&h->event_monitor_work,
+ HPSA_EVENT_MONITOR_INTERVAL);
+ spin_unlock_irqrestore(&h->lock, flags);
+}
+
+static void hpsa_rescan_ctlr_worker(struct work_struct *work)
+{
+ unsigned long flags;
+ struct ctlr_info *h = container_of(to_delayed_work(work),
+ struct ctlr_info, rescan_ctlr_work);
+
+ spin_lock_irqsave(&h->lock, flags);
+ if (h->remove_in_progress) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+
+ if (h->drv_req_rescan || hpsa_offline_devices_ready(h)) {
+ hpsa_perform_rescan(h);
} else if (h->discovery_polling) {
hpsa_disable_rld_caching(h);
if (hpsa_luns_changed(h)) {
- struct Scsi_Host *sh = NULL;
-
dev_info(&h->pdev->dev,
"driver discovery polling rescan.\n");
- sh = scsi_host_get(h->scsi_host);
- if (sh != NULL) {
- hpsa_scan_start(sh);
- scsi_host_put(sh);
- }
+ hpsa_perform_rescan(h);
}
}
spin_lock_irqsave(&h->lock, flags);
@@ -8750,8 +8280,8 @@ reinit_after_soft_reset:
spin_lock_init(&h->lock);
spin_lock_init(&h->offline_device_lock);
spin_lock_init(&h->scan_lock);
+ spin_lock_init(&h->reset_lock);
atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS);
- atomic_set(&h->abort_cmds_available, HPSA_CMDS_RESERVED_FOR_ABORTS);
/* Allocate and clear per-cpu variable lockup_detected */
h->lockup_detected = alloc_percpu(u32);
@@ -8803,7 +8333,6 @@ reinit_after_soft_reset:
if (rc)
goto clean5; /* cmd, irq, shost, pci, lu, aer/h */
init_waitqueue_head(&h->scan_wait_queue);
- init_waitqueue_head(&h->abort_cmd_wait_queue);
init_waitqueue_head(&h->event_sync_wait_queue);
mutex_init(&h->reset_mutex);
h->scan_finished = 1; /* no scan currently in progress */
@@ -8926,6 +8455,9 @@ reinit_after_soft_reset:
INIT_DELAYED_WORK(&h->rescan_ctlr_work, hpsa_rescan_ctlr_worker);
queue_delayed_work(h->rescan_ctlr_wq, &h->rescan_ctlr_work,
h->heartbeat_sample_interval);
+ INIT_DELAYED_WORK(&h->event_monitor_work, hpsa_event_monitor_worker);
+ schedule_delayed_work(&h->event_monitor_work,
+ HPSA_EVENT_MONITOR_INTERVAL);
return 0;
clean7: /* perf, sg, cmd, irq, shost, pci, lu, aer/h */
@@ -9094,6 +8626,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
spin_unlock_irqrestore(&h->lock, flags);
cancel_delayed_work_sync(&h->monitor_ctlr_work);
cancel_delayed_work_sync(&h->rescan_ctlr_work);
+ cancel_delayed_work_sync(&h->event_monitor_work);
destroy_workqueue(h->rescan_ctlr_wq);
destroy_workqueue(h->resubmit_wq);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 6f04f2ad4125..1c49741bc639 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -57,6 +57,7 @@ struct hpsa_sas_phy {
bool added_to_port;
};
+#define EXTERNAL_QD 7
struct hpsa_scsi_dev_t {
unsigned int devtype;
int bus, target, lun; /* as presented to the OS */
@@ -244,6 +245,7 @@ struct ctlr_info {
u32 __percpu *lockup_detected;
struct delayed_work monitor_ctlr_work;
struct delayed_work rescan_ctlr_work;
+ struct delayed_work event_monitor_work;
int remove_in_progress;
/* Address of h->q[x] is passed to intr handler to know which queue */
u8 q[MAX_REPLY_QUEUES];
@@ -296,11 +298,11 @@ struct ctlr_info {
struct workqueue_struct *resubmit_wq;
struct workqueue_struct *rescan_ctlr_wq;
atomic_t abort_cmds_available;
- wait_queue_head_t abort_cmd_wait_queue;
wait_queue_head_t event_sync_wait_queue;
struct mutex reset_mutex;
u8 reset_in_progress;
struct hpsa_sas_node *sas_host;
+ spinlock_t reset_lock;
};
struct offline_device_entry {
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 5961705eef76..078afe448115 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -809,10 +809,7 @@ struct bmic_identify_physical_device {
u8 max_temperature_degreesC;
u8 logical_blocks_per_phys_block_exp; /* phyblocksize = 512*2^exp */
__le16 current_queue_depth_limit;
- u8 switch_name[10];
- __le16 switch_port;
- u8 alternate_paths_switch_name[40];
- u8 alternate_paths_switch_port[8];
+ u8 reserved_switch_stuff[60];
__le16 power_on_hours; /* valid only if gas gauge supported */
__le16 percent_endurance_used; /* valid only if gas gauge supported. */
#define BMIC_PHYS_DRIVE_SSD_WEAROUT(idphydrv) \
@@ -828,11 +825,22 @@ struct bmic_identify_physical_device {
(idphydrv->smart_carrier_authentication == 0x01)
u8 smart_carrier_app_fw_version;
u8 smart_carrier_bootloader_fw_version;
+ u8 sanitize_support_flags;
+ u8 drive_key_flags;
u8 encryption_key_name[64];
__le32 misc_drive_flags;
__le16 dek_index;
- u8 padding[112];
-};
+ __le16 hba_drive_encryption_flags;
+ __le16 max_overwrite_time;
+ __le16 max_block_erase_time;
+ __le16 max_crypto_erase_time;
+ u8 device_connector_info[5];
+ u8 connector_name[8][8];
+ u8 page_83_id[16];
+ u8 max_link_rate[256];
+ u8 neg_phys_link_rate[256];
+ u8 box_conn_name[8];
+} __attribute((aligned(512)));
struct bmic_sense_subsystem_info {
u8 primary_slot_number;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index dd6828f7f772..42381adf0769 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2556,7 +2556,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
* the array. */
if (items)
num_arrays++;
- q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
+ q->pool = kvzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
if (q->pool == NULL)
return -ENOMEM;
@@ -2590,7 +2590,7 @@ void iscsi_pool_free(struct iscsi_pool *q)
for (i = 0; i < q->max; i++)
kfree(q->pool[i]);
- kfree(q->pool);
+ kvfree(q->pool);
}
EXPORT_SYMBOL_GPL(iscsi_pool_free);
diff --git a/drivers/scsi/qedi/qedi.h b/drivers/scsi/qedi/qedi.h
index 5ca3e8c28a3f..32632c9b2276 100644
--- a/drivers/scsi/qedi/qedi.h
+++ b/drivers/scsi/qedi/qedi.h
@@ -38,7 +38,7 @@ struct qedi_endpoint;
#define QEDI_MAX_ISCSI_TASK 4096
#define QEDI_MAX_TASK_NUM 0x0FFF
#define QEDI_MAX_ISCSI_CONNS_PER_HBA 1024
-#define QEDI_ISCSI_MAX_BDS_PER_CMD 256 /* Firmware max BDs is 256 */
+#define QEDI_ISCSI_MAX_BDS_PER_CMD 255 /* Firmware max BDs is 255 */
#define MAX_OUSTANDING_TASKS_PER_CON 1024
#define QEDI_MAX_BD_LEN 0xffff
@@ -63,6 +63,7 @@ struct qedi_endpoint;
#define QEDI_PAGE_MASK (~((QEDI_PAGE_SIZE) - 1))
#define QEDI_PAGE_SIZE 4096
+#define QEDI_HW_DMA_BOUNDARY 0xfff
#define QEDI_PATH_HANDLE 0xFE0000000UL
struct qedi_uio_ctrl {
diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index 7658138f2283..2ee92aa90fe9 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -1494,6 +1494,8 @@ static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
tmf_hdr = (struct iscsi_tm *)mtask->hdr;
qedi_cmd = (struct qedi_cmd *)mtask->dd_data;
ep = qedi_conn->ep;
+ if (!ep)
+ return -ENODEV;
tid = qedi_get_task_idx(qedi);
if (tid == -1)
diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
index 0c8ccffa4c38..80edd28b635f 100644
--- a/drivers/scsi/qedi/qedi_iscsi.c
+++ b/drivers/scsi/qedi/qedi_iscsi.c
@@ -59,6 +59,7 @@ struct scsi_host_template qedi_host_template = {
.this_id = -1,
.sg_tablesize = QEDI_ISCSI_MAX_BDS_PER_CMD,
.max_sectors = 0xffff,
+ .dma_boundary = QEDI_HW_DMA_BOUNDARY,
.cmd_per_lun = 128,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = qedi_shost_attrs,
@@ -1223,8 +1224,12 @@ static int qedi_set_path(struct Scsi_Host *shost, struct iscsi_path *path_data)
iscsi_cid = (u32)path_data->handle;
qedi_ep = qedi->ep_tbl[iscsi_cid];
- QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
"iscsi_cid=0x%x, qedi_ep=%p\n", iscsi_cid, qedi_ep);
+ if (!qedi_ep) {
+ ret = -EINVAL;
+ goto set_path_exit;
+ }
if (!is_valid_ether_addr(&path_data->mac_addr[0])) {
QEDI_NOTICE(&qedi->dbg_ctx, "dst mac NOT VALID\n");
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index 073b3051bb8f..f46880315ba8 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -151,6 +151,11 @@ static int qedi_uio_close(struct uio_info *uinfo, struct inode *inode)
static void __qedi_free_uio_rings(struct qedi_uio_dev *udev)
{
+ if (udev->uctrl) {
+ free_page((unsigned long)udev->uctrl);
+ udev->uctrl = NULL;
+ }
+
if (udev->ll2_ring) {
free_page((unsigned long)udev->ll2_ring);
udev->ll2_ring = NULL;
@@ -169,7 +174,6 @@ static void __qedi_free_uio(struct qedi_uio_dev *udev)
__qedi_free_uio_rings(udev);
pci_dev_put(udev->pdev);
- kfree(udev->uctrl);
kfree(udev);
}
@@ -208,6 +212,11 @@ static int __qedi_alloc_uio_rings(struct qedi_uio_dev *udev)
if (udev->ll2_ring || udev->ll2_buf)
return rc;
+ /* Memory for control area. */
+ udev->uctrl = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!udev->uctrl)
+ return -ENOMEM;
+
/* Allocating memory for LL2 ring */
udev->ll2_ring_size = QEDI_PAGE_SIZE;
udev->ll2_ring = (void *)get_zeroed_page(GFP_KERNEL | __GFP_COMP);
@@ -237,7 +246,6 @@ exit_alloc_ring:
static int qedi_alloc_uio_rings(struct qedi_ctx *qedi)
{
struct qedi_uio_dev *udev = NULL;
- struct qedi_uio_ctrl *uctrl = NULL;
int rc = 0;
list_for_each_entry(udev, &qedi_udev_list, list) {
@@ -258,21 +266,14 @@ static int qedi_alloc_uio_rings(struct qedi_ctx *qedi)
goto err_udev;
}
- uctrl = kzalloc(sizeof(*uctrl), GFP_KERNEL);
- if (!uctrl) {
- rc = -ENOMEM;
- goto err_uctrl;
- }
-
udev->uio_dev = -1;
udev->qedi = qedi;
udev->pdev = qedi->pdev;
- udev->uctrl = uctrl;
rc = __qedi_alloc_uio_rings(udev);
if (rc)
- goto err_uio_rings;
+ goto err_uctrl;
list_add(&udev->list, &qedi_udev_list);
@@ -283,8 +284,6 @@ static int qedi_alloc_uio_rings(struct qedi_ctx *qedi)
udev->rx_pkt = udev->ll2_buf + LL2_SINGLE_BUF_SIZE;
return 0;
- err_uio_rings:
- kfree(uctrl);
err_uctrl:
kfree(udev);
err_udev:
@@ -828,6 +827,8 @@ static int qedi_set_iscsi_pf_param(struct qedi_ctx *qedi)
qedi->pf_params.iscsi_pf_params.num_uhq_pages_in_ring = num_sq_pages;
qedi->pf_params.iscsi_pf_params.num_queues = qedi->num_queues;
qedi->pf_params.iscsi_pf_params.debug_mode = qedi_fw_debug;
+ qedi->pf_params.iscsi_pf_params.two_msl_timer = 4000;
+ qedi->pf_params.iscsi_pf_params.max_fin_rt = 2;
for (log_page_size = 0 ; log_page_size < 32 ; log_page_size++) {
if ((1 << log_page_size) == PAGE_SIZE)
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index d64420251194..dae278859554 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -862,7 +862,6 @@ struct qla_tgt_cmd {
struct se_cmd se_cmd;
struct fc_port *sess;
int state;
- struct work_struct free_work;
struct work_struct work;
/* Sense buffer that will be mapped into outgoing status */
unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index b673825f46b5..07ec8a8877de 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -1,6 +1,6 @@
/*
* driver for Microsemi PQI-based storage controllers
- * Copyright (c) 2016 Microsemi Corporation
+ * Copyright (c) 2016-2017 Microsemi Corporation
* Copyright (c) 2016 PMC-Sierra, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -16,6 +16,8 @@
*
*/
+#include <linux/io-64-nonatomic-lo-hi.h>
+
#if !defined(_SMARTPQI_H)
#define _SMARTPQI_H
@@ -61,7 +63,7 @@ struct pqi_device_registers {
/*
* controller registers
*
- * These are defined by the PMC implementation.
+ * These are defined by the Microsemi implementation.
*
* Some registers (those named sis_*) are only used when in
* legacy SIS mode before we transition the controller into
@@ -102,6 +104,12 @@ enum pqi_io_path {
AIO_PATH = 1
};
+enum pqi_irq_mode {
+ IRQ_MODE_NONE,
+ IRQ_MODE_INTX,
+ IRQ_MODE_MSIX
+};
+
struct pqi_sg_descriptor {
__le64 address;
__le32 length;
@@ -484,7 +492,6 @@ struct pqi_raid_error_info {
#define PQI_EVENT_TYPE_LOGICAL_DEVICE 0x5
#define PQI_EVENT_TYPE_AIO_STATE_CHANGE 0xfd
#define PQI_EVENT_TYPE_AIO_CONFIG_CHANGE 0xfe
-#define PQI_EVENT_TYPE_HEARTBEAT 0xff
#pragma pack()
@@ -629,17 +636,70 @@ struct pqi_encryption_info {
u32 encrypt_tweak_upper;
};
-#define PQI_MAX_OUTSTANDING_REQUESTS ((u32)~0)
-#define PQI_MAX_TRANSFER_SIZE (4 * 1024U * 1024U)
+#pragma pack(1)
+
+#define PQI_CONFIG_TABLE_SIGNATURE "CFGTABLE"
+#define PQI_CONFIG_TABLE_MAX_LENGTH ((u16)~0)
+
+/* configuration table section IDs */
+#define PQI_CONFIG_TABLE_SECTION_GENERAL_INFO 0
+#define PQI_CONFIG_TABLE_SECTION_FIRMWARE_FEATURES 1
+#define PQI_CONFIG_TABLE_SECTION_FIRMWARE_ERRATA 2
+#define PQI_CONFIG_TABLE_SECTION_DEBUG 3
+#define PQI_CONFIG_TABLE_SECTION_HEARTBEAT 4
+
+struct pqi_config_table {
+ u8 signature[8]; /* "CFGTABLE" */
+ __le32 first_section_offset; /* offset in bytes from the base */
+ /* address of this table to the */
+ /* first section */
+};
+
+struct pqi_config_table_section_header {
+ __le16 section_id; /* as defined by the */
+ /* PQI_CONFIG_TABLE_SECTION_* */
+ /* manifest constants above */
+ __le16 next_section_offset; /* offset in bytes from base */
+ /* address of the table of the */
+ /* next section or 0 if last entry */
+};
+
+struct pqi_config_table_general_info {
+ struct pqi_config_table_section_header header;
+ __le32 section_length; /* size of this section in bytes */
+ /* including the section header */
+ __le32 max_outstanding_requests; /* max. outstanding */
+ /* commands supported by */
+ /* the controller */
+ __le32 max_sg_size; /* max. transfer size of a single */
+ /* command */
+ __le32 max_sg_per_request; /* max. number of scatter-gather */
+ /* entries supported in a single */
+ /* command */
+};
+
+struct pqi_config_table_debug {
+ struct pqi_config_table_section_header header;
+ __le32 scratchpad;
+};
+
+struct pqi_config_table_heartbeat {
+ struct pqi_config_table_section_header header;
+ __le32 heartbeat_counter;
+};
+
+#define PQI_MAX_OUTSTANDING_REQUESTS ((u32)~0)
+#define PQI_MAX_OUTSTANDING_REQUESTS_KDUMP 32
+#define PQI_MAX_TRANSFER_SIZE (4 * 1024U * 1024U)
+#define PQI_MAX_TRANSFER_SIZE_KDUMP (512 * 1024U)
#define RAID_MAP_MAX_ENTRIES 1024
#define PQI_PHYSICAL_DEVICE_BUS 0
#define PQI_RAID_VOLUME_BUS 1
#define PQI_HBA_BUS 2
-#define PQI_MAX_BUS PQI_HBA_BUS
-
-#pragma pack(1)
+#define PQI_EXTERNAL_RAID_VOLUME_BUS 3
+#define PQI_MAX_BUS PQI_EXTERNAL_RAID_VOLUME_BUS
struct report_lun_header {
__be32 list_length;
@@ -668,7 +728,6 @@ struct report_phys_lun_extended_entry {
};
/* for device_flags field of struct report_phys_lun_extended_entry */
-#define REPORT_PHYS_LUN_DEV_FLAG_NON_DISK 0x1
#define REPORT_PHYS_LUN_DEV_FLAG_AIO_ENABLED 0x8
struct report_phys_lun_extended {
@@ -726,14 +785,15 @@ struct pqi_scsi_dev {
__be64 wwid;
u8 volume_id[16];
u8 is_physical_device : 1;
+ u8 is_external_raid_device : 1;
u8 target_lun_valid : 1;
- u8 expose_device : 1;
- u8 no_uld_attach : 1;
- u8 aio_enabled : 1; /* only valid for physical disks */
u8 device_gone : 1;
u8 new_device : 1;
u8 keep_device : 1;
u8 volume_offline : 1;
+ bool aio_enabled; /* only valid for physical disks */
+ bool in_reset;
+ bool device_offline;
u8 vendor[8]; /* bytes 8-15 of inquiry data */
u8 model[16]; /* bytes 16-31 of inquiry data */
u64 sas_address;
@@ -747,12 +807,11 @@ struct pqi_scsi_dev {
u8 bay;
u8 box[8];
u16 phys_connector[8];
- int offload_configured; /* I/O accel RAID offload configured */
- int offload_enabled; /* I/O accel RAID offload enabled */
- int offload_enabled_pending;
- int offload_to_mirror; /* Send next I/O accelerator RAID */
- /* offload request to mirror drive. */
- struct raid_map *raid_map; /* I/O accelerator RAID map */
+ bool raid_bypass_configured; /* RAID bypass configured */
+ bool raid_bypass_enabled; /* RAID bypass enabled */
+ int offload_to_mirror; /* Send next RAID bypass request */
+ /* to mirror drive. */
+ struct raid_map *raid_map; /* RAID bypass map */
struct pqi_sas_port *sas_port;
struct scsi_device *sdev;
@@ -761,13 +820,15 @@ struct pqi_scsi_dev {
struct list_head new_device_list_entry;
struct list_head add_list_entry;
struct list_head delete_list_entry;
+
+ atomic_t scsi_cmds_outstanding;
};
/* VPD inquiry pages */
#define SCSI_VPD_SUPPORTED_PAGES 0x0 /* standard page */
#define SCSI_VPD_DEVICE_ID 0x83 /* standard page */
#define CISS_VPD_LV_DEVICE_GEOMETRY 0xc1 /* vendor-specific page */
-#define CISS_VPD_LV_OFFLOAD_STATUS 0xc2 /* vendor-specific page */
+#define CISS_VPD_LV_BYPASS_STATUS 0xc2 /* vendor-specific page */
#define CISS_VPD_LV_STATUS 0xc3 /* vendor-specific page */
#define VPD_PAGE (1 << 8)
@@ -851,7 +912,9 @@ struct pqi_io_request {
void (*io_complete_callback)(struct pqi_io_request *io_request,
void *context);
void *context;
+ u8 raid_bypass : 1;
int status;
+ struct pqi_queue_group *queue_group;
struct scsi_cmnd *scmd;
void *error_info;
struct pqi_sg_descriptor *sg_chain_buffer;
@@ -860,15 +923,7 @@ struct pqi_io_request {
struct list_head request_list_entry;
};
-/* for indexing into the pending_events[] field of struct pqi_ctrl_info */
-#define PQI_EVENT_HEARTBEAT 0
-#define PQI_EVENT_HOTPLUG 1
-#define PQI_EVENT_HARDWARE 2
-#define PQI_EVENT_PHYSICAL_DEVICE 3
-#define PQI_EVENT_LOGICAL_DEVICE 4
-#define PQI_EVENT_AIO_STATE_CHANGE 5
-#define PQI_EVENT_AIO_CONFIG_CHANGE 6
-#define PQI_NUM_SUPPORTED_EVENTS 7
+#define PQI_NUM_SUPPORTED_EVENTS 6
struct pqi_event {
bool pending;
@@ -911,7 +966,7 @@ struct pqi_ctrl_info {
dma_addr_t error_buffer_dma_handle;
size_t sg_chain_buffer_length;
unsigned int num_queue_groups;
- unsigned int num_active_queue_groups;
+ u16 max_hw_queue_index;
u16 num_elements_per_iq;
u16 num_elements_per_oq;
u16 max_inbound_iu_length_per_firmware;
@@ -926,6 +981,7 @@ struct pqi_ctrl_info {
struct pqi_admin_queues admin_queues;
struct pqi_queue_group queue_groups[PQI_MAX_QUEUE_GROUPS];
struct pqi_event_queue event_queue;
+ enum pqi_irq_mode irq_mode;
int max_msix_vectors;
int num_msix_vectors_enabled;
int num_msix_vectors_initialized;
@@ -933,11 +989,12 @@ struct pqi_ctrl_info {
struct Scsi_Host *scsi_host;
struct mutex scan_mutex;
+ struct mutex lun_reset_mutex;
+ bool controller_online;
+ bool block_requests;
u8 inbound_spanning_supported : 1;
u8 outbound_spanning_supported : 1;
u8 pqi_mode_enabled : 1;
- u8 controller_online : 1;
- u8 heartbeat_timer_started : 1;
struct list_head scsi_device_list;
spinlock_t scsi_device_list_lock;
@@ -951,20 +1008,28 @@ struct pqi_ctrl_info {
struct pqi_io_request *io_request_pool;
u16 next_io_request_slot;
- struct pqi_event pending_events[PQI_NUM_SUPPORTED_EVENTS];
+ struct pqi_event events[PQI_NUM_SUPPORTED_EVENTS];
struct work_struct event_work;
atomic_t num_interrupts;
int previous_num_interrupts;
- unsigned int num_heartbeats_requested;
+ u32 previous_heartbeat_count;
+ __le32 __iomem *heartbeat_counter;
struct timer_list heartbeat_timer;
+ struct work_struct ctrl_offline_work;
struct semaphore sync_request_sem;
- struct semaphore lun_reset_sem;
+ atomic_t num_busy_threads;
+ atomic_t num_blocked_threads;
+ wait_queue_head_t block_requests_wait;
+
+ struct list_head raid_bypass_retry_list;
+ spinlock_t raid_bypass_retry_list_lock;
+ struct work_struct raid_bypass_retry_work;
};
enum pqi_ctrl_mode {
- UNKNOWN,
+ SIS_MODE = 0,
PQI_MODE
};
@@ -973,9 +1038,6 @@ enum pqi_ctrl_mode {
*/
#define PQI_PHYSICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH 27
-/* 0 = no limit */
-#define PQI_LOGICAL_DRIVE_DEFAULT_MAX_QUEUE_DEPTH 0
-
/* CISS commands */
#define CISS_READ 0xc0
#define CISS_REPORT_LOG 0xc2 /* Report Logical LUNs */
@@ -996,13 +1058,13 @@ enum pqi_ctrl_mode {
#define BMIC_WRITE_HOST_WELLNESS 0xa5
#define BMIC_CACHE_FLUSH 0xc2
-#define SA_CACHE_FLUSH 0x01
+#define SA_CACHE_FLUSH 0x1
#define MASKED_DEVICE(lunid) ((lunid)[3] & 0xc0)
-#define CISS_GET_BUS(lunid) ((lunid)[7] & 0x3f)
+#define CISS_GET_LEVEL_2_BUS(lunid) ((lunid)[7] & 0x3f)
#define CISS_GET_LEVEL_2_TARGET(lunid) ((lunid)[6])
#define CISS_GET_DRIVE_NUMBER(lunid) \
- (((CISS_GET_BUS((lunid)) - 1) << 8) + \
+ (((CISS_GET_LEVEL_2_BUS((lunid)) - 1) << 8) + \
CISS_GET_LEVEL_2_TARGET((lunid)))
#define NO_TIMEOUT ((unsigned long) -1)
@@ -1069,9 +1131,9 @@ struct bmic_identify_physical_device {
u8 multi_lun_device_lun_count;
u8 minimum_good_fw_revision[8];
u8 unique_inquiry_bytes[20];
- u8 current_temperature_degreesC;
- u8 temperature_threshold_degreesC;
- u8 max_temperature_degreesC;
+ u8 current_temperature_degrees;
+ u8 temperature_threshold_degrees;
+ u8 max_temperature_degrees;
u8 logical_blocks_per_phys_block_exp;
__le16 current_queue_depth_limit;
u8 switch_name[10];
@@ -1084,10 +1146,22 @@ struct bmic_identify_physical_device {
u8 smart_carrier_authentication;
u8 smart_carrier_app_fw_version;
u8 smart_carrier_bootloader_fw_version;
+ u8 sanitize_flags;
+ u8 encryption_key_flags;
u8 encryption_key_name[64];
__le32 misc_drive_flags;
__le16 dek_index;
- u8 padding[112];
+ __le16 hba_drive_encryption_flags;
+ __le16 max_overwrite_time;
+ __le16 max_block_erase_time;
+ __le16 max_crypto_erase_time;
+ u8 connector_info[5];
+ u8 connector_name[8][8];
+ u8 page_83_identifier[16];
+ u8 maximum_link_rate[256];
+ u8 negotiated_physical_link_rate[256];
+ u8 box_connector_name[8];
+ u8 padding_to_multiple_of_512[9];
};
#pragma pack()
@@ -1099,36 +1173,8 @@ int pqi_add_sas_device(struct pqi_sas_node *pqi_sas_node,
void pqi_remove_sas_device(struct pqi_scsi_dev *device);
struct pqi_scsi_dev *pqi_find_device_by_sas_rphy(
struct pqi_ctrl_info *ctrl_info, struct sas_rphy *rphy);
+void pqi_prep_for_scsi_done(struct scsi_cmnd *scmd);
extern struct sas_function_template pqi_sas_transport_functions;
-#if !defined(readq)
-#define readq readq
-static inline u64 readq(const volatile void __iomem *addr)
-{
- u32 lower32;
- u32 upper32;
-
- lower32 = readl(addr);
- upper32 = readl(addr + 4);
-
- return ((u64)upper32 << 32) | lower32;
-}
-#endif
-
-#if !defined(writeq)
-#define writeq writeq
-static inline void writeq(u64 value, volatile void __iomem *addr)
-{
- u32 lower32;
- u32 upper32;
-
- lower32 = lower_32_bits(value);
- upper32 = upper_32_bits(value);
-
- writel(lower32, addr);
- writel(upper32, addr + 4);
-}
-#endif
-
#endif /* _SMARTPQI_H */
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
index 657ad15682a3..cb8f886e705c 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -1,6 +1,6 @@
/*
* driver for Microsemi PQI-based storage controllers
- * Copyright (c) 2016 Microsemi Corporation
+ * Copyright (c) 2016-2017 Microsemi Corporation
* Copyright (c) 2016 PMC-Sierra, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include <linux/sched.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
+#include <linux/reboot.h>
#include <linux/cciss_ioctl.h>
#include <linux/blk-mq-pci.h>
#include <scsi/scsi_host.h>
@@ -39,15 +40,18 @@
#define BUILD_TIMESTAMP
#endif
-#define DRIVER_VERSION "0.9.13-370"
-#define DRIVER_MAJOR 0
-#define DRIVER_MINOR 9
-#define DRIVER_RELEASE 13
-#define DRIVER_REVISION 370
+#define DRIVER_VERSION "1.0.4-100"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_RELEASE 4
+#define DRIVER_REVISION 100
-#define DRIVER_NAME "Microsemi PQI Driver (v" DRIVER_VERSION ")"
+#define DRIVER_NAME "Microsemi PQI Driver (v" \
+ DRIVER_VERSION BUILD_TIMESTAMP ")"
#define DRIVER_NAME_SHORT "smartpqi"
+#define PQI_EXTRA_SGL_MEMORY (12 * sizeof(struct pqi_sg_descriptor))
+
MODULE_AUTHOR("Microsemi");
MODULE_DESCRIPTION("Driver for Microsemi Smart Family Controller version "
DRIVER_VERSION);
@@ -55,12 +59,9 @@ MODULE_SUPPORTED_DEVICE("Microsemi Smart Family Controllers");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
-#define PQI_ENABLE_MULTI_QUEUE_SUPPORT 0
-
-static char *hpe_branded_controller = "HPE Smart Array Controller";
-static char *microsemi_branded_controller = "Microsemi Smart Family Controller";
-
static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info);
+static void pqi_ctrl_offline_worker(struct work_struct *work);
+static void pqi_retry_raid_bypass_requests(struct pqi_ctrl_info *ctrl_info);
static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info);
static void pqi_scan_start(struct Scsi_Host *shost);
static void pqi_start_io(struct pqi_ctrl_info *ctrl_info,
@@ -72,7 +73,7 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info,
static int pqi_aio_submit_io(struct pqi_ctrl_info *ctrl_info,
struct scsi_cmnd *scmd, u32 aio_handle, u8 *cdb,
unsigned int cdb_length, struct pqi_queue_group *queue_group,
- struct pqi_encryption_info *encryption_info);
+ struct pqi_encryption_info *encryption_info, bool raid_bypass);
/* for flags argument to pqi_submit_raid_request_synchronous() */
#define PQI_SYNC_FLAGS_INTERRUPTABLE 0x1
@@ -81,12 +82,66 @@ static struct scsi_transport_template *pqi_sas_transport_template;
static atomic_t pqi_controller_count = ATOMIC_INIT(0);
+enum pqi_lockup_action {
+ NONE,
+ REBOOT,
+ PANIC
+};
+
+static enum pqi_lockup_action pqi_lockup_action = NONE;
+
+static struct {
+ enum pqi_lockup_action action;
+ char *name;
+} pqi_lockup_actions[] = {
+ {
+ .action = NONE,
+ .name = "none",
+ },
+ {
+ .action = REBOOT,
+ .name = "reboot",
+ },
+ {
+ .action = PANIC,
+ .name = "panic",
+ },
+};
+
+static unsigned int pqi_supported_event_types[] = {
+ PQI_EVENT_TYPE_HOTPLUG,
+ PQI_EVENT_TYPE_HARDWARE,
+ PQI_EVENT_TYPE_PHYSICAL_DEVICE,
+ PQI_EVENT_TYPE_LOGICAL_DEVICE,
+ PQI_EVENT_TYPE_AIO_STATE_CHANGE,
+ PQI_EVENT_TYPE_AIO_CONFIG_CHANGE,
+};
+
static int pqi_disable_device_id_wildcards;
module_param_named(disable_device_id_wildcards,
- pqi_disable_device_id_wildcards, int, S_IRUGO | S_IWUSR);
+ pqi_disable_device_id_wildcards, int, 0644);
MODULE_PARM_DESC(disable_device_id_wildcards,
"Disable device ID wildcards.");
+static int pqi_disable_heartbeat;
+module_param_named(disable_heartbeat,
+ pqi_disable_heartbeat, int, 0644);
+MODULE_PARM_DESC(disable_heartbeat,
+ "Disable heartbeat.");
+
+static int pqi_disable_ctrl_shutdown;
+module_param_named(disable_ctrl_shutdown,
+ pqi_disable_ctrl_shutdown, int, 0644);
+MODULE_PARM_DESC(disable_ctrl_shutdown,
+ "Disable controller shutdown when controller locked up.");
+
+static char *pqi_lockup_action_param;
+module_param_named(lockup_action,
+ pqi_lockup_action_param, charp, 0644);
+MODULE_PARM_DESC(lockup_action, "Action to take when controller locked up.\n"
+ "\t\tSupported: none, reboot, panic\n"
+ "\t\tDefault: none");
+
static char *raid_levels[] = {
"RAID-0",
"RAID-4",
@@ -102,7 +157,7 @@ static char *pqi_raid_level_to_string(u8 raid_level)
if (raid_level < ARRAY_SIZE(raid_levels))
return raid_levels[raid_level];
- return "";
+ return "RAID UNKNOWN";
}
#define SA_RAID_0 0
@@ -117,6 +172,7 @@ static char *pqi_raid_level_to_string(u8 raid_level)
static inline void pqi_scsi_done(struct scsi_cmnd *scmd)
{
+ pqi_prep_for_scsi_done(scmd);
scmd->scsi_done(scmd);
}
@@ -137,6 +193,11 @@ static inline bool pqi_is_logical_device(struct pqi_scsi_dev *device)
return !device->is_physical_device;
}
+static inline bool pqi_is_external_raid_addr(u8 *scsi3addr)
+{
+ return scsi3addr[2] != 0;
+}
+
static inline bool pqi_ctrl_offline(struct pqi_ctrl_info *ctrl_info)
{
return !ctrl_info->controller_online;
@@ -166,12 +227,124 @@ static inline void pqi_save_ctrl_mode(struct pqi_ctrl_info *ctrl_info,
sis_write_driver_scratch(ctrl_info, mode);
}
-#define PQI_RESCAN_WORK_INTERVAL (10 * HZ)
+static inline void pqi_ctrl_block_requests(struct pqi_ctrl_info *ctrl_info)
+{
+ ctrl_info->block_requests = true;
+ scsi_block_requests(ctrl_info->scsi_host);
+}
+
+static inline void pqi_ctrl_unblock_requests(struct pqi_ctrl_info *ctrl_info)
+{
+ ctrl_info->block_requests = false;
+ wake_up_all(&ctrl_info->block_requests_wait);
+ pqi_retry_raid_bypass_requests(ctrl_info);
+ scsi_unblock_requests(ctrl_info->scsi_host);
+}
+
+static inline bool pqi_ctrl_blocked(struct pqi_ctrl_info *ctrl_info)
+{
+ return ctrl_info->block_requests;
+}
+
+static unsigned long pqi_wait_if_ctrl_blocked(struct pqi_ctrl_info *ctrl_info,
+ unsigned long timeout_msecs)
+{
+ unsigned long remaining_msecs;
+
+ if (!pqi_ctrl_blocked(ctrl_info))
+ return timeout_msecs;
+
+ atomic_inc(&ctrl_info->num_blocked_threads);
+
+ if (timeout_msecs == NO_TIMEOUT) {
+ wait_event(ctrl_info->block_requests_wait,
+ !pqi_ctrl_blocked(ctrl_info));
+ remaining_msecs = timeout_msecs;
+ } else {
+ unsigned long remaining_jiffies;
+
+ remaining_jiffies =
+ wait_event_timeout(ctrl_info->block_requests_wait,
+ !pqi_ctrl_blocked(ctrl_info),
+ msecs_to_jiffies(timeout_msecs));
+ remaining_msecs = jiffies_to_msecs(remaining_jiffies);
+ }
+
+ atomic_dec(&ctrl_info->num_blocked_threads);
+
+ return remaining_msecs;
+}
+
+static inline void pqi_ctrl_busy(struct pqi_ctrl_info *ctrl_info)
+{
+ atomic_inc(&ctrl_info->num_busy_threads);
+}
+
+static inline void pqi_ctrl_unbusy(struct pqi_ctrl_info *ctrl_info)
+{
+ atomic_dec(&ctrl_info->num_busy_threads);
+}
+
+static inline void pqi_ctrl_wait_until_quiesced(struct pqi_ctrl_info *ctrl_info)
+{
+ while (atomic_read(&ctrl_info->num_busy_threads) >
+ atomic_read(&ctrl_info->num_blocked_threads))
+ usleep_range(1000, 2000);
+}
+
+static inline bool pqi_device_offline(struct pqi_scsi_dev *device)
+{
+ return device->device_offline;
+}
+
+static inline void pqi_device_reset_start(struct pqi_scsi_dev *device)
+{
+ device->in_reset = true;
+}
+
+static inline void pqi_device_reset_done(struct pqi_scsi_dev *device)
+{
+ device->in_reset = false;
+}
+
+static inline bool pqi_device_in_reset(struct pqi_scsi_dev *device)
+{
+ return device->in_reset;
+}
+
+static inline void pqi_schedule_rescan_worker_with_delay(
+ struct pqi_ctrl_info *ctrl_info, unsigned long delay)
+{
+ if (pqi_ctrl_offline(ctrl_info))
+ return;
+
+ schedule_delayed_work(&ctrl_info->rescan_work, delay);
+}
static inline void pqi_schedule_rescan_worker(struct pqi_ctrl_info *ctrl_info)
{
- schedule_delayed_work(&ctrl_info->rescan_work,
- PQI_RESCAN_WORK_INTERVAL);
+ pqi_schedule_rescan_worker_with_delay(ctrl_info, 0);
+}
+
+#define PQI_RESCAN_WORK_DELAY (10 * HZ)
+
+static inline void pqi_schedule_rescan_worker_delayed(
+ struct pqi_ctrl_info *ctrl_info)
+{
+ pqi_schedule_rescan_worker_with_delay(ctrl_info, PQI_RESCAN_WORK_DELAY);
+}
+
+static inline void pqi_cancel_rescan_worker(struct pqi_ctrl_info *ctrl_info)
+{
+ cancel_delayed_work_sync(&ctrl_info->rescan_work);
+}
+
+static inline u32 pqi_read_heartbeat_counter(struct pqi_ctrl_info *ctrl_info)
+{
+ if (!ctrl_info->heartbeat_counter)
+ return 0;
+
+ return readl(ctrl_info->heartbeat_counter);
}
static int pqi_map_single(struct pci_dev *pci_dev,
@@ -280,7 +453,6 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info,
default:
dev_err(&ctrl_info->pci_dev->dev, "unknown command 0x%c\n",
cmd);
- WARN_ON(cmd);
break;
}
@@ -305,6 +477,14 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info,
buffer, buffer_length, pci_dir);
}
+static inline void pqi_reinit_io_request(struct pqi_io_request *io_request)
+{
+ io_request->scmd = NULL;
+ io_request->status = 0;
+ io_request->error_info = NULL;
+ io_request->raid_bypass = false;
+}
+
static struct pqi_io_request *pqi_alloc_io_request(
struct pqi_ctrl_info *ctrl_info)
{
@@ -322,9 +502,7 @@ static struct pqi_io_request *pqi_alloc_io_request(
/* benignly racy */
ctrl_info->next_io_request_slot = (i + 1) % ctrl_info->max_io_slots;
- io_request->scmd = NULL;
- io_request->status = 0;
- io_request->error_info = NULL;
+ pqi_reinit_io_request(io_request);
return io_request;
}
@@ -500,7 +678,7 @@ static int pqi_write_driver_version_to_host_wellness(
buffer->driver_version_tag[1] = 'V';
put_unaligned_le16(sizeof(buffer->driver_version),
&buffer->driver_version_length);
- strncpy(buffer->driver_version, DRIVER_VERSION,
+ strncpy(buffer->driver_version, "Linux " DRIVER_VERSION,
sizeof(buffer->driver_version) - 1);
buffer->driver_version[sizeof(buffer->driver_version) - 1] = '\0';
buffer->end_tag[0] = 'Z';
@@ -586,6 +764,9 @@ static void pqi_update_time_worker(struct work_struct *work)
ctrl_info = container_of(to_delayed_work(work), struct pqi_ctrl_info,
update_time_work);
+ if (pqi_ctrl_offline(ctrl_info))
+ return;
+
rc = pqi_write_current_time_to_host_wellness(ctrl_info);
if (rc)
dev_warn(&ctrl_info->pci_dev->dev,
@@ -601,6 +782,12 @@ static inline void pqi_schedule_update_time_worker(
schedule_delayed_work(&ctrl_info->update_time_work, 0);
}
+static inline void pqi_cancel_update_time_worker(
+ struct pqi_ctrl_info *ctrl_info)
+{
+ cancel_delayed_work_sync(&ctrl_info->update_time_work);
+}
+
static int pqi_report_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd,
void *buffer, size_t buffer_length)
{
@@ -771,6 +958,9 @@ static void pqi_assign_bus_target_lun(struct pqi_scsi_dev *device)
{
u8 *scsi3addr;
u32 lunid;
+ int bus;
+ int target;
+ int lun;
scsi3addr = device->scsi3addr;
lunid = get_unaligned_le32(scsi3addr);
@@ -783,8 +973,16 @@ static void pqi_assign_bus_target_lun(struct pqi_scsi_dev *device)
}
if (pqi_is_logical_device(device)) {
- pqi_set_bus_target_lun(device, PQI_RAID_VOLUME_BUS, 0,
- lunid & 0x3fff);
+ if (device->is_external_raid_device) {
+ bus = PQI_EXTERNAL_RAID_VOLUME_BUS;
+ target = (lunid >> 16) & 0x3fff;
+ lun = lunid & 0xff;
+ } else {
+ bus = PQI_RAID_VOLUME_BUS;
+ target = 0;
+ lun = lunid & 0x3fff;
+ }
+ pqi_set_bus_target_lun(device, bus, target, lun);
device->target_lun_valid = true;
return;
}
@@ -878,7 +1076,10 @@ static int pqi_validate_raid_map(struct pqi_ctrl_info *ctrl_info,
return 0;
bad_raid_map:
- dev_warn(&ctrl_info->pci_dev->dev, "%s\n", err_msg);
+ dev_warn(&ctrl_info->pci_dev->dev,
+ "scsi %d:%d:%d:%d %s\n",
+ ctrl_info->scsi_host->host_no,
+ device->bus, device->target, device->lun, err_msg);
return -EINVAL;
}
@@ -924,35 +1125,33 @@ error:
return rc;
}
-static void pqi_get_offload_status(struct pqi_ctrl_info *ctrl_info,
+static void pqi_get_raid_bypass_status(struct pqi_ctrl_info *ctrl_info,
struct pqi_scsi_dev *device)
{
int rc;
u8 *buffer;
- u8 offload_status;
+ u8 bypass_status;
buffer = kmalloc(64, GFP_KERNEL);
if (!buffer)
return;
rc = pqi_scsi_inquiry(ctrl_info, device->scsi3addr,
- VPD_PAGE | CISS_VPD_LV_OFFLOAD_STATUS, buffer, 64);
+ VPD_PAGE | CISS_VPD_LV_BYPASS_STATUS, buffer, 64);
if (rc)
goto out;
-#define OFFLOAD_STATUS_BYTE 4
-#define OFFLOAD_CONFIGURED_BIT 0x1
-#define OFFLOAD_ENABLED_BIT 0x2
+#define RAID_BYPASS_STATUS 4
+#define RAID_BYPASS_CONFIGURED 0x1
+#define RAID_BYPASS_ENABLED 0x2
- offload_status = buffer[OFFLOAD_STATUS_BYTE];
- device->offload_configured =
- !!(offload_status & OFFLOAD_CONFIGURED_BIT);
- if (device->offload_configured) {
- device->offload_enabled_pending =
- !!(offload_status & OFFLOAD_ENABLED_BIT);
- if (pqi_get_raid_map(ctrl_info, device))
- device->offload_enabled_pending = false;
- }
+ bypass_status = buffer[RAID_BYPASS_STATUS];
+ device->raid_bypass_configured =
+ (bypass_status & RAID_BYPASS_CONFIGURED) != 0;
+ if (device->raid_bypass_configured &&
+ (bypass_status & RAID_BYPASS_ENABLED) &&
+ pqi_get_raid_map(ctrl_info, device) == 0)
+ device->raid_bypass_enabled = true;
out:
kfree(buffer);
@@ -1016,15 +1215,19 @@ static int pqi_get_device_info(struct pqi_ctrl_info *ctrl_info,
scsi_sanitize_inquiry_string(&buffer[16], 16);
device->devtype = buffer[0] & 0x1f;
- memcpy(device->vendor, &buffer[8],
- sizeof(device->vendor));
- memcpy(device->model, &buffer[16],
- sizeof(device->model));
+ memcpy(device->vendor, &buffer[8], sizeof(device->vendor));
+ memcpy(device->model, &buffer[16], sizeof(device->model));
if (pqi_is_logical_device(device) && device->devtype == TYPE_DISK) {
- pqi_get_raid_level(ctrl_info, device);
- pqi_get_offload_status(ctrl_info, device);
- pqi_get_volume_status(ctrl_info, device);
+ if (device->is_external_raid_device) {
+ device->raid_level = SA_RAID_UNKNOWN;
+ device->volume_status = CISS_LV_OK;
+ device->volume_offline = false;
+ } else {
+ pqi_get_raid_level(ctrl_info, device);
+ pqi_get_raid_bypass_status(ctrl_info, device);
+ pqi_get_volume_status(ctrl_info, device);
+ }
}
out:
@@ -1138,8 +1341,7 @@ static void pqi_show_volume_status(struct pqi_ctrl_info *ctrl_info,
status = "Volume undergoing encryption re-keying process";
break;
case CISS_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
- status =
- "Encrypted volume inaccessible - disabled on ctrl";
+ status = "Volume encrypted but encryption is disabled";
break;
case CISS_LV_PENDING_ENCRYPTION:
status = "Volume pending migration to encrypted state";
@@ -1166,85 +1368,6 @@ static void pqi_show_volume_status(struct pqi_ctrl_info *ctrl_info,
device->bus, device->target, device->lun, status);
}
-static struct pqi_scsi_dev *pqi_find_disk_by_aio_handle(
- struct pqi_ctrl_info *ctrl_info, u32 aio_handle)
-{
- struct pqi_scsi_dev *device;
-
- list_for_each_entry(device, &ctrl_info->scsi_device_list,
- scsi_device_list_entry) {
- if (device->devtype != TYPE_DISK && device->devtype != TYPE_ZBC)
- continue;
- if (pqi_is_logical_device(device))
- continue;
- if (device->aio_handle == aio_handle)
- return device;
- }
-
- return NULL;
-}
-
-static void pqi_update_logical_drive_queue_depth(
- struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *logical_drive)
-{
- unsigned int i;
- struct raid_map *raid_map;
- struct raid_map_disk_data *disk_data;
- struct pqi_scsi_dev *phys_disk;
- unsigned int num_phys_disks;
- unsigned int num_raid_map_entries;
- unsigned int queue_depth;
-
- logical_drive->queue_depth = PQI_LOGICAL_DRIVE_DEFAULT_MAX_QUEUE_DEPTH;
-
- raid_map = logical_drive->raid_map;
- if (!raid_map)
- return;
-
- disk_data = raid_map->disk_data;
- num_phys_disks = get_unaligned_le16(&raid_map->layout_map_count) *
- (get_unaligned_le16(&raid_map->data_disks_per_row) +
- get_unaligned_le16(&raid_map->metadata_disks_per_row));
- num_raid_map_entries = num_phys_disks *
- get_unaligned_le16(&raid_map->row_cnt);
-
- queue_depth = 0;
- for (i = 0; i < num_raid_map_entries; i++) {
- phys_disk = pqi_find_disk_by_aio_handle(ctrl_info,
- disk_data[i].aio_handle);
-
- if (!phys_disk) {
- dev_warn(&ctrl_info->pci_dev->dev,
- "failed to find physical disk for logical drive %016llx\n",
- get_unaligned_be64(logical_drive->scsi3addr));
- logical_drive->offload_enabled = false;
- logical_drive->offload_enabled_pending = false;
- kfree(raid_map);
- logical_drive->raid_map = NULL;
- return;
- }
-
- queue_depth += phys_disk->queue_depth;
- }
-
- logical_drive->queue_depth = queue_depth;
-}
-
-static void pqi_update_all_logical_drive_queue_depths(
- struct pqi_ctrl_info *ctrl_info)
-{
- struct pqi_scsi_dev *device;
-
- list_for_each_entry(device, &ctrl_info->scsi_device_list,
- scsi_device_list_entry) {
- if (device->devtype != TYPE_DISK && device->devtype != TYPE_ZBC)
- continue;
- if (!pqi_is_logical_device(device))
- continue;
- pqi_update_logical_drive_queue_depth(ctrl_info, device);
- }
-}
-
static void pqi_rescan_worker(struct work_struct *work)
{
struct pqi_ctrl_info *ctrl_info;
@@ -1336,24 +1459,65 @@ static enum pqi_find_result pqi_scsi_find_entry(struct pqi_ctrl_info *ctrl_info,
return DEVICE_NOT_FOUND;
}
+#define PQI_DEV_INFO_BUFFER_LENGTH 128
+
static void pqi_dev_info(struct pqi_ctrl_info *ctrl_info,
char *action, struct pqi_scsi_dev *device)
{
- dev_info(&ctrl_info->pci_dev->dev,
- "%s scsi %d:%d:%d:%d: %s %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n",
- action,
- ctrl_info->scsi_host->host_no,
- device->bus,
- device->target,
- device->lun,
+ ssize_t count;
+ char buffer[PQI_DEV_INFO_BUFFER_LENGTH];
+
+ count = snprintf(buffer, PQI_DEV_INFO_BUFFER_LENGTH,
+ "%d:%d:", ctrl_info->scsi_host->host_no, device->bus);
+
+ if (device->target_lun_valid)
+ count += snprintf(buffer + count,
+ PQI_DEV_INFO_BUFFER_LENGTH - count,
+ "%d:%d",
+ device->target,
+ device->lun);
+ else
+ count += snprintf(buffer + count,
+ PQI_DEV_INFO_BUFFER_LENGTH - count,
+ "-:-");
+
+ if (pqi_is_logical_device(device))
+ count += snprintf(buffer + count,
+ PQI_DEV_INFO_BUFFER_LENGTH - count,
+ " %08x%08x",
+ *((u32 *)&device->scsi3addr),
+ *((u32 *)&device->scsi3addr[4]));
+ else
+ count += snprintf(buffer + count,
+ PQI_DEV_INFO_BUFFER_LENGTH - count,
+ " %016llx", device->sas_address);
+
+ count += snprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count,
+ " %s %.8s %.16s ",
scsi_device_type(device->devtype),
device->vendor,
- device->model,
- pqi_raid_level_to_string(device->raid_level),
- device->offload_configured ? '+' : '-',
- device->offload_enabled_pending ? '+' : '-',
- device->expose_device ? '+' : '-',
- device->queue_depth);
+ device->model);
+
+ if (pqi_is_logical_device(device)) {
+ if (device->devtype == TYPE_DISK)
+ count += snprintf(buffer + count,
+ PQI_DEV_INFO_BUFFER_LENGTH - count,
+ "SSDSmartPathCap%c En%c %-12s",
+ device->raid_bypass_configured ? '+' : '-',
+ device->raid_bypass_enabled ? '+' : '-',
+ pqi_raid_level_to_string(device->raid_level));
+ } else {
+ count += snprintf(buffer + count,
+ PQI_DEV_INFO_BUFFER_LENGTH - count,
+ "AIO%c", device->aio_enabled ? '+' : '-');
+ if (device->devtype == TYPE_DISK ||
+ device->devtype == TYPE_ZBC)
+ count += snprintf(buffer + count,
+ PQI_DEV_INFO_BUFFER_LENGTH - count,
+ " qd=%-6d", device->queue_depth);
+ }
+
+ dev_info(&ctrl_info->pci_dev->dev, "%s %s\n", action, buffer);
}
/* Assumes the SCSI device list lock is held. */
@@ -1373,8 +1537,8 @@ static void pqi_scsi_update_device(struct pqi_scsi_dev *existing_device,
/* By definition, the scsi3addr and wwid fields are already the same. */
existing_device->is_physical_device = new_device->is_physical_device;
- existing_device->expose_device = new_device->expose_device;
- existing_device->no_uld_attach = new_device->no_uld_attach;
+ existing_device->is_external_raid_device =
+ new_device->is_external_raid_device;
existing_device->aio_enabled = new_device->aio_enabled;
memcpy(existing_device->vendor, new_device->vendor,
sizeof(existing_device->vendor));
@@ -1392,13 +1556,13 @@ static void pqi_scsi_update_device(struct pqi_scsi_dev *existing_device,
sizeof(existing_device->box));
memcpy(existing_device->phys_connector, new_device->phys_connector,
sizeof(existing_device->phys_connector));
- existing_device->offload_configured = new_device->offload_configured;
- existing_device->offload_enabled = false;
- existing_device->offload_enabled_pending =
- new_device->offload_enabled_pending;
existing_device->offload_to_mirror = 0;
kfree(existing_device->raid_map);
existing_device->raid_map = new_device->raid_map;
+ existing_device->raid_bypass_configured =
+ new_device->raid_bypass_configured;
+ existing_device->raid_bypass_enabled =
+ new_device->raid_bypass_enabled;
/* To prevent this from being freed later. */
new_device->raid_map = NULL;
@@ -1440,11 +1604,8 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info,
struct pqi_scsi_dev *device;
struct pqi_scsi_dev *next;
struct pqi_scsi_dev *matching_device;
- struct list_head add_list;
- struct list_head delete_list;
-
- INIT_LIST_HEAD(&add_list);
- INIT_LIST_HEAD(&delete_list);
+ LIST_HEAD(add_list);
+ LIST_HEAD(delete_list);
/*
* The idea here is to do as little work as possible while holding the
@@ -1490,9 +1651,6 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info,
*/
device->new_device = true;
break;
- default:
- WARN_ON(find_result);
- break;
}
}
@@ -1519,26 +1677,19 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info,
device->keep_device = true;
}
- pqi_update_all_logical_drive_queue_depths(ctrl_info);
-
- list_for_each_entry(device, &ctrl_info->scsi_device_list,
- scsi_device_list_entry)
- device->offload_enabled =
- device->offload_enabled_pending;
-
spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
/* Remove all devices that have gone away. */
list_for_each_entry_safe(device, next, &delete_list,
delete_list_entry) {
- if (device->sdev)
- pqi_remove_device(ctrl_info, device);
if (device->volume_offline) {
pqi_dev_info(ctrl_info, "offline", device);
pqi_show_volume_status(ctrl_info, device);
} else {
pqi_dev_info(ctrl_info, "removed", device);
}
+ if (device->sdev)
+ pqi_remove_device(ctrl_info, device);
list_del(&device->delete_list_entry);
pqi_free_device(device);
}
@@ -1559,7 +1710,8 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info,
/* Expose any new devices. */
list_for_each_entry_safe(device, next, &add_list, add_list_entry) {
- if (device->expose_device && !device->sdev) {
+ if (!device->sdev) {
+ pqi_dev_info(ctrl_info, "added", device);
rc = pqi_add_device(ctrl_info, device);
if (rc) {
dev_warn(&ctrl_info->pci_dev->dev,
@@ -1568,10 +1720,8 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info,
device->bus, device->target,
device->lun);
pqi_fixup_botched_add(ctrl_info, device);
- continue;
}
}
- pqi_dev_info(ctrl_info, "added", device);
}
}
@@ -1591,8 +1741,8 @@ static bool pqi_is_supported_device(struct pqi_scsi_dev *device)
/*
* Only support the HBA controller itself as a RAID
* controller. If it's a RAID controller other than
- * the HBA itself (an external RAID controller, MSA500
- * or similar), we don't support it.
+ * the HBA itself (an external RAID controller, for
+ * example), we don't support it.
*/
if (pqi_is_hba_lunid(device->scsi3addr))
is_supported = true;
@@ -1602,43 +1752,20 @@ static bool pqi_is_supported_device(struct pqi_scsi_dev *device)
return is_supported;
}
-static inline bool pqi_skip_device(u8 *scsi3addr,
- struct report_phys_lun_extended_entry *phys_lun_ext_entry)
+static inline bool pqi_skip_device(u8 *scsi3addr)
{
- u8 device_flags;
-
- if (!MASKED_DEVICE(scsi3addr))
- return false;
-
- /* The device is masked. */
-
- device_flags = phys_lun_ext_entry->device_flags;
-
- if (device_flags & REPORT_PHYS_LUN_DEV_FLAG_NON_DISK) {
- /*
- * It's a non-disk device. We ignore all devices of this type
- * when they're masked.
- */
+ /* Ignore all masked devices. */
+ if (MASKED_DEVICE(scsi3addr))
return true;
- }
return false;
}
-static inline bool pqi_expose_device(struct pqi_scsi_dev *device)
-{
- /* Expose all devices except for physical devices that are masked. */
- if (device->is_physical_device && MASKED_DEVICE(device->scsi3addr))
- return false;
-
- return true;
-}
-
static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info)
{
int i;
int rc;
- struct list_head new_device_list_head;
+ LIST_HEAD(new_device_list_head);
struct report_phys_lun_extended *physdev_list = NULL;
struct report_log_lun_extended *logdev_list = NULL;
struct report_phys_lun_extended_entry *phys_lun_ext_entry;
@@ -1654,9 +1781,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info)
bool is_physical_device;
u8 *scsi3addr;
static char *out_of_memory_msg =
- "out of memory, device discovery stopped";
-
- INIT_LIST_HEAD(&new_device_list_head);
+ "failed to allocate memory, device discovery stopped";
rc = pqi_get_device_lists(ctrl_info, &physdev_list, &logdev_list);
if (rc)
@@ -1732,8 +1857,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info)
scsi3addr = log_lun_ext_entry->lunid;
}
- if (is_physical_device &&
- pqi_skip_device(scsi3addr, phys_lun_ext_entry))
+ if (is_physical_device && pqi_skip_device(scsi3addr))
continue;
if (device)
@@ -1744,7 +1868,9 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info)
memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr));
device->is_physical_device = is_physical_device;
- device->raid_level = SA_RAID_UNKNOWN;
+ if (!is_physical_device)
+ device->is_external_raid_device =
+ pqi_is_external_raid_addr(scsi3addr);
/* Gather information about the device. */
rc = pqi_get_device_info(ctrl_info, device);
@@ -1754,9 +1880,16 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info)
goto out;
}
if (rc) {
- dev_warn(&ctrl_info->pci_dev->dev,
- "obtaining device info failed, skipping device %016llx\n",
- get_unaligned_be64(device->scsi3addr));
+ if (device->is_physical_device)
+ dev_warn(&ctrl_info->pci_dev->dev,
+ "obtaining device info failed, skipping physical device %016llx\n",
+ get_unaligned_be64(
+ &phys_lun_ext_entry->wwid));
+ else
+ dev_warn(&ctrl_info->pci_dev->dev,
+ "obtaining device info failed, skipping logical device %08x%08x\n",
+ *((u32 *)&device->scsi3addr),
+ *((u32 *)&device->scsi3addr[4]));
rc = 0;
continue;
}
@@ -1766,8 +1899,6 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info)
pqi_assign_bus_target_lun(device);
- device->expose_device = pqi_expose_device(device);
-
if (device->is_physical_device) {
device->wwid = phys_lun_ext_entry->wwid;
if ((phys_lun_ext_entry->device_flags &
@@ -1823,19 +1954,25 @@ static void pqi_remove_all_scsi_devices(struct pqi_ctrl_info *ctrl_info)
{
unsigned long flags;
struct pqi_scsi_dev *device;
- struct pqi_scsi_dev *next;
- spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
+ while (1) {
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
+
+ device = list_first_entry_or_null(&ctrl_info->scsi_device_list,
+ struct pqi_scsi_dev, scsi_device_list_entry);
+ if (device)
+ list_del(&device->scsi_device_list_entry);
+
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock,
+ flags);
+
+ if (!device)
+ break;
- list_for_each_entry_safe(device, next, &ctrl_info->scsi_device_list,
- scsi_device_list_entry) {
if (device->sdev)
pqi_remove_device(ctrl_info, device);
- list_del(&device->scsi_device_list_entry);
pqi_free_device(device);
}
-
- spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
}
static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info)
@@ -1849,7 +1986,7 @@ static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info)
rc = pqi_update_scsi_devices(ctrl_info);
if (rc)
- pqi_schedule_rescan_worker(ctrl_info);
+ pqi_schedule_rescan_worker_delayed(ctrl_info);
mutex_unlock(&ctrl_info->scan_mutex);
@@ -1873,6 +2010,18 @@ static int pqi_scan_finished(struct Scsi_Host *shost,
return !mutex_is_locked(&ctrl_info->scan_mutex);
}
+static void pqi_wait_until_scan_finished(struct pqi_ctrl_info *ctrl_info)
+{
+ mutex_lock(&ctrl_info->scan_mutex);
+ mutex_unlock(&ctrl_info->scan_mutex);
+}
+
+static void pqi_wait_until_lun_reset_finished(struct pqi_ctrl_info *ctrl_info)
+{
+ mutex_lock(&ctrl_info->lun_reset_mutex);
+ mutex_unlock(&ctrl_info->lun_reset_mutex);
+}
+
static inline void pqi_set_encryption_info(
struct pqi_encryption_info *encryption_info, struct raid_map *raid_map,
u64 first_block)
@@ -1895,7 +2044,7 @@ static inline void pqi_set_encryption_info(
}
/*
- * Attempt to perform offload RAID mapping for a logical volume I/O.
+ * Attempt to perform RAID bypass mapping for a logical volume I/O.
*/
#define PQI_RAID_BYPASS_INELIGIBLE 1
@@ -2227,7 +2376,7 @@ static int pqi_raid_bypass_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
}
return pqi_aio_submit_io(ctrl_info, scmd, aio_handle,
- cdb, cdb_length, queue_group, encryption_info_ptr);
+ cdb, cdb_length, queue_group, encryption_info_ptr, true);
}
#define PQI_STATUS_IDLE 0x0
@@ -2299,23 +2448,26 @@ static inline void pqi_aio_path_disabled(struct pqi_io_request *io_request)
struct pqi_scsi_dev *device;
device = io_request->scmd->device->hostdata;
- device->offload_enabled = false;
+ device->raid_bypass_enabled = false;
+ device->aio_enabled = false;
}
-static inline void pqi_take_device_offline(struct scsi_device *sdev)
+static inline void pqi_take_device_offline(struct scsi_device *sdev, char *path)
{
struct pqi_ctrl_info *ctrl_info;
struct pqi_scsi_dev *device;
- if (scsi_device_online(sdev)) {
- scsi_device_set_state(sdev, SDEV_OFFLINE);
- ctrl_info = shost_to_hba(sdev->host);
- schedule_delayed_work(&ctrl_info->rescan_work, 0);
- device = sdev->hostdata;
- dev_err(&ctrl_info->pci_dev->dev, "offlined scsi %d:%d:%d:%d\n",
- ctrl_info->scsi_host->host_no, device->bus,
- device->target, device->lun);
- }
+ device = sdev->hostdata;
+ if (device->device_offline)
+ return;
+
+ device->device_offline = true;
+ scsi_device_set_state(sdev, SDEV_OFFLINE);
+ ctrl_info = shost_to_hba(sdev->host);
+ pqi_schedule_rescan_worker(ctrl_info);
+ dev_err(&ctrl_info->pci_dev->dev, "offlined %s scsi %d:%d:%d:%d\n",
+ path, ctrl_info->scsi_host->host_no, device->bus,
+ device->target, device->lun);
}
static void pqi_process_raid_io_error(struct pqi_io_request *io_request)
@@ -2337,13 +2489,43 @@ static void pqi_process_raid_io_error(struct pqi_io_request *io_request)
scsi_status = error_info->status;
host_byte = DID_OK;
- if (error_info->data_out_result == PQI_DATA_IN_OUT_UNDERFLOW) {
+ switch (error_info->data_out_result) {
+ case PQI_DATA_IN_OUT_GOOD:
+ break;
+ case PQI_DATA_IN_OUT_UNDERFLOW:
xfer_count =
get_unaligned_le32(&error_info->data_out_transferred);
residual_count = scsi_bufflen(scmd) - xfer_count;
scsi_set_resid(scmd, residual_count);
if (xfer_count < scmd->underflow)
host_byte = DID_SOFT_ERROR;
+ break;
+ case PQI_DATA_IN_OUT_UNSOLICITED_ABORT:
+ case PQI_DATA_IN_OUT_ABORTED:
+ host_byte = DID_ABORT;
+ break;
+ case PQI_DATA_IN_OUT_TIMEOUT:
+ host_byte = DID_TIME_OUT;
+ break;
+ case PQI_DATA_IN_OUT_BUFFER_OVERFLOW:
+ case PQI_DATA_IN_OUT_PROTOCOL_ERROR:
+ case PQI_DATA_IN_OUT_BUFFER_ERROR:
+ case PQI_DATA_IN_OUT_BUFFER_OVERFLOW_DESCRIPTOR_AREA:
+ case PQI_DATA_IN_OUT_BUFFER_OVERFLOW_BRIDGE:
+ case PQI_DATA_IN_OUT_ERROR:
+ case PQI_DATA_IN_OUT_HARDWARE_ERROR:
+ case PQI_DATA_IN_OUT_PCIE_FABRIC_ERROR:
+ case PQI_DATA_IN_OUT_PCIE_COMPLETION_TIMEOUT:
+ case PQI_DATA_IN_OUT_PCIE_COMPLETER_ABORT_RECEIVED:
+ case PQI_DATA_IN_OUT_PCIE_UNSUPPORTED_REQUEST_RECEIVED:
+ case PQI_DATA_IN_OUT_PCIE_ECRC_CHECK_FAILED:
+ case PQI_DATA_IN_OUT_PCIE_UNSUPPORTED_REQUEST:
+ case PQI_DATA_IN_OUT_PCIE_ACS_VIOLATION:
+ case PQI_DATA_IN_OUT_PCIE_TLP_PREFIX_BLOCKED:
+ case PQI_DATA_IN_OUT_PCIE_POISONED_MEMORY_READ:
+ default:
+ host_byte = DID_ERROR;
+ break;
}
sense_data_length = get_unaligned_le16(&error_info->sense_data_length);
@@ -2360,7 +2542,7 @@ static void pqi_process_raid_io_error(struct pqi_io_request *io_request)
sshdr.sense_key == HARDWARE_ERROR &&
sshdr.asc == 0x3e &&
sshdr.ascq == 0x1) {
- pqi_take_device_offline(scmd->device);
+ pqi_take_device_offline(scmd->device, "RAID");
host_byte = DID_NO_CONNECT;
}
@@ -2419,9 +2601,11 @@ static void pqi_process_aio_io_error(struct pqi_io_request *io_request)
break;
case PQI_AIO_STATUS_NO_PATH_TO_DEVICE:
case PQI_AIO_STATUS_INVALID_DEVICE:
- device_offline = true;
- pqi_take_device_offline(scmd->device);
- host_byte = DID_NO_CONNECT;
+ if (!io_request->raid_bypass) {
+ device_offline = true;
+ pqi_take_device_offline(scmd->device, "AIO");
+ host_byte = DID_NO_CONNECT;
+ }
scsi_status = SAM_STAT_CHECK_CONDITION;
break;
case PQI_AIO_STATUS_IO_ERROR:
@@ -2547,7 +2731,6 @@ static unsigned int pqi_process_io_intr(struct pqi_ctrl_info *ctrl_info,
dev_err(&ctrl_info->pci_dev->dev,
"unexpected IU type: 0x%x\n",
response->header.iu_type);
- WARN_ON(response->header.iu_type);
break;
}
@@ -2583,23 +2766,18 @@ static inline unsigned int pqi_num_elements_free(unsigned int pi,
return elements_in_queue - num_elements_used - 1;
}
-#define PQI_EVENT_ACK_TIMEOUT 30
-
-static void pqi_start_event_ack(struct pqi_ctrl_info *ctrl_info,
+static void pqi_send_event_ack(struct pqi_ctrl_info *ctrl_info,
struct pqi_event_acknowledge_request *iu, size_t iu_length)
{
pqi_index_t iq_pi;
pqi_index_t iq_ci;
unsigned long flags;
void *next_element;
- unsigned long timeout;
struct pqi_queue_group *queue_group;
queue_group = &ctrl_info->queue_groups[PQI_DEFAULT_QUEUE_GROUP];
put_unaligned_le16(queue_group->oq_id, &iu->header.response_queue_id);
- timeout = (PQI_EVENT_ACK_TIMEOUT * HZ) + jiffies;
-
while (1) {
spin_lock_irqsave(&queue_group->submit_lock[RAID_PATH], flags);
@@ -2613,11 +2791,8 @@ static void pqi_start_event_ack(struct pqi_ctrl_info *ctrl_info,
spin_unlock_irqrestore(
&queue_group->submit_lock[RAID_PATH], flags);
- if (time_after(jiffies, timeout)) {
- dev_err(&ctrl_info->pci_dev->dev,
- "sending event acknowledge timed out\n");
+ if (pqi_ctrl_offline(ctrl_info))
return;
- }
}
next_element = queue_group->iq_element_array[RAID_PATH] +
@@ -2626,7 +2801,6 @@ static void pqi_start_event_ack(struct pqi_ctrl_info *ctrl_info,
memcpy(next_element, iu, iu_length);
iq_pi = (iq_pi + 1) % ctrl_info->num_elements_per_iq;
-
queue_group->iq_pi_copy[RAID_PATH] = iq_pi;
/*
@@ -2652,152 +2826,105 @@ static void pqi_acknowledge_event(struct pqi_ctrl_info *ctrl_info,
request.event_id = event->event_id;
request.additional_event_id = event->additional_event_id;
- pqi_start_event_ack(ctrl_info, &request, sizeof(request));
+ pqi_send_event_ack(ctrl_info, &request, sizeof(request));
}
static void pqi_event_worker(struct work_struct *work)
{
unsigned int i;
struct pqi_ctrl_info *ctrl_info;
- struct pqi_event *pending_event;
- bool got_non_heartbeat_event = false;
+ struct pqi_event *event;
ctrl_info = container_of(work, struct pqi_ctrl_info, event_work);
- pending_event = ctrl_info->pending_events;
- for (i = 0; i < PQI_NUM_SUPPORTED_EVENTS; i++) {
- if (pending_event->pending) {
- pending_event->pending = false;
- pqi_acknowledge_event(ctrl_info, pending_event);
- if (i != PQI_EVENT_HEARTBEAT)
- got_non_heartbeat_event = true;
- }
- pending_event++;
- }
-
- if (got_non_heartbeat_event)
- pqi_schedule_rescan_worker(ctrl_info);
-}
-
-static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info)
-{
- unsigned int i;
- unsigned int path;
- struct pqi_queue_group *queue_group;
- unsigned long flags;
- struct pqi_io_request *io_request;
- struct pqi_io_request *next;
- struct scsi_cmnd *scmd;
-
- ctrl_info->controller_online = false;
- dev_err(&ctrl_info->pci_dev->dev, "controller offline\n");
-
- for (i = 0; i < ctrl_info->num_queue_groups; i++) {
- queue_group = &ctrl_info->queue_groups[i];
-
- for (path = 0; path < 2; path++) {
- spin_lock_irqsave(
- &queue_group->submit_lock[path], flags);
-
- list_for_each_entry_safe(io_request, next,
- &queue_group->request_list[path],
- request_list_entry) {
-
- scmd = io_request->scmd;
- if (scmd) {
- set_host_byte(scmd, DID_NO_CONNECT);
- pqi_scsi_done(scmd);
- }
+ pqi_ctrl_busy(ctrl_info);
+ pqi_wait_if_ctrl_blocked(ctrl_info, NO_TIMEOUT);
+ if (pqi_ctrl_offline(ctrl_info))
+ goto out;
- list_del(&io_request->request_list_entry);
- }
+ pqi_schedule_rescan_worker_delayed(ctrl_info);
- spin_unlock_irqrestore(
- &queue_group->submit_lock[path], flags);
+ event = ctrl_info->events;
+ for (i = 0; i < PQI_NUM_SUPPORTED_EVENTS; i++) {
+ if (event->pending) {
+ event->pending = false;
+ pqi_acknowledge_event(ctrl_info, event);
}
+ event++;
}
+
+out:
+ pqi_ctrl_unbusy(ctrl_info);
}
-#define PQI_HEARTBEAT_TIMER_INTERVAL (5 * HZ)
-#define PQI_MAX_HEARTBEAT_REQUESTS 5
+#define PQI_HEARTBEAT_TIMER_INTERVAL (10 * HZ)
static void pqi_heartbeat_timer_handler(unsigned long data)
{
int num_interrupts;
+ u32 heartbeat_count;
struct pqi_ctrl_info *ctrl_info = (struct pqi_ctrl_info *)data;
+ pqi_check_ctrl_health(ctrl_info);
+ if (pqi_ctrl_offline(ctrl_info))
+ return;
+
num_interrupts = atomic_read(&ctrl_info->num_interrupts);
+ heartbeat_count = pqi_read_heartbeat_counter(ctrl_info);
if (num_interrupts == ctrl_info->previous_num_interrupts) {
- ctrl_info->num_heartbeats_requested++;
- if (ctrl_info->num_heartbeats_requested >
- PQI_MAX_HEARTBEAT_REQUESTS) {
+ if (heartbeat_count == ctrl_info->previous_heartbeat_count) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "no heartbeat detected - last heartbeat count: %u\n",
+ heartbeat_count);
pqi_take_ctrl_offline(ctrl_info);
return;
}
- ctrl_info->pending_events[PQI_EVENT_HEARTBEAT].pending = true;
- schedule_work(&ctrl_info->event_work);
} else {
- ctrl_info->num_heartbeats_requested = 0;
+ ctrl_info->previous_num_interrupts = num_interrupts;
}
- ctrl_info->previous_num_interrupts = num_interrupts;
+ ctrl_info->previous_heartbeat_count = heartbeat_count;
mod_timer(&ctrl_info->heartbeat_timer,
jiffies + PQI_HEARTBEAT_TIMER_INTERVAL);
}
static void pqi_start_heartbeat_timer(struct pqi_ctrl_info *ctrl_info)
{
+ if (!ctrl_info->heartbeat_counter)
+ return;
+
ctrl_info->previous_num_interrupts =
atomic_read(&ctrl_info->num_interrupts);
+ ctrl_info->previous_heartbeat_count =
+ pqi_read_heartbeat_counter(ctrl_info);
- init_timer(&ctrl_info->heartbeat_timer);
ctrl_info->heartbeat_timer.expires =
jiffies + PQI_HEARTBEAT_TIMER_INTERVAL;
ctrl_info->heartbeat_timer.data = (unsigned long)ctrl_info;
ctrl_info->heartbeat_timer.function = pqi_heartbeat_timer_handler;
add_timer(&ctrl_info->heartbeat_timer);
- ctrl_info->heartbeat_timer_started = true;
}
static inline void pqi_stop_heartbeat_timer(struct pqi_ctrl_info *ctrl_info)
{
- if (ctrl_info->heartbeat_timer_started)
- del_timer_sync(&ctrl_info->heartbeat_timer);
+ del_timer_sync(&ctrl_info->heartbeat_timer);
}
-static int pqi_event_type_to_event_index(unsigned int event_type)
+static inline int pqi_event_type_to_event_index(unsigned int event_type)
{
int index;
- switch (event_type) {
- case PQI_EVENT_TYPE_HEARTBEAT:
- index = PQI_EVENT_HEARTBEAT;
- break;
- case PQI_EVENT_TYPE_HOTPLUG:
- index = PQI_EVENT_HOTPLUG;
- break;
- case PQI_EVENT_TYPE_HARDWARE:
- index = PQI_EVENT_HARDWARE;
- break;
- case PQI_EVENT_TYPE_PHYSICAL_DEVICE:
- index = PQI_EVENT_PHYSICAL_DEVICE;
- break;
- case PQI_EVENT_TYPE_LOGICAL_DEVICE:
- index = PQI_EVENT_LOGICAL_DEVICE;
- break;
- case PQI_EVENT_TYPE_AIO_STATE_CHANGE:
- index = PQI_EVENT_AIO_STATE_CHANGE;
- break;
- case PQI_EVENT_TYPE_AIO_CONFIG_CHANGE:
- index = PQI_EVENT_AIO_CONFIG_CHANGE;
- break;
- default:
- index = -1;
- break;
- }
+ for (index = 0; index < ARRAY_SIZE(pqi_supported_event_types); index++)
+ if (event_type == pqi_supported_event_types[index])
+ return index;
- return index;
+ return -1;
+}
+
+static inline bool pqi_is_supported_event(unsigned int event_type)
+{
+ return pqi_event_type_to_event_index(event_type) != -1;
}
static unsigned int pqi_process_event_intr(struct pqi_ctrl_info *ctrl_info)
@@ -2807,13 +2934,11 @@ static unsigned int pqi_process_event_intr(struct pqi_ctrl_info *ctrl_info)
pqi_index_t oq_ci;
struct pqi_event_queue *event_queue;
struct pqi_event_response *response;
- struct pqi_event *pending_event;
- bool need_delayed_work;
+ struct pqi_event *event;
int event_index;
event_queue = &ctrl_info->event_queue;
num_events = 0;
- need_delayed_work = false;
oq_ci = event_queue->oq_ci_copy;
while (1) {
@@ -2830,17 +2955,12 @@ static unsigned int pqi_process_event_intr(struct pqi_ctrl_info *ctrl_info)
if (event_index >= 0) {
if (response->request_acknowlege) {
- pending_event =
- &ctrl_info->pending_events[event_index];
- pending_event->event_type =
- response->event_type;
- pending_event->event_id = response->event_id;
- pending_event->additional_event_id =
+ event = &ctrl_info->events[event_index];
+ event->pending = true;
+ event->event_type = response->event_type;
+ event->event_id = response->event_id;
+ event->additional_event_id =
response->additional_event_id;
- if (event_index != PQI_EVENT_HEARTBEAT) {
- pending_event->pending = true;
- need_delayed_work = true;
- }
}
}
@@ -2850,14 +2970,112 @@ static unsigned int pqi_process_event_intr(struct pqi_ctrl_info *ctrl_info)
if (num_events) {
event_queue->oq_ci_copy = oq_ci;
writel(oq_ci, event_queue->oq_ci);
-
- if (need_delayed_work)
- schedule_work(&ctrl_info->event_work);
+ schedule_work(&ctrl_info->event_work);
}
return num_events;
}
+#define PQI_LEGACY_INTX_MASK 0x1
+
+static inline void pqi_configure_legacy_intx(struct pqi_ctrl_info *ctrl_info,
+ bool enable_intx)
+{
+ u32 intx_mask;
+ struct pqi_device_registers __iomem *pqi_registers;
+ volatile void __iomem *register_addr;
+
+ pqi_registers = ctrl_info->pqi_registers;
+
+ if (enable_intx)
+ register_addr = &pqi_registers->legacy_intx_mask_clear;
+ else
+ register_addr = &pqi_registers->legacy_intx_mask_set;
+
+ intx_mask = readl(register_addr);
+ intx_mask |= PQI_LEGACY_INTX_MASK;
+ writel(intx_mask, register_addr);
+}
+
+static void pqi_change_irq_mode(struct pqi_ctrl_info *ctrl_info,
+ enum pqi_irq_mode new_mode)
+{
+ switch (ctrl_info->irq_mode) {
+ case IRQ_MODE_MSIX:
+ switch (new_mode) {
+ case IRQ_MODE_MSIX:
+ break;
+ case IRQ_MODE_INTX:
+ pqi_configure_legacy_intx(ctrl_info, true);
+ sis_disable_msix(ctrl_info);
+ sis_enable_intx(ctrl_info);
+ break;
+ case IRQ_MODE_NONE:
+ sis_disable_msix(ctrl_info);
+ break;
+ }
+ break;
+ case IRQ_MODE_INTX:
+ switch (new_mode) {
+ case IRQ_MODE_MSIX:
+ pqi_configure_legacy_intx(ctrl_info, false);
+ sis_disable_intx(ctrl_info);
+ sis_enable_msix(ctrl_info);
+ break;
+ case IRQ_MODE_INTX:
+ break;
+ case IRQ_MODE_NONE:
+ pqi_configure_legacy_intx(ctrl_info, false);
+ sis_disable_intx(ctrl_info);
+ break;
+ }
+ break;
+ case IRQ_MODE_NONE:
+ switch (new_mode) {
+ case IRQ_MODE_MSIX:
+ sis_enable_msix(ctrl_info);
+ break;
+ case IRQ_MODE_INTX:
+ pqi_configure_legacy_intx(ctrl_info, true);
+ sis_enable_intx(ctrl_info);
+ break;
+ case IRQ_MODE_NONE:
+ break;
+ }
+ break;
+ }
+
+ ctrl_info->irq_mode = new_mode;
+}
+
+#define PQI_LEGACY_INTX_PENDING 0x1
+
+static inline bool pqi_is_valid_irq(struct pqi_ctrl_info *ctrl_info)
+{
+ bool valid_irq;
+ u32 intx_status;
+
+ switch (ctrl_info->irq_mode) {
+ case IRQ_MODE_MSIX:
+ valid_irq = true;
+ break;
+ case IRQ_MODE_INTX:
+ intx_status =
+ readl(&ctrl_info->pqi_registers->legacy_intx_status);
+ if (intx_status & PQI_LEGACY_INTX_PENDING)
+ valid_irq = true;
+ else
+ valid_irq = false;
+ break;
+ case IRQ_MODE_NONE:
+ default:
+ valid_irq = false;
+ break;
+ }
+
+ return valid_irq;
+}
+
static irqreturn_t pqi_irq_handler(int irq, void *data)
{
struct pqi_ctrl_info *ctrl_info;
@@ -2867,7 +3085,7 @@ static irqreturn_t pqi_irq_handler(int irq, void *data)
queue_group = data;
ctrl_info = queue_group->ctrl_info;
- if (!ctrl_info || !queue_group->oq_ci)
+ if (!pqi_is_valid_irq(ctrl_info))
return IRQ_NONE;
num_responses_handled = pqi_process_io_intr(ctrl_info, queue_group);
@@ -2886,19 +3104,19 @@ static irqreturn_t pqi_irq_handler(int irq, void *data)
static int pqi_request_irqs(struct pqi_ctrl_info *ctrl_info)
{
- struct pci_dev *pdev = ctrl_info->pci_dev;
+ struct pci_dev *pci_dev = ctrl_info->pci_dev;
int i;
int rc;
- ctrl_info->event_irq = pci_irq_vector(pdev, 0);
+ ctrl_info->event_irq = pci_irq_vector(pci_dev, 0);
for (i = 0; i < ctrl_info->num_msix_vectors_enabled; i++) {
- rc = request_irq(pci_irq_vector(pdev, i), pqi_irq_handler, 0,
+ rc = request_irq(pci_irq_vector(pci_dev, i), pqi_irq_handler, 0,
DRIVER_NAME_SHORT, &ctrl_info->queue_groups[i]);
if (rc) {
- dev_err(&pdev->dev,
+ dev_err(&pci_dev->dev,
"irq %u init failed with error %d\n",
- pci_irq_vector(pdev, i), rc);
+ pci_irq_vector(pci_dev, i), rc);
return rc;
}
ctrl_info->num_msix_vectors_initialized++;
@@ -2907,23 +3125,44 @@ static int pqi_request_irqs(struct pqi_ctrl_info *ctrl_info)
return 0;
}
+static void pqi_free_irqs(struct pqi_ctrl_info *ctrl_info)
+{
+ int i;
+
+ for (i = 0; i < ctrl_info->num_msix_vectors_initialized; i++)
+ free_irq(pci_irq_vector(ctrl_info->pci_dev, i),
+ &ctrl_info->queue_groups[i]);
+
+ ctrl_info->num_msix_vectors_initialized = 0;
+}
+
static int pqi_enable_msix_interrupts(struct pqi_ctrl_info *ctrl_info)
{
- int ret;
+ int num_vectors_enabled;
- ret = pci_alloc_irq_vectors(ctrl_info->pci_dev,
+ num_vectors_enabled = pci_alloc_irq_vectors(ctrl_info->pci_dev,
PQI_MIN_MSIX_VECTORS, ctrl_info->num_queue_groups,
PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
- if (ret < 0) {
+ if (num_vectors_enabled < 0) {
dev_err(&ctrl_info->pci_dev->dev,
- "MSI-X init failed with error %d\n", ret);
- return ret;
+ "MSI-X init failed with error %d\n",
+ num_vectors_enabled);
+ return num_vectors_enabled;
}
- ctrl_info->num_msix_vectors_enabled = ret;
+ ctrl_info->num_msix_vectors_enabled = num_vectors_enabled;
+ ctrl_info->irq_mode = IRQ_MODE_MSIX;
return 0;
}
+static void pqi_disable_msix_interrupts(struct pqi_ctrl_info *ctrl_info)
+{
+ if (ctrl_info->num_msix_vectors_enabled) {
+ pci_free_irq_vectors(ctrl_info->pci_dev);
+ ctrl_info->num_msix_vectors_enabled = 0;
+ }
+}
+
static int pqi_alloc_operational_queues(struct pqi_ctrl_info *ctrl_info)
{
unsigned int i;
@@ -2976,16 +3215,15 @@ static int pqi_alloc_operational_queues(struct pqi_ctrl_info *ctrl_info)
alloc_length = (size_t)aligned_pointer +
PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT;
+ alloc_length += PQI_EXTRA_SGL_MEMORY;
+
ctrl_info->queue_memory_base =
dma_zalloc_coherent(&ctrl_info->pci_dev->dev,
alloc_length,
&ctrl_info->queue_memory_base_dma_handle, GFP_KERNEL);
- if (!ctrl_info->queue_memory_base) {
- dev_err(&ctrl_info->pci_dev->dev,
- "failed to allocate memory for PQI admin queues\n");
+ if (!ctrl_info->queue_memory_base)
return -ENOMEM;
- }
ctrl_info->queue_memory_length = alloc_length;
@@ -3235,6 +3473,8 @@ static void pqi_submit_admin_request(struct pqi_ctrl_info *ctrl_info,
writel(iq_pi, admin_queues->iq_pi);
}
+#define PQI_ADMIN_REQUEST_TIMEOUT_SECS 60
+
static int pqi_poll_for_admin_response(struct pqi_ctrl_info *ctrl_info,
struct pqi_general_admin_response *response)
{
@@ -3246,7 +3486,7 @@ static int pqi_poll_for_admin_response(struct pqi_ctrl_info *ctrl_info,
admin_queues = &ctrl_info->admin_queues;
oq_ci = admin_queues->oq_ci_copy;
- timeout = (3 * HZ) + jiffies;
+ timeout = (PQI_ADMIN_REQUEST_TIMEOUT_SECS * HZ) + jiffies;
while (1) {
oq_pi = *admin_queues->oq_pi;
@@ -3257,6 +3497,8 @@ static int pqi_poll_for_admin_response(struct pqi_ctrl_info *ctrl_info,
"timed out waiting for admin response\n");
return -ETIMEDOUT;
}
+ if (!sis_is_firmware_running(ctrl_info))
+ return -ENXIO;
usleep_range(1000, 2000);
}
@@ -3287,9 +3529,11 @@ static void pqi_start_io(struct pqi_ctrl_info *ctrl_info,
spin_lock_irqsave(&queue_group->submit_lock[path], flags);
- if (io_request)
+ if (io_request) {
+ io_request->queue_group = queue_group;
list_add_tail(&io_request->request_list_entry,
&queue_group->request_list[path]);
+ }
iq_pi = queue_group->iq_pi_copy[path];
@@ -3348,6 +3592,30 @@ static void pqi_start_io(struct pqi_ctrl_info *ctrl_info,
spin_unlock_irqrestore(&queue_group->submit_lock[path], flags);
}
+#define PQI_WAIT_FOR_COMPLETION_IO_TIMEOUT_SECS 10
+
+static int pqi_wait_for_completion_io(struct pqi_ctrl_info *ctrl_info,
+ struct completion *wait)
+{
+ int rc;
+
+ while (1) {
+ if (wait_for_completion_io_timeout(wait,
+ PQI_WAIT_FOR_COMPLETION_IO_TIMEOUT_SECS * HZ)) {
+ rc = 0;
+ break;
+ }
+
+ pqi_check_ctrl_health(ctrl_info);
+ if (pqi_ctrl_offline(ctrl_info)) {
+ rc = -ENXIO;
+ break;
+ }
+ }
+
+ return rc;
+}
+
static void pqi_raid_synchronous_complete(struct pqi_io_request *io_request,
void *context)
{
@@ -3371,7 +3639,7 @@ static int pqi_submit_raid_request_synchronous_with_io_request(
io_request);
if (timeout_msecs == NO_TIMEOUT) {
- wait_for_completion_io(&wait);
+ pqi_wait_for_completion_io(ctrl_info, &wait);
} else {
if (!wait_for_completion_io_timeout(&wait,
msecs_to_jiffies(timeout_msecs))) {
@@ -3418,6 +3686,18 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info,
}
}
+ pqi_ctrl_busy(ctrl_info);
+ timeout_msecs = pqi_wait_if_ctrl_blocked(ctrl_info, timeout_msecs);
+ if (timeout_msecs == 0) {
+ rc = -ETIMEDOUT;
+ goto out;
+ }
+
+ if (pqi_ctrl_offline(ctrl_info)) {
+ rc = -ENXIO;
+ goto out;
+ }
+
io_request = pqi_alloc_io_request(ctrl_info);
put_unaligned_le16(io_request->index,
@@ -3458,6 +3738,8 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info,
pqi_free_io_request(io_request);
+out:
+ pqi_ctrl_unbusy(ctrl_info);
up(&ctrl_info->sync_request_sem);
return rc;
@@ -3688,16 +3970,15 @@ static int pqi_create_event_queue(struct pqi_ctrl_info *ctrl_info)
return 0;
}
-static int pqi_create_queue_group(struct pqi_ctrl_info *ctrl_info)
+static int pqi_create_queue_group(struct pqi_ctrl_info *ctrl_info,
+ unsigned int group_number)
{
- unsigned int i;
int rc;
struct pqi_queue_group *queue_group;
struct pqi_general_admin_request request;
struct pqi_general_admin_response response;
- i = ctrl_info->num_active_queue_groups;
- queue_group = &ctrl_info->queue_groups[i];
+ queue_group = &ctrl_info->queue_groups[group_number];
/*
* Create IQ (Inbound Queue - host to device queue) for
@@ -3827,8 +4108,6 @@ static int pqi_create_queue_group(struct pqi_ctrl_info *ctrl_info)
get_unaligned_le64(
&response.data.create_operational_oq.oq_ci_offset);
- ctrl_info->num_active_queue_groups++;
-
return 0;
delete_inbound_queue_aio:
@@ -3855,7 +4134,7 @@ static int pqi_create_queues(struct pqi_ctrl_info *ctrl_info)
}
for (i = 0; i < ctrl_info->num_queue_groups; i++) {
- rc = pqi_create_queue_group(ctrl_info);
+ rc = pqi_create_queue_group(ctrl_info, i);
if (rc) {
dev_err(&ctrl_info->pci_dev->dev,
"error creating queue group number %u/%u\n",
@@ -3871,11 +4150,13 @@ static int pqi_create_queues(struct pqi_ctrl_info *ctrl_info)
(offsetof(struct pqi_event_config, descriptors) + \
(PQI_MAX_EVENT_DESCRIPTORS * sizeof(struct pqi_event_descriptor)))
-static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info)
+static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info,
+ bool enable_events)
{
int rc;
unsigned int i;
struct pqi_event_config *event_config;
+ struct pqi_event_descriptor *event_descriptor;
struct pqi_general_management_request request;
event_config = kmalloc(PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH,
@@ -3909,9 +4190,15 @@ static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info)
if (rc)
goto out;
- for (i = 0; i < event_config->num_event_descriptors; i++)
- put_unaligned_le16(ctrl_info->event_queue.oq_id,
- &event_config->descriptors[i].oq_id);
+ for (i = 0; i < event_config->num_event_descriptors; i++) {
+ event_descriptor = &event_config->descriptors[i];
+ if (enable_events &&
+ pqi_is_supported_event(event_descriptor->event_type))
+ put_unaligned_le16(ctrl_info->event_queue.oq_id,
+ &event_descriptor->oq_id);
+ else
+ put_unaligned_le16(0, &event_descriptor->oq_id);
+ }
memset(&request, 0, sizeof(request));
@@ -3942,6 +4229,16 @@ out:
return rc;
}
+static inline int pqi_enable_events(struct pqi_ctrl_info *ctrl_info)
+{
+ return pqi_configure_events(ctrl_info, true);
+}
+
+static inline int pqi_disable_events(struct pqi_ctrl_info *ctrl_info)
+{
+ return pqi_configure_events(ctrl_info, false);
+}
+
static void pqi_free_all_io_requests(struct pqi_ctrl_info *ctrl_info)
{
unsigned int i;
@@ -4056,8 +4353,12 @@ static void pqi_calculate_io_resources(struct pqi_ctrl_info *ctrl_info)
ctrl_info->error_buffer_length =
ctrl_info->max_io_slots * PQI_ERROR_BUFFER_ELEMENT_LENGTH;
- max_transfer_size =
- min(ctrl_info->max_transfer_size, PQI_MAX_TRANSFER_SIZE);
+ if (reset_devices)
+ max_transfer_size = min(ctrl_info->max_transfer_size,
+ PQI_MAX_TRANSFER_SIZE_KDUMP);
+ else
+ max_transfer_size = min(ctrl_info->max_transfer_size,
+ PQI_MAX_TRANSFER_SIZE);
max_sg_entries = max_transfer_size / PAGE_SIZE;
@@ -4069,28 +4370,35 @@ static void pqi_calculate_io_resources(struct pqi_ctrl_info *ctrl_info)
max_transfer_size = (max_sg_entries - 1) * PAGE_SIZE;
ctrl_info->sg_chain_buffer_length =
- max_sg_entries * sizeof(struct pqi_sg_descriptor);
+ (max_sg_entries * sizeof(struct pqi_sg_descriptor)) +
+ PQI_EXTRA_SGL_MEMORY;
ctrl_info->sg_tablesize = max_sg_entries;
ctrl_info->max_sectors = max_transfer_size / 512;
}
static void pqi_calculate_queue_resources(struct pqi_ctrl_info *ctrl_info)
{
- int num_cpus;
- int max_queue_groups;
int num_queue_groups;
u16 num_elements_per_iq;
u16 num_elements_per_oq;
- max_queue_groups = min(ctrl_info->max_inbound_queues / 2,
- ctrl_info->max_outbound_queues - 1);
- max_queue_groups = min(max_queue_groups, PQI_MAX_QUEUE_GROUPS);
+ if (reset_devices) {
+ num_queue_groups = 1;
+ } else {
+ int num_cpus;
+ int max_queue_groups;
+
+ max_queue_groups = min(ctrl_info->max_inbound_queues / 2,
+ ctrl_info->max_outbound_queues - 1);
+ max_queue_groups = min(max_queue_groups, PQI_MAX_QUEUE_GROUPS);
- num_cpus = num_online_cpus();
- num_queue_groups = min(num_cpus, ctrl_info->max_msix_vectors);
- num_queue_groups = min(num_queue_groups, max_queue_groups);
+ num_cpus = num_online_cpus();
+ num_queue_groups = min(num_cpus, ctrl_info->max_msix_vectors);
+ num_queue_groups = min(num_queue_groups, max_queue_groups);
+ }
ctrl_info->num_queue_groups = num_queue_groups;
+ ctrl_info->max_hw_queue_index = num_queue_groups - 1;
/*
* Make sure that the max. inbound IU length is an even multiple
@@ -4276,21 +4584,18 @@ static void pqi_raid_io_complete(struct pqi_io_request *io_request,
pqi_scsi_done(scmd);
}
-static int pqi_raid_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
+static int pqi_raid_submit_scsi_cmd_with_io_request(
+ struct pqi_ctrl_info *ctrl_info, struct pqi_io_request *io_request,
struct pqi_scsi_dev *device, struct scsi_cmnd *scmd,
struct pqi_queue_group *queue_group)
{
int rc;
size_t cdb_length;
- struct pqi_io_request *io_request;
struct pqi_raid_path_request *request;
- io_request = pqi_alloc_io_request(ctrl_info);
io_request->io_complete_callback = pqi_raid_io_complete;
io_request->scmd = scmd;
- scmd->host_scribble = (unsigned char *)io_request;
-
request = io_request->iu;
memset(request, 0,
offsetof(struct pqi_raid_path_request, sg_descriptors));
@@ -4355,7 +4660,6 @@ static int pqi_raid_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
dev_err(&ctrl_info->pci_dev->dev,
"unknown data direction: %d\n",
scmd->sc_data_direction);
- WARN_ON(scmd->sc_data_direction);
break;
}
@@ -4370,6 +4674,176 @@ static int pqi_raid_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
return 0;
}
+static inline int pqi_raid_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device, struct scsi_cmnd *scmd,
+ struct pqi_queue_group *queue_group)
+{
+ struct pqi_io_request *io_request;
+
+ io_request = pqi_alloc_io_request(ctrl_info);
+
+ return pqi_raid_submit_scsi_cmd_with_io_request(ctrl_info, io_request,
+ device, scmd, queue_group);
+}
+
+static inline void pqi_schedule_bypass_retry(struct pqi_ctrl_info *ctrl_info)
+{
+ if (!pqi_ctrl_blocked(ctrl_info))
+ schedule_work(&ctrl_info->raid_bypass_retry_work);
+}
+
+static bool pqi_raid_bypass_retry_needed(struct pqi_io_request *io_request)
+{
+ struct scsi_cmnd *scmd;
+ struct pqi_scsi_dev *device;
+ struct pqi_ctrl_info *ctrl_info;
+
+ if (!io_request->raid_bypass)
+ return false;
+
+ scmd = io_request->scmd;
+ if ((scmd->result & 0xff) == SAM_STAT_GOOD)
+ return false;
+ if (host_byte(scmd->result) == DID_NO_CONNECT)
+ return false;
+
+ device = scmd->device->hostdata;
+ if (pqi_device_offline(device))
+ return false;
+
+ ctrl_info = shost_to_hba(scmd->device->host);
+ if (pqi_ctrl_offline(ctrl_info))
+ return false;
+
+ return true;
+}
+
+static inline void pqi_add_to_raid_bypass_retry_list(
+ struct pqi_ctrl_info *ctrl_info,
+ struct pqi_io_request *io_request, bool at_head)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl_info->raid_bypass_retry_list_lock, flags);
+ if (at_head)
+ list_add(&io_request->request_list_entry,
+ &ctrl_info->raid_bypass_retry_list);
+ else
+ list_add_tail(&io_request->request_list_entry,
+ &ctrl_info->raid_bypass_retry_list);
+ spin_unlock_irqrestore(&ctrl_info->raid_bypass_retry_list_lock, flags);
+}
+
+static void pqi_queued_raid_bypass_complete(struct pqi_io_request *io_request,
+ void *context)
+{
+ struct scsi_cmnd *scmd;
+
+ scmd = io_request->scmd;
+ pqi_free_io_request(io_request);
+ pqi_scsi_done(scmd);
+}
+
+static void pqi_queue_raid_bypass_retry(struct pqi_io_request *io_request)
+{
+ struct scsi_cmnd *scmd;
+ struct pqi_ctrl_info *ctrl_info;
+
+ io_request->io_complete_callback = pqi_queued_raid_bypass_complete;
+ scmd = io_request->scmd;
+ scmd->result = 0;
+ ctrl_info = shost_to_hba(scmd->device->host);
+
+ pqi_add_to_raid_bypass_retry_list(ctrl_info, io_request, false);
+ pqi_schedule_bypass_retry(ctrl_info);
+}
+
+static int pqi_retry_raid_bypass(struct pqi_io_request *io_request)
+{
+ struct scsi_cmnd *scmd;
+ struct pqi_scsi_dev *device;
+ struct pqi_ctrl_info *ctrl_info;
+ struct pqi_queue_group *queue_group;
+
+ scmd = io_request->scmd;
+ device = scmd->device->hostdata;
+ if (pqi_device_in_reset(device)) {
+ pqi_free_io_request(io_request);
+ set_host_byte(scmd, DID_RESET);
+ pqi_scsi_done(scmd);
+ return 0;
+ }
+
+ ctrl_info = shost_to_hba(scmd->device->host);
+ queue_group = io_request->queue_group;
+
+ pqi_reinit_io_request(io_request);
+
+ return pqi_raid_submit_scsi_cmd_with_io_request(ctrl_info, io_request,
+ device, scmd, queue_group);
+}
+
+static inline struct pqi_io_request *pqi_next_queued_raid_bypass_request(
+ struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned long flags;
+ struct pqi_io_request *io_request;
+
+ spin_lock_irqsave(&ctrl_info->raid_bypass_retry_list_lock, flags);
+ io_request = list_first_entry_or_null(
+ &ctrl_info->raid_bypass_retry_list,
+ struct pqi_io_request, request_list_entry);
+ if (io_request)
+ list_del(&io_request->request_list_entry);
+ spin_unlock_irqrestore(&ctrl_info->raid_bypass_retry_list_lock, flags);
+
+ return io_request;
+}
+
+static void pqi_retry_raid_bypass_requests(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ struct pqi_io_request *io_request;
+
+ pqi_ctrl_busy(ctrl_info);
+
+ while (1) {
+ if (pqi_ctrl_blocked(ctrl_info))
+ break;
+ io_request = pqi_next_queued_raid_bypass_request(ctrl_info);
+ if (!io_request)
+ break;
+ rc = pqi_retry_raid_bypass(io_request);
+ if (rc) {
+ pqi_add_to_raid_bypass_retry_list(ctrl_info, io_request,
+ true);
+ pqi_schedule_bypass_retry(ctrl_info);
+ break;
+ }
+ }
+
+ pqi_ctrl_unbusy(ctrl_info);
+}
+
+static void pqi_raid_bypass_retry_worker(struct work_struct *work)
+{
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = container_of(work, struct pqi_ctrl_info,
+ raid_bypass_retry_work);
+ pqi_retry_raid_bypass_requests(ctrl_info);
+}
+
+static void pqi_clear_all_queued_raid_bypass_retries(
+ struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl_info->raid_bypass_retry_list_lock, flags);
+ INIT_LIST_HEAD(&ctrl_info->raid_bypass_retry_list);
+ spin_unlock_irqrestore(&ctrl_info->raid_bypass_retry_list_lock, flags);
+}
+
static void pqi_aio_io_complete(struct pqi_io_request *io_request,
void *context)
{
@@ -4379,6 +4853,10 @@ static void pqi_aio_io_complete(struct pqi_io_request *io_request,
scsi_dma_unmap(scmd);
if (io_request->status == -EAGAIN)
set_host_byte(scmd, DID_IMM_RETRY);
+ else if (pqi_raid_bypass_retry_needed(io_request)) {
+ pqi_queue_raid_bypass_retry(io_request);
+ return;
+ }
pqi_free_io_request(io_request);
pqi_scsi_done(scmd);
}
@@ -4388,13 +4866,13 @@ static inline int pqi_aio_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
struct pqi_queue_group *queue_group)
{
return pqi_aio_submit_io(ctrl_info, scmd, device->aio_handle,
- scmd->cmnd, scmd->cmd_len, queue_group, NULL);
+ scmd->cmnd, scmd->cmd_len, queue_group, NULL, false);
}
static int pqi_aio_submit_io(struct pqi_ctrl_info *ctrl_info,
struct scsi_cmnd *scmd, u32 aio_handle, u8 *cdb,
unsigned int cdb_length, struct pqi_queue_group *queue_group,
- struct pqi_encryption_info *encryption_info)
+ struct pqi_encryption_info *encryption_info, bool raid_bypass)
{
int rc;
struct pqi_io_request *io_request;
@@ -4403,8 +4881,7 @@ static int pqi_aio_submit_io(struct pqi_ctrl_info *ctrl_info,
io_request = pqi_alloc_io_request(ctrl_info);
io_request->io_complete_callback = pqi_aio_io_complete;
io_request->scmd = scmd;
-
- scmd->host_scribble = (unsigned char *)io_request;
+ io_request->raid_bypass = raid_bypass;
request = io_request->iu;
memset(request, 0,
@@ -4438,7 +4915,6 @@ static int pqi_aio_submit_io(struct pqi_ctrl_info *ctrl_info,
dev_err(&ctrl_info->pci_dev->dev,
"unknown data direction: %d\n",
scmd->sc_data_direction);
- WARN_ON(scmd->sc_data_direction);
break;
}
@@ -4463,47 +4939,74 @@ static int pqi_aio_submit_io(struct pqi_ctrl_info *ctrl_info,
return 0;
}
+static inline u16 pqi_get_hw_queue(struct pqi_ctrl_info *ctrl_info,
+ struct scsi_cmnd *scmd)
+{
+ u16 hw_queue;
+
+ hw_queue = blk_mq_unique_tag_to_hwq(blk_mq_unique_tag(scmd->request));
+ if (hw_queue > ctrl_info->max_hw_queue_index)
+ hw_queue = 0;
+
+ return hw_queue;
+}
+
+/*
+ * This function gets called just before we hand the completed SCSI request
+ * back to the SML.
+ */
+
+void pqi_prep_for_scsi_done(struct scsi_cmnd *scmd)
+{
+ struct pqi_scsi_dev *device;
+
+ device = scmd->device->hostdata;
+ atomic_dec(&device->scsi_cmds_outstanding);
+}
+
static int pqi_scsi_queue_command(struct Scsi_Host *shost,
struct scsi_cmnd *scmd)
{
int rc;
struct pqi_ctrl_info *ctrl_info;
struct pqi_scsi_dev *device;
- u16 hwq;
+ u16 hw_queue;
struct pqi_queue_group *queue_group;
bool raid_bypassed;
device = scmd->device->hostdata;
ctrl_info = shost_to_hba(shost);
+ atomic_inc(&device->scsi_cmds_outstanding);
+
if (pqi_ctrl_offline(ctrl_info)) {
set_host_byte(scmd, DID_NO_CONNECT);
pqi_scsi_done(scmd);
return 0;
}
+ pqi_ctrl_busy(ctrl_info);
+ if (pqi_ctrl_blocked(ctrl_info) || pqi_device_in_reset(device)) {
+ rc = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ }
+
/*
* This is necessary because the SML doesn't zero out this field during
* error recovery.
*/
scmd->result = 0;
- hwq = blk_mq_unique_tag_to_hwq(blk_mq_unique_tag(scmd->request));
- if (hwq >= ctrl_info->num_queue_groups)
- hwq = 0;
-
- queue_group = &ctrl_info->queue_groups[hwq];
+ hw_queue = pqi_get_hw_queue(ctrl_info, scmd);
+ queue_group = &ctrl_info->queue_groups[hw_queue];
if (pqi_is_logical_device(device)) {
raid_bypassed = false;
- if (device->offload_enabled &&
+ if (device->raid_bypass_enabled &&
!blk_rq_is_passthrough(scmd->request)) {
rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device,
scmd, queue_group);
- if (rc == 0 ||
- rc == SCSI_MLQUEUE_HOST_BUSY ||
- rc == SAM_STAT_CHECK_CONDITION ||
- rc == SAM_STAT_RESERVATION_CONFLICT)
+ if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY)
raid_bypassed = true;
}
if (!raid_bypassed)
@@ -4518,9 +5021,162 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost,
queue_group);
}
+out:
+ pqi_ctrl_unbusy(ctrl_info);
+ if (rc)
+ atomic_dec(&device->scsi_cmds_outstanding);
+
return rc;
}
+static int pqi_wait_until_queued_io_drained(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_queue_group *queue_group)
+{
+ unsigned int path;
+ unsigned long flags;
+ bool list_is_empty;
+
+ for (path = 0; path < 2; path++) {
+ while (1) {
+ spin_lock_irqsave(
+ &queue_group->submit_lock[path], flags);
+ list_is_empty =
+ list_empty(&queue_group->request_list[path]);
+ spin_unlock_irqrestore(
+ &queue_group->submit_lock[path], flags);
+ if (list_is_empty)
+ break;
+ pqi_check_ctrl_health(ctrl_info);
+ if (pqi_ctrl_offline(ctrl_info))
+ return -ENXIO;
+ usleep_range(1000, 2000);
+ }
+ }
+
+ return 0;
+}
+
+static int pqi_wait_until_inbound_queues_empty(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+ unsigned int i;
+ unsigned int path;
+ struct pqi_queue_group *queue_group;
+ pqi_index_t iq_pi;
+ pqi_index_t iq_ci;
+
+ for (i = 0; i < ctrl_info->num_queue_groups; i++) {
+ queue_group = &ctrl_info->queue_groups[i];
+
+ rc = pqi_wait_until_queued_io_drained(ctrl_info, queue_group);
+ if (rc)
+ return rc;
+
+ for (path = 0; path < 2; path++) {
+ iq_pi = queue_group->iq_pi_copy[path];
+
+ while (1) {
+ iq_ci = *queue_group->iq_ci[path];
+ if (iq_ci == iq_pi)
+ break;
+ pqi_check_ctrl_health(ctrl_info);
+ if (pqi_ctrl_offline(ctrl_info))
+ return -ENXIO;
+ usleep_range(1000, 2000);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void pqi_fail_io_queued_for_device(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ unsigned int i;
+ unsigned int path;
+ struct pqi_queue_group *queue_group;
+ unsigned long flags;
+ struct pqi_io_request *io_request;
+ struct pqi_io_request *next;
+ struct scsi_cmnd *scmd;
+ struct pqi_scsi_dev *scsi_device;
+
+ for (i = 0; i < ctrl_info->num_queue_groups; i++) {
+ queue_group = &ctrl_info->queue_groups[i];
+
+ for (path = 0; path < 2; path++) {
+ spin_lock_irqsave(
+ &queue_group->submit_lock[path], flags);
+
+ list_for_each_entry_safe(io_request, next,
+ &queue_group->request_list[path],
+ request_list_entry) {
+ scmd = io_request->scmd;
+ if (!scmd)
+ continue;
+
+ scsi_device = scmd->device->hostdata;
+ if (scsi_device != device)
+ continue;
+
+ list_del(&io_request->request_list_entry);
+ set_host_byte(scmd, DID_RESET);
+ pqi_scsi_done(scmd);
+ }
+
+ spin_unlock_irqrestore(
+ &queue_group->submit_lock[path], flags);
+ }
+ }
+}
+
+static int pqi_device_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info,
+ struct pqi_scsi_dev *device)
+{
+ while (atomic_read(&device->scsi_cmds_outstanding)) {
+ pqi_check_ctrl_health(ctrl_info);
+ if (pqi_ctrl_offline(ctrl_info))
+ return -ENXIO;
+ usleep_range(1000, 2000);
+ }
+
+ return 0;
+}
+
+static int pqi_ctrl_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info)
+{
+ bool io_pending;
+ unsigned long flags;
+ struct pqi_scsi_dev *device;
+
+ while (1) {
+ io_pending = false;
+
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
+ scsi_device_list_entry) {
+ if (atomic_read(&device->scsi_cmds_outstanding)) {
+ io_pending = true;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock,
+ flags);
+
+ if (!io_pending)
+ break;
+
+ pqi_check_ctrl_health(ctrl_info);
+ if (pqi_ctrl_offline(ctrl_info))
+ return -ENXIO;
+
+ usleep_range(1000, 2000);
+ }
+
+ return 0;
+}
+
static void pqi_lun_reset_complete(struct pqi_io_request *io_request,
void *context)
{
@@ -4535,7 +5191,6 @@ static int pqi_wait_for_lun_reset_completion(struct pqi_ctrl_info *ctrl_info,
struct pqi_scsi_dev *device, struct completion *wait)
{
int rc;
- unsigned int wait_secs = 0;
while (1) {
if (wait_for_completion_io_timeout(wait,
@@ -4546,16 +5201,9 @@ static int pqi_wait_for_lun_reset_completion(struct pqi_ctrl_info *ctrl_info,
pqi_check_ctrl_health(ctrl_info);
if (pqi_ctrl_offline(ctrl_info)) {
- rc = -ETIMEDOUT;
+ rc = -ENXIO;
break;
}
-
- wait_secs += PQI_LUN_RESET_TIMEOUT_SECS;
-
- dev_err(&ctrl_info->pci_dev->dev,
- "resetting scsi %d:%d:%d:%d - waiting %u seconds\n",
- ctrl_info->scsi_host->host_no, device->bus,
- device->target, device->lun, wait_secs);
}
return rc;
@@ -4569,8 +5217,6 @@ static int pqi_lun_reset(struct pqi_ctrl_info *ctrl_info,
DECLARE_COMPLETION_ONSTACK(wait);
struct pqi_task_management_request *request;
- down(&ctrl_info->lun_reset_sem);
-
io_request = pqi_alloc_io_request(ctrl_info);
io_request->io_complete_callback = pqi_lun_reset_complete;
io_request->context = &wait;
@@ -4595,7 +5241,6 @@ static int pqi_lun_reset(struct pqi_ctrl_info *ctrl_info,
rc = io_request->status;
pqi_free_io_request(io_request);
- up(&ctrl_info->lun_reset_sem);
return rc;
}
@@ -4607,11 +5252,9 @@ static int pqi_device_reset(struct pqi_ctrl_info *ctrl_info,
{
int rc;
- pqi_check_ctrl_health(ctrl_info);
- if (pqi_ctrl_offline(ctrl_info))
- return FAILED;
-
rc = pqi_lun_reset(ctrl_info, device);
+ if (rc == 0)
+ rc = pqi_device_wait_for_pending_io(ctrl_info, device);
return rc == 0 ? SUCCESS : FAILED;
}
@@ -4619,23 +5262,46 @@ static int pqi_device_reset(struct pqi_ctrl_info *ctrl_info,
static int pqi_eh_device_reset_handler(struct scsi_cmnd *scmd)
{
int rc;
+ struct Scsi_Host *shost;
struct pqi_ctrl_info *ctrl_info;
struct pqi_scsi_dev *device;
- ctrl_info = shost_to_hba(scmd->device->host);
+ shost = scmd->device->host;
+ ctrl_info = shost_to_hba(shost);
device = scmd->device->hostdata;
dev_err(&ctrl_info->pci_dev->dev,
"resetting scsi %d:%d:%d:%d\n",
- ctrl_info->scsi_host->host_no,
- device->bus, device->target, device->lun);
+ shost->host_no, device->bus, device->target, device->lun);
+
+ pqi_check_ctrl_health(ctrl_info);
+ if (pqi_ctrl_offline(ctrl_info)) {
+ rc = FAILED;
+ goto out;
+ }
+
+ mutex_lock(&ctrl_info->lun_reset_mutex);
+
+ pqi_ctrl_block_requests(ctrl_info);
+ pqi_ctrl_wait_until_quiesced(ctrl_info);
+ pqi_fail_io_queued_for_device(ctrl_info, device);
+ rc = pqi_wait_until_inbound_queues_empty(ctrl_info);
+ pqi_device_reset_start(device);
+ pqi_ctrl_unblock_requests(ctrl_info);
+
+ if (rc)
+ rc = FAILED;
+ else
+ rc = pqi_device_reset(ctrl_info, device);
+
+ pqi_device_reset_done(device);
- rc = pqi_device_reset(ctrl_info, device);
+ mutex_unlock(&ctrl_info->lun_reset_mutex);
+out:
dev_err(&ctrl_info->pci_dev->dev,
"reset of scsi %d:%d:%d:%d: %s\n",
- ctrl_info->scsi_host->host_no,
- device->bus, device->target, device->lun,
+ shost->host_no, device->bus, device->target, device->lun,
rc == SUCCESS ? "SUCCESS" : "FAILED");
return rc;
@@ -4667,7 +5333,7 @@ static int pqi_slave_alloc(struct scsi_device *sdev)
sdev_id(sdev), sdev->lun);
}
- if (device && device->expose_device) {
+ if (device) {
sdev->hostdata = device;
device->sdev = sdev;
if (device->queue_depth) {
@@ -4682,17 +5348,6 @@ static int pqi_slave_alloc(struct scsi_device *sdev)
return 0;
}
-static int pqi_slave_configure(struct scsi_device *sdev)
-{
- struct pqi_scsi_dev *device;
-
- device = sdev->hostdata;
- if (!device->expose_device)
- sdev->no_uld_attach = true;
-
- return 0;
-}
-
static int pqi_map_queues(struct Scsi_Host *shost)
{
struct pqi_ctrl_info *ctrl_info = shost_to_hba(shost);
@@ -5005,12 +5660,55 @@ static ssize_t pqi_host_rescan_store(struct device *dev,
return count;
}
-static DEVICE_ATTR(version, S_IRUGO, pqi_version_show, NULL);
-static DEVICE_ATTR(rescan, S_IWUSR, NULL, pqi_host_rescan_store);
+static ssize_t pqi_lockup_action_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ int count = 0;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(pqi_lockup_actions); i++) {
+ if (pqi_lockup_actions[i].action == pqi_lockup_action)
+ count += snprintf(buffer + count, PAGE_SIZE - count,
+ "[%s] ", pqi_lockup_actions[i].name);
+ else
+ count += snprintf(buffer + count, PAGE_SIZE - count,
+ "%s ", pqi_lockup_actions[i].name);
+ }
+
+ count += snprintf(buffer + count, PAGE_SIZE - count, "\n");
+
+ return count;
+}
+
+static ssize_t pqi_lockup_action_store(struct device *dev,
+ struct device_attribute *attr, const char *buffer, size_t count)
+{
+ unsigned int i;
+ char *action_name;
+ char action_name_buffer[32];
+
+ strlcpy(action_name_buffer, buffer, sizeof(action_name_buffer));
+ action_name = strstrip(action_name_buffer);
+
+ for (i = 0; i < ARRAY_SIZE(pqi_lockup_actions); i++) {
+ if (strcmp(action_name, pqi_lockup_actions[i].name) == 0) {
+ pqi_lockup_action = pqi_lockup_actions[i].action;
+ return count;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(version, 0444, pqi_version_show, NULL);
+static DEVICE_ATTR(rescan, 0200, NULL, pqi_host_rescan_store);
+static DEVICE_ATTR(lockup_action, 0644,
+ pqi_lockup_action_show, pqi_lockup_action_store);
static struct device_attribute *pqi_shost_attrs[] = {
&dev_attr_version,
&dev_attr_rescan,
+ &dev_attr_lockup_action,
NULL
};
@@ -5055,7 +5753,7 @@ static ssize_t pqi_ssd_smart_path_enabled_show(struct device *dev,
spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
device = sdev->hostdata;
- buffer[0] = device->offload_enabled ? '1' : '0';
+ buffer[0] = device->raid_bypass_enabled ? '1' : '0';
buffer[1] = '\n';
buffer[2] = '\0';
@@ -5064,13 +5762,41 @@ static ssize_t pqi_ssd_smart_path_enabled_show(struct device *dev,
return 2;
}
-static DEVICE_ATTR(sas_address, S_IRUGO, pqi_sas_address_show, NULL);
-static DEVICE_ATTR(ssd_smart_path_enabled, S_IRUGO,
+static ssize_t pqi_raid_level_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ struct pqi_ctrl_info *ctrl_info;
+ struct scsi_device *sdev;
+ struct pqi_scsi_dev *device;
+ unsigned long flags;
+ char *raid_level;
+
+ sdev = to_scsi_device(dev);
+ ctrl_info = shost_to_hba(sdev->host);
+
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
+
+ device = sdev->hostdata;
+
+ if (pqi_is_logical_device(device))
+ raid_level = pqi_raid_level_to_string(device->raid_level);
+ else
+ raid_level = "N/A";
+
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
+
+ return snprintf(buffer, PAGE_SIZE, "%s\n", raid_level);
+}
+
+static DEVICE_ATTR(sas_address, 0444, pqi_sas_address_show, NULL);
+static DEVICE_ATTR(ssd_smart_path_enabled, 0444,
pqi_ssd_smart_path_enabled_show, NULL);
+static DEVICE_ATTR(raid_level, 0444, pqi_raid_level_show, NULL);
static struct device_attribute *pqi_sdev_attrs[] = {
&dev_attr_sas_address,
&dev_attr_ssd_smart_path_enabled,
+ &dev_attr_raid_level,
NULL
};
@@ -5086,7 +5812,6 @@ static struct scsi_host_template pqi_driver_template = {
.eh_device_reset_handler = pqi_eh_device_reset_handler,
.ioctl = pqi_ioctl,
.slave_alloc = pqi_slave_alloc,
- .slave_configure = pqi_slave_configure,
.map_queues = pqi_map_queues,
.sdev_attrs = pqi_sdev_attrs,
.shost_attrs = pqi_shost_attrs,
@@ -5217,49 +5942,113 @@ out:
return rc;
}
-static int pqi_kdump_init(struct pqi_ctrl_info *ctrl_info)
+static int pqi_process_config_table(struct pqi_ctrl_info *ctrl_info)
{
- if (!sis_is_firmware_running(ctrl_info))
- return -ENXIO;
+ u32 table_length;
+ u32 section_offset;
+ void __iomem *table_iomem_addr;
+ struct pqi_config_table *config_table;
+ struct pqi_config_table_section_header *section;
+
+ table_length = ctrl_info->config_table_length;
+
+ config_table = kmalloc(table_length, GFP_KERNEL);
+ if (!config_table) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to allocate memory for PQI configuration table\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * Copy the config table contents from I/O memory space into the
+ * temporary buffer.
+ */
+ table_iomem_addr = ctrl_info->iomem_base +
+ ctrl_info->config_table_offset;
+ memcpy_fromio(config_table, table_iomem_addr, table_length);
+
+ section_offset =
+ get_unaligned_le32(&config_table->first_section_offset);
+
+ while (section_offset) {
+ section = (void *)config_table + section_offset;
- if (pqi_get_ctrl_mode(ctrl_info) == PQI_MODE) {
- sis_disable_msix(ctrl_info);
- if (pqi_reset(ctrl_info) == 0)
- sis_reenable_sis_mode(ctrl_info);
+ switch (get_unaligned_le16(&section->section_id)) {
+ case PQI_CONFIG_TABLE_SECTION_HEARTBEAT:
+ if (pqi_disable_heartbeat)
+ dev_warn(&ctrl_info->pci_dev->dev,
+ "heartbeat disabled by module parameter\n");
+ else
+ ctrl_info->heartbeat_counter =
+ table_iomem_addr +
+ section_offset +
+ offsetof(
+ struct pqi_config_table_heartbeat,
+ heartbeat_counter);
+ break;
+ }
+
+ section_offset =
+ get_unaligned_le16(&section->next_section_offset);
}
+ kfree(config_table);
+
return 0;
}
-static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
+/* Switches the controller from PQI mode back into SIS mode. */
+
+static int pqi_revert_to_sis_mode(struct pqi_ctrl_info *ctrl_info)
{
int rc;
- if (reset_devices) {
- rc = pqi_kdump_init(ctrl_info);
- if (rc)
- return rc;
+ pqi_change_irq_mode(ctrl_info, IRQ_MODE_NONE);
+ rc = pqi_reset(ctrl_info);
+ if (rc)
+ return rc;
+ sis_reenable_sis_mode(ctrl_info);
+ pqi_save_ctrl_mode(ctrl_info, SIS_MODE);
+
+ return 0;
+}
+
+/*
+ * If the controller isn't already in SIS mode, this function forces it into
+ * SIS mode.
+ */
+
+static int pqi_force_sis_mode(struct pqi_ctrl_info *ctrl_info)
+{
+ if (!sis_is_firmware_running(ctrl_info))
+ return -ENXIO;
+
+ if (pqi_get_ctrl_mode(ctrl_info) == SIS_MODE)
+ return 0;
+
+ if (sis_is_kernel_up(ctrl_info)) {
+ pqi_save_ctrl_mode(ctrl_info, SIS_MODE);
+ return 0;
}
- /*
- * When the controller comes out of reset, it is always running
- * in legacy SIS mode. This is so that it can be compatible
- * with legacy drivers shipped with OSes. So we have to talk
- * to it using SIS commands at first. Once we are satisified
- * that the controller supports PQI, we transition it into PQI
- * mode.
- */
+ return pqi_revert_to_sis_mode(ctrl_info);
+}
+
+static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+
+ rc = pqi_force_sis_mode(ctrl_info);
+ if (rc)
+ return rc;
/*
* Wait until the controller is ready to start accepting SIS
* commands.
*/
rc = sis_wait_for_ctrl_ready(ctrl_info);
- if (rc) {
- dev_err(&ctrl_info->pci_dev->dev,
- "error initializing SIS interface\n");
+ if (rc)
return rc;
- }
/*
* Get the controller properties. This allows us to determine
@@ -5279,9 +6068,17 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
return rc;
}
- if (ctrl_info->max_outstanding_requests > PQI_MAX_OUTSTANDING_REQUESTS)
- ctrl_info->max_outstanding_requests =
- PQI_MAX_OUTSTANDING_REQUESTS;
+ if (reset_devices) {
+ if (ctrl_info->max_outstanding_requests >
+ PQI_MAX_OUTSTANDING_REQUESTS_KDUMP)
+ ctrl_info->max_outstanding_requests =
+ PQI_MAX_OUTSTANDING_REQUESTS_KDUMP;
+ } else {
+ if (ctrl_info->max_outstanding_requests >
+ PQI_MAX_OUTSTANDING_REQUESTS)
+ ctrl_info->max_outstanding_requests =
+ PQI_MAX_OUTSTANDING_REQUESTS;
+ }
pqi_calculate_io_resources(ctrl_info);
@@ -5316,10 +6113,14 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
ctrl_info->pqi_mode_enabled = true;
pqi_save_ctrl_mode(ctrl_info, PQI_MODE);
+ rc = pqi_process_config_table(ctrl_info);
+ if (rc)
+ return rc;
+
rc = pqi_alloc_admin_queues(ctrl_info);
if (rc) {
dev_err(&ctrl_info->pci_dev->dev,
- "error allocating admin queues\n");
+ "failed to allocate admin queues\n");
return rc;
}
@@ -5358,8 +6159,11 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
return rc;
rc = pqi_alloc_operational_queues(ctrl_info);
- if (rc)
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to allocate operational queues\n");
return rc;
+ }
pqi_init_operational_queues(ctrl_info);
@@ -5371,19 +6175,18 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
if (rc)
return rc;
- sis_enable_msix(ctrl_info);
+ pqi_change_irq_mode(ctrl_info, IRQ_MODE_MSIX);
+
+ ctrl_info->controller_online = true;
+ pqi_start_heartbeat_timer(ctrl_info);
- rc = pqi_configure_events(ctrl_info);
+ rc = pqi_enable_events(ctrl_info);
if (rc) {
dev_err(&ctrl_info->pci_dev->dev,
- "error configuring events\n");
+ "error enabling events\n");
return rc;
}
- pqi_start_heartbeat_timer(ctrl_info);
-
- ctrl_info->controller_online = true;
-
/* Register with the SCSI subsystem. */
rc = pqi_register_scsi(ctrl_info);
if (rc)
@@ -5410,6 +6213,119 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
return 0;
}
+static void pqi_reinit_queues(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned int i;
+ struct pqi_admin_queues *admin_queues;
+ struct pqi_event_queue *event_queue;
+
+ admin_queues = &ctrl_info->admin_queues;
+ admin_queues->iq_pi_copy = 0;
+ admin_queues->oq_ci_copy = 0;
+ *admin_queues->oq_pi = 0;
+
+ for (i = 0; i < ctrl_info->num_queue_groups; i++) {
+ ctrl_info->queue_groups[i].iq_pi_copy[RAID_PATH] = 0;
+ ctrl_info->queue_groups[i].iq_pi_copy[AIO_PATH] = 0;
+ ctrl_info->queue_groups[i].oq_ci_copy = 0;
+
+ *ctrl_info->queue_groups[i].iq_ci[RAID_PATH] = 0;
+ *ctrl_info->queue_groups[i].iq_ci[AIO_PATH] = 0;
+ *ctrl_info->queue_groups[i].oq_pi = 0;
+ }
+
+ event_queue = &ctrl_info->event_queue;
+ *event_queue->oq_pi = 0;
+ event_queue->oq_ci_copy = 0;
+}
+
+static int pqi_ctrl_init_resume(struct pqi_ctrl_info *ctrl_info)
+{
+ int rc;
+
+ rc = pqi_force_sis_mode(ctrl_info);
+ if (rc)
+ return rc;
+
+ /*
+ * Wait until the controller is ready to start accepting SIS
+ * commands.
+ */
+ rc = sis_wait_for_ctrl_ready_resume(ctrl_info);
+ if (rc)
+ return rc;
+
+ /*
+ * If the function we are about to call succeeds, the
+ * controller will transition from legacy SIS mode
+ * into PQI mode.
+ */
+ rc = sis_init_base_struct_addr(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error initializing PQI mode\n");
+ return rc;
+ }
+
+ /* Wait for the controller to complete the SIS -> PQI transition. */
+ rc = pqi_wait_for_pqi_mode_ready(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "transition to PQI mode failed\n");
+ return rc;
+ }
+
+ /* From here on, we are running in PQI mode. */
+ ctrl_info->pqi_mode_enabled = true;
+ pqi_save_ctrl_mode(ctrl_info, PQI_MODE);
+
+ pqi_reinit_queues(ctrl_info);
+
+ rc = pqi_create_admin_queues(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error creating admin queues\n");
+ return rc;
+ }
+
+ rc = pqi_create_queues(ctrl_info);
+ if (rc)
+ return rc;
+
+ pqi_change_irq_mode(ctrl_info, IRQ_MODE_MSIX);
+
+ ctrl_info->controller_online = true;
+ pqi_start_heartbeat_timer(ctrl_info);
+ pqi_ctrl_unblock_requests(ctrl_info);
+
+ rc = pqi_enable_events(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error enabling events\n");
+ return rc;
+ }
+
+ rc = pqi_write_driver_version_to_host_wellness(ctrl_info);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "error updating host wellness\n");
+ return rc;
+ }
+
+ pqi_schedule_update_time_worker(ctrl_info);
+
+ pqi_scan_scsi_devices(ctrl_info);
+
+ return 0;
+}
+
+static inline int pqi_set_pcie_completion_timeout(struct pci_dev *pci_dev,
+ u16 timeout)
+{
+ return pcie_capability_clear_and_set_word(pci_dev, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_COMP_TIMEOUT, timeout);
+}
+
static int pqi_pci_init(struct pqi_ctrl_info *ctrl_info)
{
int rc;
@@ -5450,12 +6366,23 @@ static int pqi_pci_init(struct pqi_ctrl_info *ctrl_info)
goto release_regions;
}
- ctrl_info->registers = ctrl_info->iomem_base;
- ctrl_info->pqi_registers = &ctrl_info->registers->pqi_registers;
+#define PCI_EXP_COMP_TIMEOUT_65_TO_210_MS 0x6
+
+ /* Increase the PCIe completion timeout. */
+ rc = pqi_set_pcie_completion_timeout(ctrl_info->pci_dev,
+ PCI_EXP_COMP_TIMEOUT_65_TO_210_MS);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "failed to set PCIe completion timeout\n");
+ goto release_regions;
+ }
/* Enable bus mastering. */
pci_set_master(ctrl_info->pci_dev);
+ ctrl_info->registers = ctrl_info->iomem_base;
+ ctrl_info->pqi_registers = &ctrl_info->registers->pqi_registers;
+
pci_set_drvdata(ctrl_info->pci_dev, ctrl_info);
return 0;
@@ -5472,7 +6399,8 @@ static void pqi_cleanup_pci_init(struct pqi_ctrl_info *ctrl_info)
{
iounmap(ctrl_info->iomem_base);
pci_release_regions(ctrl_info->pci_dev);
- pci_disable_device(ctrl_info->pci_dev);
+ if (pci_is_enabled(ctrl_info->pci_dev))
+ pci_disable_device(ctrl_info->pci_dev);
pci_set_drvdata(ctrl_info->pci_dev, NULL);
}
@@ -5486,6 +6414,7 @@ static struct pqi_ctrl_info *pqi_alloc_ctrl_info(int numa_node)
return NULL;
mutex_init(&ctrl_info->scan_mutex);
+ mutex_init(&ctrl_info->lun_reset_mutex);
INIT_LIST_HEAD(&ctrl_info->scsi_device_list);
spin_lock_init(&ctrl_info->scsi_device_list_lock);
@@ -5496,11 +6425,20 @@ static struct pqi_ctrl_info *pqi_alloc_ctrl_info(int numa_node)
INIT_DELAYED_WORK(&ctrl_info->rescan_work, pqi_rescan_worker);
INIT_DELAYED_WORK(&ctrl_info->update_time_work, pqi_update_time_worker);
+ init_timer(&ctrl_info->heartbeat_timer);
+ INIT_WORK(&ctrl_info->ctrl_offline_work, pqi_ctrl_offline_worker);
+
sema_init(&ctrl_info->sync_request_sem,
PQI_RESERVED_IO_SLOTS_SYNCHRONOUS_REQUESTS);
- sema_init(&ctrl_info->lun_reset_sem, PQI_RESERVED_IO_SLOTS_LUN_RESET);
+ init_waitqueue_head(&ctrl_info->block_requests_wait);
+
+ INIT_LIST_HEAD(&ctrl_info->raid_bypass_retry_list);
+ spin_lock_init(&ctrl_info->raid_bypass_retry_list_lock);
+ INIT_WORK(&ctrl_info->raid_bypass_retry_work,
+ pqi_raid_bypass_retry_worker);
ctrl_info->ctrl_id = atomic_inc_return(&pqi_controller_count) - 1;
+ ctrl_info->irq_mode = IRQ_MODE_NONE;
ctrl_info->max_msix_vectors = PQI_MAX_MSIX_VECTORS;
return ctrl_info;
@@ -5513,14 +6451,8 @@ static inline void pqi_free_ctrl_info(struct pqi_ctrl_info *ctrl_info)
static void pqi_free_interrupts(struct pqi_ctrl_info *ctrl_info)
{
- int i;
-
- for (i = 0; i < ctrl_info->num_msix_vectors_initialized; i++) {
- free_irq(pci_irq_vector(ctrl_info->pci_dev, i),
- &ctrl_info->queue_groups[i]);
- }
-
- pci_free_irq_vectors(ctrl_info->pci_dev);
+ pqi_free_irqs(ctrl_info);
+ pqi_disable_msix_interrupts(ctrl_info);
}
static void pqi_free_ctrl_resources(struct pqi_ctrl_info *ctrl_info)
@@ -5550,73 +6482,142 @@ static void pqi_free_ctrl_resources(struct pqi_ctrl_info *ctrl_info)
static void pqi_remove_ctrl(struct pqi_ctrl_info *ctrl_info)
{
- cancel_delayed_work_sync(&ctrl_info->rescan_work);
- cancel_delayed_work_sync(&ctrl_info->update_time_work);
+ pqi_cancel_rescan_worker(ctrl_info);
+ pqi_cancel_update_time_worker(ctrl_info);
pqi_remove_all_scsi_devices(ctrl_info);
pqi_unregister_scsi(ctrl_info);
+ if (ctrl_info->pqi_mode_enabled)
+ pqi_revert_to_sis_mode(ctrl_info);
+ pqi_free_ctrl_resources(ctrl_info);
+}
- if (ctrl_info->pqi_mode_enabled) {
- sis_disable_msix(ctrl_info);
- if (pqi_reset(ctrl_info) == 0)
- sis_reenable_sis_mode(ctrl_info);
+static void pqi_perform_lockup_action(void)
+{
+ switch (pqi_lockup_action) {
+ case PANIC:
+ panic("FATAL: Smart Family Controller lockup detected");
+ break;
+ case REBOOT:
+ emergency_restart();
+ break;
+ case NONE:
+ default:
+ break;
+ }
+}
+
+static struct pqi_raid_error_info pqi_ctrl_offline_raid_error_info = {
+ .data_out_result = PQI_DATA_IN_OUT_HARDWARE_ERROR,
+ .status = SAM_STAT_CHECK_CONDITION,
+};
+
+static void pqi_fail_all_outstanding_requests(struct pqi_ctrl_info *ctrl_info)
+{
+ unsigned int i;
+ struct pqi_io_request *io_request;
+ struct scsi_cmnd *scmd;
+
+ for (i = 0; i < ctrl_info->max_io_slots; i++) {
+ io_request = &ctrl_info->io_request_pool[i];
+ if (atomic_read(&io_request->refcount) == 0)
+ continue;
+
+ scmd = io_request->scmd;
+ if (scmd) {
+ set_host_byte(scmd, DID_NO_CONNECT);
+ } else {
+ io_request->status = -ENXIO;
+ io_request->error_info =
+ &pqi_ctrl_offline_raid_error_info;
+ }
+
+ io_request->io_complete_callback(io_request,
+ io_request->context);
}
- pqi_free_ctrl_resources(ctrl_info);
}
-static void pqi_print_ctrl_info(struct pci_dev *pdev,
+static void pqi_take_ctrl_offline_deferred(struct pqi_ctrl_info *ctrl_info)
+{
+ pqi_perform_lockup_action();
+ pqi_stop_heartbeat_timer(ctrl_info);
+ pqi_free_interrupts(ctrl_info);
+ pqi_cancel_rescan_worker(ctrl_info);
+ pqi_cancel_update_time_worker(ctrl_info);
+ pqi_ctrl_wait_until_quiesced(ctrl_info);
+ pqi_fail_all_outstanding_requests(ctrl_info);
+ pqi_clear_all_queued_raid_bypass_retries(ctrl_info);
+ pqi_ctrl_unblock_requests(ctrl_info);
+}
+
+static void pqi_ctrl_offline_worker(struct work_struct *work)
+{
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = container_of(work, struct pqi_ctrl_info, ctrl_offline_work);
+ pqi_take_ctrl_offline_deferred(ctrl_info);
+}
+
+static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info)
+{
+ if (!ctrl_info->controller_online)
+ return;
+
+ ctrl_info->controller_online = false;
+ ctrl_info->pqi_mode_enabled = false;
+ pqi_ctrl_block_requests(ctrl_info);
+ if (!pqi_disable_ctrl_shutdown)
+ sis_shutdown_ctrl(ctrl_info);
+ pci_disable_device(ctrl_info->pci_dev);
+ dev_err(&ctrl_info->pci_dev->dev, "controller offline\n");
+ schedule_work(&ctrl_info->ctrl_offline_work);
+}
+
+static void pqi_print_ctrl_info(struct pci_dev *pci_dev,
const struct pci_device_id *id)
{
char *ctrl_description;
- if (id->driver_data) {
+ if (id->driver_data)
ctrl_description = (char *)id->driver_data;
- } else {
- switch (id->subvendor) {
- case PCI_VENDOR_ID_HP:
- ctrl_description = hpe_branded_controller;
- break;
- case PCI_VENDOR_ID_ADAPTEC2:
- default:
- ctrl_description = microsemi_branded_controller;
- break;
- }
- }
+ else
+ ctrl_description = "Microsemi Smart Family Controller";
- dev_info(&pdev->dev, "%s found\n", ctrl_description);
+ dev_info(&pci_dev->dev, "%s found\n", ctrl_description);
}
-static int pqi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int pqi_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
{
int rc;
int node;
struct pqi_ctrl_info *ctrl_info;
- pqi_print_ctrl_info(pdev, id);
+ pqi_print_ctrl_info(pci_dev, id);
if (pqi_disable_device_id_wildcards &&
id->subvendor == PCI_ANY_ID &&
id->subdevice == PCI_ANY_ID) {
- dev_warn(&pdev->dev,
+ dev_warn(&pci_dev->dev,
"controller not probed because device ID wildcards are disabled\n");
return -ENODEV;
}
if (id->subvendor == PCI_ANY_ID || id->subdevice == PCI_ANY_ID)
- dev_warn(&pdev->dev,
+ dev_warn(&pci_dev->dev,
"controller device ID matched using wildcards\n");
- node = dev_to_node(&pdev->dev);
+ node = dev_to_node(&pci_dev->dev);
if (node == NUMA_NO_NODE)
- set_dev_node(&pdev->dev, 0);
+ set_dev_node(&pci_dev->dev, 0);
ctrl_info = pqi_alloc_ctrl_info(node);
if (!ctrl_info) {
- dev_err(&pdev->dev,
+ dev_err(&pci_dev->dev,
"failed to allocate controller info block\n");
return -ENOMEM;
}
- ctrl_info->pci_dev = pdev;
+ ctrl_info->pci_dev = pci_dev;
rc = pqi_pci_init(ctrl_info);
if (rc)
@@ -5634,23 +6635,23 @@ error:
return rc;
}
-static void pqi_pci_remove(struct pci_dev *pdev)
+static void pqi_pci_remove(struct pci_dev *pci_dev)
{
struct pqi_ctrl_info *ctrl_info;
- ctrl_info = pci_get_drvdata(pdev);
+ ctrl_info = pci_get_drvdata(pci_dev);
if (!ctrl_info)
return;
pqi_remove_ctrl(ctrl_info);
}
-static void pqi_shutdown(struct pci_dev *pdev)
+static void pqi_shutdown(struct pci_dev *pci_dev)
{
int rc;
struct pqi_ctrl_info *ctrl_info;
- ctrl_info = pci_get_drvdata(pdev);
+ ctrl_info = pci_get_drvdata(pci_dev);
if (!ctrl_info)
goto error;
@@ -5663,115 +6664,284 @@ static void pqi_shutdown(struct pci_dev *pdev)
return;
error:
- dev_warn(&pdev->dev,
+ dev_warn(&pci_dev->dev,
"unable to flush controller cache\n");
}
+static void pqi_process_lockup_action_param(void)
+{
+ unsigned int i;
+
+ if (!pqi_lockup_action_param)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(pqi_lockup_actions); i++) {
+ if (strcmp(pqi_lockup_action_param,
+ pqi_lockup_actions[i].name) == 0) {
+ pqi_lockup_action = pqi_lockup_actions[i].action;
+ return;
+ }
+ }
+
+ pr_warn("%s: invalid lockup action setting \"%s\" - supported settings: none, reboot, panic\n",
+ DRIVER_NAME_SHORT, pqi_lockup_action_param);
+}
+
+static void pqi_process_module_params(void)
+{
+ pqi_process_lockup_action_param();
+}
+
+static __maybe_unused int pqi_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = pci_get_drvdata(pci_dev);
+
+ pqi_disable_events(ctrl_info);
+ pqi_cancel_update_time_worker(ctrl_info);
+ pqi_cancel_rescan_worker(ctrl_info);
+ pqi_wait_until_scan_finished(ctrl_info);
+ pqi_wait_until_lun_reset_finished(ctrl_info);
+ pqi_flush_cache(ctrl_info);
+ pqi_ctrl_block_requests(ctrl_info);
+ pqi_ctrl_wait_until_quiesced(ctrl_info);
+ pqi_wait_until_inbound_queues_empty(ctrl_info);
+ pqi_ctrl_wait_for_pending_io(ctrl_info);
+ pqi_stop_heartbeat_timer(ctrl_info);
+
+ if (state.event == PM_EVENT_FREEZE)
+ return 0;
+
+ pci_save_state(pci_dev);
+ pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+
+ ctrl_info->controller_online = false;
+ ctrl_info->pqi_mode_enabled = false;
+
+ return 0;
+}
+
+static __maybe_unused int pqi_resume(struct pci_dev *pci_dev)
+{
+ int rc;
+ struct pqi_ctrl_info *ctrl_info;
+
+ ctrl_info = pci_get_drvdata(pci_dev);
+
+ if (pci_dev->current_state != PCI_D0) {
+ ctrl_info->max_hw_queue_index = 0;
+ pqi_free_interrupts(ctrl_info);
+ pqi_change_irq_mode(ctrl_info, IRQ_MODE_INTX);
+ rc = request_irq(pci_irq_vector(pci_dev, 0), pqi_irq_handler,
+ IRQF_SHARED, DRIVER_NAME_SHORT,
+ &ctrl_info->queue_groups[0]);
+ if (rc) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "irq %u init failed with error %d\n",
+ pci_dev->irq, rc);
+ return rc;
+ }
+ pqi_start_heartbeat_timer(ctrl_info);
+ pqi_ctrl_unblock_requests(ctrl_info);
+ return 0;
+ }
+
+ pci_set_power_state(pci_dev, PCI_D0);
+ pci_restore_state(pci_dev);
+
+ return pqi_ctrl_init_resume(ctrl_info);
+}
+
/* Define the PCI IDs for the controllers that we support. */
static const struct pci_device_id pqi_pci_id_table[] = {
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x152d, 0x8a22)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x152d, 0x8a23)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x152d, 0x8a24)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x152d, 0x8a36)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x152d, 0x8a37)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
PCI_VENDOR_ID_ADAPTEC2, 0x0110)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0600)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0605)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0601)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0800)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0602)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0801)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0603)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0802)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0650)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0803)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0651)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0804)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0652)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0805)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0653)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0806)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0654)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0900)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0655)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0901)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0700)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0902)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_HP, 0x0701)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0903)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0800)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0904)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0801)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0905)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0802)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0906)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0803)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0907)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0804)
+ PCI_VENDOR_ID_ADAPTEC2, 0x0908)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0805)
+ PCI_VENDOR_ID_ADAPTEC2, 0x1200)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0900)
+ PCI_VENDOR_ID_ADAPTEC2, 0x1201)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0901)
+ PCI_VENDOR_ID_ADAPTEC2, 0x1202)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0902)
+ PCI_VENDOR_ID_ADAPTEC2, 0x1280)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0903)
+ PCI_VENDOR_ID_ADAPTEC2, 0x1281)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0904)
+ PCI_VENDOR_ID_ADAPTEC2, 0x1300)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0905)
+ PCI_VENDOR_ID_ADAPTEC2, 0x1301)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
- PCI_VENDOR_ID_ADAPTEC2, 0x0906)
+ PCI_VENDOR_ID_ADAPTEC2, 0x1380)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0600)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0601)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0602)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0603)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0604)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0606)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0650)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0651)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0652)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0653)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0654)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0655)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0656)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0657)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0700)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ PCI_VENDOR_ID_HP, 0x0701)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
@@ -5808,6 +6978,10 @@ static struct pci_driver pqi_pci_driver = {
.probe = pqi_pci_probe,
.remove = pqi_pci_remove,
.shutdown = pqi_shutdown,
+#if defined(CONFIG_PM)
+ .suspend = pqi_suspend,
+ .resume = pqi_resume,
+#endif
};
static int __init pqi_init(void)
@@ -5821,6 +6995,8 @@ static int __init pqi_init(void)
if (!pqi_sas_transport_template)
return -ENODEV;
+ pqi_process_module_params();
+
rc = pci_register_driver(&pqi_pci_driver);
if (rc)
sas_release_transport(pqi_sas_transport_template);
@@ -6173,6 +7349,9 @@ static void __attribute__((unused)) verify_structures(void)
BUILD_BUG_ON(offsetof(struct pqi_event_config,
descriptors) != 4);
+ BUILD_BUG_ON(PQI_NUM_SUPPORTED_EVENTS !=
+ ARRAY_SIZE(pqi_supported_event_types));
+
BUILD_BUG_ON(offsetof(struct pqi_event_response,
header.iu_type) != 0);
BUILD_BUG_ON(offsetof(struct pqi_event_response,
@@ -6246,6 +7425,22 @@ static void __attribute__((unused)) verify_structures(void)
BUILD_BUG_ON(offsetof(struct bmic_identify_controller,
controller_mode) != 292);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+ phys_bay_in_box) != 115);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+ device_type) != 120);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+ redundant_path_present_map) != 1736);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+ active_path_number) != 1738);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+ alternate_paths_phys_connector) != 1739);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+ alternate_paths_phys_box_on_port) != 1755);
+ BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+ current_queue_depth_limit) != 1796);
+ BUILD_BUG_ON(sizeof(struct bmic_identify_physical_device) != 2560);
+
BUILD_BUG_ON(PQI_ADMIN_IQ_NUM_ELEMENTS > 255);
BUILD_BUG_ON(PQI_ADMIN_OQ_NUM_ELEMENTS > 255);
BUILD_BUG_ON(PQI_ADMIN_IQ_ELEMENT_LENGTH %
@@ -6260,4 +7455,6 @@ static void __attribute__((unused)) verify_structures(void)
PQI_QUEUE_ELEMENT_LENGTH_ALIGNMENT != 0);
BUILD_BUG_ON(PQI_RESERVED_IO_SLOTS >= PQI_MAX_OUTSTANDING_REQUESTS);
+ BUILD_BUG_ON(PQI_RESERVED_IO_SLOTS >=
+ PQI_MAX_OUTSTANDING_REQUESTS_KDUMP);
}
diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c b/drivers/scsi/smartpqi/smartpqi_sas_transport.c
index 52ca4f93f1b2..0d89d3728b43 100644
--- a/drivers/scsi/smartpqi/smartpqi_sas_transport.c
+++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c
@@ -1,6 +1,6 @@
/*
* driver for Microsemi PQI-based storage controllers
- * Copyright (c) 2016 Microsemi Corporation
+ * Copyright (c) 2016-2017 Microsemi Corporation
* Copyright (c) 2016 PMC-Sierra, Inc.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c
index 71408f9e8f75..e55dfcf200e5 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.c
+++ b/drivers/scsi/smartpqi/smartpqi_sis.c
@@ -1,6 +1,6 @@
/*
* driver for Microsemi PQI-based storage controllers
- * Copyright (c) 2016 Microsemi Corporation
+ * Copyright (c) 2016-2017 Microsemi Corporation
* Copyright (c) 2016 PMC-Sierra, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,9 @@
/* for submission of legacy SIS commands */
#define SIS_REENABLE_SIS_MODE 0x1
#define SIS_ENABLE_MSIX 0x40
+#define SIS_ENABLE_INTX 0x80
#define SIS_SOFT_RESET 0x100
+#define SIS_TRIGGER_SHUTDOWN 0x800000
#define SIS_CMD_READY 0x200
#define SIS_CMD_COMPLETE 0x1000
#define SIS_CLEAR_CTRL_TO_HOST_DOORBELL 0x1000
@@ -55,6 +57,7 @@
#define SIS_CTRL_KERNEL_UP 0x80
#define SIS_CTRL_KERNEL_PANIC 0x100
#define SIS_CTRL_READY_TIMEOUT_SECS 30
+#define SIS_CTRL_READY_RESUME_TIMEOUT_SECS 90
#define SIS_CTRL_READY_POLL_INTERVAL_MSECS 10
#pragma pack(1)
@@ -78,12 +81,13 @@ struct sis_base_struct {
#pragma pack()
-int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info)
+static int sis_wait_for_ctrl_ready_with_timeout(struct pqi_ctrl_info *ctrl_info,
+ unsigned int timeout_secs)
{
unsigned long timeout;
u32 status;
- timeout = (SIS_CTRL_READY_TIMEOUT_SECS * HZ) + jiffies;
+ timeout = (timeout_secs * HZ) + jiffies;
while (1) {
status = readl(&ctrl_info->registers->sis_firmware_status);
@@ -98,14 +102,30 @@ int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info)
if (status & SIS_CTRL_KERNEL_UP)
break;
}
- if (time_after(jiffies, timeout))
+ if (time_after(jiffies, timeout)) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "controller not ready after %u seconds\n",
+ timeout_secs);
return -ETIMEDOUT;
+ }
msleep(SIS_CTRL_READY_POLL_INTERVAL_MSECS);
}
return 0;
}
+int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info)
+{
+ return sis_wait_for_ctrl_ready_with_timeout(ctrl_info,
+ SIS_CTRL_READY_TIMEOUT_SECS);
+}
+
+int sis_wait_for_ctrl_ready_resume(struct pqi_ctrl_info *ctrl_info)
+{
+ return sis_wait_for_ctrl_ready_with_timeout(ctrl_info,
+ SIS_CTRL_READY_RESUME_TIMEOUT_SECS);
+}
+
bool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info)
{
bool running;
@@ -126,6 +146,12 @@ bool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info)
return running;
}
+bool sis_is_kernel_up(struct pqi_ctrl_info *ctrl_info)
+{
+ return readl(&ctrl_info->registers->sis_firmware_status) &
+ SIS_CTRL_KERNEL_UP;
+}
+
/* used for passing command parameters/results when issuing SIS commands */
struct sis_sync_cmd_params {
u32 mailbox[6]; /* mailboxes 0-5 */
@@ -308,6 +334,34 @@ out:
return rc;
}
+#define SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS 30
+
+static void sis_wait_for_doorbell_bit_to_clear(
+ struct pqi_ctrl_info *ctrl_info, u32 bit)
+{
+ u32 doorbell_register;
+ unsigned long timeout;
+
+ timeout = (SIS_DOORBELL_BIT_CLEAR_TIMEOUT_SECS * HZ) + jiffies;
+
+ while (1) {
+ doorbell_register =
+ readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell);
+ if ((doorbell_register & bit) == 0)
+ break;
+ if (readl(&ctrl_info->registers->sis_firmware_status) &
+ SIS_CTRL_KERNEL_PANIC)
+ break;
+ if (time_after(jiffies, timeout)) {
+ dev_err(&ctrl_info->pci_dev->dev,
+ "doorbell register bit 0x%x not cleared\n",
+ bit);
+ break;
+ }
+ usleep_range(1000, 2000);
+ }
+}
+
/* Enable MSI-X interrupts on the controller. */
void sis_enable_msix(struct pqi_ctrl_info *ctrl_info)
@@ -320,6 +374,8 @@ void sis_enable_msix(struct pqi_ctrl_info *ctrl_info)
writel(doorbell_register,
&ctrl_info->registers->sis_host_to_ctrl_doorbell);
+
+ sis_wait_for_doorbell_bit_to_clear(ctrl_info, SIS_ENABLE_MSIX);
}
/* Disable MSI-X interrupts on the controller. */
@@ -336,12 +392,48 @@ void sis_disable_msix(struct pqi_ctrl_info *ctrl_info)
&ctrl_info->registers->sis_host_to_ctrl_doorbell);
}
+void sis_enable_intx(struct pqi_ctrl_info *ctrl_info)
+{
+ u32 doorbell_register;
+
+ doorbell_register =
+ readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell);
+ doorbell_register |= SIS_ENABLE_INTX;
+
+ writel(doorbell_register,
+ &ctrl_info->registers->sis_host_to_ctrl_doorbell);
+
+ sis_wait_for_doorbell_bit_to_clear(ctrl_info, SIS_ENABLE_INTX);
+}
+
+void sis_disable_intx(struct pqi_ctrl_info *ctrl_info)
+{
+ u32 doorbell_register;
+
+ doorbell_register =
+ readl(&ctrl_info->registers->sis_host_to_ctrl_doorbell);
+ doorbell_register &= ~SIS_ENABLE_INTX;
+
+ writel(doorbell_register,
+ &ctrl_info->registers->sis_host_to_ctrl_doorbell);
+}
+
void sis_soft_reset(struct pqi_ctrl_info *ctrl_info)
{
writel(SIS_SOFT_RESET,
&ctrl_info->registers->sis_host_to_ctrl_doorbell);
}
+void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info)
+{
+ if (readl(&ctrl_info->registers->sis_firmware_status) &
+ SIS_CTRL_KERNEL_PANIC)
+ return;
+
+ writel(SIS_TRIGGER_SHUTDOWN,
+ &ctrl_info->registers->sis_host_to_ctrl_doorbell);
+}
+
#define SIS_MODE_READY_TIMEOUT_SECS 30
int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info)
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h b/drivers/scsi/smartpqi/smartpqi_sis.h
index bd6e7b08338e..983184b69373 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.h
+++ b/drivers/scsi/smartpqi/smartpqi_sis.h
@@ -1,6 +1,6 @@
/*
* driver for Microsemi PQI-based storage controllers
- * Copyright (c) 2016 Microsemi Corporation
+ * Copyright (c) 2016-2017 Microsemi Corporation
* Copyright (c) 2016 PMC-Sierra, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -20,13 +20,18 @@
#define _SMARTPQI_SIS_H
int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info);
+int sis_wait_for_ctrl_ready_resume(struct pqi_ctrl_info *ctrl_info);
bool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info);
+bool sis_is_kernel_up(struct pqi_ctrl_info *ctrl_info);
int sis_get_ctrl_properties(struct pqi_ctrl_info *ctrl_info);
int sis_get_pqi_capabilities(struct pqi_ctrl_info *ctrl_info);
int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info);
void sis_enable_msix(struct pqi_ctrl_info *ctrl_info);
void sis_disable_msix(struct pqi_ctrl_info *ctrl_info);
+void sis_enable_intx(struct pqi_ctrl_info *ctrl_info);
+void sis_disable_intx(struct pqi_ctrl_info *ctrl_info);
void sis_soft_reset(struct pqi_ctrl_info *ctrl_info);
+void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info);
int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info);
void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value);
u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info);
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index ae966dc3bbc5..8d955db6424f 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1149,13 +1149,9 @@ static void storvsc_on_receive(struct storvsc_device *stor_device,
static void storvsc_on_channel_callback(void *context)
{
struct vmbus_channel *channel = (struct vmbus_channel *)context;
+ const struct vmpacket_descriptor *desc;
struct hv_device *device;
struct storvsc_device *stor_device;
- u32 bytes_recvd;
- u64 request_id;
- unsigned char packet[ALIGN(sizeof(struct vstor_packet), 8)];
- struct storvsc_cmd_request *request;
- int ret;
if (channel->primary_channel != NULL)
device = channel->primary_channel->device_obj;
@@ -1166,32 +1162,22 @@ static void storvsc_on_channel_callback(void *context)
if (!stor_device)
return;
- do {
- ret = vmbus_recvpacket(channel, packet,
- ALIGN((sizeof(struct vstor_packet) -
- vmscsi_size_delta), 8),
- &bytes_recvd, &request_id);
- if (ret == 0 && bytes_recvd > 0) {
-
- request = (struct storvsc_cmd_request *)
- (unsigned long)request_id;
-
- if ((request == &stor_device->init_request) ||
- (request == &stor_device->reset_request)) {
-
- memcpy(&request->vstor_packet, packet,
- (sizeof(struct vstor_packet) -
- vmscsi_size_delta));
- complete(&request->wait_event);
- } else {
- storvsc_on_receive(stor_device,
- (struct vstor_packet *)packet,
- request);
- }
+ foreach_vmbus_pkt(desc, channel) {
+ void *packet = hv_pkt_data(desc);
+ struct storvsc_cmd_request *request;
+
+ request = (struct storvsc_cmd_request *)
+ ((unsigned long)desc->trans_id);
+
+ if (request == &stor_device->init_request ||
+ request == &stor_device->reset_request) {
+ memcpy(&request->vstor_packet, packet,
+ (sizeof(struct vstor_packet) - vmscsi_size_delta));
+ complete(&request->wait_event);
} else {
- break;
+ storvsc_on_receive(stor_device, packet, request);
}
- } while (1);
+ }
}
static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size,
@@ -1220,13 +1206,13 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size,
static int storvsc_dev_remove(struct hv_device *device)
{
struct storvsc_device *stor_device;
- unsigned long flags;
stor_device = hv_get_drvdata(device);
- spin_lock_irqsave(&device->channel->inbound_lock, flags);
stor_device->destroy = true;
- spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
+
+ /* Make sure flag is set before waiting */
+ wmb();
/*
* At this point, all outbound traffic should be disable. We
@@ -1243,9 +1229,7 @@ static int storvsc_dev_remove(struct hv_device *device)
* we have drained - to drain the outgoing packets, we need to
* allow incoming packets.
*/
- spin_lock_irqsave(&device->channel->inbound_lock, flags);
hv_set_drvdata(device, NULL);
- spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
/* Close the channel */
vmbus_close(device->channel);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index e09fc8290c2f..b7d7bbec74e0 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -744,7 +744,6 @@ struct vmbus_channel {
u32 ringbuffer_pagecount;
struct hv_ring_buffer_info outbound; /* send to parent */
struct hv_ring_buffer_info inbound; /* receive from parent */
- spinlock_t inbound_lock;
struct vmbus_close_msg close_msg;