aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2006-11-07 20:28:55 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-11-22 12:05:59 -0500
commitdea22214790d1306f3a3444db13d2c726037b189 (patch)
treec5bd0d382c73c02f3416aac584e3d3a011cd1261
parent504fb37a0801d843bc1907c1a1f9c719c3509863 (diff)
[PATCH] aic94xx: handle REQ_DEVICE_RESET
This patch implements a REQ_DEVICE_RESET handler for the aic94xx driver. Like the earlier REQ_TASK_ABORT patch, this patch defers the device reset to the Scsi_Host's workqueue, which has the added benefit of ensuring that the device reset does not happen at the same time that the abort tmfs are being processed. After the phy reset, the busted drive should go away and be re-detected later, which is indeed what I've seen on both a x260 and a x206m. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c51
-rw-r--r--drivers/scsi/libsas/sas_init.c2
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c1
-rw-r--r--include/scsi/libsas.h1
-rw-r--r--include/scsi/scsi_transport_sas.h2
5 files changed, 49 insertions, 8 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 1911c5d17875..a014418d670e 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -343,6 +343,27 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
343 } 343 }
344} 344}
345 345
346/* hard reset a phy later */
347static void do_phy_reset_later(void *data)
348{
349 struct sas_phy *sas_phy = data;
350 int error;
351
352 ASD_DPRINTK("%s: About to hard reset phy %d\n", __FUNCTION__,
353 sas_phy->identify.phy_identifier);
354 /* Reset device port */
355 error = sas_phy_reset(sas_phy, 1);
356 if (error)
357 ASD_DPRINTK("%s: Hard reset of phy %d failed (%d).\n",
358 __FUNCTION__, sas_phy->identify.phy_identifier, error);
359}
360
361static void phy_reset_later(struct sas_phy *sas_phy, struct Scsi_Host *shost)
362{
363 INIT_WORK(&sas_phy->reset_work, do_phy_reset_later, sas_phy);
364 queue_work(shost->work_q, &sas_phy->reset_work);
365}
366
346/* start up the ABORT TASK tmf... */ 367/* start up the ABORT TASK tmf... */
347static void task_kill_later(struct asd_ascb *ascb) 368static void task_kill_later(struct asd_ascb *ascb)
348{ 369{
@@ -402,7 +423,9 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
402 goto out; 423 goto out;
403 } 424 }
404 case REQ_DEVICE_RESET: { 425 case REQ_DEVICE_RESET: {
405 struct asd_ascb *a, *b; 426 struct Scsi_Host *shost = sas_ha->core.shost;
427 struct sas_phy *dev_phy;
428 struct asd_ascb *a;
406 u16 conn_handle; 429 u16 conn_handle;
407 430
408 conn_handle = *((u16*)(&dl->status_block[1])); 431 conn_handle = *((u16*)(&dl->status_block[1]));
@@ -412,17 +435,31 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
412 dl->status_block[3]); 435 dl->status_block[3]);
413 436
414 /* Kill all pending tasks and reset the device */ 437 /* Kill all pending tasks and reset the device */
415 list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) { 438 dev_phy = NULL;
416 struct sas_task *task = a->uldd_task; 439 list_for_each_entry(a, &asd_ha->seq.pend_q, list) {
417 struct domain_device *dev = task->dev; 440 struct sas_task *task;
441 struct domain_device *dev;
418 u16 x; 442 u16 x;
419 443
420 x = *((u16*)(&dev->lldd_dev)); 444 task = a->uldd_task;
421 if (x == conn_handle) 445 if (!task)
446 continue;
447 dev = task->dev;
448
449 x = (u16)dev->lldd_dev;
450 if (x == conn_handle) {
451 dev_phy = dev->port->phy;
422 task_kill_later(a); 452 task_kill_later(a);
453 }
423 } 454 }
424 455
425 /* FIXME: Reset device port (huh?) */ 456 /* Reset device port */
457 if (!dev_phy) {
458 ASD_DPRINTK("%s: No pending commands; can't reset.\n",
459 __FUNCTION__);
460 goto out;
461 }
462 phy_reset_later(dev_phy, shost);
426 goto out; 463 goto out;
427 } 464 }
428 case SIGNAL_NCQ_ERROR: 465 case SIGNAL_NCQ_ERROR:
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index a2b479a65908..0fb347b4b1a2 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -144,7 +144,7 @@ static int sas_get_linkerrors(struct sas_phy *phy)
144 return sas_smp_get_phy_events(phy); 144 return sas_smp_get_phy_events(phy);
145} 145}
146 146
147static int sas_phy_reset(struct sas_phy *phy, int hard_reset) 147int sas_phy_reset(struct sas_phy *phy, int hard_reset)
148{ 148{
149 int ret; 149 int ret;
150 enum phy_func reset_type; 150 enum phy_func reset_type;
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index c5fd37522728..e064aac06b90 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -865,3 +865,4 @@ EXPORT_SYMBOL_GPL(sas_change_queue_depth);
865EXPORT_SYMBOL_GPL(sas_change_queue_type); 865EXPORT_SYMBOL_GPL(sas_change_queue_type);
866EXPORT_SYMBOL_GPL(sas_bios_param); 866EXPORT_SYMBOL_GPL(sas_bios_param);
867EXPORT_SYMBOL_GPL(sas_task_abort); 867EXPORT_SYMBOL_GPL(sas_task_abort);
868EXPORT_SYMBOL_GPL(sas_phy_reset);
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index a1fc20a47c50..29f6e1af1bf9 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -597,6 +597,7 @@ struct sas_domain_function_template {
597extern int sas_register_ha(struct sas_ha_struct *); 597extern int sas_register_ha(struct sas_ha_struct *);
598extern int sas_unregister_ha(struct sas_ha_struct *); 598extern int sas_unregister_ha(struct sas_ha_struct *);
599 599
600int sas_phy_reset(struct sas_phy *phy, int hard_reset);
600extern int sas_queuecommand(struct scsi_cmnd *, 601extern int sas_queuecommand(struct scsi_cmnd *,
601 void (*scsi_done)(struct scsi_cmnd *)); 602 void (*scsi_done)(struct scsi_cmnd *));
602extern int sas_target_alloc(struct scsi_target *); 603extern int sas_target_alloc(struct scsi_target *);
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index 53024377f3b8..59633a82de47 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -73,6 +73,8 @@ struct sas_phy {
73 73
74 /* for the list of phys belonging to a port */ 74 /* for the list of phys belonging to a port */
75 struct list_head port_siblings; 75 struct list_head port_siblings;
76
77 struct work_struct reset_work;
76}; 78};
77 79
78#define dev_to_phy(d) \ 80#define dev_to_phy(d) \