aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic94xx
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2006-10-30 18:18:56 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-11-15 13:31:27 -0500
commitfe4a36cf652031d2744a536ba5121032840380cb (patch)
tree42ee998e9d8b543b74f6f2c935023b604183c85f /drivers/scsi/aic94xx
parent79a5eb609b74e7b3638861c41b98eafa74920a1f (diff)
[SCSI] aic94xx: handle REQ_TASK_ABORT
This patch straightens out the code that distinguishes the various escb opcodes in escb_tasklet_complete so that they can be handled correctly. It also provides all the necessary code to create a workqueue item that tells libsas to abort a sas_task. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/aic94xx')
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c83
1 files changed, 66 insertions, 17 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 7ee49b51b724..1911c5d17875 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -25,6 +25,7 @@
25 */ 25 */
26 26
27#include <linux/pci.h> 27#include <linux/pci.h>
28#include <scsi/scsi_host.h>
28 29
29#include "aic94xx.h" 30#include "aic94xx.h"
30#include "aic94xx_reg.h" 31#include "aic94xx_reg.h"
@@ -342,6 +343,18 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
342 } 343 }
343} 344}
344 345
346/* start up the ABORT TASK tmf... */
347static void task_kill_later(struct asd_ascb *ascb)
348{
349 struct asd_ha_struct *asd_ha = ascb->ha;
350 struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
351 struct Scsi_Host *shost = sas_ha->core.shost;
352 struct sas_task *task = ascb->uldd_task;
353
354 INIT_WORK(&task->abort_work, (void (*)(void *))sas_task_abort, task);
355 queue_work(shost->work_q, &task->abort_work);
356}
357
345static void escb_tasklet_complete(struct asd_ascb *ascb, 358static void escb_tasklet_complete(struct asd_ascb *ascb,
346 struct done_list_struct *dl) 359 struct done_list_struct *dl)
347{ 360{
@@ -368,6 +381,58 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
368 ascb->scb->header.opcode); 381 ascb->scb->header.opcode);
369 } 382 }
370 383
384 /* Catch these before we mask off the sb_opcode bits */
385 switch (sb_opcode) {
386 case REQ_TASK_ABORT: {
387 struct asd_ascb *a, *b;
388 u16 tc_abort;
389
390 tc_abort = *((u16*)(&dl->status_block[1]));
391 tc_abort = le16_to_cpu(tc_abort);
392
393 ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
394 __FUNCTION__, dl->status_block[3]);
395
396 /* Find the pending task and abort it. */
397 list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list)
398 if (a->tc_index == tc_abort) {
399 task_kill_later(a);
400 break;
401 }
402 goto out;
403 }
404 case REQ_DEVICE_RESET: {
405 struct asd_ascb *a, *b;
406 u16 conn_handle;
407
408 conn_handle = *((u16*)(&dl->status_block[1]));
409 conn_handle = le16_to_cpu(conn_handle);
410
411 ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__,
412 dl->status_block[3]);
413
414 /* Kill all pending tasks and reset the device */
415 list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
416 struct sas_task *task = a->uldd_task;
417 struct domain_device *dev = task->dev;
418 u16 x;
419
420 x = *((u16*)(&dev->lldd_dev));
421 if (x == conn_handle)
422 task_kill_later(a);
423 }
424
425 /* FIXME: Reset device port (huh?) */
426 goto out;
427 }
428 case SIGNAL_NCQ_ERROR:
429 ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __FUNCTION__);
430 goto out;
431 case CLEAR_NCQ_ERROR:
432 ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __FUNCTION__);
433 goto out;
434 }
435
371 sb_opcode &= ~DL_PHY_MASK; 436 sb_opcode &= ~DL_PHY_MASK;
372 437
373 switch (sb_opcode) { 438 switch (sb_opcode) {
@@ -397,22 +462,6 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
397 sas_phy_disconnected(sas_phy); 462 sas_phy_disconnected(sas_phy);
398 sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT); 463 sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
399 break; 464 break;
400 case REQ_TASK_ABORT:
401 ASD_DPRINTK("%s: phy%d: REQ_TASK_ABORT\n", __FUNCTION__,
402 phy_id);
403 break;
404 case REQ_DEVICE_RESET:
405 ASD_DPRINTK("%s: phy%d: REQ_DEVICE_RESET\n", __FUNCTION__,
406 phy_id);
407 break;
408 case SIGNAL_NCQ_ERROR:
409 ASD_DPRINTK("%s: phy%d: SIGNAL_NCQ_ERROR\n", __FUNCTION__,
410 phy_id);
411 break;
412 case CLEAR_NCQ_ERROR:
413 ASD_DPRINTK("%s: phy%d: CLEAR_NCQ_ERROR\n", __FUNCTION__,
414 phy_id);
415 break;
416 default: 465 default:
417 ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__, 466 ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
418 phy_id, sb_opcode); 467 phy_id, sb_opcode);
@@ -432,7 +481,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
432 481
433 break; 482 break;
434 } 483 }
435 484out:
436 asd_invalidate_edb(ascb, edb); 485 asd_invalidate_edb(ascb, edb);
437} 486}
438 487