diff options
Diffstat (limited to 'sys/dev/aic7xxx/aic7xxx.c')
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.c | 2253 |
1 files changed, 756 insertions, 1497 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index e442be536b9e6..48014aef3e1a2 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -5,7 +5,7 @@ * pci/ahc_pci.c 3985, 3980, 3940, 2940, aic7895, aic7890, * aic7880, aic7870, aic7860, and aic7850 controllers * - * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999 Justin T. Gibbs. + * Copyright (c) 1994, 1995, 1996, 1997, 1998 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,7 +36,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aic7xxx.c,v 1.15 1999/01/14 06:14:14 gibbs Exp $ + * $Id: aic7xxx.c,v 1.8 1998/10/15 18:21:47 gibbs Exp $ */ /* * A few notes on features of the driver. @@ -133,8 +133,9 @@ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define ALL_TARGETS (~0) +#define ALL_LUNS (~0) #define ALL_CHANNELS '\0' -#define ALL_TARGETS_MASK 0xFFFF #define SIM_IS_SCSIBUS_B(ahc, sim) \ (sim == ahc->sim_b) @@ -154,22 +155,11 @@ #define ccb_scb_ptr spriv_ptr0 #define ccb_ahc_ptr spriv_ptr1 -typedef enum { - ROLE_UNKNOWN, - ROLE_INITIATOR, - ROLE_TARGET, -} role_t; - struct ahc_devinfo { int target_offset; u_int16_t target_mask; u_int8_t target; - u_int8_t lun; char channel; - role_t role; /* - * Only guaranteed to be correct if not - * in the busfree state. - */ }; typedef enum { @@ -188,10 +178,9 @@ static int ahc_debug = AHC_DEBUG; void ahc_pci_intr(struct ahc_softc *ahc); #endif -#if UNUSED static void ahc_dump_targcmd(struct target_cmd *cmd); -#endif static void ahc_shutdown(int howto, void *arg); +static void ahcminphys(struct buf *bp); static cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, @@ -215,33 +204,16 @@ static struct scb * static void ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); static void ahc_compile_devinfo(struct ahc_devinfo *devinfo, - u_int target, u_int lun, char channel, - role_t role); + u_int target, char channel); static u_int ahc_abort_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev); static void ahc_done(struct ahc_softc *ahc, struct scb *scbp); -static void ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, - union ccb *ccb); -static int ahc_handle_target_cmd(struct ahc_softc *ahc, - struct target_cmd *cmd); +static void ahc_handle_target_cmd(struct ahc_softc *ahc); static void ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat); static void ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat); -static void ahc_build_transfer_msg(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_setup_initiator_msgout(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct scb *scb); -static void ahc_setup_target_msgin(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static int ahc_handle_msg_reject(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_clear_msg_state(struct ahc_softc *ahc); -static void ahc_handle_message_phase(struct ahc_softc *ahc, - struct cam_path *path); -static int ahc_sent_msg(struct ahc_softc *ahc, u_int msgtype, int full); -static int ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, +static void ahc_handle_reqinit(struct ahc_softc *ahc, + struct scb *scb); +static int ahc_parse_msg(struct ahc_softc *ahc, struct scb *scb, struct ahc_devinfo *devinfo); -static void ahc_handle_ign_wide_residue(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); static void ahc_handle_devreset(struct ahc_softc *ahc, int target, char channel, cam_status status, ac_code acode, char *message, @@ -260,8 +232,6 @@ static void ahc_print_scb(struct scb *scb); static int ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, u_int32_t status, ahc_search_action action); -static void ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, - union ccb *ccb); static int ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset); static int ahc_abort_scbs(struct ahc_softc *ahc, int target, @@ -275,8 +245,6 @@ static void ahc_add_curscb_to_free_list(struct ahc_softc *ahc); static void ahc_clear_intstat(struct ahc_softc *ahc); static void ahc_reset_current_bus(struct ahc_softc *ahc); static struct ahc_syncrate * - ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period); -static struct ahc_syncrate * ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, u_int maxsync); static u_int ahc_find_period(struct ahc_softc *ahc, u_int scsirate, @@ -284,13 +252,6 @@ static u_int ahc_find_period(struct ahc_softc *ahc, u_int scsirate, static void ahc_validate_offset(struct ahc_softc *ahc, struct ahc_syncrate *syncrate, u_int *offset, int wide); -static void ahc_update_target_msg_request(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct ahc_target_tinfo *tinfo, - int force); -static int ahc_create_path(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct cam_path **path); static void ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct cam_path *path, @@ -312,7 +273,6 @@ static void ahc_set_recoveryscb(struct ahc_softc *ahc, struct scb *scb); static timeout_t ahc_timeout; -static __inline int sequencer_paused(struct ahc_softc *ahc); static __inline void pause_sequencer(struct ahc_softc *ahc); static __inline void unpause_sequencer(struct ahc_softc *ahc, int unpause_always); @@ -335,12 +295,6 @@ ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index) #define AHC_BUSRESET_DELAY 25 /* Reset delay in us */ -static __inline int -sequencer_paused(struct ahc_softc *ahc) -{ - return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0); -} - static __inline void pause_sequencer(struct ahc_softc *ahc) { @@ -350,15 +304,16 @@ pause_sequencer(struct ahc_softc *ahc) * Since the sequencer can disable pausing in a critical section, we * must loop until it actually stops. */ - while (sequencer_paused(ahc) == 0) + while ((ahc_inb(ahc, HCNTRL) & PAUSE) == 0) ; } static __inline void unpause_sequencer(struct ahc_softc *ahc, int unpause_always) { - if (unpause_always - || (ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) + if ((ahc->flags & AHC_HANDLING_REQINITS) == 0 + && (unpause_always + || (ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)) ahc_outb(ahc, HCNTRL, ahc->unpause); } @@ -418,7 +373,7 @@ ahc_name(struct ahc_softc *ahc) { static char name[10]; - snprintf(name, sizeof(name), "ahc%d", ahc->unit); + sprintf(name, "ahc%d", ahc->unit); return (name); } @@ -604,30 +559,6 @@ ahc_reset(struct ahc_softc *ahc) } /* - * Called when we have an active connection to a target on the bus, - * this function finds the nearest syncrate to the input period limited - * by the capabilities of the bus connectivity of the target. - */ -static struct ahc_syncrate * -ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period) { - u_int maxsync; - - if ((ahc->features & AHC_ULTRA2) != 0) { - if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0 - && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) { - maxsync = AHC_SYNCRATE_ULTRA2; - } else { - maxsync = AHC_SYNCRATE_ULTRA; - } - } else if ((ahc->features & AHC_ULTRA) != 0) { - maxsync = AHC_SYNCRATE_ULTRA; - } else { - maxsync = AHC_SYNCRATE_FAST; - } - return (ahc_find_syncrate(ahc, period, maxsync)); -} - -/* * Look up the valid period to SCSIRATE conversion in our table. * Return the period and offset that should be sent to the target * if this was the beginning of an SDTR. @@ -721,62 +652,10 @@ ahc_validate_offset(struct ahc_softc *ahc, struct ahc_syncrate *syncrate, } static void -ahc_update_target_msg_request(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct ahc_target_tinfo *tinfo, - int force) -{ - int paused; - u_int targ_msg_req_orig; - - targ_msg_req_orig = ahc->targ_msg_req; - if (tinfo->current.period != tinfo->goal.period - || tinfo->current.width != tinfo->goal.width - || (force - && (tinfo->goal.period != 0 - || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT))) - ahc->targ_msg_req |= devinfo->target_mask; - else - ahc->targ_msg_req &= ~devinfo->target_mask; - - if (ahc->targ_msg_req != targ_msg_req_orig) { - /* Update the message request bit for this target */ - paused = sequencer_paused(ahc); - - if (!paused) - pause_sequencer(ahc); - - ahc_outb(ahc, TARGET_MSG_REQUEST, ahc->targ_msg_req & 0xFF); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, - (ahc->targ_msg_req >> 8) & 0xFF); - - if (!paused) - unpause_sequencer(ahc, /*unpause always*/FALSE); - } -} - -static int -ahc_create_path(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct cam_path **path) -{ - path_id_t path_id; - - if (devinfo->channel == 'B') - path_id = cam_sim_path(ahc->sim_b); - else - path_id = cam_sim_path(ahc->sim); - - return (xpt_create_path(path, /*periph*/NULL, - path_id, devinfo->target, - devinfo->lun)); -} - -static void ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct cam_path *path, struct ahc_syncrate *syncrate, u_int period, u_int offset, u_int type) { - struct ahc_target_tinfo *tinfo; u_int old_period; u_int old_offset; @@ -785,16 +664,15 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, offset = 0; } - tinfo = &ahc->transinfo[devinfo->target_offset]; - old_period = tinfo->current.period; - old_offset = tinfo->current.offset; + old_period = ahc->transinfo[devinfo->target_offset].current.period; + old_offset = ahc->transinfo[devinfo->target_offset].current.offset; if ((type & AHC_TRANS_CUR) != 0 && (old_period != period || old_offset != offset)) { - struct cam_path *path2; + struct ccb_trans_settings neg; u_int scsirate; - scsirate = tinfo->scsirate; + scsirate = ahc->transinfo[devinfo->target_offset].scsirate; if ((ahc->features & AHC_ULTRA2) != 0) { scsirate &= ~SXFR_ULTRA2; @@ -803,8 +681,11 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, scsirate |= syncrate->sxfr_ultra2; } - if ((type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE) + if ((type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE) { ahc_outb(ahc, SCSIOFFSET, offset); + } + ahc_outb(ahc, TARG_OFFSET + devinfo->target_offset, + offset); } else { scsirate &= ~(SXFR|SOFS); @@ -833,45 +714,25 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, if ((type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE) ahc_outb(ahc, SCSIRATE, scsirate); - tinfo->scsirate = scsirate; - tinfo->current.period = period; - tinfo->current.offset = offset; + ahc->transinfo[devinfo->target_offset].scsirate = scsirate; + ahc->transinfo[devinfo->target_offset].current.period = period; + ahc->transinfo[devinfo->target_offset].current.offset = offset; /* Update the syncrates in any pending scbs */ ahc_update_pending_syncrates(ahc); /* - * If possible, tell the SCSI layer about the + * Tell the SCSI layer about the * new transfer parameters. */ - /* If possible, update the XPT's notion of our transfer rate */ - path2 = NULL; - if (path == NULL) { - int error; - - error = ahc_create_path(ahc, devinfo, &path2); - if (error == CAM_REQ_CMP) - path = path2; - else - path2 = NULL; - } - - if (path != NULL) { - struct ccb_trans_settings neg; - - neg.sync_period = period; - neg.sync_offset = offset; - neg.valid = CCB_TRANS_SYNC_RATE_VALID - | CCB_TRANS_SYNC_OFFSET_VALID; - xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1); - xpt_async(AC_TRANSFER_NEG, path, &neg); - } - - if (path2 != NULL) - xpt_free_path(path2); - + neg.sync_period = period; + neg.sync_offset = offset; + neg.valid = CCB_TRANS_SYNC_RATE_VALID + | CCB_TRANS_SYNC_OFFSET_VALID; + xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1); + xpt_async(AC_TRANSFER_NEG, path, &neg); if (bootverbose) { - if (offset != 0) { + if (neg.sync_offset != 0) { printf("%s: target %d synchronous at %sMHz, " "offset = 0x%x\n", ahc_name(ahc), devinfo->target, syncrate->rate, offset); @@ -884,80 +745,57 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, } if ((type & AHC_TRANS_GOAL) != 0) { - tinfo->goal.period = period; - tinfo->goal.offset = offset; + ahc->transinfo[devinfo->target_offset].goal.period = period; + ahc->transinfo[devinfo->target_offset].goal.offset = offset; } if ((type & AHC_TRANS_USER) != 0) { - tinfo->user.period = period; - tinfo->user.offset = offset; + ahc->transinfo[devinfo->target_offset].user.period = period; + ahc->transinfo[devinfo->target_offset].user.offset = offset; } - - ahc_update_target_msg_request(ahc, devinfo, tinfo, /*force*/FALSE); } static void ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct cam_path *path, u_int width, u_int type) { - struct ahc_target_tinfo *tinfo; - u_int oldwidth; + u_int oldwidth; - tinfo = &ahc->transinfo[devinfo->target_offset]; - oldwidth = tinfo->current.width; + oldwidth = ahc->transinfo[devinfo->target_offset].current.width; if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { - struct cam_path *path2; + struct ccb_trans_settings neg; u_int scsirate; - scsirate = tinfo->scsirate; + scsirate = ahc->transinfo[devinfo->target_offset].scsirate; scsirate &= ~WIDEXFER; if (width == MSG_EXT_WDTR_BUS_16_BIT) scsirate |= WIDEXFER; - tinfo->scsirate = scsirate; + ahc->transinfo[devinfo->target_offset].scsirate = scsirate; if ((type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE) ahc_outb(ahc, SCSIRATE, scsirate); - tinfo->current.width = width; - - /* If possible, update the XPT's notion of our transfer rate */ - path2 = NULL; - if (path == NULL) { - int error; - - error = ahc_create_path(ahc, devinfo, &path2); - if (error == CAM_REQ_CMP) - path = path2; - else - path2 = NULL; - } - - if (path != NULL) { - struct ccb_trans_settings neg; - - neg.bus_width = width; - neg.valid = CCB_TRANS_BUS_WIDTH_VALID; - xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1); - xpt_async(AC_TRANSFER_NEG, path, &neg); - } - - if (path2 != NULL) - xpt_free_path(path2); + ahc->transinfo[devinfo->target_offset].current.width = width; + /* Tell the SCSI layer about the new transfer params */ + neg.bus_width = width; + neg.valid = CCB_TRANS_BUS_WIDTH_VALID; + xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1); + xpt_async(AC_TRANSFER_NEG, path, &neg); if (bootverbose) { printf("%s: target %d using %dbit transfers\n", ahc_name(ahc), devinfo->target, - 8 * (0x01 << width)); + 8 * (0x01 << neg.bus_width)); } } - if ((type & AHC_TRANS_GOAL) != 0) - tinfo->goal.width = width; - if ((type & AHC_TRANS_USER) != 0) - tinfo->user.width = width; - - ahc_update_target_msg_request(ahc, devinfo, tinfo, /*force*/FALSE); + if ((type & AHC_TRANS_GOAL) != 0) { + ahc->transinfo[devinfo->target_offset].goal.width = width; + } + if ((type & AHC_TRANS_USER) != 0) { + ahc->transinfo[devinfo->target_offset].user.width = width; + } } /* @@ -1089,29 +927,19 @@ fail: static void ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { - u_int saved_tcl; - role_t role; - - if (ahc_inb(ahc, SSTAT0) & TARGET) - role = ROLE_TARGET; - else - role = ROLE_INITIATOR; + u_int saved_tcl; saved_tcl = ahc_inb(ahc, SAVED_TCL); ahc_compile_devinfo(devinfo, (saved_tcl >> 4) & 0x0f, - saved_tcl & 0x3, (saved_tcl & SELBUSB) ? 'B': 'A', - role); + (saved_tcl & SELBUSB) ? 'B': 'A'); } static void -ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int target, u_int lun, - char channel, role_t role) +ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int target, char channel) { devinfo->target = target; - devinfo->lun = lun; devinfo->target_offset = target; devinfo->channel = channel; - devinfo->role = role; if (channel == 'B') devinfo->target_offset += 8; devinfo->target_mask = (0x01 << devinfo->target_offset); @@ -1161,6 +989,12 @@ ahc_intr(void *arg) scb_index = ahc->qoutfifo[ahc->qoutfifonext]; ahc->qoutfifo[ahc->qoutfifonext++] = SCB_LIST_NULL; + if (scb_index == TARGET_CMD_CMPLT + && (ahc->flags & AHC_TARGETMODE) != 0) { + ahc_handle_target_cmd(ahc); + continue; + } + scb = ahc->scb_data->scbarray[scb_index]; if (!scb || !(scb->flags & SCB_ACTIVE)) { printf("%s: WARNING no command for scb %d " @@ -1178,23 +1012,6 @@ ahc_intr(void *arg) ahc_calc_residual(scb); ahc_done(ahc, scb); } - - if ((ahc->flags & AHC_TARGETMODE) != 0) { - while (ahc->targetcmds[ahc->tqinfifonext].cmd_valid) { - struct target_cmd *cmd; - - cmd = &ahc->targetcmds[ahc->tqinfifonext]; - - /* - * Only advance through the queue if we - * had the resources to process the command. - */ - if (ahc_handle_target_cmd(ahc, cmd) != 0) - break; - ahc->tqinfifonext++; - cmd->cmd_valid = 0; - } - } } if (intstat & BRKADRINT) { /* @@ -1213,8 +1030,8 @@ ahc_intr(void *arg) (ahc_inb(ahc, SEQADDR1) << 8)); /* Tell everyone that this HBA is no longer availible */ - ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS, - CAM_LUN_WILDCARD, SCB_LIST_NULL, CAM_NO_HBA); + ahc_abort_scbs(ahc, ALL_TARGETS, ALL_CHANNELS, + ALL_LUNS, SCB_LIST_NULL, CAM_NO_HBA); } if (intstat & SEQINT) ahc_handle_seqint(ahc, intstat); @@ -1224,207 +1041,31 @@ ahc_intr(void *arg) } static void -ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) -{ - struct tmode_tstate *tstate; - struct tmode_lstate *lstate; - struct ccb_en_lun *cel; - cam_status status; - int target; - int lun; - - status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate, - /* notfound_failure*/FALSE); - - if (status != CAM_REQ_CMP) { - ccb->ccb_h.status = status; - return; - } - - cel = &ccb->cel; - target = ccb->ccb_h.target_id; - lun = ccb->ccb_h.target_lun; - if (cel->enable != 0) { - u_int scsiseq; - - /* Are we already enabled?? */ - if (lstate != NULL) { - ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; - return; - } - - if (cel->grp6_len != 0 - || cel->grp7_len != 0) { - /* - * Don't (yet?) support vendor - * specific commands. - */ - ccb->ccb_h.status = CAM_REQ_INVALID; - return; - } - - /* - * Seems to be okay. - * Setup our data structures. - */ - if (target != CAM_TARGET_WILDCARD && tstate == NULL) { - tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT); - if (tstate == NULL) { - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - bzero(tstate, sizeof(*tstate)); - ahc->enabled_targets[target] = tstate; - } - lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT); - if (lstate == NULL) { - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - bzero(lstate, sizeof(*lstate)); - SLIST_INIT(&lstate->accept_tios); - SLIST_INIT(&lstate->immed_notifies); - if (target != CAM_TARGET_WILDCARD) { - tstate->enabled_luns[lun] = lstate; - ahc->enabled_luns++; - } else - ahc->black_hole = lstate; - pause_sequencer(ahc); - if ((ahc->features & AHC_MULTI_TID) != 0) { - u_int16_t targid_mask; - - targid_mask = ahc_inb(ahc, TARGID) - | (ahc_inb(ahc, TARGID + 1) << 8); - - targid_mask |= (0x01 << target); - ahc_outb(ahc, TARGID, targid_mask); - ahc_outb(ahc, TARGID+1, (targid_mask >> 8)); - } - /* Allow select-in operations */ - if (ahc->black_hole != NULL && ahc->enabled_luns > 0) { - scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); - scsiseq |= ENSELI; - ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq); - scsiseq = ahc_inb(ahc, SCSISEQ); - scsiseq |= ENSELI; - ahc_outb(ahc, SCSISEQ, scsiseq); - } - unpause_sequencer(ahc, /*always?*/FALSE); - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_print_path(ccb->ccb_h.path); - printf("Lun now enabled for target mode\n"); - xpt_done(ccb); - } else { - struct ccb_hdr *elm; - - if (lstate == NULL) { - ccb->ccb_h.status = CAM_LUN_INVALID; - return; - } - - ccb->ccb_h.status = CAM_REQ_CMP; - LIST_FOREACH(elm, &ahc->pending_ccbs, sim_links.le) { - if (elm->func_code == XPT_CONT_TARGET_IO - && !xpt_path_comp(elm->path, ccb->ccb_h.path)){ - printf("CTIO pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - return; - } - } - - if (SLIST_FIRST(&lstate->accept_tios) != NULL) { - printf("ATIOs pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - } - - if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { - printf("INOTs pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - } - - if (ccb->ccb_h.status == CAM_REQ_CMP) { - int i, empty; - - xpt_print_path(ccb->ccb_h.path); - printf("Target mode disabled\n"); - free(lstate, M_DEVBUF); - - pause_sequencer(ahc); - /* Can we clean up the target too? */ - if (target != CAM_TARGET_WILDCARD) { - tstate->enabled_luns[lun] = NULL; - ahc->enabled_luns--; - for (empty = 1, i = 0; i < 8; i++) - if (tstate->enabled_luns[i] != NULL) { - empty = 0; - break; - } - if (empty) { - free(tstate, M_DEVBUF); - ahc->enabled_targets[target] = NULL; - if (ahc->features & AHC_MULTI_TID) { - u_int16_t targid_mask; - - targid_mask = - ahc_inb(ahc, TARGID) - | (ahc_inb(ahc, TARGID + 1) - << 8); - - targid_mask &= (0x01 << target); - ahc_outb(ahc, TARGID, - targid_mask); - ahc_outb(ahc, TARGID+1, - (targid_mask >> 8)); - } - - for (empty = 1, i = 0; i < 16; i++) - if (ahc->enabled_targets[i] - != NULL) { - empty = 0; - break; - } - } - } else { - - ahc->black_hole = NULL; - - /* - * We can't allow selections without - * our black hole device. - */ - empty = TRUE; - } - if (empty) { - /* Disallow select-in */ - u_int scsiseq; - - scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); - scsiseq &= ~ENSELI; - ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq); - scsiseq = ahc_inb(ahc, SCSISEQ); - scsiseq &= ~ENSELI; - ahc_outb(ahc, SCSISEQ, scsiseq); - } - unpause_sequencer(ahc, /*always?*/FALSE); - } - } -} - -static int -ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) +ahc_handle_target_cmd(struct ahc_softc *ahc) { struct tmode_tstate *tstate; struct tmode_lstate *lstate; struct ccb_accept_tio *atio; + struct target_cmd *cmd; u_int8_t *byte; int initiator; int target; int lun; - initiator = cmd->initiator_channel >> 4; + cmd = &ahc->targetcmds[ahc->next_targetcmd]; + ahc->next_targetcmd++; + if (ahc->next_targetcmd >= ahc->num_targetcmds) + ahc->next_targetcmd = 0; + + initiator = cmd->icl >> 4; target = cmd->targ_id; lun = (cmd->identify & MSG_IDENTIFY_LUNMASK); + xpt_print_path(ahc->path); + printf("Received Target Command (%d:%d:%d)\n", + initiator, target, lun); + ahc_dump_targcmd(cmd); + byte = cmd->bytes; tstate = ahc->enabled_targets[target]; lstate = NULL; @@ -1432,28 +1073,23 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) lstate = tstate->enabled_luns[lun]; /* - * Commands for disabled luns go to the black hole driver. + * XXX Need to have a default TMODE devce that attaches to luns + * that wouldn't otherwise be enabled and returns the proper + * inquiry information. After all, we don't want to duplicate + * this code in each driver. For now, simply drop it on the + * floor. */ if (lstate == NULL) { printf("Incoming Command on disabled lun\n"); - lstate = ahc->black_hole; - atio = - (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios); - /* Fill in the wildcards */ - atio->ccb_h.target_id = target; - atio->ccb_h.target_lun = lun; - } else { - atio = - (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios); + return; } + + atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios); + /* XXX Should reconnect and return BUSY status */ if (atio == NULL) { printf("No ATIOs for incoming command\n"); - /* - * Wait for more ATIOs from the peripheral driver for this lun. - */ - return (1); + return; } - SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); /* * Package it up and send it off to @@ -1494,6 +1130,7 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) } bcopy(byte, atio->cdb_io.cdb_bytes, atio->cdb_len); + SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); atio->ccb_h.status |= CAM_CDB_RECVD; if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) { @@ -1503,10 +1140,11 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) * continue target I/O comes in response * to this accept tio. */ + xpt_print_path(atio->ccb_h.path); + printf("Incoming Command did not disconnect %p\n", lstate); ahc->pending_device = lstate; } xpt_done((union ccb*)atio); - return (0); } static void @@ -1581,6 +1219,130 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) devinfo.target); } break; + case EXTENDED_MSG: + { + ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN; + ahc->msg_len = 0; + ahc->msg_index = 0; + + /* + * To actually receive the message, simply turn on + * REQINIT interrupts and let our interrupt handler + * do the rest (REQINIT should already be true). + */ + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENREQINIT); + ahc->flags |= AHC_HANDLING_REQINITS; + return; + } + case REJECT_MSG: + { + /* + * What we care about here is if we had an + * outstanding SDTR or WDTR message for this + * target. If we did, this is a signal that + * the target is refusing negotiation. + */ + u_int scb_index; + u_int last_msg; + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc->scb_data->scbarray[scb_index]; + + last_msg = ahc_inb(ahc, LAST_MSG); + + if ((last_msg == MSG_IDENTIFYFLAG + || last_msg == HOST_MSG) + && (scb->flags & SCB_MSGOUT_WDTR) != 0 + && (scb->flags & SCB_MSGOUT_SENT) != 0) { + struct ahc_target_tinfo *tinfo; + + /* note 8bit xfers and clear flag */ + printf("%s:%c:%d: refuses WIDE negotiation. Using " + "8bit transfers\n", ahc_name(ahc), + devinfo.channel, devinfo.target); + scb->flags &= ~SCB_MSGOUT_BITS; + ahc->wdtrpending &= ~devinfo.target_mask; + ahc_set_width(ahc, &devinfo, scb->ccb->ccb_h.path, + MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL); + ahc_set_syncrate(ahc, &devinfo, scb->ccb->ccb_h.path, + /*syncrate*/NULL, /*period*/0, + /*offset*/0, AHC_TRANS_ACTIVE); + tinfo = &ahc->transinfo[devinfo.target_offset]; + if (tinfo->goal.period) { + /* Start the sync negotiation */ + ahc->sdtrpending |= devinfo.target_mask; + scb->flags |= SCB_MSGOUT_SDTR; + ahc_outb(ahc, MSG_OUT, HOST_MSG); + ahc_outb(ahc, SCSISIGO, + ahc_inb(ahc, SCSISIGO) | ATNO); + } + } else if ((last_msg == MSG_IDENTIFYFLAG + || last_msg == HOST_MSG) + && (scb->flags & SCB_MSGOUT_SDTR) != 0 + && (scb->flags & SCB_MSGOUT_SENT) != 0) { + + /* note asynch xfers and clear flag */ + ahc_set_syncrate(ahc, &devinfo, scb->ccb->ccb_h.path, + /*syncrate*/NULL, /*period*/0, + /*offset*/0, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL); + scb->flags &= ~SCB_MSGOUT_BITS; + ahc->sdtrpending &= ~devinfo.target_mask; + printf("%s:%c:%d: refuses synchronous negotiation. " + "Using asynchronous transfers\n", + ahc_name(ahc), + devinfo.channel, devinfo.target); + } else if ((last_msg == MSG_IDENTIFYFLAG) + && (scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) { + struct ccb_trans_settings neg; + + printf("%s:%c:%d: refuses tagged commands. Performing " + "non-tagged I/O\n", ahc_name(ahc), + devinfo.channel, devinfo.target); + + ahc->tagenable &= ~devinfo.target_mask; + neg.flags = 0; + neg.valid = CCB_TRANS_TQ_VALID; + xpt_setup_ccb(&neg.ccb_h, scb->ccb->ccb_h.path, + /*priority*/1); + xpt_async(AC_TRANSFER_NEG, scb->ccb->ccb_h.path, &neg); + /* + * Resend the identify for this CCB as the target + * may believe that the selection is invalid otherwise. + */ + ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) + & ~MSG_SIMPLE_Q_TAG); + scb->hscb->control &= ~MSG_SIMPLE_Q_TAG; + scb->ccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID; + ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); + ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + + /* + * Requeue all tagged commands for this target + * currently in our posession so they can be + * converted to untagged commands. + */ + ahc_search_qinfifo(ahc, SCB_TARGET(scb), + SCB_CHANNEL(scb), + SCB_LUN(scb), + /*tag*/SCB_LIST_NULL, + CAM_REQUEUE_REQ, + SEARCH_COMPLETE); + } else { + /* + * Otherwise, we ignore it. + */ +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWMISC) + printf("%s:%c:%d: Message reject -- ignored\n", + ahc_name(ahc), devinfo.channel, + devinfo.target); +#endif + break; + } + break; + } case BAD_STATUS: { u_int scb_index; @@ -1683,17 +1445,31 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) * but due to the way we page SCBs, we can't. */ hscb->control = 0; - /* * This request sense could be because the * the device lost power or in some other * way has lost our transfer negotiations. * Renegotiate if appropriate. */ + ahc_set_width(ahc, &devinfo, + scb->ccb->ccb_h.path, + MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_CUR); + ahc_set_syncrate(ahc, &devinfo, + scb->ccb->ccb_h.path, + /*syncrate*/NULL, /*period*/0, + /*offset*/0, AHC_TRANS_CUR); + scb->flags &= ~SCB_MSGOUT_BITS; tinfo = &ahc->transinfo[devinfo.target_offset]; - ahc_update_target_msg_request(ahc, &devinfo, - tinfo, - /*force*/TRUE); + if (tinfo->goal.width) { + ahc->wdtrpending |= devinfo.target_mask; + hscb->control |= MK_MESSAGE; + scb->flags |= SCB_MSGOUT_WDTR; + } else if (tinfo->goal.period) { + ahc->sdtrpending |= devinfo.target_mask; + hscb->control |= MK_MESSAGE; + scb->flags |= SCB_MSGOUT_SDTR; + } hscb->status = 0; hscb->SG_count = 1; hscb->SG_pointer = scb->ahc_dmaphys; @@ -1736,15 +1512,19 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) } break; } - case TRACE_POINT: + case TARGET_SYNC_CMD: { - printf("SSTAT2 = 0x%x DFCNTRL = 0x%x\n", ahc_inb(ahc, SSTAT2), - ahc_inb(ahc, DFCNTRL)); - printf("SSTAT3 = 0x%x DSTATUS = 0x%x\n", ahc_inb(ahc, SSTAT3), - ahc_inb(ahc, DFSTATUS)); - printf("SSTAT0 = 0x%x, SCB_DATACNT = 0x%x\n", - ahc_inb(ahc, SSTAT0), - ahc_inb(ahc, SCB_DATACNT)); + /* + * We've already processed the command. If the command + * is still pending, don't unpause the sequencer until + * it returns. + */ + xpt_print_path(ahc->path); + printf("Saw a target sync cmd\n"); + if (ahc->pending_device != NULL) { + printf(" Pending device too.\n"); + return; + } break; } case TARGET_MSG_HELP: @@ -1755,56 +1535,105 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) restart_sequencer(ahc); return; } - case HOST_MSG_LOOP: + case AWAITING_MSG: { + u_int scb_index; + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc->scb_data->scbarray[scb_index]; + + /* + * To facilitate adding multiple messages together, + * each routine should increment the index and len + * variables instead of setting them explicitly. + */ + ahc->msg_index = 0; + ahc->msg_len = 0; + /* - * The sequencer has encountered a message phase - * that requires host assistance for completion. - * While handling the message phase(s), we will be - * notified by the sequencer after each byte is - * transfered so we can track bus phases. - * - * If this is the first time we've seen a HOST_MSG_LOOP, - * initialize the state of the host message loop. + * This SCB had MK_MESSAGE set in its control byte or + * we have explicitly set HOST_MSG in MSG_OUT, + * informing the sequencer that we want to send a + * special message to this target. */ - if (ahc->msg_type == MSG_TYPE_NONE) { - u_int bus_phase; - - bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - if (bus_phase != P_MESGIN && bus_phase != P_MESGOUT) - panic("ahc_intr: HOST_MSG_LOOP bad phase 0x%x", - bus_phase); - - if (devinfo.role == ROLE_INITIATOR) { - struct scb *scb; - u_int scb_index; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - - if (bus_phase == P_MESGOUT) - ahc_setup_initiator_msgout(ahc, - &devinfo, - scb); - else { - ahc->msg_type = - MSG_TYPE_INITIATOR_MSGIN; - ahc->msgin_index = 0; + if ((scb->flags & SCB_DEVICE_RESET) == 0 + && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG + && (scb->hscb->control & TAG_ENB) != 0) { + ahc->msg_buf[ahc->msg_index++] = + scb->ccb->csio.tag_action; + ahc->msg_buf[ahc->msg_index++] = + scb->hscb->tag; + ahc->msg_len += 2; + } + + if (scb->flags & SCB_DEVICE_RESET) { + ahc->msg_buf[ahc->msg_index++] = MSG_BUS_DEV_RESET; + ahc->msg_len++; + xpt_print_path(scb->ccb->ccb_h.path); + printf("Bus Device Reset Message Sent\n"); + } else if (scb->flags & SCB_ABORT) { + if ((scb->hscb->control & TAG_ENB) != 0) + ahc->msg_buf[ahc->msg_index++] = MSG_ABORT_TAG; + else + ahc->msg_buf[ahc->msg_index++] = MSG_ABORT; + ahc->msg_len++; + xpt_print_path(scb->ccb->ccb_h.path); + printf("Abort Message Sent\n"); + } else if (scb->flags & SCB_MSGOUT_WDTR) { + struct ahc_target_tinfo *tinfo; + + tinfo = &ahc->transinfo[devinfo.target_offset]; + ahc_construct_wdtr(ahc, tinfo->goal.width); + } else if (scb->flags & SCB_MSGOUT_SDTR) { + struct ahc_target_tinfo *tinfo; + u_int period; + u_int maxsync; + + /* + * Now that the target is actually selected, we + * can further refine our sync rate based on the + * output transceiver mode. + */ + if ((ahc->features & AHC_ULTRA2) != 0) { + if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0 + && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) { + maxsync = AHC_SYNCRATE_ULTRA2; + } else { + maxsync = AHC_SYNCRATE_ULTRA; } + } else if ((ahc->features & AHC_ULTRA) != 0) { + maxsync = AHC_SYNCRATE_ULTRA; } else { - if (bus_phase == P_MESGOUT) { - ahc->msg_type = - MSG_TYPE_TARGET_MSGOUT; - ahc->msgin_index = 0; - } else - /* XXX Ever executed??? */ - ahc_setup_target_msgin(ahc, &devinfo); + maxsync = AHC_SYNCRATE_FAST; } + tinfo = &ahc->transinfo[devinfo.target_offset]; + period = tinfo->goal.period; + ahc_find_syncrate(ahc, &period, maxsync); + ahc_construct_sdtr(ahc, period, tinfo->goal.offset); + } else { + printf("ahc_intr: AWAITING_MSG for an SCB that " + "does not have a waiting message"); + panic("SCB = %d, SCB Control = %x, MSG_OUT = %x " + "SCB flags = %x", scb_index, scb->hscb->control, + ahc_inb(ahc, MSG_OUT), scb->flags); } - /* Pass a NULL path so that handlers generate their own */ - ahc_handle_message_phase(ahc, /*path*/NULL); - break; + /* + * Record the fact that we attempted to send a message. + */ + scb->flags |= SCB_MSGOUT_SENT; + + /* + * To actually send the message, simply turn on + * REQINIT interrupts and let our interrupt handler + * do the rest (REQINIT should already be true). + */ + ahc->msg_index = 0; + ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; + ahc->flags |= AHC_HANDLING_REQINITS; + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENREQINIT); + + return; } case DATA_OVERRUN: { @@ -1997,7 +1826,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) CAM_UNEXP_BUSFREE); } else { ahc_abort_scbs(ahc, target, channel, - CAM_LUN_WILDCARD, SCB_LIST_NULL, + ALL_LUNS, SCB_LIST_NULL, CAM_UNEXP_BUSFREE); printf("%s: ", ahc_name(ahc)); } @@ -2006,8 +1835,10 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) lastphase, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); } - ahc_clear_msg_state(ahc); - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); + ahc_outb(ahc, MSG_OUT, MSG_NOOP); + ahc_outb(ahc, SIMODE1, + ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENREQINIT)); + ahc->flags &= ~AHC_HANDLING_REQINITS; ahc_outb(ahc, CLRSINT1, CLRBUSFREE); ahc_outb(ahc, CLRINT, CLRSCSIINT); restart_sequencer(ahc); @@ -2030,6 +1861,11 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) "valid during SELTO scb(%d, %d)\n", ahc_name(ahc), scbptr, scb_index); } else { + /* + * Clear any pending messages for the timed out + * target. + */ + ahc_outb(ahc, MSG_OUT, MSG_NOOP); ahc_handle_devreset(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb), CAM_SEL_TIMEOUT, /*ac_code*/0, "Selection Timeout", @@ -2038,7 +1874,9 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) /* Stop the selection */ ahc_outb(ahc, SCSISEQ, 0); - ahc_clear_msg_state(ahc); + ahc_outb(ahc, SIMODE1, + ahc_inb(ahc, SIMODE1) & ~ENREQINIT); + ahc->flags &= ~AHC_HANDLING_REQINITS; ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE); @@ -2109,14 +1947,14 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) * mesg_out to something other than MSG_NOP. */ if (mesg_out != MSG_NOOP) { - if (ahc->msg_type != MSG_TYPE_NONE) - ahc->send_msg_perror = TRUE; - else - ahc_outb(ahc, MSG_OUT, mesg_out); + ahc_outb(ahc, MSG_OUT, mesg_out); } ahc_outb(ahc, CLRSINT1, CLRSCSIPERR); ahc_outb(ahc, CLRINT, CLRSCSIINT); unpause_sequencer(ahc, /*unpause_always*/TRUE); + } else if ((status & REQINIT) != 0 + && (ahc->flags & AHC_HANDLING_REQINITS) != 0) { + ahc_handle_reqinit(ahc, scb); } else { xpt_print_path(scb->ccb->ccb_h.path); printf("Unknown SCSIINT. Status = 0x%x\n", status); @@ -2127,529 +1965,101 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) } static void -ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - /* - * We need to initiate transfer negotiations. - * If our current and goal settings are identical, - * we want to renegotiate due to a check condition. - */ - struct ahc_target_tinfo *tinfo; - int dowide; - int dosync; - - tinfo = &ahc->transinfo[devinfo->target_offset]; - dowide = tinfo->current.width != tinfo->goal.width; - dosync = tinfo->current.period != tinfo->goal.period; - - if (!dowide && !dosync) { - dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; - dosync = tinfo->goal.period != 0; - } - - if (dowide) - ahc_construct_wdtr(ahc, tinfo->goal.width); - else if (dosync) { - struct ahc_syncrate *rate; - u_int period; - u_int offset; - - period = tinfo->goal.period; - rate = ahc_devlimited_syncrate(ahc, &period); - offset = tinfo->goal.offset; - ahc_validate_offset(ahc, rate, &offset, - tinfo->current.width); - ahc_construct_sdtr(ahc, period, offset); - } else { - panic("ahc_intr: AWAITING_MSG for negotiation, " - "but no negotiation needed\n"); - } -} - -static void -ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct scb *scb) -{ - /* - * To facilitate adding multiple messages together, - * each routine should increment the index and len - * variables instead of setting them explicitly. - */ - ahc->msgout_index = 0; - ahc->msgout_len = 0; - - if ((scb->flags & SCB_DEVICE_RESET) == 0 - && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) { - u_int identify_msg; - - identify_msg = MSG_IDENTIFYFLAG | SCB_LUN(scb); - if ((scb->hscb->control & DISCENB) != 0) - identify_msg |= MSG_IDENTIFY_DISCFLAG; - ahc->msgout_buf[ahc->msgout_index++] = identify_msg; - ahc->msgout_len++; - - if ((scb->hscb->control & TAG_ENB) != 0) { - ahc->msgout_buf[ahc->msgout_index++] = - scb->ccb->csio.tag_action; - ahc->msgout_buf[ahc->msgout_index++] = scb->hscb->tag; - ahc->msgout_len += 2; - } - } - - if (scb->flags & SCB_DEVICE_RESET) { - ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET; - ahc->msgout_len++; - xpt_print_path(scb->ccb->ccb_h.path); - printf("Bus Device Reset Message Sent\n"); - } else if (scb->flags & SCB_ABORT) { - if ((scb->hscb->control & TAG_ENB) != 0) - ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG; - else - ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT; - ahc->msgout_len++; - xpt_print_path(scb->ccb->ccb_h.path); - printf("Abort Message Sent\n"); - } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0) { - ahc_build_transfer_msg(ahc, devinfo); - } else { - printf("ahc_intr: AWAITING_MSG for an SCB that " - "does not have a waiting message"); - panic("SCB = %d, SCB Control = %x, MSG_OUT = %x " - "SCB flags = %x", scb->hscb->tag, scb->hscb->control, - ahc_inb(ahc, MSG_OUT), scb->flags); - } - - /* - * Clear the MK_MESSAGE flag from the SCB so we aren't - * asked to send this message again. - */ - ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE); - ahc->msgout_index = 0; - ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; -} - -static void -ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - /* - * To facilitate adding multiple messages together, - * each routine should increment the index and len - * variables instead of setting them explicitly. - */ - ahc->msgout_index = 0; - ahc->msgout_len = 0; - - if ((ahc->targ_msg_req & devinfo->target_mask) != 0) - ahc_build_transfer_msg(ahc, devinfo); - else - panic("ahc_intr: AWAITING target message with no message"); - - ahc->msgout_index = 0; - ahc->msg_type = MSG_TYPE_TARGET_MSGIN; -} - -static int -ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - /* - * What we care about here is if we had an - * outstanding SDTR or WDTR message for this - * target. If we did, this is a signal that - * the target is refusing negotiation. - */ - struct scb *scb; - u_int scb_index; - u_int last_msg; - int response = 0; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - - /* Might be necessary */ - last_msg = ahc_inb(ahc, LAST_MSG); - - if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/FALSE)) { - struct ahc_target_tinfo *tinfo; - - /* note 8bit xfers and clear flag */ - printf("%s:%c:%d: refuses WIDE negotiation. Using " - "8bit transfers\n", ahc_name(ahc), - devinfo->channel, devinfo->target); - ahc_set_width(ahc, devinfo, scb->ccb->ccb_h.path, - MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL); - ahc_set_syncrate(ahc, devinfo, scb->ccb->ccb_h.path, - /*syncrate*/NULL, /*period*/0, - /*offset*/0, AHC_TRANS_ACTIVE); - tinfo = &ahc->transinfo[devinfo->target_offset]; - if (tinfo->goal.period) { - u_int period; - - /* Start the sync negotiation */ - period = tinfo->goal.period; - ahc_devlimited_syncrate(ahc, &period); - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_construct_sdtr(ahc, period, tinfo->goal.offset); - ahc->msgout_index = 0; - response = 1; - } - } else if (ahc_sent_msg(ahc, MSG_EXT_SDTR, /*full*/FALSE)) { - /* note asynch xfers and clear flag */ - ahc_set_syncrate(ahc, devinfo, scb->ccb->ccb_h.path, - /*syncrate*/NULL, /*period*/0, - /*offset*/0, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL); - printf("%s:%c:%d: refuses synchronous negotiation. " - "Using asynchronous transfers\n", - ahc_name(ahc), - devinfo->channel, devinfo->target); - } else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) { - struct ccb_trans_settings neg; - - printf("%s:%c:%d: refuses tagged commands. Performing " - "non-tagged I/O\n", ahc_name(ahc), - devinfo->channel, devinfo->target); - - ahc->tagenable &= ~devinfo->target_mask; - neg.flags = 0; - neg.valid = CCB_TRANS_TQ_VALID; - xpt_setup_ccb(&neg.ccb_h, scb->ccb->ccb_h.path, /*priority*/1); - xpt_async(AC_TRANSFER_NEG, scb->ccb->ccb_h.path, &neg); - - /* - * Resend the identify for this CCB as the target - * may believe that the selection is invalid otherwise. - */ - ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) - & ~MSG_SIMPLE_Q_TAG); - scb->hscb->control &= ~MSG_SIMPLE_Q_TAG; - scb->ccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID; - ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); - - /* - * Requeue all tagged commands for this target - * currently in our posession so they can be - * converted to untagged commands. - */ - ahc_search_qinfifo(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb), - SCB_LUN(scb), /*tag*/SCB_LIST_NULL, - CAM_REQUEUE_REQ, SEARCH_COMPLETE); - } else { - /* - * Otherwise, we ignore it. - */ - printf("%s:%c:%d: Message reject for %x -- ignored\n", - ahc_name(ahc), devinfo->channel, devinfo->target, - last_msg); - } - return (response); -} - -static void -ahc_clear_msg_state(struct ahc_softc *ahc) -{ - ahc->msgout_len = 0; - ahc->msgin_index = 0; - ahc->msg_type = MSG_TYPE_NONE; - ahc_outb(ahc, MSG_OUT, MSG_NOOP); -} - -static void -ahc_handle_message_phase(struct ahc_softc *ahc, struct cam_path *path) +ahc_handle_reqinit(struct ahc_softc *ahc, struct scb *scb) { struct ahc_devinfo devinfo; - u_int bus_phase; - int end_session; + u_int simode1; ahc_fetch_devinfo(ahc, &devinfo); - - end_session = FALSE; - bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - -reswitch: switch (ahc->msg_type) { case MSG_TYPE_INITIATOR_MSGOUT: { - int lastbyte; - int phasemis; - int msgdone; + int lastbyte; + int phasemis; + u_int bus_phase; - if (ahc->msgout_len == 0) + if (ahc->msg_len == 0) panic("REQINIT interrupt with no active message"); + lastbyte = (ahc->msg_index == ahc->msg_len - 1); + bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; phasemis = bus_phase != P_MESGOUT; - if (phasemis) { - if (bus_phase == P_MESGIN) { - /* - * Change gears and see if - * this messages is of interest to - * us or should be passed back to - * the sequencer. - */ - ahc_outb(ahc, CLRSINT1, CLRATNO); - ahc->send_msg_perror = FALSE; - ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN; - ahc->msgin_index = 0; - goto reswitch; - } - end_session = TRUE; - break; - } - - if (ahc->send_msg_perror) { - ahc_outb(ahc, CLRSINT1, CLRATNO); - ahc_outb(ahc, CLRSINT1, CLRREQINIT); - ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR); - break; - } - - msgdone = ahc->msgout_index == ahc->msgout_len; - if (msgdone) { - /* - * The target has requested a retry. - * Re-assert ATN, reset our message index to - * 0, and try again. - */ - ahc->msgout_index = 0; - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); - } - - lastbyte = ahc->msgout_index == (ahc->msgout_len - 1); - if (lastbyte) { - /* Last byte is signified by dropping ATN */ - ahc_outb(ahc, CLRSINT1, CLRATNO); - } - /* - * Clear our interrupt status and present - * the next byte on the bus. - */ - ahc_outb(ahc, CLRSINT1, CLRREQINIT); - ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); - break; - } - case MSG_TYPE_INITIATOR_MSGIN: - { - int phasemis; - int message_done; - - phasemis = bus_phase != P_MESGIN; - - if (phasemis) { - ahc->msgin_index = 0; - if (bus_phase == P_MESGOUT - && (ahc->send_msg_perror == TRUE - || (ahc->msgout_len != 0 - && ahc->msgout_index == 0))) { - ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - goto reswitch; + if (lastbyte || phasemis) { + /* Time to end our message session */ + ahc->msg_len = 0; + ahc->msg_type = MSG_TYPE_NONE; + simode1 = ahc_inb(ahc, SIMODE1) & ~ENREQINIT; + ahc_outb(ahc, SIMODE1, simode1); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc->flags &= ~AHC_HANDLING_REQINITS; + + if (phasemis == 0) { + ahc_outb(ahc, SINDEX, + ahc->msg_buf[ahc->msg_index]); + ahc_outb(ahc, RETURN_1, 0); + } else { + ahc_outb(ahc, RETURN_1, MSGOUT_PHASEMIS); } - end_session = TRUE; - break; - } - - /* Pull the byte in without acking it */ - ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL); - - message_done = ahc_parse_msg(ahc, path, &devinfo); - - if (message_done) { - /* - * Clear our incoming message buffer in case there - * is another message following this one. - */ - ahc->msgin_index = 0; + unpause_sequencer(ahc, /* unpause_always */TRUE); + } else { /* - * If this message illicited a response, - * assert ATN so the target takes us to the - * message out phase. + * Clear our interrupt status and present the byte + * on the bus, but don't unpause the sequencer. */ - if (ahc->msgout_len != 0) - ahc_outb(ahc, SCSISIGO, - ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_outb(ahc, CLRSINT1, CLRREQINIT); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_outb(ahc, SCSIDATL, ahc->msg_buf[ahc->msg_index++]); } - - /* Ack the byte */ - ahc_outb(ahc, CLRSINT1, CLRREQINIT); - ahc_inb(ahc, SCSIDATL); - ahc->msgin_index++; break; } - case MSG_TYPE_TARGET_MSGIN: + case MSG_TYPE_INITIATOR_MSGIN: { - int msgdone; - int msgout_request; + int phasemis; + int done; - if (ahc->msgout_len == 0) - panic("Target MSGIN with no active message"); + phasemis = (ahc_inb(ahc, SCSISIGI) & PHASE_MASK) != P_MESGIN; - /* - * If we interrupted a mesgout session, the initiator - * will not know this until our first REQ. So, we - * only honor mesgout requests after we've sent our - * first byte. - */ - if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0 - && ahc->msgout_index > 0) - msgout_request = TRUE; - else - msgout_request = FALSE; + if (phasemis == 0) { - if (msgout_request) { - - /* - * Change gears and see if - * this messages is of interest to - * us or should be passed back to - * the sequencer. - */ - ahc->msg_type = MSG_TYPE_TARGET_MSGOUT; - ahc_outb(ahc, SCSISIGO, P_MESGOUT | BSYO); - ahc->msgin_index = 0; - /* Dummy read to REQ for first byte */ + ahc->msg_len++; + /* Pull the byte in without acking it */ + ahc->msg_buf[ahc->msg_index] = ahc_inb(ahc, SCSIBUSL); + done = ahc_parse_msg(ahc, scb, &devinfo); + /* Ack the byte */ + ahc_outb(ahc, CLRSINT1, CLRREQINIT); + ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_inb(ahc, SCSIDATL); - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | SPIOEN); - break; + ahc->msg_index++; } - - msgdone = ahc->msgout_index == ahc->msgout_len; - if (msgdone) { - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); - end_session = TRUE; - break; + if (phasemis || done) { + /* Time to end our message session */ + ahc->msg_len = 0; + ahc->msg_type = MSG_TYPE_NONE; + simode1 = ahc_inb(ahc, SIMODE1) & ~ENREQINIT; + ahc->flags &= ~AHC_HANDLING_REQINITS; + ahc_outb(ahc, SIMODE1, simode1); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + unpause_sequencer(ahc, /* unpause_always */TRUE); } - - /* - * Present the next byte on the bus. - */ - ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN); - ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); - break; - } - case MSG_TYPE_TARGET_MSGOUT: - { - int lastbyte; - int msgdone; - - /* - * The initiator signals that this is - * the last byte by dropping ATN. - */ - lastbyte = (ahc_inb(ahc, SCSISIGI) & ATNI) == 0; - - /* - * Read the latched byte, but turn off SPIOEN first - * so that we don't inadvertantly cause a REQ for the - * next byte. - */ - ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); - ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIDATL); - msgdone = ahc_parse_msg(ahc, path, &devinfo); - ahc->msgin_index++; - - /* - * XXX Read spec about initiator dropping ATN too soon - * and use msgdone to detect it. - */ - if (msgdone) { - ahc->msgin_index = 0; - - /* - * If this message illicited a response, transition - * to the Message in phase and send it. - */ - if (ahc->msgout_len != 0) { - ahc_outb(ahc, SCSISIGO, P_MESGIN | BSYO); - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | SPIOEN); - ahc->msg_type = MSG_TYPE_TARGET_MSGIN; - ahc->msgin_index = 0; - break; - } - } - - if (lastbyte) - end_session = TRUE; - else { - /* Ask for the next byte. */ - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | SPIOEN); - } - break; } default: panic("Unknown REQINIT message type"); } - - if (end_session) { - ahc_clear_msg_state(ahc); - ahc_outb(ahc, RETURN_1, EXIT_MSG_LOOP); - } else - ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP); } -/* - * See if we sent a particular extended message to the target. - * If "full" is true, the target saw the full message. - * If "full" is false, the target saw at least the first - * byte of the message. - */ static int -ahc_sent_msg(struct ahc_softc *ahc, u_int msgtype, int full) -{ - int found; - int index; - - found = FALSE; - index = 0; - - while (index < ahc->msgout_len) { - if ((ahc->msgout_buf[index] & MSG_IDENTIFYFLAG) != 0 - || ahc->msgout_buf[index] == MSG_MESSAGE_REJECT) - index++; - else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG - && ahc->msgout_buf[index] < MSG_IGN_WIDE_RESIDUE) { - /* Skip tag type and tag id */ - index += 2; - } else if (ahc->msgout_buf[index] == MSG_EXTENDED) { - /* Found a candidate */ - if (ahc->msgout_buf[index+2] == msgtype) { - u_int end_index; - - end_index = index + 1 - + ahc->msgout_buf[index + 1]; - if (full) { - if (ahc->msgout_index > end_index) - found = TRUE; - } else if (ahc->msgout_index > index) - found = TRUE; - } - break; - } else { - panic("ahc_sent_msg: Inconsistent msg buffer"); - } - } - return (found); -} - -static int -ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, +ahc_parse_msg(struct ahc_softc *ahc, struct scb *scb, struct ahc_devinfo *devinfo) { int reject; int done; - int response; u_int targ_scsirate; done = FALSE; - response = FALSE; reject = FALSE; targ_scsirate = ahc->transinfo[devinfo->target_offset].scsirate; /* @@ -2658,48 +2068,26 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, * the entire message is availible and has been * handled, return TRUE indicating that we have * parsed an entire message. - * - * In the case of extended messages, we accept the length - * byte outright and perform more checking once we know the - * extended message type. */ - switch (ahc->msgin_buf[0]) { - case MSG_MESSAGE_REJECT: - response = ahc_handle_msg_reject(ahc, devinfo); - /* FALLTHROUGH */ - case MSG_NOOP: - done = TRUE; - break; - case MSG_IGN_WIDE_RESIDUE: - { - struct ahc_target_tinfo *tinfo; - - tinfo = &ahc->transinfo[devinfo->target_offset]; - /* Wait for the whole message */ - if (ahc->msgin_index >= 1) { - if (ahc->msgin_buf[1] != 1 - || tinfo->current.width == MSG_EXT_WDTR_BUS_8_BIT) { - reject = TRUE; - done = TRUE; - } else - ahc_handle_ign_wide_residue(ahc, devinfo); - } - break; + if (ahc->msg_buf[0] != MSG_EXTENDED) { + reject = TRUE; } - case MSG_EXTENDED: - { - /* Wait for enough of the message to begin validation */ - if (ahc->msgin_index < 2) - break; - switch (ahc->msgin_buf[2]) { + + /* + * Just accept the length byte outright and perform + * more checking once we know the message type. + */ + if (!reject && (ahc->msg_len > 2)) { + switch (ahc->msg_buf[2]) { case MSG_EXT_SDTR: { struct ahc_syncrate *syncrate; u_int period; u_int offset; u_int saved_offset; + u_int maxsync; - if (ahc->msgin_buf[1] != MSG_EXT_SDTR_LEN) { + if (ahc->msg_buf[1] != MSG_EXT_SDTR_LEN) { reject = TRUE; break; } @@ -2707,19 +2095,28 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, /* * Wait until we have both args before validating * and acting on this message. - * - * Add one to MSG_EXT_SDTR_LEN to account for - * the extended message preamble. */ - if (ahc->msgin_index < (MSG_EXT_SDTR_LEN + 1)) + if (ahc->msg_len < (MSG_EXT_SDTR_LEN + /*preamble*/2)) break; - period = ahc->msgin_buf[3]; - saved_offset = offset = ahc->msgin_buf[4]; - syncrate = ahc_devlimited_syncrate(ahc, &period); + period = ahc->msg_buf[3]; + saved_offset = offset = ahc->msg_buf[4]; + if ((ahc->features & AHC_ULTRA2) != 0) { + if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0 + && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) { + maxsync = AHC_SYNCRATE_ULTRA2; + } else { + maxsync = AHC_SYNCRATE_ULTRA; + } + } else if ((ahc->features & AHC_ULTRA) != 0) { + maxsync = AHC_SYNCRATE_ULTRA; + } else { + maxsync = AHC_SYNCRATE_FAST; + } + syncrate = ahc_find_syncrate(ahc, &period, maxsync); ahc_validate_offset(ahc, syncrate, &offset, targ_scsirate & WIDEXFER); - ahc_set_syncrate(ahc, devinfo, path, + ahc_set_syncrate(ahc, devinfo, scb->ccb->ccb_h.path, syncrate, period, offset, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL); @@ -2728,23 +2125,27 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, * and didn't have to fall down to async * transfers. */ - if (ahc_sent_msg(ahc, MSG_EXT_SDTR, /*full*/TRUE)) { + if ((scb->flags & (SCB_MSGOUT_SDTR|SCB_MSGOUT_SENT)) + == (SCB_MSGOUT_SDTR|SCB_MSGOUT_SENT)) { /* We started it */ if (saved_offset != offset) { /* Went too low - force async */ reject = TRUE; } + scb->flags &= ~SCB_MSGOUT_BITS; + ahc->sdtrpending &= ~devinfo->target_mask; } else { /* * Send our own SDTR in reply */ - if (bootverbose) - printf("Sending SDTR!\n"); - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_construct_sdtr(ahc, period, offset); - ahc->msgout_index = 0; - response = TRUE; + scb->flags &= ~SCB_MSGOUT_BITS; + scb->flags |= SCB_MSGOUT_SDTR; + ahc->sdtrpending |= devinfo->target_mask; + xpt_print_path(scb->ccb->ccb_h.path); + printf("Sending SDTR!!\n"); + ahc_outb(ahc, MSG_OUT, HOST_MSG); + ahc_outb(ahc, SCSISIGO, + ahc_inb(ahc, SCSISIGO) | ATNO); } done = TRUE; break; @@ -2752,10 +2153,8 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, case MSG_EXT_WDTR: { u_int bus_width; - u_int sending_reply; - sending_reply = FALSE; - if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) { + if (ahc->msg_buf[1] != MSG_EXT_WDTR_LEN) { reject = TRUE; break; } @@ -2763,26 +2162,13 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, /* * Wait until we have our arg before validating * and acting on this message. - * - * Add one to MSG_EXT_WDTR_LEN to account for - * the extended message preamble. - */ - if (ahc->msgin_index < (MSG_EXT_WDTR_LEN + 1)) - break; - - /* - * Due to a problem with sync/wide transfers - * on the aic7880 only allow this on Ultra2 - * controllers for the moment. */ - if (devinfo->role == ROLE_TARGET - && (ahc->features & AHC_ULTRA2) == 0) { - reject = TRUE; + if (ahc->msg_len < (MSG_EXT_WDTR_LEN + /*preamble*/2)) break; - } - bus_width = ahc->msgin_buf[3]; - if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/TRUE)) { + bus_width = ahc->msg_buf[3]; + if ((scb->flags & (SCB_MSGOUT_WDTR|SCB_MSGOUT_SENT)) + == (SCB_MSGOUT_WDTR|SCB_MSGOUT_SENT)) { /* * Don't send a WDTR back to the * target, since we asked first. @@ -2806,12 +2192,15 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, case MSG_EXT_WDTR_BUS_16_BIT: break; } + scb->flags &= ~SCB_MSGOUT_WDTR; + ahc->wdtrpending &= ~devinfo->target_mask; } else { /* * Send our own WDTR in reply */ - if (bootverbose) - printf("Sending WDTR!\n"); + printf("Sending WDTR!\n"); + scb->flags &= ~SCB_MSGOUT_BITS; + scb->flags |= SCB_MSGOUT_WDTR; switch (bus_width) { default: if (ahc->features & AHC_WIDE) { @@ -2825,41 +2214,33 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, bus_width = MSG_EXT_WDTR_BUS_8_BIT; break; } - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_construct_wdtr(ahc, bus_width); - ahc->msgout_index = 0; - response = TRUE; - sending_reply = TRUE; + ahc_outb(ahc, MSG_OUT, HOST_MSG); + ahc_outb(ahc, SCSISIGO, + ahc_inb(ahc, SCSISIGO) | ATNO); + ahc->wdtrpending |= devinfo->target_mask; } - ahc_set_width(ahc, devinfo, path, bus_width, + ahc_set_width(ahc, devinfo, scb->ccb->ccb_h.path, + bus_width, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL); /* After a wide message, we are async */ - ahc_set_syncrate(ahc, devinfo, path, + ahc_set_syncrate(ahc, devinfo, scb->ccb->ccb_h.path, /*syncrate*/NULL, /*period*/0, /*offset*/0, AHC_TRANS_ACTIVE); - if (sending_reply == FALSE && reject == FALSE) { + if ((ahc->wdtrpending & devinfo->target_mask) == 0 + && (reject == 0)) { struct ahc_target_tinfo *tinfo; + scb->flags &= ~SCB_MSGOUT_WDTR; tinfo = &ahc->transinfo[devinfo->target_offset]; if (tinfo->goal.period) { - struct ahc_syncrate *rate; - u_int period; - u_int offset; - /* Start the sync negotiation */ - period = tinfo->goal.period; - rate = ahc_devlimited_syncrate(ahc, - &period); - offset = tinfo->goal.offset; - ahc_validate_offset(ahc, rate, &offset, - tinfo->current.width); - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_construct_sdtr(ahc, period, offset); - ahc->msgout_index = 0; - response = TRUE; + ahc->sdtrpending |= + devinfo->target_mask; + scb->flags |= SCB_MSGOUT_SDTR; + ahc_outb(ahc, MSG_OUT, HOST_MSG); + ahc_outb(ahc, SCSISIGO, + ahc_inb(ahc, SCSISIGO) | ATNO); } } done = TRUE; @@ -2870,20 +2251,6 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, reject = TRUE; break; } - break; - } - case MSG_ABORT: - case MSG_ABORT_TAG: - case MSG_BUS_DEV_RESET: - case MSG_CLEAR_QUEUE: - case MSG_TERM_IO_PROC: - /* Target mode messages */ - if (devinfo->role != ROLE_TARGET) - reject = TRUE; - break; - default: - reject = TRUE; - break; } if (reject) { @@ -2891,128 +2258,43 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, * Assert attention and setup to * reject the message. */ - ahc->msgout_index = 0; - ahc->msgout_len = 1; - ahc->msgout_buf[0] = MSG_MESSAGE_REJECT; + ahc_outb(ahc, MSG_OUT, MSG_MESSAGE_REJECT); + ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); done = TRUE; - response = TRUE; } - - if (done && !response) - /* Clear the outgoing message buffer */ - ahc->msgout_len = 0; - return (done); } static void -ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - u_int scb_index; - struct scb *scb; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; - if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0 - || (scb->ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_IN) { - /* - * Ignore the message if we haven't - * seen an appropriate data phase yet. - */ - } else { - /* - * If the residual occurred on the last - * transfer and the transfer request was - * expected to end on an odd count, do - * nothing. Otherwise, subtract a byte - * and update the residual count accordingly. - */ - u_int resid_sgcnt; - - resid_sgcnt = ahc_inb(ahc, SCB_RESID_SGCNT); - if (resid_sgcnt == 0 - && ahc_inb(ahc, DATA_COUNT_ODD) == 1) { - /* - * If the residual occurred on the last - * transfer and the transfer request was - * expected to end on an odd count, do - * nothing. - */ - } else { - u_int data_cnt; - u_int data_addr; - u_int sg_index; - - data_cnt = (ahc_inb(ahc, SCB_RESID_DCNT + 2) << 16) - | (ahc_inb(ahc, SCB_RESID_DCNT + 1) << 8) - | (ahc_inb(ahc, SCB_RESID_DCNT)); - - data_addr = (ahc_inb(ahc, SHADDR + 3) << 24) - | (ahc_inb(ahc, SHADDR + 2) << 16) - | (ahc_inb(ahc, SHADDR + 1) << 8) - | (ahc_inb(ahc, SHADDR)); - - data_cnt += 1; - data_addr -= 1; - - sg_index = scb->sg_count - resid_sgcnt; - - /* - * scb->ahc_dma starts with the second S/G entry. - */ - if (sg_index-- != 0 - && (scb->ahc_dma[sg_index].len < data_cnt)) { - u_int sg_addr; - - data_cnt = 1; - data_addr = scb->ahc_dma[sg_index - 1].addr - + scb->ahc_dma[sg_index - 1].len - 1; - - sg_addr = scb->ahc_dmaphys - + (sg_index * sizeof(*scb->ahc_dma)); - ahc_outb(ahc, SG_NEXT + 3, sg_addr >> 24); - ahc_outb(ahc, SG_NEXT + 2, sg_addr >> 16); - ahc_outb(ahc, SG_NEXT + 1, sg_addr >> 8); - ahc_outb(ahc, SG_NEXT, sg_addr); - } - - ahc_outb(ahc, SCB_RESID_DCNT + 2, data_cnt >> 16); - ahc_outb(ahc, SCB_RESID_DCNT + 1, data_cnt >> 8); - ahc_outb(ahc, SCB_RESID_DCNT, data_cnt); - - ahc_outb(ahc, SHADDR + 3, data_addr >> 24); - ahc_outb(ahc, SHADDR + 2, data_addr >> 16); - ahc_outb(ahc, SHADDR + 1, data_addr >> 8); - ahc_outb(ahc, SHADDR, data_addr); - } - } -} - -static void ahc_handle_devreset(struct ahc_softc *ahc, int target, char channel, cam_status status, ac_code acode, char *message, int verbose_only) { struct ahc_devinfo devinfo; struct cam_path *path; + path_id_t path_id; int found; int error; - ahc_compile_devinfo(&devinfo, target, CAM_LUN_WILDCARD, channel, - ROLE_UNKNOWN); + ahc_compile_devinfo(&devinfo, target, channel); - error = ahc_create_path(ahc, &devinfo, &path); + if (channel == 'B') + path_id = cam_sim_path(ahc->sim_b); + else + path_id = cam_sim_path(ahc->sim); + error = xpt_create_path(&path, /*periph*/NULL, path_id, target, + CAM_LUN_WILDCARD); /* * Go back to async/narrow transfers and renegotiate. - * ahc_set_width and ahc_set_syncrate can cope with NULL - * paths. */ - ahc_set_width(ahc, &devinfo, path, MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_CUR); - ahc_set_syncrate(ahc, &devinfo, path, /*syncrate*/NULL, - /*period*/0, /*offset*/0, AHC_TRANS_CUR); - found = ahc_abort_scbs(ahc, target, channel, CAM_LUN_WILDCARD, + if (error == CAM_REQ_CMP) { + ahc_set_width(ahc, &devinfo, path, MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_CUR); + ahc_set_syncrate(ahc, &devinfo, path, /*syncrate*/NULL, + /*period*/0, /*offset*/0, AHC_TRANS_CUR); + } + found = ahc_abort_scbs(ahc, target, channel, ALL_LUNS, SCB_LIST_NULL, status); if (error == CAM_REQ_CMP && acode != 0) @@ -3064,6 +2346,8 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) ahc_index_busy_tcl(ahc, scb->hscb->tcl, /*unbusy*/TRUE); if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { + xpt_print_path(ccb->ccb_h.path); + printf("CONT_TARGET_IO complete\n"); ccb->ccb_h.status = CAM_REQ_CMP; ahc_free_scb(ahc, scb); xpt_done(ccb); @@ -3108,6 +2392,22 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) ccb->ccb_h.status); } + if ((scb->flags & (SCB_MSGOUT_WDTR|SCB_MSGOUT_SDTR)) != 0) { + /* + * Turn off the pending flags for any DTR messages + * regardless of whether they completed successfully + * or not. This ensures that we don't have lingering + * state after we abort an SCB. + */ + u_int16_t mask; + + mask = (0x01 << (SCB_TARGET(scb) + | (SCB_IS_SCSIBUS_B(scb) ? SELBUSB : 0))); + if (scb->flags & SCB_MSGOUT_WDTR) + ahc->wdtrpending &= ~mask; + if (scb->flags & SCB_MSGOUT_SDTR) + ahc->sdtrpending &= ~mask; + } /* Don't clobber any existing error state */ if (ahc_ccb_status(ccb) == CAM_REQ_INPROG) { ccb->ccb_h.status |= CAM_REQ_CMP; @@ -3150,7 +2450,6 @@ ahc_init(struct ahc_softc *ahc) int i; int term; u_int scsi_conf; - u_int scsiseq_template; #ifdef AHC_PRINT_SRAM printf("Scratch Ram:"); @@ -3179,21 +2478,11 @@ ahc_init(struct ahc_softc *ahc) } /* - * Default to allowing initiator operations. - */ - ahc->flags |= AHC_INITIATORMODE; - - /* * XXX Would be better to use a per device flag, but PCI and EISA * devices don't have them yet. */ - if ((AHC_TMODE_ENABLE & (0x01 << ahc->unit)) != 0) { + if ((AHC_TMODE_ENABLE & (0x01 << ahc->unit)) != 0) ahc->flags |= AHC_TARGETMODE; - if ((ahc->features & AHC_ULTRA2) == 0) - /* Only have space for both on the Ultra2 chips */ - ahc->flags &= ~AHC_INITIATORMODE; - } - if ((ahc->features & AHC_TWIN) != 0) { printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, primary %c, ", @@ -3246,10 +2535,18 @@ ahc_init(struct ahc_softc *ahc) if (ahc->scb_data->maxhscbs < AHC_SCB_MAX) { ahc->flags |= AHC_PAGESCBS; ahc->scb_data->maxscbs = AHC_SCB_MAX; + if ((ahc->flags & AHC_TARGETMODE) != 0) { + /* Steal one slot for TMODE commands */ + ahc->scb_data->maxscbs--; + } printf("%d/%d SCBs\n", ahc->scb_data->maxhscbs, ahc->scb_data->maxscbs); } else { ahc->scb_data->maxscbs = ahc->scb_data->maxhscbs; + if ((ahc->flags & AHC_TARGETMODE) != 0) { + /* Steal one slot for TMODE commands */ + ahc->scb_data->maxscbs--; + } ahc->flags &= ~AHC_PAGESCBS; printf("%d SCBs\n", ahc->scb_data->maxhscbs); } @@ -3283,14 +2580,13 @@ ahc_init(struct ahc_softc *ahc) ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); -#if 0 - if ((scsi_conf & RESET_SCSI) != 0 - && (ahc->flags & AHC_INITIATORMODE) != 0) - ahc->flags |= AHC_RESET_BUS_B; -#else - if ((ahc->flags & AHC_INITIATORMODE) != 0) - ahc->flags |= AHC_RESET_BUS_B; -#endif + if (scsi_conf & RESET_SCSI) { + /* Reset the bus */ + if (bootverbose) + printf("%s: Resetting Channel B\n", + ahc_name(ahc)); + ahc_reset_current_bus(ahc); + } /* Select Channel A */ ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); @@ -3318,14 +2614,14 @@ ahc_init(struct ahc_softc *ahc) ahc_name(ahc)); } -#if 0 - if ((scsi_conf & RESET_SCSI) != 0 - && (ahc->flags & AHC_INITIATORMODE) != 0) - ahc->flags |= AHC_RESET_BUS_A; -#else - if ((ahc->flags & AHC_INITIATORMODE) != 0) - ahc->flags |= AHC_RESET_BUS_A; -#endif + if (scsi_conf & RESET_SCSI) { + /* Reset the bus */ + if (bootverbose) + printf("%s: Resetting Channel %c\n", ahc_name(ahc), + ahc->channel); + + ahc_reset_current_bus(ahc); + } /* * Look at the information that board initialization or @@ -3337,7 +2633,7 @@ ahc_init(struct ahc_softc *ahc) * flag. */ ahc->ultraenb = 0; - ahc->tagenable = ALL_TARGETS_MASK; + ahc->tagenable = ALL_TARGETS; /* Grab the disconnection disable table and invert it for our needs */ if (ahc->flags & AHC_USEDEFAULTS) { @@ -3345,7 +2641,7 @@ ahc_init(struct ahc_softc *ahc) "device parameters\n", ahc_name(ahc)); ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B| AHC_TERM_ENB_A|AHC_TERM_ENB_B; - ahc->discenable = ALL_TARGETS_MASK; + ahc->discenable = ALL_TARGETS; if ((ahc->features & AHC_ULTRA) != 0) ahc->ultraenb = 0xffff; } else { @@ -3421,6 +2717,8 @@ ahc_init(struct ahc_softc *ahc) } } + ahc->sdtrpending = 0; + ahc->wdtrpending = 0; #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWMISC) @@ -3463,10 +2761,9 @@ ahc_init(struct ahc_softc *ahc) if ((ahc->flags & AHC_TARGETMODE) != 0) { size_t array_size; - array_size = AHC_TMODE_CMDS * sizeof(struct target_cmd); - ahc->targetcmds = contigmalloc(array_size, M_DEVBUF, - M_NOWAIT, 0ul, 0xffffffff, - PAGE_SIZE, 0x10000); + ahc->num_targetcmds = 32; + array_size = ahc->num_targetcmds * sizeof(struct target_cmd); + ahc->targetcmds = malloc(array_size, M_DEVBUF, M_NOWAIT); if (ahc->targetcmds == NULL) { printf("%s: unable to allocate targetcmd array. " @@ -3474,11 +2771,8 @@ ahc_init(struct ahc_softc *ahc) return (-1); } - /* All target command blocks start out invalid. */ - for (i = 0; i < AHC_TMODE_CMDS; i++) - ahc->targetcmds[i].cmd_valid = 0; - ahc_outb(ahc, KERNEL_TQINPOS, 0); - ahc_outb(ahc, TQINPOS, 0); + bzero(ahc->targetcmds, array_size); + ahc_outb(ahc, TMODE_CMDADDR_NEXT, 0); } /* @@ -3535,10 +2829,6 @@ ahc_init(struct ahc_softc *ahc) ahc_outb(ahc, QINPOS, 0); ahc_outb(ahc, QOUTPOS, 0); - /* Don't have any special messages to send to targets */ - ahc_outb(ahc, TARGET_MSG_REQUEST, 0); - ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0); - /* * Use the built in queue management registers * if they are available. @@ -3561,16 +2851,6 @@ ahc_init(struct ahc_softc *ahc) ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* - * Setup the allowed SCSI Sequences based on operational mode. - * If we are a target, we'll enalbe select in operations once - * we've had a lun enabled. - */ - scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP; - if ((ahc->flags & AHC_INITIATORMODE) != 0) - scsiseq_template |= ENRSELI; - ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template); - - /* * Load the Sequencer program and Enable the adapter * in "fast" mode. */ @@ -3586,6 +2866,21 @@ ahc_init(struct ahc_softc *ahc) return (0); } +static void +ahcminphys(struct buf *bp) +{ +/* + * Even though the card can transfer up to 16megs per command + * we are limited by the number of segments in the dma segment + * list that we can hold. The worst case is that all pages are + * discontinuous physically, hense the "page per segment" limit + * enforced here. + */ + if (bp->b_bcount > ((AHC_NSEG - 1) * PAGE_SIZE)) { + bp->b_bcount = ((AHC_NSEG - 1) * PAGE_SIZE); + } +} + static cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, struct tmode_tstate **tstate, struct tmode_lstate **lstate, @@ -3601,34 +2896,22 @@ ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, return (CAM_REQ_INVALID); /* Range check target and lun */ + if (cam_sim_bus(sim) == 0) + our_id = ahc->our_id; + else + our_id = ahc->our_id_b; + if (ccb->ccb_h.target_id > ((ahc->features & AHC_WIDE) ? 15 : 7) + || ((ahc->features & AHC_MULTI_TID) == 0 + && (ccb->ccb_h.target_id != our_id))) + return (CAM_TID_INVALID); - /* - * Handle the 'black hole' device that sucks up - * requests to unattached luns on enabled targets. - */ - if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD - && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { - *tstate = NULL; - *lstate = ahc->black_hole; - } else { - if (cam_sim_bus(sim) == 0) - our_id = ahc->our_id; - else - our_id = ahc->our_id_b; - if (ccb->ccb_h.target_id > ((ahc->features & AHC_WIDE) ? 15 : 7) - || ((ahc->features & AHC_MULTI_TID) == 0 - && (ccb->ccb_h.target_id != our_id))) - return (CAM_TID_INVALID); - - if (ccb->ccb_h.target_lun > 8) - return (CAM_LUN_INVALID); - - *tstate = ahc->enabled_targets[ccb->ccb_h.target_id]; - *lstate = NULL; - if (*tstate != NULL) - *lstate = - (*tstate)->enabled_luns[ccb->ccb_h.target_lun]; - } + if (ccb->ccb_h.target_lun > 8) + return (CAM_LUN_INVALID); + + *tstate = ahc->enabled_targets[ccb->ccb_h.target_id]; + *lstate = NULL; + if (*tstate != NULL) + *lstate = (*tstate)->enabled_luns[ccb->ccb_h.target_lun]; if (notfound_failure != 0 && *lstate == NULL) return (CAM_PATH_INVALID); @@ -3662,15 +2945,9 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) &lstate, TRUE); if (status != CAM_REQ_CMP) { - if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { - /* Response from the black hole device */ - tstate = NULL; - lstate = ahc->black_hole; - } else { - ccb->ccb_h.status = status; - xpt_done(ccb); - break; - } + ccb->ccb_h.status = status; + xpt_done(ccb); + break; } if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, @@ -3685,6 +2962,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) * the original command. */ target_id = ccb->csio.init_id; + xpt_print_path(ccb->ccb_h.path); + printf("Sending a continue TIO\n"); /* FALLTHROUGH */ } case XPT_SCSI_IO: /* Execute the requested I/O operation */ @@ -3746,7 +3025,21 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) hscb->control |= MK_MESSAGE; ahc_execute_scb(scb, NULL, 0, 0); } else { - if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { + if (ccb->ccb_h.func_code == XPT_SCSI_IO) { + if (tinfo->current.width != tinfo->goal.width) { + if ((ahc->wdtrpending & mask) == 0) { + ahc->wdtrpending |= mask; + hscb->control |= MK_MESSAGE; + scb->flags |= SCB_MSGOUT_WDTR; + } + } else if ((tinfo->current.period + != tinfo->goal.period) + && (ahc->sdtrpending & mask) == 0) { + ahc->sdtrpending |= mask; + hscb->control |= MK_MESSAGE; + scb->flags |= SCB_MSGOUT_SDTR; + } + } else { if (ahc->pending_device == lstate) { scb->flags |= SCB_TARGET_IMMEDIATE; ahc->pending_device = NULL; @@ -3797,14 +3090,105 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) break; } case XPT_EN_LUN: /* Enable LUN as a target */ - ahc_handle_en_lun(ahc, sim, ccb); - xpt_done(ccb); - break; - case XPT_ABORT: /* Abort the specified CCB */ { - ahc_abort_ccb(ahc, sim, ccb); + struct tmode_tstate *tstate; + struct tmode_lstate *lstate; + struct ccb_en_lun *cel; + cam_status status; + int target; + int lun; + + status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate, + /* notfound_failure*/FALSE); + + if (status != CAM_REQ_CMP) { + ccb->ccb_h.status = status; + xpt_done(ccb); + break; + } + + cel = &ccb->cel; + target = ccb->ccb_h.target_id; + lun = ccb->ccb_h.target_lun; + if (cel->enable != 0) { + /* Are we already enabled?? */ + if (lstate != NULL) { + ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; + xpt_done(ccb); + break; + } + + if (cel->grp6_len != 0 + || cel->grp7_len != 0) { + /* + * Don't (yet?) support vendor + * specific commands. + */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + } + + /* + * Seems to be okay. + * Setup our data structures. + */ + if (tstate == NULL) { + tstate = malloc(sizeof(*tstate), + M_DEVBUF, M_NOWAIT); + if (tstate == NULL) { + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + break; + } + bzero(tstate, sizeof(*tstate)); + ahc->enabled_targets[target] = tstate; + } + lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT); + if (lstate == NULL) { + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + break; + } + bzero(lstate, sizeof(*lstate)); + SLIST_INIT(&lstate->accept_tios); + SLIST_INIT(&lstate->immed_notifies); + tstate->enabled_luns[lun] = lstate; + if ((ahc->features & AHC_MULTI_TID) != 0) { + u_int16_t targid_mask; + + pause_sequencer(ahc); + targid_mask = ahc_inb(ahc, TARGID) + | (ahc_inb(ahc, TARGID + 1) << 8); + + targid_mask |= (0x01 << target); + ahc_outb(ahc, TARGID, targid_mask); + ahc_outb(ahc, TARGID+1, (targid_mask >> 8)); + unpause_sequencer(ahc, /*always?*/FALSE); + } + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_print_path(ccb->ccb_h.path); + printf("Lun now enabled for target mode\n"); + xpt_done(ccb); + break; + } else { + /* XXX Fully Implement Disable */ + if (lstate == NULL) { + ccb->ccb_h.status = CAM_LUN_INVALID; + xpt_done(ccb); + break; + } + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } break; } + case XPT_ABORT: /* Abort the specified CCB */ + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; case XPT_SET_TRAN_SETTINGS: { struct ahc_devinfo devinfo; @@ -3815,9 +3199,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) cts = &ccb->cts; ahc_compile_devinfo(&devinfo, cts->ccb_h.target_id, - cts->ccb_h.target_lun, - SIM_IS_SCSIBUS_B(ahc, sim) ? 'B' : 'A', - ROLE_UNKNOWN); + SIM_IS_SCSIBUS_B(ahc, sim) ? 'B' : 'A'); tinfo = &ahc->transinfo[devinfo.target_offset]; update_type = 0; if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) @@ -3853,8 +3235,10 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; break; } - ahc_set_width(ahc, &devinfo, cts->ccb_h.path, - cts->bus_width, update_type); + if ((update_type & AHC_TRANS_GOAL) != 0) + tinfo->goal.width = cts->bus_width; + if ((update_type & AHC_TRANS_USER) != 0) + tinfo->user.width = cts->bus_width; } if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) { @@ -3868,21 +3252,30 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) else maxsync = AHC_SYNCRATE_FAST; - if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) + if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) { + if (cts->sync_offset != 0) + cts->sync_offset = ~0; + } else { cts->sync_offset = 0; + } syncrate = ahc_find_syncrate(ahc, &cts->sync_period, maxsync); ahc_validate_offset(ahc, syncrate, &cts->sync_offset, - MSG_EXT_WDTR_BUS_8_BIT); + tinfo->goal.width); /* We use a period of 0 to represent async */ if (cts->sync_offset == 0) cts->sync_period = 0; - ahc_set_syncrate(ahc, &devinfo, cts->ccb_h.path, - syncrate, cts->sync_period, - cts->sync_offset, update_type); + if ((update_type & AHC_TRANS_GOAL) != 0) { + tinfo->goal.period = cts->sync_period; + tinfo->goal.offset = cts->sync_offset; + } + if ((update_type & AHC_TRANS_USER) != 0) { + tinfo->user.period = cts->sync_period; + tinfo->user.offset = cts->sync_offset; + } } splx(s); ccb->ccb_h.status = CAM_REQ_CMP; @@ -3900,9 +3293,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) cts = &ccb->cts; ahc_compile_devinfo(&devinfo, cts->ccb_h.target_id, - cts->ccb_h.target_lun, - SIM_IS_SCSIBUS_B(ahc, sim) ? 'B' : 'A', - ROLE_UNKNOWN); + SIM_IS_SCSIBUS_B(ahc, sim) ? 'B' : 'A'); targ_info = &ahc->transinfo[devinfo.target_offset]; if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) @@ -4007,20 +3398,14 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } else { cpi->target_sprt = 0; } - cpi->hba_misc = (ahc->flags & AHC_INITIATORMODE) - ? 0 : PIM_NOINITIATOR; + cpi->hba_misc = 0; cpi->hba_eng_cnt = 0; cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7; cpi->max_lun = 7; - if (SIM_IS_SCSIBUS_B(ahc, sim)) { + if (SIM_IS_SCSIBUS_B(ahc, sim)) cpi->initiator_id = ahc->our_id_b; - if ((ahc->flags & AHC_RESET_BUS_B) == 0) - cpi->hba_misc |= PIM_NOBUSRESET; - } else { + else cpi->initiator_id = ahc->our_id; - if ((ahc->flags & AHC_RESET_BUS_A) == 0) - cpi->hba_misc |= PIM_NOBUSRESET; - } cpi->bus_id = cam_sim_bus(sim); strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); @@ -4051,9 +3436,7 @@ ahc_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) struct ahc_devinfo devinfo; ahc_compile_devinfo(&devinfo, xpt_path_target_id(path), - xpt_path_lun_id(path), - SIM_IS_SCSIBUS_B(ahc, sim) ? 'B' : 'A', - ROLE_UNKNOWN); + SIM_IS_SCSIBUS_B(ahc, sim) ? 'B' : 'A'); /* * Revert to async/narrow transfers @@ -4152,12 +3535,12 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, (ccb->ccb_h.timeout * hz) / 1000); if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) { + xpt_print_path(ccb->ccb_h.path); + printf("Returning an immediate CTIO\n"); if ((ahc->flags & AHC_PAGESCBS) == 0) ahc_outb(ahc, SCBPTR, scb->hscb->tag); - pause_sequencer(ahc); ahc_outb(ahc, SCB_TAG, scb->hscb->tag); - ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP); - unpause_sequencer(ahc, /*unpause_always*/FALSE); + unpause_sequencer(ahc, /*unpause_always*/TRUE); } else { ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; @@ -4428,10 +3811,7 @@ ahc_loadseq(struct ahc_softc *ahc) u_int8_t download_consts[4]; /* Setup downloadable constant table */ -#if 0 - /* No downloaded constants are currently defined. */ download_consts[TMODE_NUMCMDS] = ahc->num_targetcmds; -#endif cur_patch = patches; downloaded = 0; @@ -4716,14 +4096,12 @@ ahc_timeout(void *arg) break; } - printf(", SEQADDR == 0x%x\n", - ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); - -#if 0 printf(", SCSISIGI == 0x%x\n", ahc_inb(ahc, SCSISIGI)); - printf("SIMODE1 = 0x%x\n", ahc_inb(ahc, SIMODE1)); - printf("INTSTAT = 0x%x\n", ahc_inb(ahc, INTSTAT)); + + printf("SEQADDR == 0x%x\n", ahc_inb(ahc, SEQADDR0) + | (ahc_inb(ahc, SEQADDR1) << 8)); printf("SSTAT1 == 0x%x\n", ahc_inb(ahc, SSTAT1)); +#if 0 printf("SCSIRATE == 0x%x\n", ahc_inb(ahc, SCSIRATE)); printf("CCSCBCTL == 0x%x\n", ahc_inb(ahc, CCSCBCTL)); printf("CCSCBCNT == 0x%x\n", ahc_inb(ahc, CCSCBCNT)); @@ -4731,6 +4109,7 @@ ahc_timeout(void *arg) printf("DFSTATUS == 0x%x\n", ahc_inb(ahc, DFSTATUS)); printf("CCHCNT == 0x%x\n", ahc_inb(ahc, CCHCNT)); #endif + /* Decide our course of action */ if (scb->flags & SCB_DEVICE_RESET) { /* * Been down this road before. @@ -4743,26 +4122,18 @@ bus_reset: "%d SCBs aborted\n", ahc_name(ahc), channel, found); } else { /* - * If we are a target, transition to bus free and report - * the timeout. - * - * The target/initiator that is holding up the bus may not + * Send a Bus Device Reset message: + * The target that is holding up the bus may not * be the same as the one that triggered this timeout * (different commands have different timeout lengths). - * If the bus is idle and we are actiing as the initiator - * for this request, queue a BDR message to the timed out - * target. Otherwise, if the timed out transaction is - * active: - * Initiator transaction: - * Stuff the message buffer with a BDR message and assert - * ATN in the hopes that the target will let go of the bus - * and go to the mesgout phase. If this fails, we'll - * get another timeout 2 seconds later which will attempt - * a bus reset. - * - * Target transaction: - * Transition to BUS FREE and report the error. - * It's good to be the target! + * Our strategy here is to queue a BDR message + * to the timed out target if the bus is idle. + * Otherwise, if we have an active target we stuff the + * message buffer with a BDR message and assert ATN + * in the hopes that the target will let go of the bus + * and go to the mesgout phase. If this fails, we'll + * get another timeout 2 seconds later which will attempt + * a bus reset. */ u_int active_scb_index; @@ -4793,25 +4164,7 @@ bus_reset: (newtimeout * hz) / 1000); splx(s); return; - } - - /* It's us */ - if ((scb->hscb->control & TARGET_SCB) != 0) { - - /* - * Send back any queued up transactions - * and properly record the error condition. - */ - ahc_freeze_devq(ahc, scb->ccb->ccb_h.path); - ahc_set_ccb_status(scb->ccb, CAM_CMD_TIMEOUT); - ahc_freeze_ccb(scb->ccb); - ahc_done(ahc, scb); - - /* Will clear us from the bus */ - restart_sequencer(ahc); - return; } - ahc_set_recoveryscb(ahc, active_scb); ahc_outb(ahc, MSG_OUT, MSG_BUS_DEV_RESET); ahc_outb(ahc, SCSISIGO, bus_state|ATNO); @@ -4824,15 +4177,6 @@ bus_reset: } else { int disconnected; - if (bus_state != P_BUSFREE - && (ahc_inb(ahc, SSTAT0) & TARGET) != 0) { - /* Hung target selection. Goto busfree */ - printf("%s: Hung target selection\n", - ahc_name(ahc)); - restart_sequencer(ahc); - return; - } - if (ahc_search_qinfifo(ahc, target, channel, lun, scb->hscb->tag, /*status*/0, SEARCH_COUNT) > 0) { @@ -4959,86 +4303,6 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, } -static void -ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) -{ - union ccb *abort_ccb; - - abort_ccb = ccb->cab.abort_ccb; - switch (abort_ccb->ccb_h.func_code) { - case XPT_ACCEPT_TARGET_IO: - case XPT_IMMED_NOTIFY: - case XPT_CONT_TARGET_IO: - { - struct tmode_tstate *tstate; - struct tmode_lstate *lstate; - struct ccb_hdr_slist *list; - cam_status status; - - status = ahc_find_tmode_devs(ahc, sim, abort_ccb, &tstate, - &lstate, TRUE); - - if (status != CAM_REQ_CMP) { - ccb->ccb_h.status = status; - break; - } - - if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) - list = &lstate->accept_tios; - else if (abort_ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) - list = &lstate->immed_notifies; - else - list = NULL; - - if (list != NULL) { - struct ccb_hdr *curelm; - int found; - - curelm = SLIST_FIRST(list); - found = 0; - if (curelm == &abort_ccb->ccb_h) { - found = 1; - SLIST_REMOVE_HEAD(list, sim_links.sle); - } else { - while(curelm != NULL) { - struct ccb_hdr *nextelm; - - nextelm = - SLIST_NEXT(curelm, sim_links.sle); - - if (nextelm == &abort_ccb->ccb_h) { - found = 1; - SLIST_NEXT(curelm, - sim_links.sle) = - SLIST_NEXT(nextelm, - sim_links.sle); - break; - } - curelm = nextelm; - } - } - - if (found) - abort_ccb->ccb_h.status = CAM_REQ_ABORTED; - else { - printf("Not found\n"); - ccb->ccb_h.status = CAM_PATH_INVALID; - } - break; - } - /* FALLTHROUGH */ - } - case XPT_SCSI_IO: - /* XXX Fully implement the hard ones */ - ccb->ccb_h.status = CAM_UA_ABORT; - break; - default: - ccb->ccb_h.status = CAM_REQ_INVALID; - break; - } - xpt_done(ccb); -} - /* * Abort all SCBs that match the given description (target/channel/lun/tag), * setting their status to the passed in status if the status has not already @@ -5303,9 +4567,8 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) * Clean up all the state information for the * pending transactions on this bus. */ - found = ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, channel, - CAM_LUN_WILDCARD, SCB_LIST_NULL, - CAM_SCSI_BUS_RESET); + found = ahc_abort_scbs(ahc, ALL_TARGETS, channel, ALL_LUNS, + SCB_LIST_NULL, CAM_SCSI_BUS_RESET); path = channel == 'B' ? ahc->path_b : ahc->path; /* Notify the XPT that a bus reset occurred */ @@ -5318,8 +4581,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) for (target = 0; target <= max_target; target++) { struct ahc_devinfo devinfo; - ahc_compile_devinfo(&devinfo, target, CAM_LUN_WILDCARD, - channel, ROLE_UNKNOWN); + ahc_compile_devinfo(&devinfo, target, channel); ahc_set_width(ahc, &devinfo, path, MSG_EXT_WDTR_BUS_8_BIT, AHC_TRANS_CUR); ahc_set_syncrate(ahc, &devinfo, path, /*syncrate*/NULL, @@ -5341,7 +4603,8 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) * upsetting the current bus. */ ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB); - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); + ahc_outb(ahc, SIMODE1, + ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENREQINIT)); ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); if (initiate_reset) @@ -5351,8 +4614,10 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) unpause_sequencer(ahc, /*unpause_always*/FALSE); } else { /* Case 2: A command from this bus is active or we're idle */ - ahc_clear_msg_state(ahc); - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); + ahc_outb(ahc, SIMODE1, + ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENREQINIT)); + ahc->flags &= ~AHC_HANDLING_REQINITS; + ahc->msg_type = MSG_TYPE_NONE; ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); if (initiate_reset) @@ -5373,9 +4638,9 @@ ahc_match_scb (struct scb *scb, int target, char channel, int lun, u_int tag) match = ((chan == channel) || (channel == ALL_CHANNELS)); if (match != 0) - match = ((targ == target) || (target == CAM_TARGET_WILDCARD)); + match = ((targ == target) || (target == ALL_TARGETS)); if (match != 0) - match = ((lun == slun) || (lun == CAM_LUN_WILDCARD)); + match = ((lun == slun) || (lun == ALL_LUNS)); if (match != 0) match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); @@ -5385,22 +4650,22 @@ ahc_match_scb (struct scb *scb, int target, char channel, int lun, u_int tag) static void ahc_construct_sdtr(struct ahc_softc *ahc, u_int period, u_int offset) { - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN; - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR; - ahc->msgout_buf[ahc->msgout_index++] = period; - ahc->msgout_buf[ahc->msgout_index++] = offset; - ahc->msgout_len += 5; + ahc->msg_buf[ahc->msg_index++] = MSG_EXTENDED; + ahc->msg_buf[ahc->msg_index++] = MSG_EXT_SDTR_LEN; + ahc->msg_buf[ahc->msg_index++] = MSG_EXT_SDTR; + ahc->msg_buf[ahc->msg_index++] = period; + ahc->msg_buf[ahc->msg_index++] = offset; + ahc->msg_len += 5; } static void ahc_construct_wdtr(struct ahc_softc *ahc, u_int bus_width) { - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR_LEN; - ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR; - ahc->msgout_buf[ahc->msgout_index++] = bus_width; - ahc->msgout_len += 4; + ahc->msg_buf[ahc->msg_index++] = MSG_EXTENDED; + ahc->msg_buf[ahc->msg_index++] = MSG_EXT_WDTR_LEN; + ahc->msg_buf[ahc->msg_index++] = MSG_EXT_WDTR; + ahc->msg_buf[ahc->msg_index++] = bus_width; + ahc->msg_len += 4; } static void @@ -5495,9 +4760,7 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc) pending_scb = (struct scb *)ccbh->ccb_scb_ptr; pending_hscb = pending_scb->hscb; ahc_compile_devinfo(&devinfo, SCB_TARGET(pending_scb), - SCB_LUN(pending_scb), - SCB_CHANNEL(pending_scb), - ROLE_UNKNOWN); + SCB_CHANNEL(pending_scb)); tinfo = &ahc->transinfo[devinfo.target_offset]; pending_hscb->control &= ~ULTRAENB; if ((ahc->ultraenb & devinfo.target_mask) != 0) @@ -5528,9 +4791,7 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc) pending_scb = ahc->scb_data->scbarray[scb_tag]; pending_hscb = pending_scb->hscb; ahc_compile_devinfo(&devinfo, SCB_TARGET(pending_scb), - SCB_LUN(pending_scb), - SCB_CHANNEL(pending_scb), - ROLE_UNKNOWN); + SCB_CHANNEL(pending_scb)); tinfo = &ahc->transinfo[devinfo.target_offset]; control = ahc_inb(ahc, SCB_CONTROL); control &= ~ULTRAENB; @@ -5544,7 +4805,6 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc) ahc_outb(ahc, SCBPTR, saved_scbptr); } -#if UNUSED static void ahc_dump_targcmd(struct target_cmd *cmd) { @@ -5552,9 +4812,9 @@ ahc_dump_targcmd(struct target_cmd *cmd) u_int8_t *last_byte; int i; - byte = &cmd->initiator_channel; + byte = &cmd->icl; /* Debugging info for received commands */ - last_byte = &cmd[1].initiator_channel; + last_byte = &cmd[1].icl; i = 0; while (byte < last_byte) { @@ -5570,7 +4830,6 @@ ahc_dump_targcmd(struct target_cmd *cmd) } } } -#endif static void ahc_shutdown(int howto, void *arg) |