aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic94xx
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2007-01-11 17:15:23 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-01-13 17:18:40 -0500
commit3cd041fb7f50f4cee3bc3a2b0ce02b1562894894 (patch)
treee3c7acee96ace5f1e5ffcace7b9201ccc4807d5a /drivers/scsi/aic94xx
parent396819fba821ad56f1b90090d256f0ab726c89c5 (diff)
[SCSI] aic94xx: Remove workqueue code from REQ_TASK_ABORT/REQ_DEVICE_RESET code
Now that task aborts and device port resets are done by the EH, we can remove all the code that set up workqueues and such and simply call sas_task_abort and let libsas figure things out. Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/aic94xx')
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c122
1 files changed, 66 insertions, 56 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 75ed6b0569d1..8f43ff772f23 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -413,40 +413,6 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
413 } 413 }
414} 414}
415 415
416/* hard reset a phy later */
417static void do_phy_reset_later(struct work_struct *work)
418{
419 struct sas_phy *sas_phy =
420 container_of(work, struct sas_phy, reset_work);
421 int error;
422
423 ASD_DPRINTK("%s: About to hard reset phy %d\n", __FUNCTION__,
424 sas_phy->identify.phy_identifier);
425 /* Reset device port */
426 error = sas_phy_reset(sas_phy, 1);
427 if (error)
428 ASD_DPRINTK("%s: Hard reset of phy %d failed (%d).\n",
429 __FUNCTION__, sas_phy->identify.phy_identifier, error);
430}
431
432static void phy_reset_later(struct sas_phy *sas_phy, struct Scsi_Host *shost)
433{
434 INIT_WORK(&sas_phy->reset_work, do_phy_reset_later);
435 queue_work(shost->work_q, &sas_phy->reset_work);
436}
437
438/* start up the ABORT TASK tmf... */
439static void task_kill_later(struct asd_ascb *ascb)
440{
441 struct asd_ha_struct *asd_ha = ascb->ha;
442 struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
443 struct Scsi_Host *shost = sas_ha->core.shost;
444 struct sas_task *task = ascb->uldd_task;
445
446 INIT_WORK(&task->abort_work, sas_task_abort);
447 queue_work(shost->work_q, &task->abort_work);
448}
449
450static void escb_tasklet_complete(struct asd_ascb *ascb, 416static void escb_tasklet_complete(struct asd_ascb *ascb,
451 struct done_list_struct *dl) 417 struct done_list_struct *dl)
452{ 418{
@@ -479,26 +445,55 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
479 case REQ_TASK_ABORT: { 445 case REQ_TASK_ABORT: {
480 struct asd_ascb *a, *b; 446 struct asd_ascb *a, *b;
481 u16 tc_abort; 447 u16 tc_abort;
448 struct domain_device *failed_dev = NULL;
449
450 ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
451 __FUNCTION__, dl->status_block[3]);
482 452
453 /*
454 * Find the task that caused the abort and abort it first.
455 * The sequencer won't put anything on the done list until
456 * that happens.
457 */
483 tc_abort = *((u16*)(&dl->status_block[1])); 458 tc_abort = *((u16*)(&dl->status_block[1]));
484 tc_abort = le16_to_cpu(tc_abort); 459 tc_abort = le16_to_cpu(tc_abort);
485 460
486 ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n", 461 list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
487 __FUNCTION__, dl->status_block[3]); 462 struct sas_task *task = ascb->uldd_task;
488 463
489 /* Find the pending task and abort it. */ 464 if (task && a->tc_index == tc_abort) {
490 list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) 465 failed_dev = task->dev;
491 if (a->tc_index == tc_abort) { 466 sas_task_abort(task);
492 task_kill_later(a);
493 break; 467 break;
494 } 468 }
469 }
470
471 if (!failed_dev) {
472 ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n",
473 __FUNCTION__, tc_abort);
474 goto out;
475 }
476
477 /*
478 * Now abort everything else for that device (hba?) so
479 * that the EH will wake up and do something.
480 */
481 list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
482 struct sas_task *task = ascb->uldd_task;
483
484 if (task &&
485 task->dev == failed_dev &&
486 a->tc_index != tc_abort)
487 sas_task_abort(task);
488 }
489
495 goto out; 490 goto out;
496 } 491 }
497 case REQ_DEVICE_RESET: { 492 case REQ_DEVICE_RESET: {
498 struct Scsi_Host *shost = sas_ha->core.shost;
499 struct sas_phy *dev_phy;
500 struct asd_ascb *a; 493 struct asd_ascb *a;
501 u16 conn_handle; 494 u16 conn_handle;
495 unsigned long flags;
496 struct sas_task *last_dev_task = NULL;
502 497
503 conn_handle = *((u16*)(&dl->status_block[1])); 498 conn_handle = *((u16*)(&dl->status_block[1]));
504 conn_handle = le16_to_cpu(conn_handle); 499 conn_handle = le16_to_cpu(conn_handle);
@@ -506,32 +501,47 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
506 ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__, 501 ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__,
507 dl->status_block[3]); 502 dl->status_block[3]);
508 503
509 /* Kill all pending tasks and reset the device */ 504 /* Find the last pending task for the device... */
510 dev_phy = NULL;
511 list_for_each_entry(a, &asd_ha->seq.pend_q, list) { 505 list_for_each_entry(a, &asd_ha->seq.pend_q, list) {
512 struct sas_task *task;
513 struct domain_device *dev;
514 u16 x; 506 u16 x;
507 struct domain_device *dev;
508 struct sas_task *task = a->uldd_task;
515 509
516 task = a->uldd_task;
517 if (!task) 510 if (!task)
518 continue; 511 continue;
519 dev = task->dev; 512 dev = task->dev;
520 513
521 x = (unsigned long)dev->lldd_dev; 514 x = (unsigned long)dev->lldd_dev;
522 if (x == conn_handle) { 515 if (x == conn_handle)
523 dev_phy = dev->port->phy; 516 last_dev_task = task;
524 task_kill_later(a);
525 }
526 } 517 }
527 518
528 /* Reset device port */ 519 if (!last_dev_task) {
529 if (!dev_phy) { 520 ASD_DPRINTK("%s: Device reset for idle device %d?\n",
530 ASD_DPRINTK("%s: No pending commands; can't reset.\n", 521 __FUNCTION__, conn_handle);
531 __FUNCTION__);
532 goto out; 522 goto out;
533 } 523 }
534 phy_reset_later(dev_phy, shost); 524
525 /* ...and set the reset flag */
526 spin_lock_irqsave(&last_dev_task->task_state_lock, flags);
527 last_dev_task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
528 spin_unlock_irqrestore(&last_dev_task->task_state_lock, flags);
529
530 /* Kill all pending tasks for the device */
531 list_for_each_entry(a, &asd_ha->seq.pend_q, list) {
532 u16 x;
533 struct domain_device *dev;
534 struct sas_task *task = a->uldd_task;
535
536 if (!task)
537 continue;
538 dev = task->dev;
539
540 x = (unsigned long)dev->lldd_dev;
541 if (x == conn_handle)
542 sas_task_abort(task);
543 }
544
535 goto out; 545 goto out;
536 } 546 }
537 case SIGNAL_NCQ_ERROR: 547 case SIGNAL_NCQ_ERROR: