aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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) \