aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-11-17 20:59:54 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-29 13:49:36 -0500
commit36a399473902a57218dc493c5a814708a56b73ab (patch)
treee64a9f136bbacaded9fdd3d3d39c342953d9be34 /drivers/scsi/libsas
parent50824d6c5657ce340e3911171865a8d99fdd8eba (diff)
[SCSI] libsas: poll for ata device readiness after reset
Use ata_wait_after_reset() to poll for link recovery after a reset. This combined with sas_ha->eh_mutex prevents expander rediscovery from probing phys in an intermediate state. Local discovery does not have a mechanism to filter link status changes during this timeout, so it remains the responsibility of lldds to prevent premature port teardown. Although once all lldd's support ->lldd_ata_check_ready() that could be used as a gate to local port teardown. The signature fis is re-transmitted when the link comes back so we should be revalidating the ata device class, but that is left to a future patch. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/sas_ata.c104
-rw-r--r--drivers/scsi/libsas/sas_expander.c10
-rw-r--r--drivers/scsi/libsas/sas_internal.h3
3 files changed, 82 insertions, 35 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 4beca66728b4..5fdb63ad94b7 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -272,39 +272,84 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
272 return true; 272 return true;
273} 273}
274 274
275static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class, 275static struct sas_internal *dev_to_sas_internal(struct domain_device *dev)
276 unsigned long deadline) 276{
277 return to_sas_internal(dev->port->ha->core.shost->transportt);
278}
279
280static int smp_ata_check_ready(struct ata_link *link)
277{ 281{
282 int res;
283 u8 addr[8];
278 struct ata_port *ap = link->ap; 284 struct ata_port *ap = link->ap;
279 struct domain_device *dev = ap->private_data; 285 struct domain_device *dev = ap->private_data;
280 struct sas_internal *i = 286 struct domain_device *ex_dev = dev->parent;
281 to_sas_internal(dev->port->ha->core.shost->transportt); 287 struct sas_phy *phy = sas_find_local_phy(dev);
282 int res = TMF_RESP_FUNC_FAILED;
283 int ret = 0;
284 288
285 if (i->dft->lldd_I_T_nexus_reset) 289 res = sas_get_phy_attached_sas_addr(ex_dev, phy->number, addr);
286 res = i->dft->lldd_I_T_nexus_reset(dev); 290 /* break the wait early if the expander is unreachable,
291 * otherwise keep polling
292 */
293 if (res == -ECOMM)
294 return res;
295 if (res != SMP_RESP_FUNC_ACC || SAS_ADDR(addr) == 0)
296 return 0;
297 else
298 return 1;
299}
287 300
288 if (res != TMF_RESP_FUNC_COMPLETE) { 301static int local_ata_check_ready(struct ata_link *link)
289 SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__); 302{
290 ret = -EAGAIN; 303 struct ata_port *ap = link->ap;
304 struct domain_device *dev = ap->private_data;
305 struct sas_internal *i = dev_to_sas_internal(dev);
306
307 if (i->dft->lldd_ata_check_ready)
308 return i->dft->lldd_ata_check_ready(dev);
309 else {
310 /* lldd's that don't implement 'ready' checking get the
311 * old default behavior of not coordinating reset
312 * recovery with libata
313 */
314 return 1;
291 } 315 }
316}
292 317
318static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
319 unsigned long deadline)
320{
321 int ret = 0, res;
322 struct ata_port *ap = link->ap;
323 int (*check_ready)(struct ata_link *link);
324 struct domain_device *dev = ap->private_data;
325 struct sas_phy *phy = sas_find_local_phy(dev);
326 struct sas_internal *i = dev_to_sas_internal(dev);
327
328 res = i->dft->lldd_I_T_nexus_reset(dev);
329
330 if (res != TMF_RESP_FUNC_COMPLETE)
331 SAS_DPRINTK("%s: Unable to reset ata device?\n", __func__);
332
333 if (scsi_is_sas_phy_local(phy))
334 check_ready = local_ata_check_ready;
335 else
336 check_ready = smp_ata_check_ready;
337
338 ret = ata_wait_after_reset(link, deadline, check_ready);
339 if (ret && ret != -EAGAIN)
340 ata_link_err(link, "COMRESET failed (errno=%d)\n", ret);
341
342 /* XXX: if the class changes during the reset the upper layer
343 * should be informed, if the device has gone away we assume
344 * libsas will eventually delete it
345 */
293 switch (dev->sata_dev.command_set) { 346 switch (dev->sata_dev.command_set) {
294 case ATA_COMMAND_SET: 347 case ATA_COMMAND_SET:
295 SAS_DPRINTK("%s: Found ATA device.\n", __func__); 348 *class = ATA_DEV_ATA;
296 *class = ATA_DEV_ATA; 349 break;
297 break; 350 case ATAPI_COMMAND_SET:
298 case ATAPI_COMMAND_SET: 351 *class = ATA_DEV_ATAPI;
299 SAS_DPRINTK("%s: Found ATAPI device.\n", __func__); 352 break;
300 *class = ATA_DEV_ATAPI;
301 break;
302 default:
303 SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
304 __func__,
305 dev->sata_dev.command_set);
306 *class = ATA_DEV_UNKNOWN;
307 break;
308 } 353 }
309 354
310 ap->cbl = ATA_CBL_SATA; 355 ap->cbl = ATA_CBL_SATA;
@@ -316,8 +361,7 @@ static int sas_ata_soft_reset(struct ata_link *link, unsigned int *class,
316{ 361{
317 struct ata_port *ap = link->ap; 362 struct ata_port *ap = link->ap;
318 struct domain_device *dev = ap->private_data; 363 struct domain_device *dev = ap->private_data;
319 struct sas_internal *i = 364 struct sas_internal *i = dev_to_sas_internal(dev);
320 to_sas_internal(dev->port->ha->core.shost->transportt);
321 int res = TMF_RESP_FUNC_FAILED; 365 int res = TMF_RESP_FUNC_FAILED;
322 int ret = 0; 366 int ret = 0;
323 367
@@ -355,8 +399,7 @@ static int sas_ata_soft_reset(struct ata_link *link, unsigned int *class,
355 */ 399 */
356static void sas_ata_internal_abort(struct sas_task *task) 400static void sas_ata_internal_abort(struct sas_task *task)
357{ 401{
358 struct sas_internal *si = 402 struct sas_internal *si = dev_to_sas_internal(task->dev);
359 to_sas_internal(task->dev->port->ha->core.shost->transportt);
360 unsigned long flags; 403 unsigned long flags;
361 int res; 404 int res;
362 405
@@ -425,8 +468,7 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc)
425static void sas_ata_set_dmamode(struct ata_port *ap, struct ata_device *ata_dev) 468static void sas_ata_set_dmamode(struct ata_port *ap, struct ata_device *ata_dev)
426{ 469{
427 struct domain_device *dev = ap->private_data; 470 struct domain_device *dev = ap->private_data;
428 struct sas_internal *i = 471 struct sas_internal *i = dev_to_sas_internal(dev);
429 to_sas_internal(dev->port->ha->core.shost->transportt);
430 472
431 if (i->dft->lldd_ata_set_dmamode) 473 if (i->dft->lldd_ata_set_dmamode)
432 i->dft->lldd_ata_set_dmamode(dev); 474 i->dft->lldd_ata_set_dmamode(dev);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 7c59f97c0287..32e417e6c2f7 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -125,7 +125,11 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
125 task->task_status.stat == SAS_DATA_OVERRUN) { 125 task->task_status.stat == SAS_DATA_OVERRUN) {
126 res = -EMSGSIZE; 126 res = -EMSGSIZE;
127 break; 127 break;
128 } else { 128 }
129 if (task->task_status.resp == SAS_TASK_UNDELIVERED &&
130 task->task_status.stat == SAS_DEVICE_UNKNOWN)
131 break;
132 else {
129 SAS_DPRINTK("%s: task to dev %016llx response: 0x%x " 133 SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
130 "status 0x%x\n", __func__, 134 "status 0x%x\n", __func__,
131 SAS_ADDR(dev->sas_addr), 135 SAS_ADDR(dev->sas_addr),
@@ -1648,8 +1652,8 @@ static int sas_get_phy_change_count(struct domain_device *dev,
1648 return res; 1652 return res;
1649} 1653}
1650 1654
1651static int sas_get_phy_attached_sas_addr(struct domain_device *dev, 1655int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id,
1652 int phy_id, u8 *attached_sas_addr) 1656 u8 *attached_sas_addr)
1653{ 1657{
1654 int res; 1658 int res;
1655 struct smp_resp *disc_resp; 1659 struct smp_resp *disc_resp;
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 9e960b2d535a..a9a3bb94c1bc 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -89,7 +89,8 @@ int sas_smp_get_phy_events(struct sas_phy *phy);
89 89
90struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); 90struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
91struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); 91struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
92 92int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id,
93 u8 *attached_sas_addr);
93void sas_hae_reset(struct work_struct *work); 94void sas_hae_reset(struct work_struct *work);
94 95
95void sas_free_device(struct kref *kref); 96void sas_free_device(struct kref *kref);