Commit 8aecd34f authored by Justin T. Gibbs's avatar Justin T. Gibbs

Aic79xx Driver Update

	Enable abort and bus device reset handlers for both legacy
	and packetized connections.
parent 5e332e62
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
* *
* $FreeBSD$ * $FreeBSD$
*/ */
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#59 $" VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#60 $"
/* /*
* This file is processed by the aic7xxx_asm utility for use in assembling * This file is processed by the aic7xxx_asm utility for use in assembling
...@@ -173,6 +173,23 @@ register SEQINTCODE { ...@@ -173,6 +173,23 @@ register SEQINTCODE {
STATUS_OVERRUN, STATUS_OVERRUN,
CFG4OVERRUN, CFG4OVERRUN,
ENTERING_NONPACK, ENTERING_NONPACK,
TASKMGMT_FUNC_COMPLETE, /*
* Task management function
* request completed with
* an expected busfree.
*/
TASKMGMT_CMD_CMPLT_OKAY, /*
* A command with a non-zero
* task management function
* has completed via the normal
* command completion method
* for commands with a zero
* task management function.
* This happens when an attempt
* to abort a command loses
* the race for the command to
* complete normally.
*/
TRACEPOINT0, TRACEPOINT0,
TRACEPOINT1, TRACEPOINT1,
TRACEPOINT2, TRACEPOINT2,
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
* $FreeBSD$ * $FreeBSD$
*/ */
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#77 $" VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $"
PATCH_ARG_LIST = "struct ahd_softc *ahd" PATCH_ARG_LIST = "struct ahd_softc *ahd"
PREFIX = "ahd_" PREFIX = "ahd_"
...@@ -107,6 +107,16 @@ idle_loop_gsfifo_in_scsi_mode: ...@@ -107,6 +107,16 @@ idle_loop_gsfifo_in_scsi_mode:
good_status_IU_done: good_status_IU_done:
bmov SCBPTR, GSFIFO, 2; bmov SCBPTR, GSFIFO, 2;
clr SCB_SCSI_STATUS; clr SCB_SCSI_STATUS;
/*
* If a command completed before an attempted task management
* function completed, notify the host after disabling any
* pending select-outs.
*/
test SCB_TASK_MANAGEMENT, 0xFF jz gsfifo_complete_normally;
test SSTAT0, SELDO|SELINGO jnz . + 2;
and SCSISEQ0, ~ENSELO;
SET_SEQINTCODE(TASKMGMT_CMD_CMPLT_OKAY)
gsfifo_complete_normally:
or SCB_CONTROL, STATUS_RCVD; or SCB_CONTROL, STATUS_RCVD;
/* /*
...@@ -471,7 +481,7 @@ select_in: ...@@ -471,7 +481,7 @@ select_in:
/* /*
* This exposes a window whereby a * This exposes a window whereby a
* busfree just after a selection will * busfree just after a selection will
* be missed, but there is not other safe * be missed, but there is no other safe
* way to enable busfree detection if * way to enable busfree detection if
* the busfreerev function is broken. * the busfreerev function is broken.
*/ */
...@@ -597,7 +607,6 @@ select_out_inc_tid_q: ...@@ -597,7 +607,6 @@ select_out_inc_tid_q:
cmp WAITING_TID_HEAD[1], SCB_LIST_NULL jne . + 2; cmp WAITING_TID_HEAD[1], SCB_LIST_NULL jne . + 2;
mvi WAITING_TID_TAIL[1], SCB_LIST_NULL; mvi WAITING_TID_TAIL[1], SCB_LIST_NULL;
bmov SCBPTR, CURRSCB, 2; bmov SCBPTR, CURRSCB, 2;
END_CRITICAL;
mvi CLRSINT0, CLRSELDO; mvi CLRSINT0, CLRSELDO;
test LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_phase; test LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_phase;
test LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_phase; test LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_phase;
...@@ -606,17 +615,23 @@ END_CRITICAL; ...@@ -606,17 +615,23 @@ END_CRITICAL;
* If this is a packetized connection, return to our * If this is a packetized connection, return to our
* idle_loop and let our interrupt handler deal with * idle_loop and let our interrupt handler deal with
* any connection setup/teardown issues. The only * any connection setup/teardown issues. The only
* exception is the case of MK_MESSAGE SCBs. In the * exceptions are the case of MK_MESSAGE and task management
* A, the LQO manager transitions to LQOSTOP0 even if * SCBs.
* we have selected out with ATN asserted and the target
* REQs in a non-packet phase.
*/ */
if ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0) { if ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0) {
/*
* In the A, the LQO manager transitions to LQOSTOP0 even if
* we have selected out with ATN asserted and the target
* REQs in a non-packet phase.
*/
test SCB_CONTROL, MK_MESSAGE jz select_out_no_message; test SCB_CONTROL, MK_MESSAGE jz select_out_no_message;
test SCSISIGO, ATNO jnz select_out_non_packetized; test SCSISIGO, ATNO jnz select_out_non_packetized;
select_out_no_message: select_out_no_message:
} }
test LQOSTAT2, LQOSTOP0 jnz idle_loop; test LQOSTAT2, LQOSTOP0 jz select_out_non_packetized;
test SCB_TASK_MANAGEMENT, 0xFF jz idle_loop;
SET_SEQINTCODE(TASKMGMT_FUNC_COMPLETE)
jmp idle_loop;
select_out_non_packetized: select_out_non_packetized:
/* Non packetized request. */ /* Non packetized request. */
...@@ -625,7 +640,7 @@ select_out_non_packetized: ...@@ -625,7 +640,7 @@ select_out_non_packetized:
/* /*
* This exposes a window whereby a * This exposes a window whereby a
* busfree just after a selection will * busfree just after a selection will
* be missed, but there is not other safe * be missed, but there is no other safe
* way to enable busfree detection if * way to enable busfree detection if
* the busfreerev function is broken. * the busfreerev function is broken.
*/ */
...@@ -634,6 +649,8 @@ select_out_non_packetized: ...@@ -634,6 +649,8 @@ select_out_non_packetized:
} }
mov SAVED_SCSIID, SCB_SCSIID; mov SAVED_SCSIID, SCB_SCSIID;
mov SAVED_LUN, SCB_LUN; mov SAVED_LUN, SCB_LUN;
mvi SEQ_FLAGS, NO_CDB_SENT;
END_CRITICAL;
or SXFRCTL0, SPIOEN; or SXFRCTL0, SPIOEN;
/* /*
...@@ -642,7 +659,6 @@ select_out_non_packetized: ...@@ -642,7 +659,6 @@ select_out_non_packetized:
* asserted. * asserted.
*/ */
mvi MSG_OUT, MSG_IDENTIFYFLAG; mvi MSG_OUT, MSG_IDENTIFYFLAG;
mvi SEQ_FLAGS, NO_CDB_SENT;
/* /*
* Main loop for information transfer phases. Wait for the * Main loop for information transfer phases. Wait for the
...@@ -1608,7 +1624,12 @@ cfg4istat_setup_handler: ...@@ -1608,7 +1624,12 @@ cfg4istat_setup_handler:
/* /*
* Status pkt is transferring to host. * Status pkt is transferring to host.
* Wait in idle loop for transfer to complete. * Wait in idle loop for transfer to complete.
* If a command completed before an attempted
* task management function completed, notify the host.
*/ */
test SCB_TASK_MANAGEMENT, 0xFF jz cfg4istat_no_taskmgmt_func;
SET_SEQINTCODE(TASKMGMT_CMD_CMPLT_OKAY)
cfg4istat_no_taskmgmt_func:
call pkt_handle_status; call pkt_handle_status;
or SEQINTCTL, IRET ret; or SEQINTCTL, IRET ret;
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * POSSIBILITY OF SUCH DAMAGES.
* *
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#150 $ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#151 $
* *
* $FreeBSD$ * $FreeBSD$
*/ */
...@@ -438,11 +438,27 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd) ...@@ -438,11 +438,27 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
scbid = next_scbid; scbid = next_scbid;
} }
ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL); ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL);
ahd_set_scbptr(ahd, saved_scbptr);
/*
* Flush the good status FIFO for compelted packetized commands.
*/
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
while ((ahd_inb(ahd, LQISTAT2) & LQIGSAVAIL) != 0) {
scbid = (ahd_inb(ahd, GSFIFO+1) << 8)
| ahd_inb(ahd, GSFIFO);
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
printf("%s: Warning - GSFIFO SCB %d invalid\n",
ahd_name(ahd), scbid);
continue;
}
ahd_complete_scb(ahd, scb);
}
/* /*
* Restore state. * Restore state.
*/ */
ahd_set_scbptr(ahd, saved_scbptr);
ahd_restore_modes(ahd, saved_modes); ahd_restore_modes(ahd, saved_modes);
ahd->flags |= AHD_UPDATE_PEND_CMDS; ahd->flags |= AHD_UPDATE_PEND_CMDS;
} }
...@@ -988,6 +1004,63 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) ...@@ -988,6 +1004,63 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
ahd_inb(ahd, SCB_CONTROL) & ~MK_MESSAGE); ahd_inb(ahd, SCB_CONTROL) & ~MK_MESSAGE);
break; break;
} }
case TASKMGMT_FUNC_COMPLETE:
{
u_int scbid;
struct scb *scb;
scbid = ahd_get_scbptr(ahd);
scb = ahd_lookup_scb(ahd, scbid);
if (scb != NULL) {
u_int lun;
u_int tag;
cam_status error;
lun = CAM_LUN_WILDCARD;
tag = SCB_LIST_NULL;
switch (scb->hscb->task_management) {
case SIU_TASKMGMT_ABORT_TASK:
tag = scb->hscb->tag;
case SIU_TASKMGMT_ABORT_TASK_SET:
case SIU_TASKMGMT_CLEAR_TASK_SET:
lun = scb->hscb->lun;
error = CAM_REQ_ABORTED;
break;
case SIU_TASKMGMT_LUN_RESET:
lun = scb->hscb->lun;
case SIU_TASKMGMT_TARGET_RESET:
error = CAM_BDR_SENT;
break;
default:
panic("Unexpected TaskMgmt Func\n");
break;
}
ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb),
'A', lun, tag, ROLE_INITIATOR, error);
}
break;
}
case TASKMGMT_CMD_CMPLT_OKAY:
{
u_int scbid;
struct scb *scb;
scbid = ahd_get_scbptr(ahd);
scb = ahd_lookup_scb(ahd, scbid);
if (scb != NULL) {
/*
* Remove the second instance of this SCB from
* the QINFIFO if it is still there.
*/
ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb),
SCB_GET_CHANNEL(ahd, scb),
SCB_GET_LUN(scb), scb->hscb->tag,
ROLE_INITIATOR, /*status*/0,
SEARCH_REMOVE);
}
break;
}
case TRACEPOINT0: case TRACEPOINT0:
case TRACEPOINT1: case TRACEPOINT1:
case TRACEPOINT2: case TRACEPOINT2:
...@@ -2410,8 +2483,9 @@ ahd_update_neg_request(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ...@@ -2410,8 +2483,9 @@ ahd_update_neg_request(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
* occurs the need to renegotiate is * occurs the need to renegotiate is
* recorded persistently. * recorded persistently.
*/ */
if ((ahd->features & AHD_WIDE) != 0)
tinfo->curr.width = AHD_WIDTH_UNKNOWN;
tinfo->curr.period = AHD_PERIOD_UNKNOWN; tinfo->curr.period = AHD_PERIOD_UNKNOWN;
tinfo->curr.width = AHD_WIDTH_UNKNOWN;
tinfo->curr.offset = AHD_OFFSET_UNKNOWN; tinfo->curr.offset = AHD_OFFSET_UNKNOWN;
} }
if (tinfo->curr.period != tinfo->goal.period if (tinfo->curr.period != tinfo->goal.period
......
/* /*
* Adaptec AIC79xx device driver for Linux. * Adaptec AIC79xx device driver for Linux.
* *
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#105 $ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#106 $
* *
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
* Copyright (c) 1994-2000 Justin T. Gibbs. * Copyright (c) 1994-2000 Justin T. Gibbs.
...@@ -482,10 +482,8 @@ static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, ...@@ -482,10 +482,8 @@ static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd,
static void ahd_linux_filter_inquiry(struct ahd_softc *ahd, static void ahd_linux_filter_inquiry(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo); struct ahd_devinfo *devinfo);
static void ahd_linux_dev_timed_unfreeze(u_long arg); static void ahd_linux_dev_timed_unfreeze(u_long arg);
#if NO_YET
static void ahd_linux_sem_timeout(u_long arg); static void ahd_linux_sem_timeout(u_long arg);
static int ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); static int ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
#endif
static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd);
static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd); static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd);
static void ahd_linux_start_dv(struct ahd_softc *ahd); static void ahd_linux_start_dv(struct ahd_softc *ahd);
...@@ -1210,32 +1208,14 @@ ahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) ...@@ -1210,32 +1208,14 @@ ahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
static int static int
ahd_linux_abort(Scsi_Cmnd *cmd) ahd_linux_abort(Scsi_Cmnd *cmd)
{ {
struct ahd_softc *ahd; struct ahd_softc *ahd;
u_long s; int error;
#if NOTYET
struct ahd_cmd *acmd;
int found;
#endif
ahd = *(struct ahd_softc **)cmd->host->hostdata; ahd = *(struct ahd_softc **)cmd->host->hostdata;
#if NOTYET
int error;
error = ahd_linux_queue_recovery_cmd(cmd, SCB_ABORT); error = ahd_linux_queue_recovery_cmd(cmd, SCB_ABORT);
if (error != 0) if (error != 0)
printf("aic79xx_abort returns 0x%x\n", error); printf("aic79xx_abort returns 0x%x\n", error);
return (error); return (error);
#else
ahd_midlayer_entrypoint_lock(ahd, &s);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
printf("%s: Abort called for cmd %p\n", ahd_name(ahd), cmd);
ahd_dump_card_state(ahd);
}
#endif
ahd_midlayer_entrypoint_unlock(ahd, &s);
return (FAILED);
#endif
} }
/* /*
...@@ -1244,29 +1224,15 @@ ahd_linux_abort(Scsi_Cmnd *cmd) ...@@ -1244,29 +1224,15 @@ ahd_linux_abort(Scsi_Cmnd *cmd)
static int static int
ahd_linux_dev_reset(Scsi_Cmnd *cmd) ahd_linux_dev_reset(Scsi_Cmnd *cmd)
{ {
struct ahd_softc *ahd; struct ahd_softc *ahd;
#if NOTYET int error;
struct ahd_cmd *acmd;
u_long s;
int found;
#endif
ahd = *(struct ahd_softc **)cmd->host->hostdata; ahd = *(struct ahd_softc **)cmd->host->hostdata;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
printf("%s: Dev reset called for cmd %p\n",
ahd_name(ahd), cmd);
#endif
#if NOTYET
int error;
error = ahd_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); error = ahd_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
if (error != 0) if (error != 0)
printf("aic79xx_dev_reset returns 0x%x\n", error); printf("aic79xx_dev_reset returns 0x%x\n", error);
return (error); return (error);
#else
return (FAILED);
#endif
} }
/* /*
...@@ -4536,8 +4502,11 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, ...@@ -4536,8 +4502,11 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
printf("Copied %d bytes of sense data at %d:", printf("Copied %d bytes of sense data at %d:",
sense_size, sense_offset); sense_size, sense_offset);
for (i = 0; i < sense_size; i++) for (i = 0; i < sense_size; i++) {
printf(" 0x%x", cmd->sense_buffer[i]); if ((i & 0xF) == 0)
printf("\n");
printf("0x%x ", cmd->sense_buffer[i]);
}
printf("\n"); printf("\n");
} }
#endif #endif
...@@ -4941,7 +4910,6 @@ ahd_release_simq(struct ahd_softc *ahd) ...@@ -4941,7 +4910,6 @@ ahd_release_simq(struct ahd_softc *ahd)
ahd_schedule_runq(ahd); ahd_schedule_runq(ahd);
} }
#if NOT_YET
static void static void
ahd_linux_sem_timeout(u_long arg) ahd_linux_sem_timeout(u_long arg)
{ {
...@@ -4967,12 +4935,13 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) ...@@ -4967,12 +4935,13 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
struct scb *pending_scb; struct scb *pending_scb;
u_long s; u_long s;
u_int saved_scbptr; u_int saved_scbptr;
u_int active_scb_index; u_int active_scbptr;
u_int last_phase; u_int last_phase;
int retval; int retval;
int paused; int paused;
int wait; int wait;
int disconnected; int disconnected;
ahd_mode_state saved_modes;
pending_scb = NULL; pending_scb = NULL;
paused = FALSE; paused = FALSE;
...@@ -5080,16 +5049,11 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) ...@@ -5080,16 +5049,11 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
* didn't "just" miss an interrupt that would * didn't "just" miss an interrupt that would
* affect this cmd. * affect this cmd.
*/ */
ahd->flags |= AHD_ALL_INTERRUPTS; ahd_pause_and_flushwork(ahd);
do {
ahd_intr(ahd);
ahd_pause(ahd);
ahd_clear_critical_section(ahd);
} while (ahd_inb(ahd, INTSTAT) & INT_PEND);
ahd->flags &= ~AHD_ALL_INTERRUPTS;
paused = TRUE; paused = TRUE;
ahd_dump_card_state(ahd); if (bootverbose)
ahd_dump_card_state(ahd);
if ((pending_scb->flags & SCB_ACTIVE) == 0) { if ((pending_scb->flags & SCB_ACTIVE) == 0) {
printf("%s:%d:%d:%d: Command already completed\n", printf("%s:%d:%d:%d: Command already completed\n",
...@@ -5116,6 +5080,23 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) ...@@ -5116,6 +5080,23 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
disconnected = FALSE; disconnected = FALSE;
} }
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
last_phase = ahd_inb(ahd, LASTPHASE);
saved_scbptr = ahd_get_scbptr(ahd);
active_scbptr = saved_scbptr;
if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) {
struct scb *bus_scb;
bus_scb = ahd_lookup_scb(ahd, active_scbptr);
if (bus_scb == pending_scb)
disconnected = FALSE;
else if (flag != SCB_ABORT
&& ahd_inb(ahd, SAVED_SCSIID) == pending_scb->hscb->scsiid
&& ahd_inb(ahd, SAVED_LUN) == pending_scb->hscb->lun)
disconnected = FALSE;
}
/* /*
* At this point, pending_scb is the scb associated with the * At this point, pending_scb is the scb associated with the
* passed in command. That command is currently active on the * passed in command. That command is currently active on the
...@@ -5124,11 +5105,8 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) ...@@ -5124,11 +5105,8 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
* send a BDR. Queue the appropriate message based on which of * send a BDR. Queue the appropriate message based on which of
* these states we are in. * these states we are in.
*/ */
last_phase = ahd_inb(ahd, LASTPHASE);
saved_scbptr = ahd_inb(ahd, SCBPTR);
active_scb_index = ahd_inb(ahd, SCB_TAG);
if (last_phase != P_BUSFREE if (last_phase != P_BUSFREE
&& (pending_scb->hscb->tag == active_scb_index && (pending_scb->hscb->tag == active_scbptr
|| (flag == SCB_DEVICE_RESET || (flag == SCB_DEVICE_RESET
&& SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)) == cmd->target))) { && SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)) == cmd->target))) {
...@@ -5136,7 +5114,7 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) ...@@ -5136,7 +5114,7 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
* We're active on the bus, so assert ATN * We're active on the bus, so assert ATN
* and hope that the target responds. * and hope that the target responds.
*/ */
pending_scb = ahd_lookup_scb(ahd, active_scb_index); pending_scb = ahd_lookup_scb(ahd, active_scbptr);
pending_scb->flags |= SCB_RECOVERY_SCB|flag; pending_scb->flags |= SCB_RECOVERY_SCB|flag;
ahd_outb(ahd, MSG_OUT, HOST_MSG); ahd_outb(ahd, MSG_OUT, HOST_MSG);
ahd_outb(ahd, SCSISIGO, last_phase|ATNO); ahd_outb(ahd, SCSISIGO, last_phase|ATNO);
...@@ -5148,32 +5126,56 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) ...@@ -5148,32 +5126,56 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
/* /*
* Actually re-queue this SCB in an attempt * Actually re-queue this SCB in an attempt
* to select the device before it reconnects. * to select the device before it reconnects.
* In either case (selection or reselection),
* we will now issue the approprate message
* to the timed-out device.
*
* Set the MK_MESSAGE control bit indicating
* that we desire to send a message. We
* also set the disconnected flag since
* in the paging case there is no guarantee
* that our SCB control byte matches the
* version on the card. We don't want the
* sequencer to abort the command thinking
* an unsolicited reselection occurred.
*/ */
pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED;
pending_scb->flags |= SCB_RECOVERY_SCB|flag; pending_scb->flags |= SCB_RECOVERY_SCB|flag;
ahd_set_scbptr(ahd, pending_scb->hscb->tag);
pending_scb->hscb->cdb_len = 0;
pending_scb->hscb->task_attribute = 0;
switch (flag) {
case SCB_ABORT:
pending_scb->hscb->task_management =
SIU_TASKMGMT_ABORT_TASK;
break;
case SCB_DEVICE_RESET:
default:
pending_scb->hscb->task_management =
SIU_TASKMGMT_TARGET_RESET;
pending_scb->hscb->lun = 0;
memset(pending_scb->hscb->pkt_long_lun, 0, 8);
break;
}
/* if ((pending_scb->flags & SCB_PACKETIZED) != 0) {
* In the non-paging case, the sequencer will /*
* never re-reference the in-core SCB. * Mark the SCB has having an outstanding
* To make sure we are notified during * task management function. Should the command
* reslection, set the MK_MESSAGE flag in * complete normally before the task management
* the card's copy of the SCB. * function can be sent, the host will be notified
*/ * to abort our requeued SCB.
ahd_outb(ahd, SCBPTR, pending_scb->hscb->tag); */
ahd_outb(ahd, SCB_CONTROL, ahd_outb(ahd, SCB_TASK_MANAGEMENT,
ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE); pending_scb->hscb->task_management);
} else {
/*
* If non-packetized, set the MK_MESSAGE control
* bit indicating that we desire to send a message.
* We also set the disconnected flag since there is
* no guarantee that our SCB control byte matches
* the version on the card. We don't want the
* sequencer to abort the command thinking an
* unsolicited reselection occurred.
*/
pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED;
/*
* The sequencer will never re-reference the
* in-core SCB. To make sure we are notified
* during reslection, set the MK_MESSAGE flag in
* the card's copy of the SCB.
*/
ahd_outb(ahd, SCB_CONTROL,
ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE);
}
/* /*
* Clear out any entries in the QINFIFO first * Clear out any entries in the QINFIFO first
...@@ -5183,12 +5185,10 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) ...@@ -5183,12 +5185,10 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
ahd_search_qinfifo(ahd, cmd->target, cmd->channel + 'A', ahd_search_qinfifo(ahd, cmd->target, cmd->channel + 'A',
cmd->lun, SCB_LIST_NULL, ROLE_INITIATOR, cmd->lun, SCB_LIST_NULL, ROLE_INITIATOR,
CAM_REQUEUE_REQ, SEARCH_COMPLETE); CAM_REQUEUE_REQ, SEARCH_COMPLETE);
ahd_print_path(ahd, pending_scb);
printf("Queuing a recovery SCB\n");
ahd_qinfifo_requeue_tail(ahd, pending_scb); ahd_qinfifo_requeue_tail(ahd, pending_scb);
ahd_outb(ahd, SCBPTR, saved_scbptr); ahd_set_scbptr(ahd, saved_scbptr);
printf("%s:%d:%d:%d: Device is disconnected, re-queuing SCB\n", ahd_print_path(ahd, pending_scb);
ahd_name(ahd), cmd->channel, cmd->target, cmd->lun); printf("Device is disconnected, re-queuing SCB\n");
wait = TRUE; wait = TRUE;
} else { } else {
printf("%s:%d:%d:%d: Unable to deliver message\n", printf("%s:%d:%d:%d: Unable to deliver message\n",
...@@ -5239,7 +5239,7 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) ...@@ -5239,7 +5239,7 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
} }
acmd = TAILQ_FIRST(&ahd->platform_data->completeq); acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
TAILQ_INIT(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->completeq);
ahd_midlayer_entry_unlock(ahd, &s); ahd_midlayer_entrypoint_unlock(ahd, &s);
if (acmd != NULL) { if (acmd != NULL) {
acmd = ahd_linux_run_complete_queue(ahd, acmd); acmd = ahd_linux_run_complete_queue(ahd, acmd);
if (acmd != NULL) { if (acmd != NULL) {
...@@ -5254,7 +5254,6 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) ...@@ -5254,7 +5254,6 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
#endif #endif
return (retval); return (retval);
} }
#endif
static void static void
ahd_linux_dev_timed_unfreeze(u_long arg) ahd_linux_dev_timed_unfreeze(u_long arg)
......
...@@ -28,4 +28,12 @@ struct scsi_status_iu_header ...@@ -28,4 +28,12 @@ struct scsi_status_iu_header
(12 + (((siu)->flags & SIU_RSPVALID) \ (12 + (((siu)->flags & SIU_RSPVALID) \
? scsi_4btoul((siu)->pkt_failures_length) \ ? scsi_4btoul((siu)->pkt_failures_length) \
: 0)) : 0))
#define SIU_TASKMGMT_NONE 0x00
#define SIU_TASKMGMT_ABORT_TASK 0x01
#define SIU_TASKMGMT_ABORT_TASK_SET 0x02
#define SIU_TASKMGMT_CLEAR_TASK_SET 0x04
#define SIU_TASKMGMT_LUN_RESET 0x08
#define SIU_TASKMGMT_TARGET_RESET 0x20
#define SIU_TASKMGMT_CLEAR_ACA 0x40
#endif /*_SCSI_SCSI_IU_H*/ #endif /*_SCSI_SCSI_IU_H*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment