Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 47736
b: refs/heads/master
c: 3cd041f
h: refs/heads/master
v: v3
  • Loading branch information
Darrick J. Wong authored and James Bottomley committed Jan 13, 2007
1 parent 161bb80 commit 8203536
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 57 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 396819fba821ad56f1b90090d256f0ab726c89c5
refs/heads/master: 3cd041fb7f50f4cee3bc3a2b0ce02b1562894894
122 changes: 66 additions & 56 deletions trunk/drivers/scsi/aic94xx/aic94xx_scb.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,40 +413,6 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
}
}

/* hard reset a phy later */
static void do_phy_reset_later(struct work_struct *work)
{
struct sas_phy *sas_phy =
container_of(work, struct sas_phy, reset_work);
int error;

ASD_DPRINTK("%s: About to hard reset phy %d\n", __FUNCTION__,
sas_phy->identify.phy_identifier);
/* Reset device port */
error = sas_phy_reset(sas_phy, 1);
if (error)
ASD_DPRINTK("%s: Hard reset of phy %d failed (%d).\n",
__FUNCTION__, sas_phy->identify.phy_identifier, error);
}

static void phy_reset_later(struct sas_phy *sas_phy, struct Scsi_Host *shost)
{
INIT_WORK(&sas_phy->reset_work, do_phy_reset_later);
queue_work(shost->work_q, &sas_phy->reset_work);
}

/* 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, sas_task_abort);
queue_work(shost->work_q, &task->abort_work);
}

static void escb_tasklet_complete(struct asd_ascb *ascb,
struct done_list_struct *dl)
{
Expand Down Expand Up @@ -479,59 +445,103 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
case REQ_TASK_ABORT: {
struct asd_ascb *a, *b;
u16 tc_abort;
struct domain_device *failed_dev = NULL;

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

/*
* Find the task that caused the abort and abort it first.
* The sequencer won't put anything on the done list until
* that happens.
*/
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]);
list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
struct sas_task *task = ascb->uldd_task;

/* 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);
if (task && a->tc_index == tc_abort) {
failed_dev = task->dev;
sas_task_abort(task);
break;
}
}

if (!failed_dev) {
ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n",
__FUNCTION__, tc_abort);
goto out;
}

/*
* Now abort everything else for that device (hba?) so
* that the EH will wake up and do something.
*/
list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
struct sas_task *task = ascb->uldd_task;

if (task &&
task->dev == failed_dev &&
a->tc_index != tc_abort)
sas_task_abort(task);
}

goto out;
}
case REQ_DEVICE_RESET: {
struct Scsi_Host *shost = sas_ha->core.shost;
struct sas_phy *dev_phy;
struct asd_ascb *a;
u16 conn_handle;
unsigned long flags;
struct sas_task *last_dev_task = NULL;

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 */
dev_phy = NULL;
/* Find the last pending task for the device... */
list_for_each_entry(a, &asd_ha->seq.pend_q, list) {
struct sas_task *task;
struct domain_device *dev;
u16 x;
struct domain_device *dev;
struct sas_task *task = a->uldd_task;

task = a->uldd_task;
if (!task)
continue;
dev = task->dev;

x = (unsigned long)dev->lldd_dev;
if (x == conn_handle) {
dev_phy = dev->port->phy;
task_kill_later(a);
}
if (x == conn_handle)
last_dev_task = task;
}

/* Reset device port */
if (!dev_phy) {
ASD_DPRINTK("%s: No pending commands; can't reset.\n",
__FUNCTION__);
if (!last_dev_task) {
ASD_DPRINTK("%s: Device reset for idle device %d?\n",
__FUNCTION__, conn_handle);
goto out;
}
phy_reset_later(dev_phy, shost);

/* ...and set the reset flag */
spin_lock_irqsave(&last_dev_task->task_state_lock, flags);
last_dev_task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
spin_unlock_irqrestore(&last_dev_task->task_state_lock, flags);

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

if (!task)
continue;
dev = task->dev;

x = (unsigned long)dev->lldd_dev;
if (x == conn_handle)
sas_task_abort(task);
}

goto out;
}
case SIGNAL_NCQ_ERROR:
Expand Down

0 comments on commit 8203536

Please sign in to comment.