Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe4a36cf authored by Darrick J. Wong's avatar Darrick J. Wong Committed by James Bottomley
Browse files

[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: default avatarDarrick J. Wong <djwong@us.ibm.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 79a5eb60
Loading
Loading
Loading
Loading
+66 −17
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@
 */
 */


#include <linux/pci.h>
#include <linux/pci.h>
#include <scsi/scsi_host.h>


#include "aic94xx.h"
#include "aic94xx.h"
#include "aic94xx_reg.h"
#include "aic94xx_reg.h"
@@ -342,6 +343,18 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
	}
	}
}
}


/* start up the ABORT TASK tmf... */
static void task_kill_later(struct asd_ascb *ascb)
{
	struct asd_ha_struct *asd_ha = ascb->ha;
	struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
	struct Scsi_Host *shost = sas_ha->core.shost;
	struct sas_task *task = ascb->uldd_task;

	INIT_WORK(&task->abort_work, (void (*)(void *))sas_task_abort, task);
	queue_work(shost->work_q, &task->abort_work);
}

static void escb_tasklet_complete(struct asd_ascb *ascb,
static void escb_tasklet_complete(struct asd_ascb *ascb,
				  struct done_list_struct *dl)
				  struct done_list_struct *dl)
{
{
@@ -368,6 +381,58 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
			    ascb->scb->header.opcode);
			    ascb->scb->header.opcode);
	}
	}


	/* Catch these before we mask off the sb_opcode bits */
	switch (sb_opcode) {
	case REQ_TASK_ABORT: {
		struct asd_ascb *a, *b;
		u16 tc_abort;

		tc_abort = *((u16*)(&dl->status_block[1]));
		tc_abort = le16_to_cpu(tc_abort);

		ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
			    __FUNCTION__, dl->status_block[3]);

		/* Find the pending task and abort it. */
		list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list)
			if (a->tc_index == tc_abort) {
				task_kill_later(a);
				break;
			}
		goto out;
	}
	case REQ_DEVICE_RESET: {
		struct asd_ascb *a, *b;
		u16 conn_handle;

		conn_handle = *((u16*)(&dl->status_block[1]));
		conn_handle = le16_to_cpu(conn_handle);

		ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__,
			    dl->status_block[3]);

		/* Kill all pending tasks and reset the device */
		list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
			struct sas_task *task = a->uldd_task;
			struct domain_device *dev = task->dev;
			u16 x;

			x = *((u16*)(&dev->lldd_dev));
			if (x == conn_handle)
				task_kill_later(a);
		}

		/* FIXME: Reset device port (huh?) */
		goto out;
	}
	case SIGNAL_NCQ_ERROR:
		ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __FUNCTION__);
		goto out;
	case CLEAR_NCQ_ERROR:
		ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __FUNCTION__);
		goto out;
	}

	sb_opcode &= ~DL_PHY_MASK;
	sb_opcode &= ~DL_PHY_MASK;


	switch (sb_opcode) {
	switch (sb_opcode) {
@@ -397,22 +462,6 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
		sas_phy_disconnected(sas_phy);
		sas_phy_disconnected(sas_phy);
		sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
		sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
		break;
		break;
	case REQ_TASK_ABORT:
		ASD_DPRINTK("%s: phy%d: REQ_TASK_ABORT\n", __FUNCTION__,
			    phy_id);
		break;
	case REQ_DEVICE_RESET:
		ASD_DPRINTK("%s: phy%d: REQ_DEVICE_RESET\n", __FUNCTION__,
			    phy_id);
		break;
	case SIGNAL_NCQ_ERROR:
		ASD_DPRINTK("%s: phy%d: SIGNAL_NCQ_ERROR\n", __FUNCTION__,
			    phy_id);
		break;
	case CLEAR_NCQ_ERROR:
		ASD_DPRINTK("%s: phy%d: CLEAR_NCQ_ERROR\n", __FUNCTION__,
			    phy_id);
		break;
	default:
	default:
		ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
		ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
			    phy_id, sb_opcode);
			    phy_id, sb_opcode);
@@ -432,7 +481,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,


		break;
		break;
	}
	}

out:
	asd_invalidate_edb(ascb, edb);
	asd_invalidate_edb(ascb, edb);
}
}