diff options
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_scb.c | 51 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 2 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 1 | ||||
-rw-r--r-- | include/scsi/libsas.h | 1 | ||||
-rw-r--r-- | include/scsi/scsi_transport_sas.h | 2 |
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 */ | ||
347 | static 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 | |||
361 | static 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... */ |
347 | static void task_kill_later(struct asd_ascb *ascb) | 368 | static 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 | ||
147 | static int sas_phy_reset(struct sas_phy *phy, int hard_reset) | 147 | int 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); | |||
865 | EXPORT_SYMBOL_GPL(sas_change_queue_type); | 865 | EXPORT_SYMBOL_GPL(sas_change_queue_type); |
866 | EXPORT_SYMBOL_GPL(sas_bios_param); | 866 | EXPORT_SYMBOL_GPL(sas_bios_param); |
867 | EXPORT_SYMBOL_GPL(sas_task_abort); | 867 | EXPORT_SYMBOL_GPL(sas_task_abort); |
868 | EXPORT_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 { | |||
597 | extern int sas_register_ha(struct sas_ha_struct *); | 597 | extern int sas_register_ha(struct sas_ha_struct *); |
598 | extern int sas_unregister_ha(struct sas_ha_struct *); | 598 | extern int sas_unregister_ha(struct sas_ha_struct *); |
599 | 599 | ||
600 | int sas_phy_reset(struct sas_phy *phy, int hard_reset); | ||
600 | extern int sas_queuecommand(struct scsi_cmnd *, | 601 | extern int sas_queuecommand(struct scsi_cmnd *, |
601 | void (*scsi_done)(struct scsi_cmnd *)); | 602 | void (*scsi_done)(struct scsi_cmnd *)); |
602 | extern int sas_target_alloc(struct scsi_target *); | 603 | extern 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) \ |