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
No related merge requests found
......@@ -39,7 +39,7 @@
*
* $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
......@@ -173,6 +173,23 @@ register SEQINTCODE {
STATUS_OVERRUN,
CFG4OVERRUN,
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,
TRACEPOINT1,
TRACEPOINT2,
......
......@@ -40,7 +40,7 @@
* $FreeBSD$
*/
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#77 $"
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $"
PATCH_ARG_LIST = "struct ahd_softc *ahd"
PREFIX = "ahd_"
......@@ -107,6 +107,16 @@ idle_loop_gsfifo_in_scsi_mode:
good_status_IU_done:
bmov SCBPTR, GSFIFO, 2;
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;
/*
......@@ -471,7 +481,7 @@ select_in:
/*
* This exposes a window whereby a
* 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
* the busfreerev function is broken.
*/
......@@ -597,7 +607,6 @@ select_out_inc_tid_q:
cmp WAITING_TID_HEAD[1], SCB_LIST_NULL jne . + 2;
mvi WAITING_TID_TAIL[1], SCB_LIST_NULL;
bmov SCBPTR, CURRSCB, 2;
END_CRITICAL;
mvi CLRSINT0, CLRSELDO;
test LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_phase;
test LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_phase;
......@@ -606,17 +615,23 @@ END_CRITICAL;
* If this is a packetized connection, return to our
* idle_loop and let our interrupt handler deal with
* any connection setup/teardown issues. The only
* exception is the case of MK_MESSAGE SCBs. 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.
* exceptions are the case of MK_MESSAGE and task management
* SCBs.
*/
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 SCSISIGO, ATNO jnz select_out_non_packetized;
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:
/* Non packetized request. */
......@@ -625,7 +640,7 @@ select_out_non_packetized:
/*
* This exposes a window whereby a
* 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
* the busfreerev function is broken.
*/
......@@ -634,6 +649,8 @@ select_out_non_packetized:
}
mov SAVED_SCSIID, SCB_SCSIID;
mov SAVED_LUN, SCB_LUN;
mvi SEQ_FLAGS, NO_CDB_SENT;
END_CRITICAL;
or SXFRCTL0, SPIOEN;
/*
......@@ -642,7 +659,6 @@ select_out_non_packetized:
* asserted.
*/
mvi MSG_OUT, MSG_IDENTIFYFLAG;
mvi SEQ_FLAGS, NO_CDB_SENT;
/*
* Main loop for information transfer phases. Wait for the
......@@ -1608,7 +1624,12 @@ cfg4istat_setup_handler:
/*
* Status pkt is transferring to host.
* 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;
or SEQINTCTL, IRET ret;
......
......@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#150 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#151 $
*
* $FreeBSD$
*/
......@@ -438,11 +438,27 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
scbid = next_scbid;
}
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.
*/
ahd_set_scbptr(ahd, saved_scbptr);
ahd_restore_modes(ahd, saved_modes);
ahd->flags |= AHD_UPDATE_PEND_CMDS;
}
......@@ -988,6 +1004,63 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
ahd_inb(ahd, SCB_CONTROL) & ~MK_MESSAGE);
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 TRACEPOINT1:
case TRACEPOINT2:
......@@ -2410,8 +2483,9 @@ ahd_update_neg_request(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
* occurs the need to renegotiate is
* recorded persistently.
*/
if ((ahd->features & AHD_WIDE) != 0)
tinfo->curr.width = AHD_WIDTH_UNKNOWN;
tinfo->curr.period = AHD_PERIOD_UNKNOWN;
tinfo->curr.width = AHD_WIDTH_UNKNOWN;
tinfo->curr.offset = AHD_OFFSET_UNKNOWN;
}
if (tinfo->curr.period != tinfo->goal.period
......
/*
* 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.
......@@ -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,
struct ahd_devinfo *devinfo);
static void ahd_linux_dev_timed_unfreeze(u_long arg);
#if NO_YET
static void ahd_linux_sem_timeout(u_long arg);
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_thread_run_complete_queue(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[])
static int
ahd_linux_abort(Scsi_Cmnd *cmd)
{
struct ahd_softc *ahd;
u_long s;
#if NOTYET
struct ahd_cmd *acmd;
int found;
#endif
struct ahd_softc *ahd;
int error;
ahd = *(struct ahd_softc **)cmd->host->hostdata;
#if NOTYET
int error;
error = ahd_linux_queue_recovery_cmd(cmd, SCB_ABORT);
if (error != 0)
printf("aic79xx_abort returns 0x%x\n", 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)
static int
ahd_linux_dev_reset(Scsi_Cmnd *cmd)
{
struct ahd_softc *ahd;
#if NOTYET
struct ahd_cmd *acmd;
u_long s;
int found;
#endif
struct ahd_softc *ahd;
int error;
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);
if (error != 0)
printf("aic79xx_dev_reset returns 0x%x\n", error);
return (error);
#else
return (FAILED);
#endif
}
/*
......@@ -4536,8 +4502,11 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
printf("Copied %d bytes of sense data at %d:",
sense_size, sense_offset);
for (i = 0; i < sense_size; i++)
printf(" 0x%x", cmd->sense_buffer[i]);
for (i = 0; i < sense_size; i++) {
if ((i & 0xF) == 0)
printf("\n");
printf("0x%x ", cmd->sense_buffer[i]);
}
printf("\n");
}
#endif
......@@ -4941,7 +4910,6 @@ ahd_release_simq(struct ahd_softc *ahd)
ahd_schedule_runq(ahd);
}
#if NOT_YET
static void
ahd_linux_sem_timeout(u_long arg)
{
......@@ -4967,12 +4935,13 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
struct scb *pending_scb;
u_long s;
u_int saved_scbptr;
u_int active_scb_index;
u_int active_scbptr;
u_int last_phase;
int retval;
int paused;
int wait;
int disconnected;
ahd_mode_state saved_modes;
pending_scb = NULL;
paused = FALSE;
......@@ -5080,16 +5049,11 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
* didn't "just" miss an interrupt that would
* affect this cmd.
*/
ahd->flags |= AHD_ALL_INTERRUPTS;
do {
ahd_intr(ahd);
ahd_pause(ahd);
ahd_clear_critical_section(ahd);
} while (ahd_inb(ahd, INTSTAT) & INT_PEND);
ahd->flags &= ~AHD_ALL_INTERRUPTS;
ahd_pause_and_flushwork(ahd);
paused = TRUE;
ahd_dump_card_state(ahd);
if (bootverbose)
ahd_dump_card_state(ahd);
if ((pending_scb->flags & SCB_ACTIVE) == 0) {
printf("%s:%d:%d:%d: Command already completed\n",
......@@ -5116,6 +5080,23 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
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
* 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)
* send a BDR. Queue the appropriate message based on which of
* 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
&& (pending_scb->hscb->tag == active_scb_index
&& (pending_scb->hscb->tag == active_scbptr
|| (flag == SCB_DEVICE_RESET
&& 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)
* We're active on the bus, so assert ATN
* 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;
ahd_outb(ahd, MSG_OUT, HOST_MSG);
ahd_outb(ahd, SCSISIGO, last_phase|ATNO);
......@@ -5148,32 +5126,56 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
/*
* Actually re-queue this SCB in an attempt
* 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;
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;
}
/*
* In the non-paging case, 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, SCBPTR, pending_scb->hscb->tag);
ahd_outb(ahd, SCB_CONTROL,
ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE);
if ((pending_scb->flags & SCB_PACKETIZED) != 0) {
/*
* Mark the SCB has having an outstanding
* task management function. Should the command
* complete normally before the task management
* function can be sent, the host will be notified
* to abort our requeued SCB.
*/
ahd_outb(ahd, SCB_TASK_MANAGEMENT,
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
......@@ -5183,12 +5185,10 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
ahd_search_qinfifo(ahd, cmd->target, cmd->channel + 'A',
cmd->lun, SCB_LIST_NULL, ROLE_INITIATOR,
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_outb(ahd, SCBPTR, saved_scbptr);
printf("%s:%d:%d:%d: Device is disconnected, re-queuing SCB\n",
ahd_name(ahd), cmd->channel, cmd->target, cmd->lun);
ahd_set_scbptr(ahd, saved_scbptr);
ahd_print_path(ahd, pending_scb);
printf("Device is disconnected, re-queuing SCB\n");
wait = TRUE;
} else {
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)
}
acmd = TAILQ_FIRST(&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) {
acmd = ahd_linux_run_complete_queue(ahd, acmd);
if (acmd != NULL) {
......@@ -5254,7 +5254,6 @@ ahd_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
#endif
return (retval);
}
#endif
static void
ahd_linux_dev_timed_unfreeze(u_long arg)
......
......@@ -28,4 +28,12 @@ struct scsi_status_iu_header
(12 + (((siu)->flags & SIU_RSPVALID) \
? scsi_4btoul((siu)->pkt_failures_length) \
: 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*/
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