aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorDon Brace <don.brace@microsemi.com>2016-04-27 18:14:17 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2016-04-29 19:08:24 -0400
commitba74fdc411b84064d7abe4b10d0708f6dad03eb2 (patch)
tree71eea04b9c9745857cd4399304285335904f1b08 /drivers/scsi
parent064d1b1d2d8e0b90f1a0a49112eca0d5c2a09b16 (diff)
hpsa: correct handling of HBA device removal
Need to report HBA device removal faster than the event handler polling interval. Stop I/O to the removed disk and wait for all I/O operations to flush before removing the device. Reviewed-by: Scott Teel <scott.teel@microsemi.com> Reviewed-by: Kevin Barnett <kevin.barnett@microsemi.com> Signed-off-by: Don Brace <don.brace@microsemi.com> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/hpsa.c89
-rw-r--r--drivers/scsi/hpsa.h1
2 files changed, 85 insertions, 5 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 4f8e3285baa9..034624f1ca64 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -294,6 +294,9 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h);
294static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h, 294static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h,
295 struct ReportExtendedLUNdata *buf, int bufsize); 295 struct ReportExtendedLUNdata *buf, int bufsize);
296static int hpsa_luns_changed(struct ctlr_info *h); 296static int hpsa_luns_changed(struct ctlr_info *h);
297static bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c,
298 struct hpsa_scsi_dev_t *dev,
299 unsigned char *scsi3addr);
297 300
298static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) 301static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
299{ 302{
@@ -1745,6 +1748,51 @@ static int hpsa_add_device(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
1745 return rc; 1748 return rc;
1746} 1749}
1747 1750
1751static int hpsa_find_outstanding_commands_for_dev(struct ctlr_info *h,
1752 struct hpsa_scsi_dev_t *dev)
1753{
1754 int i;
1755 int count = 0;
1756
1757 for (i = 0; i < h->nr_cmds; i++) {
1758 struct CommandList *c = h->cmd_pool + i;
1759 int refcount = atomic_inc_return(&c->refcount);
1760
1761 if (refcount > 1 && hpsa_cmd_dev_match(h, c, dev,
1762 dev->scsi3addr)) {
1763 unsigned long flags;
1764
1765 spin_lock_irqsave(&h->lock, flags); /* Implied MB */
1766 if (!hpsa_is_cmd_idle(c))
1767 ++count;
1768 spin_unlock_irqrestore(&h->lock, flags);
1769 }
1770
1771 cmd_free(h, c);
1772 }
1773
1774 return count;
1775}
1776
1777static void hpsa_wait_for_outstanding_commands_for_dev(struct ctlr_info *h,
1778 struct hpsa_scsi_dev_t *device)
1779{
1780 int cmds = 0;
1781 int waits = 0;
1782
1783 while (1) {
1784 cmds = hpsa_find_outstanding_commands_for_dev(h, device);
1785 if (cmds == 0)
1786 break;
1787 if (++waits > 20)
1788 break;
1789 dev_warn(&h->pdev->dev,
1790 "%s: removing device with %d outstanding commands!\n",
1791 __func__, cmds);
1792 msleep(1000);
1793 }
1794}
1795
1748static void hpsa_remove_device(struct ctlr_info *h, 1796static void hpsa_remove_device(struct ctlr_info *h,
1749 struct hpsa_scsi_dev_t *device) 1797 struct hpsa_scsi_dev_t *device)
1750{ 1798{
@@ -1768,8 +1816,13 @@ static void hpsa_remove_device(struct ctlr_info *h,
1768 hpsa_show_dev_msg(KERN_WARNING, h, device, 1816 hpsa_show_dev_msg(KERN_WARNING, h, device,
1769 "didn't find device for removal."); 1817 "didn't find device for removal.");
1770 } 1818 }
1771 } else /* HBA */ 1819 } else { /* HBA */
1820
1821 device->removed = 1;
1822 hpsa_wait_for_outstanding_commands_for_dev(h, device);
1823
1772 hpsa_remove_sas_device(device); 1824 hpsa_remove_sas_device(device);
1825 }
1773} 1826}
1774 1827
1775static void adjust_hpsa_scsi_table(struct ctlr_info *h, 1828static void adjust_hpsa_scsi_table(struct ctlr_info *h,
@@ -2171,7 +2224,8 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
2171static int handle_ioaccel_mode2_error(struct ctlr_info *h, 2224static int handle_ioaccel_mode2_error(struct ctlr_info *h,
2172 struct CommandList *c, 2225 struct CommandList *c,
2173 struct scsi_cmnd *cmd, 2226 struct scsi_cmnd *cmd,
2174 struct io_accel2_cmd *c2) 2227 struct io_accel2_cmd *c2,
2228 struct hpsa_scsi_dev_t *dev)
2175{ 2229{
2176 int data_len; 2230 int data_len;
2177 int retry = 0; 2231 int retry = 0;
@@ -2235,8 +2289,27 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h,
2235 case IOACCEL2_STATUS_SR_NO_PATH_TO_DEVICE: 2289 case IOACCEL2_STATUS_SR_NO_PATH_TO_DEVICE:
2236 case IOACCEL2_STATUS_SR_INVALID_DEVICE: 2290 case IOACCEL2_STATUS_SR_INVALID_DEVICE:
2237 case IOACCEL2_STATUS_SR_IOACCEL_DISABLED: 2291 case IOACCEL2_STATUS_SR_IOACCEL_DISABLED:
2238 /* We will get an event from ctlr to trigger rescan */ 2292 /*
2239 retry = 1; 2293 * Did an HBA disk disappear? We will eventually
2294 * get a state change event from the controller but
2295 * in the meantime, we need to tell the OS that the
2296 * HBA disk is no longer there and stop I/O
2297 * from going down. This allows the potential re-insert
2298 * of the disk to get the same device node.
2299 */
2300 if (dev->physical_device && dev->expose_device) {
2301 cmd->result = DID_NO_CONNECT << 16;
2302 dev->removed = 1;
2303 h->drv_req_rescan = 1;
2304 dev_warn(&h->pdev->dev,
2305 "%s: device is gone!\n", __func__);
2306 } else
2307 /*
2308 * Retry by sending down the RAID path.
2309 * We will get an event from ctlr to
2310 * trigger rescan regardless.
2311 */
2312 retry = 1;
2240 break; 2313 break;
2241 default: 2314 default:
2242 retry = 1; 2315 retry = 1;
@@ -2368,7 +2441,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
2368 return hpsa_retry_cmd(h, c); 2441 return hpsa_retry_cmd(h, c);
2369 } 2442 }
2370 2443
2371 if (handle_ioaccel_mode2_error(h, c, cmd, c2)) 2444 if (handle_ioaccel_mode2_error(h, c, cmd, c2, dev))
2372 return hpsa_retry_cmd(h, c); 2445 return hpsa_retry_cmd(h, c);
2373 2446
2374 return hpsa_cmd_free_and_done(h, c, cmd); 2447 return hpsa_cmd_free_and_done(h, c, cmd);
@@ -5263,6 +5336,12 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
5263 5336
5264 dev = cmd->device->hostdata; 5337 dev = cmd->device->hostdata;
5265 if (!dev) { 5338 if (!dev) {
5339 cmd->result = NOT_READY << 16; /* host byte */
5340 cmd->scsi_done(cmd);
5341 return 0;
5342 }
5343
5344 if (dev->removed) {
5266 cmd->result = DID_NO_CONNECT << 16; 5345 cmd->result = DID_NO_CONNECT << 16;
5267 cmd->scsi_done(cmd); 5346 cmd->scsi_done(cmd);
5268 return 0; 5347 return 0;
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index d06bb7417e36..a1487e67f7a1 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -63,6 +63,7 @@ struct hpsa_scsi_dev_t {
63 unsigned char scsi3addr[8]; /* as presented to the HW */ 63 unsigned char scsi3addr[8]; /* as presented to the HW */
64 u8 physical_device : 1; 64 u8 physical_device : 1;
65 u8 expose_device; 65 u8 expose_device;
66 u8 removed : 1; /* device is marked for death */
66#define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0" 67#define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0"
67 unsigned char device_id[16]; /* from inquiry pg. 0x83 */ 68 unsigned char device_id[16]; /* from inquiry pg. 0x83 */
68 u64 sas_address; 69 u64 sas_address;