aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic94xx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/aic94xx')
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c51
1 files changed, 44 insertions, 7 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: