diff options
| author | Justin T. Gibbs <gibbs@FreeBSD.org> | 1999-03-05 23:35:48 +0000 |
|---|---|---|
| committer | Justin T. Gibbs <gibbs@FreeBSD.org> | 1999-03-05 23:35:48 +0000 |
| commit | c562189829c1615c9ca97925efa1c799089dd024 (patch) | |
| tree | 1d9ee12019fa1a107812d2b3acc62fd6fdaf3be4 | |
| parent | f15aa8d8d944cf0bff05fa4da18984905b513a39 (diff) | |
Notes
| -rw-r--r-- | sys/dev/aic7xxx/aic7xxx.c | 802 | ||||
| -rw-r--r-- | sys/dev/aic7xxx/aic7xxx.h | 74 | ||||
| -rw-r--r-- | sys/dev/aic7xxx/aic7xxx.reg | 11 | ||||
| -rw-r--r-- | sys/dev/aic7xxx/aic7xxx.seq | 56 |
4 files changed, 667 insertions, 276 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index 22aa52def5cb..8a3eeb2855b5 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -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.16 1999/01/15 23:24:23 gibbs Exp $ + * $Id: aic7xxx.c,v 1.17 1999/02/11 07:07:27 gibbs Exp $ */ /* * A few notes on features of the driver. @@ -135,9 +135,16 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define ALL_CHANNELS '\0' #define ALL_TARGETS_MASK 0xFFFF +#define INITIATOR_WILDCARD (~0) #define SIM_IS_SCSIBUS_B(ahc, sim) \ - (sim == ahc->sim_b) + ((sim) == ahc->sim_b) +#define SIM_CHANNEL(ahc, sim) \ + (((sim) == ahc->sim_b) ? 'B' : 'A') +#define SIM_SCSI_ID(ahc, sim) \ + (((sim) == ahc->sim_b) ? ahc->our_id_b : ahc->our_id) +#define SIM_PATH(ahc, sim) \ + (((sim) == ahc->sim_b) ? ahc->path_b : ahc->path) #define SCB_IS_SCSIBUS_B(scb) \ (((scb)->hscb->tcl & SELBUSB) != 0) #define SCB_TARGET(scb) \ @@ -150,6 +157,10 @@ (SCB_TARGET(scb) + (SCB_IS_SCSIBUS_B(scb) ? 8 : 0)) #define SCB_TARGET_MASK(scb) \ (0x01 << (SCB_TARGET_OFFSET(scb))) +#define TCL_CHANNEL(ahc, tcl) \ + ((((ahc)->features & AHC_TWIN) && ((tcl) & SELBUSB)) ? 'B' : 'A') +#define TCL_TARGET(tcl) (((tcl) & TID) >> TCL_TARGET_SHIFT) +#define TCL_LUN(tcl) ((tcl) & LID) #define ccb_scb_ptr spriv_ptr0 #define ccb_ahc_ptr spriv_ptr1 @@ -161,6 +172,7 @@ typedef enum { } role_t; struct ahc_devinfo { + int our_scsiid; int target_offset; u_int16_t target_mask; u_int8_t target; @@ -212,13 +224,21 @@ static struct scb * static void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb); static struct scb * ahc_alloc_scb(struct ahc_softc *ahc); +static void ahc_scb_devinfo(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct scb *scb); static void ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); -static void ahc_compile_devinfo(struct ahc_devinfo *devinfo, +static void ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, u_int lun, char channel, role_t role); 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 struct tmode_tstate * + ahc_alloc_tstate(struct ahc_softc *ahc, + u_int scsi_id, char channel); +static void ahc_free_tstate(struct ahc_softc *ahc, + u_int scsi_id, char channel, int force); 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, @@ -242,9 +262,10 @@ static int ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, 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, +static void ahc_handle_devreset(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + cam_status status, ac_code acode, + char *message, int verbose_only); static void ahc_loadseq(struct ahc_softc *ahc); static int ahc_check_patch(struct ahc_softc *ahc, @@ -286,7 +307,7 @@ static void ahc_validate_offset(struct ahc_softc *ahc, 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, + struct ahc_initiator_tinfo *tinfo, int force); static int ahc_create_path(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, @@ -299,6 +320,9 @@ static void ahc_set_syncrate(struct ahc_softc *ahc, static void ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct cam_path *path, u_int width, u_int type); +static void ahc_set_tags(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + int enable); static void ahc_construct_sdtr(struct ahc_softc *ahc, u_int period, u_int offset); @@ -326,6 +350,13 @@ static __inline void ahc_freeze_ccb(union ccb* ccb); static __inline cam_status ahc_ccb_status(union ccb* ccb); static __inline void ahc_set_ccb_status(union ccb* ccb, cam_status status); +static __inline void ahc_run_tqinfifo(struct ahc_softc *ahc); + +static __inline struct ahc_initiator_tinfo * + ahc_fetch_transinfo(struct ahc_softc *ahc, + char channel, + u_int our_id, u_int target, + struct tmode_tstate **tstate); static __inline u_int32_t ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index) @@ -413,6 +444,51 @@ ahc_set_ccb_status(union ccb* ccb, cam_status status) ccb->ccb_h.status |= status; } +static __inline struct ahc_initiator_tinfo * +ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, + u_int remote_id, struct tmode_tstate **tstate) +{ + /* + * Transfer data structures are stored from the perspective + * of the target role. Since the parameters for a connection + * in the initiator role to a given target are the same as + * when the roles are reversed, we pretend we are the target. + */ + if (channel == 'B') + our_id += 8; + *tstate = ahc->enabled_targets[our_id]; + return (&(*tstate)->transinfo[remote_id]); +} + +static __inline void +ahc_run_tqinfifo(struct ahc_softc *ahc) +{ + struct target_cmd *cmd; + + while ((cmd = &ahc->targetcmds[ahc->tqinfifonext])->cmd_valid != 0) { + + /* + * 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; + + /* + * Lazily update our position in the target mode incomming + * command queue as seen by the sequencer. + */ + if ((ahc->tqinfifonext & (TQINFIFO_UPDATE_CNT-1)) == 0) { + pause_sequencer(ahc); + ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); + unpause_sequencer(ahc, /*unpause_always*/FALSE); + } + } +} + char * ahc_name(struct ahc_softc *ahc) { @@ -723,7 +799,7 @@ 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, + struct ahc_initiator_tinfo *tinfo, int force) { int paused; @@ -776,7 +852,8 @@ 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; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; u_int old_period; u_int old_offset; @@ -785,7 +862,8 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, offset = 0; } - tinfo = &ahc->transinfo[devinfo->target_offset]; + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); old_period = tinfo->current.period; old_offset = tinfo->current.offset; @@ -812,10 +890,11 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, * Ensure Ultra mode is set properly for * this target. */ - ahc->ultraenb &= ~devinfo->target_mask; + tstate->ultraenb &= ~devinfo->target_mask; if (syncrate != NULL) { if (syncrate->sxfr & ULTRA_SXFR) { - ahc->ultraenb |= devinfo->target_mask; + tstate->ultraenb |= + devinfo->target_mask; } scsirate |= syncrate->sxfr & SXFR; scsirate |= offset & SOFS; @@ -825,7 +904,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, sxfrctl0 = ahc_inb(ahc, SXFRCTL0); sxfrctl0 &= ~FAST20; - if (ahc->ultraenb & devinfo->target_mask) + if (tstate->ultraenb & devinfo->target_mask) sxfrctl0 |= FAST20; ahc_outb(ahc, SXFRCTL0, sxfrctl0); } @@ -900,10 +979,12 @@ 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; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; u_int oldwidth; - tinfo = &ahc->transinfo[devinfo->target_offset]; + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); oldwidth = tinfo->current.width; if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { @@ -960,6 +1041,21 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc_update_target_msg_request(ahc, devinfo, tinfo, /*force*/FALSE); } +static void +ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int enable) +{ + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + + if (enable) + tstate->tagenable |= devinfo->target_mask; + else + tstate->tagenable &= ~devinfo->target_mask; +} + /* * Attach all the sub-devices we can find */ @@ -1087,26 +1183,56 @@ fail: } static void +ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct scb *scb) +{ + role_t role; + int our_id; + + if (scb->ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { + our_id = scb->ccb->ccb_h.target_id; + role = ROLE_TARGET; + } else { + our_id = SCB_CHANNEL(scb) == 'B' ? ahc->our_id_b : ahc->our_id; + role = ROLE_INITIATOR; + } + ahc_compile_devinfo(devinfo, our_id, SCB_TARGET(scb), + SCB_LUN(scb), SCB_CHANNEL(scb), role); +} + +static void ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { - u_int saved_tcl; - role_t role; + u_int saved_tcl; + role_t role; + int our_id; if (ahc_inb(ahc, SSTAT0) & TARGET) role = ROLE_TARGET; else role = ROLE_INITIATOR; + if (role == ROLE_TARGET + && (ahc->features & AHC_MULTI_TID) != 0 + && (ahc_inb(ahc, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) { + /* We were selected, so pull our id from TARGIDIN */ + our_id = ahc_inb(ahc, TARGIDIN) & OID; + } else if ((ahc->features & AHC_ULTRA2) != 0) + our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; + else + our_id = ahc_inb(ahc, SCSIID) & OID; + saved_tcl = ahc_inb(ahc, SAVED_TCL); - ahc_compile_devinfo(devinfo, (saved_tcl >> 4) & 0x0f, - saved_tcl & 0x3, (saved_tcl & SELBUSB) ? 'B': 'A', + ahc_compile_devinfo(devinfo, our_id, TCL_TARGET(saved_tcl), + TCL_LUN(saved_tcl), TCL_CHANNEL(ahc, saved_tcl), role); } 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 our_id, u_int target, + u_int lun, char channel, role_t role) { + devinfo->our_scsiid = our_id; devinfo->target = target; devinfo->lun = lun; devinfo->target_offset = target; @@ -1180,20 +1306,7 @@ ahc_intr(void *arg) } 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; - } + ahc_run_tqinfifo(ahc); } } if (intstat & BRKADRINT) { @@ -1223,6 +1336,68 @@ ahc_intr(void *arg) ahc_handle_scsiint(ahc, intstat); } +static struct tmode_tstate * +ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) +{ + struct tmode_tstate *master_tstate; + struct tmode_tstate *tstate; + int i; + + master_tstate = ahc->enabled_targets[ahc->our_id]; + if (channel == 'B') { + scsi_id += 8; + master_tstate = ahc->enabled_targets[ahc->our_id_b + 8]; + } + if (ahc->enabled_targets[scsi_id] != NULL + && ahc->enabled_targets[scsi_id] != master_tstate) + panic("%s: ahc_alloc_tstate - Target already allocated", + ahc_name(ahc)); + tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT); + if (tstate == NULL) + return (NULL); + + /* + * If we have allocated a master tstate, copy user settings from + * the master tstate (taken from SRAM or the EEPROM) for this + * channel, but reset our current and goal settings to async/narrow + * until an initiator talks to us. + */ + if (master_tstate != NULL) { + bcopy(master_tstate, tstate, sizeof(*tstate)); + bzero(tstate->enabled_luns, sizeof(tstate->enabled_luns)); + tstate->ultraenb = 0; + for (i = 0; i < 16; i++) { + bzero(&tstate->transinfo[i].current, + sizeof(tstate->transinfo[i].current)); + bzero(&tstate->transinfo[i].goal, + sizeof(tstate->transinfo[i].goal)); + } + } else + bzero(tstate, sizeof(*tstate)); + ahc->enabled_targets[scsi_id] = tstate; + return (tstate); +} + +static void +ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) +{ + struct tmode_tstate *tstate; + + /* Don't clean up the entry for our initiator role */ + if ((ahc->flags & AHC_INITIATORMODE) != 0 + && ((channel == 'B' && scsi_id == ahc->our_id_b) + || (channel == 'A' && scsi_id == ahc->our_id)) + && force == FALSE) + return; + + if (channel == 'B') + scsi_id += 8; + tstate = ahc->enabled_targets[scsi_id]; + if (tstate != NULL) + free(tstate, M_DEVBUF); + ahc->enabled_targets[scsi_id] = NULL; +} + static void ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) { @@ -1232,6 +1407,8 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) cam_status status; int target; int lun; + u_int target_mask; + char channel; status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate, /* notfound_failure*/FALSE); @@ -1244,11 +1421,17 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) cel = &ccb->cel; target = ccb->ccb_h.target_id; lun = ccb->ccb_h.target_lun; + channel = SIM_CHANNEL(ahc, sim); + target_mask = 0x01 << target; + if (channel == 'B') + target_mask <<= 8; + if (cel->enable != 0) { u_int scsiseq; /* Are we already enabled?? */ if (lstate != NULL) { + printf("Lun already enabled\n"); ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; return; } @@ -1260,6 +1443,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) * specific commands. */ ccb->ccb_h.status = CAM_REQ_INVALID; + printf("Non-zero Group Codes\n"); return; } @@ -1268,38 +1452,75 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) * Setup our data structures. */ if (target != CAM_TARGET_WILDCARD && tstate == NULL) { - tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT); + tstate = ahc_alloc_tstate(ahc, target, channel); if (tstate == NULL) { + printf("Couldn't allocate tstate\n"); 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) { + printf("Couldn't allocate lstate\n"); ccb->ccb_h.status = CAM_RESRC_UNAVAIL; return; } bzero(lstate, sizeof(*lstate)); SLIST_INIT(&lstate->accept_tios); SLIST_INIT(&lstate->immed_notifies); + pause_sequencer(ahc); 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); + if ((ahc->features & AHC_MULTI_TID) != 0) { + u_int16_t targid_mask; - targid_mask |= (0x01 << target); - ahc_outb(ahc, TARGID, targid_mask); - ahc_outb(ahc, TARGID+1, (targid_mask >> 8)); - } + targid_mask = ahc_inb(ahc, TARGID) + | (ahc_inb(ahc, TARGID + 1) << 8); + + targid_mask |= target_mask; + ahc_outb(ahc, TARGID, targid_mask); + ahc_outb(ahc, TARGID+1, (targid_mask >> 8)); + } else { + int our_id; + char channel; + + channel = SIM_CHANNEL(ahc, sim); + our_id = SIM_SCSI_ID(ahc, sim); + + /* + * This can only happen if selections + * are not enabled + */ + if (target != our_id) { + u_int sblkctl; + char cur_channel; + int swap; + + sblkctl = ahc_inb(ahc, SBLKCTL); + cur_channel = (sblkctl & SELBUSB) + ? 'B' : 'A'; + if ((ahc->features & AHC_TWIN) == 0) + cur_channel = 'A'; + swap = cur_channel != channel; + if (channel == 'A') + ahc->our_id = target; + else + ahc->our_id_b = target; + + if (swap) + ahc_outb(ahc, SBLKCTL, + sblkctl ^ SELBUSB); + + ahc_outb(ahc, SCSIID, target); + + if (swap) + ahc_outb(ahc, SBLKCTL, sblkctl); + } + } + } else + ahc->black_hole = lstate; /* Allow select-in operations */ if (ahc->black_hole != NULL && ahc->enabled_luns > 0) { scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); @@ -1313,7 +1534,6 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) 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; @@ -1359,9 +1579,10 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) empty = 0; break; } + if (empty) { - free(tstate, M_DEVBUF); - ahc->enabled_targets[target] = NULL; + ahc_free_tstate(ahc, target, channel, + /*force*/FALSE); if (ahc->features & AHC_MULTI_TID) { u_int16_t targid_mask; @@ -1370,19 +1591,12 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) | (ahc_inb(ahc, TARGID + 1) << 8); - targid_mask &= (0x01 << target); + targid_mask &= ~target_mask; 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 { @@ -1394,7 +1608,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) */ empty = TRUE; } - if (empty) { + if (ahc->enabled_luns == 0) { /* Disallow select-in */ u_int scsiseq; @@ -1435,26 +1649,30 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) * Commands for disabled luns go to the black hole driver. */ 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); } if (atio == NULL) { + ahc->flags |= AHC_TQINFIFO_BLOCKED; printf("No ATIOs for incoming command\n"); /* * Wait for more ATIOs from the peripheral driver for this lun. */ return (1); - } + } else + ahc->flags &= ~AHC_TQINFIFO_BLOCKED; SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); + if (lstate == ahc->black_hole) { + /* Fill in the wildcards */ + atio->ccb_h.target_id = target; + atio->ccb_h.target_lun = lun; + } + /* * Package it up and send it off to * whomever has this lun enabled. @@ -1503,6 +1721,10 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) * continue target I/O comes in response * to this accept tio. */ +#if 0 + printf("Received Immediate Command %d:%d:%d - %p\n", + initiator, target, lun, ahc->pending_device); +#endif ahc->pending_device = lstate; } xpt_done((union ccb*)atio); @@ -1646,7 +1868,8 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) struct ahc_dma_seg *sg = scb->ahc_dma; struct scsi_sense *sc = (struct scsi_sense *)(&hscb->cmdstore); - struct ahc_target_tinfo *tinfo; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; /* * Save off the residual if there is one. @@ -1690,7 +1913,11 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) * way has lost our transfer negotiations. * Renegotiate if appropriate. */ - tinfo = &ahc->transinfo[devinfo.target_offset]; + tinfo = ahc_fetch_transinfo(ahc, + devinfo.channel, + devinfo.our_scsiid, + devinfo.target, + &tstate); ahc_update_target_msg_request(ahc, &devinfo, tinfo, /*force*/TRUE); @@ -1830,11 +2057,13 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) printf("%s seen Data Phase. Length = %d. NumSGs = %d.\n", ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", scb->ccb->csio.dxfer_len, scb->sg_count); - for (i = 0; i < scb->sg_count - 1; i++) { - printf("sg[%d] - Addr 0x%x : Length %d\n", - i, - scb->ahc_dma[i].addr, - scb->ahc_dma[i].len); + if (scb->sg_count > 0) { + for (i = 0; i < scb->sg_count - 1; i++) { + printf("sg[%d] - Addr 0x%x : Length %d\n", + i, + scb->ahc_dma[i].addr, + scb->ahc_dma[i].len); + } } /* * Set this and it will take affect when the @@ -1974,12 +2203,17 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) printerror = 0; break; case MSG_BUS_DEV_RESET: - ahc_handle_devreset(ahc, target, channel, + { + struct ahc_devinfo devinfo; + + ahc_scb_devinfo(ahc, &devinfo, scb); + ahc_handle_devreset(ahc, &devinfo, CAM_BDR_SENT, AC_SENT_BDR, "Bus Device Reset", /*verbose_only*/FALSE); printerror = 0; break; + } default: break; } @@ -2030,8 +2264,10 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) "valid during SELTO scb(%d, %d)\n", ahc_name(ahc), scbptr, scb_index); } else { - ahc_handle_devreset(ahc, SCB_TARGET(scb), - SCB_CHANNEL(scb), CAM_SEL_TIMEOUT, + struct ahc_devinfo devinfo; + + ahc_scb_devinfo(ahc, &devinfo, scb); + ahc_handle_devreset(ahc, &devinfo, CAM_SEL_TIMEOUT, /*ac_code*/0, "Selection Timeout", /*verbose_only*/TRUE); } @@ -2134,11 +2370,13 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) * If our current and goal settings are identical, * we want to renegotiate due to a check condition. */ - struct ahc_target_tinfo *tinfo; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; int dowide; int dosync; - tinfo = &ahc->transinfo[devinfo->target_offset]; + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); dowide = tinfo->current.width != tinfo->goal.width; dosync = tinfo->current.period != tinfo->goal.period; @@ -2269,7 +2507,8 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) last_msg = ahc_inb(ahc, LAST_MSG); if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/FALSE)) { - struct ahc_target_tinfo *tinfo; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; /* note 8bit xfers and clear flag */ printf("%s:%c:%d: refuses WIDE negotiation. Using " @@ -2281,7 +2520,9 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) 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]; + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, + devinfo->our_scsiid, + devinfo->target, &tstate); if (tinfo->goal.period) { u_int period; @@ -2311,7 +2552,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) "non-tagged I/O\n", ahc_name(ahc), devinfo->channel, devinfo->target); - ahc->tagenable &= ~devinfo->target_mask; + ahc_set_tags(ahc, devinfo, FALSE); neg.flags = 0; neg.valid = CCB_TRANS_TQ_VALID; xpt_setup_ccb(&neg.ccb_h, scb->ccb->ccb_h.path, /*priority*/1); @@ -2643,15 +2884,20 @@ static int ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, struct ahc_devinfo *devinfo) { - int reject; - int done; - int response; - u_int targ_scsirate; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + int reject; + int done; + int response; + u_int targ_scsirate; done = FALSE; response = FALSE; reject = FALSE; - targ_scsirate = ahc->transinfo[devinfo->target_offset].scsirate; + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + targ_scsirate = tinfo->scsirate; + /* * Parse as much of the message as is availible, * rejecting it if we don't support it. When @@ -2672,9 +2918,6 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, 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 @@ -2840,9 +3083,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct cam_path *path, /*syncrate*/NULL, /*period*/0, /*offset*/0, AHC_TRANS_ACTIVE); if (sending_reply == FALSE && reject == FALSE) { - struct ahc_target_tinfo *tinfo; - tinfo = &ahc->transinfo[devinfo->target_offset]; if (tinfo->goal.period) { struct ahc_syncrate *rate; u_int period; @@ -2989,31 +3230,27 @@ 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, +ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, cam_status status, ac_code acode, char *message, int verbose_only) { - struct ahc_devinfo devinfo; struct cam_path *path; int found; int error; - ahc_compile_devinfo(&devinfo, target, CAM_LUN_WILDCARD, channel, - ROLE_UNKNOWN); - - error = ahc_create_path(ahc, &devinfo, &path); + error = ahc_create_path(ahc, devinfo, &path); /* * 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_set_width(ahc, devinfo, path, MSG_EXT_WDTR_BUS_8_BIT, AHC_TRANS_CUR); - ahc_set_syncrate(ahc, &devinfo, path, /*syncrate*/NULL, + 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, - SCB_LIST_NULL, status); + found = ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, + CAM_LUN_WILDCARD, SCB_LIST_NULL, status); if (error == CAM_REQ_CMP && acode != 0) xpt_async(AC_SENT_BDR, path, NULL); @@ -3024,7 +3261,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, int target, char channel, if (message != NULL && (verbose_only == 0 || bootverbose != 0)) printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc), - message, channel, target, found); + message, devinfo->channel, devinfo->target, found); } /* @@ -3151,6 +3388,9 @@ ahc_init(struct ahc_softc *ahc) int term; u_int scsi_conf; u_int scsiseq_template; + u_int ultraenb; + u_int discenable; + u_int tagenable; #ifdef AHC_PRINT_SRAM printf("Scratch Ram:"); @@ -3189,13 +3429,35 @@ ahc_init(struct ahc_softc *ahc) */ 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; + /* + * Although we have space for both the initiator and + * target roles on ULTRA2 chips, we currently disable + * the initiator role to allow multi-scsi-id target mode + * configurations. We can only respond on the same SCSI + * ID as our initiator role if we allow initiator operation. + * At some point, we should add a configuration knob to + * allow both roles to be loaded. + */ + ahc->flags &= ~AHC_INITIATORMODE; } + /* + * Allocate a tstate to house information for our + * initiator presence on the bus as well as the user + * data for any target mode initiator. + */ + if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { + printf("%s: unable to allocate tmode_tstate. " + "Failing attach\n", ahc_name(ahc)); + return (-1); + } if ((ahc->features & AHC_TWIN) != 0) { + if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { + printf("%s: unable to allocate tmode_tstate. " + "Failing attach\n", ahc_name(ahc)); + return (-1); + } printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, primary %c, ", ahc->our_id, ahc->our_id_b, ahc->flags & AHC_CHANNEL_B_PRIMARY? 'B': 'A'); @@ -3336,8 +3598,8 @@ ahc_init(struct ahc_softc *ahc) * negotiation to that target so we don't activate the needsdtr * flag. */ - ahc->ultraenb = 0; - ahc->tagenable = ALL_TARGETS_MASK; + ultraenb = 0; + tagenable = ALL_TARGETS_MASK; /* Grab the disconnection disable table and invert it for our needs */ if (ahc->flags & AHC_USEDEFAULTS) { @@ -3345,14 +3607,14 @@ 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; + discenable = ALL_TARGETS_MASK; if ((ahc->features & AHC_ULTRA) != 0) - ahc->ultraenb = ALL_TARGETS_MASK; + ultraenb = ALL_TARGETS_MASK; } else { - ahc->discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8) - | ahc_inb(ahc, DISC_DSB)); + discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8) + | ahc_inb(ahc, DISC_DSB)); if ((ahc->features & (AHC_ULTRA|AHC_ULTRA2)) != 0) - ahc->ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8) + ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8) | ahc_inb(ahc, ULTRA_ENB); } @@ -3360,21 +3622,34 @@ ahc_init(struct ahc_softc *ahc) max_targ = 7; for (i = 0; i <= max_targ; i++) { - struct ahc_target_tinfo *transinfo; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int our_id; + u_int target_id; + char channel; - transinfo = &ahc->transinfo[i]; + channel = 'A'; + our_id = ahc->our_id; + target_id = i; + if (i > 7 && (ahc->features & AHC_TWIN) != 0) { + channel = 'B'; + our_id = ahc->our_id_b; + target_id = i % 8; + } + tinfo = ahc_fetch_transinfo(ahc, channel, our_id, + target_id, &tstate); /* Default to async narrow across the board */ - bzero(transinfo, sizeof(*transinfo)); + bzero(tinfo, sizeof(*tinfo)); if (ahc->flags & AHC_USEDEFAULTS) { if ((ahc->features & AHC_WIDE) != 0) - transinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; + tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; /* * These will be truncated when we determine the * connection type we have with the target. */ - transinfo->user.period = ahc_syncrates->period; - transinfo->user.offset = ~0; + tinfo->user.period = ahc_syncrates->period; + tinfo->user.offset = ~0; } else { u_int scsirate; u_int16_t mask; @@ -3391,7 +3666,7 @@ ahc_init(struct ahc_softc *ahc) * so the format is different. */ scsirate = (scsirate & SXFR) >> 4 - | (ahc->ultraenb & mask) + | (ultraenb & mask) ? 0x18 : 0x10 | (scsirate & WIDEXFER); offset = MAX_OFFSET_ULTRA2; @@ -3400,26 +3675,27 @@ ahc_init(struct ahc_softc *ahc) ahc_find_period(ahc, scsirate, AHC_SYNCRATE_ULTRA2); if (offset == 0) - transinfo->user.period = 0; + tinfo->user.period = 0; else - transinfo->user.offset = ~0; + tinfo->user.offset = ~0; } else if ((scsirate & SOFS) != 0) { - transinfo->user.period = + tinfo->user.period = ahc_find_period(ahc, scsirate, - (ahc->ultraenb & mask) + (ultraenb & mask) ? AHC_SYNCRATE_ULTRA : AHC_SYNCRATE_FAST); if ((scsirate & SOFS) != 0 - && transinfo->user.period != 0) { - transinfo->user.offset = ~0; + && tinfo->user.period != 0) { + tinfo->user.offset = ~0; } } if ((scsirate & WIDEXFER) != 0 - && (ahc->features & AHC_WIDE) != 0) { - transinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; - } - + && (ahc->features & AHC_WIDE) != 0) + tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; } + tstate->ultraenb = ultraenb; + tstate->discenable = discenable; + tstate->tagenable = tagenable; } #ifdef AHC_DEBUG @@ -3427,7 +3703,7 @@ ahc_init(struct ahc_softc *ahc) printf("NEEDSDTR == 0x%x\nNEEDWDTR == 0x%x\n" "DISCENABLE == 0x%x\nULTRAENB == 0x%x\n", ahc->needsdtr_orig, ahc->needwdtr_orig, - ahc->discenable, ahc->ultraenb); + discenable, ultraenb); #endif /* * Allocate enough "hardware scbs" to handle @@ -3477,7 +3753,7 @@ ahc_init(struct ahc_softc *ahc) /* 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, KERNEL_TQINPOS, ahc->tqinfifonext - 1); ahc_outb(ahc, TQINPOS, 0); } @@ -3611,18 +3887,45 @@ ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, *tstate = NULL; *lstate = ahc->black_hole; } else { + u_int max_id; + 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))) + + max_id = (ahc->features & AHC_WIDE) ? 15 : 7; + if (ccb->ccb_h.target_id > max_id) return (CAM_TID_INVALID); - if (ccb->ccb_h.target_lun > 8) + if (ccb->ccb_h.target_lun > 7) return (CAM_LUN_INVALID); + if (ccb->ccb_h.target_id != our_id) { + if ((ahc->features & AHC_MULTI_TID) != 0) { + /* + * Only allow additional targets if + * the initiator role is disabled. + * The hardware cannot handle a re-select-in + * on the initiator id during a re-select-out + * on a different target id. + */ + if ((ahc->flags & AHC_INITIATORMODE) != 0) + return (CAM_TID_INVALID); + } else { + /* + * Only allow our target id to change + * if the initiator role is not configured + * and there are no enabled luns which + * are attached to the currently registered + * scsi id. + */ + if ((ahc->flags & AHC_INITIATORMODE) != 0 + || ahc->enabled_luns > 0) + return (CAM_TID_INVALID); + } + } + *tstate = ahc->enabled_targets[ccb->ccb_h.target_id]; *lstate = NULL; if (*tstate != NULL) @@ -3639,16 +3942,18 @@ ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, static void ahc_action(struct cam_sim *sim, union ccb *ccb) { - struct ahc_softc *ahc; - struct tmode_lstate *lstate; - int target_id; - int s; + struct ahc_softc *ahc; + struct tmode_lstate *lstate; + u_int target_id; + u_int our_id; + int s; CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahc_action\n")); ahc = (struct ahc_softc *)cam_sim_softc(sim); target_id = ccb->ccb_h.target_id; + our_id = SIM_SCSI_ID(ahc, sim); switch (ccb->ccb_h.func_code) { /* Common cases first */ @@ -3676,6 +3981,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h, sim_links.sle); ccb->ccb_h.status = CAM_REQ_INPROG; + if ((ahc->flags & AHC_TQINFIFO_BLOCKED) != 0) + ahc_run_tqinfifo(ahc); break; } @@ -3684,6 +3991,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) * select. In target mode, this is the initiator of * the original command. */ + our_id = target_id; target_id = ccb->csio.init_id; /* FALLTHROUGH */ } @@ -3692,7 +4000,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) { struct scb *scb; struct hardware_scb *hscb; - struct ahc_target_tinfo *tinfo; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; u_int16_t mask; /* @@ -3729,14 +4038,15 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) | (ccb->ccb_h.target_lun & 0x07); mask = SCB_TARGET_MASK(scb); - tinfo = &ahc->transinfo[SCB_TARGET_OFFSET(scb)]; + tinfo = ahc_fetch_transinfo(ahc, SIM_CHANNEL(ahc, sim), our_id, + target_id, &tstate); hscb->scsirate = tinfo->scsirate; hscb->scsioffset = tinfo->current.offset; - if ((ahc->ultraenb & mask) != 0) + if ((tstate->ultraenb & mask) != 0) hscb->control |= ULTRAENB; - if ((ahc->discenable & mask) != 0 + if ((tstate->discenable & mask) != 0 && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) hscb->control |= DISCENB; @@ -3761,10 +4071,11 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) /* Overloaded with tag ID */ hscb->cmdlen = ccb->csio.tag_id; /* - * Overloaded with our target ID to - * use for reselection. + * Overloaded with the value to place + * in SCSIID for reselection. */ - hscb->next = ccb->ccb_h.target_id; + hscb->cmdpointer |= + (our_id|(hscb->tcl & 0xF0)) << 16; } if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) hscb->control |= ccb->csio.tag_action; @@ -3807,18 +4118,22 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } case XPT_SET_TRAN_SETTINGS: { - struct ahc_devinfo devinfo; - struct ccb_trans_settings *cts; - struct ahc_target_tinfo *tinfo; - u_int update_type; - int s; + struct ahc_devinfo devinfo; + struct ccb_trans_settings *cts; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int update_type; + int s; cts = &ccb->cts; - ahc_compile_devinfo(&devinfo, cts->ccb_h.target_id, + ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim), + cts->ccb_h.target_id, cts->ccb_h.target_lun, - SIM_IS_SCSIBUS_B(ahc, sim) ? 'B' : 'A', + SIM_CHANNEL(ahc, sim), ROLE_UNKNOWN); - tinfo = &ahc->transinfo[devinfo.target_offset]; + tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, + devinfo.our_scsiid, + devinfo.target, &tstate); update_type = 0; if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) update_type |= AHC_TRANS_GOAL; @@ -3829,16 +4144,16 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) - ahc->discenable |= devinfo.target_mask; + tstate->discenable |= devinfo.target_mask; else - ahc->discenable &= ~devinfo.target_mask; + tstate->discenable &= ~devinfo.target_mask; } if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) - ahc->tagenable |= devinfo.target_mask; + tstate->tagenable |= devinfo.target_mask; else - ahc->tagenable &= ~devinfo.target_mask; + tstate->tagenable &= ~devinfo.target_mask; } if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { @@ -3869,7 +4184,10 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) maxsync = AHC_SYNCRATE_FAST; if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) - cts->sync_offset = 0; + if (update_type & AHC_TRANS_USER) + cts->sync_offset = tinfo->user.offset; + else + cts->sync_offset = tinfo->goal.offset; syncrate = ahc_find_syncrate(ahc, &cts->sync_period, maxsync); @@ -3892,18 +4210,22 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) case XPT_GET_TRAN_SETTINGS: /* Get default/user set transfer settings for the target */ { - struct ahc_devinfo devinfo; - struct ccb_trans_settings *cts; - struct ahc_target_tinfo *targ_info; - struct ahc_transinfo *tinfo; - int s; + struct ahc_devinfo devinfo; + struct ccb_trans_settings *cts; + struct ahc_initiator_tinfo *targ_info; + struct tmode_tstate *tstate; + struct ahc_transinfo *tinfo; + int s; cts = &ccb->cts; - ahc_compile_devinfo(&devinfo, cts->ccb_h.target_id, + ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim), + cts->ccb_h.target_id, cts->ccb_h.target_lun, - SIM_IS_SCSIBUS_B(ahc, sim) ? 'B' : 'A', + SIM_CHANNEL(ahc, sim), ROLE_UNKNOWN); - targ_info = &ahc->transinfo[devinfo.target_offset]; + targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, + devinfo.our_scsiid, + devinfo.target, &tstate); if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) tinfo = &targ_info->current; @@ -3913,10 +4235,10 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) s = splcam(); cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); - if ((ahc->discenable & devinfo.target_mask) != 0) + if ((tstate->discenable & devinfo.target_mask) != 0) cts->flags |= CCB_TRANS_DISC_ENB; - if ((ahc->tagenable & devinfo.target_mask) != 0) + if ((tstate->tagenable & devinfo.target_mask) != 0) cts->flags |= CCB_TRANS_TAG_ENB; cts->sync_period = tinfo->period; @@ -3964,22 +4286,14 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } case XPT_RESET_BUS: /* Reset the specified SCSI bus */ { - struct cam_path *path; - char channel; int found; s = splcam(); - if (SIM_IS_SCSIBUS_B(ahc, sim)) { - channel = 'B'; - path = ahc->path_b; - } else { - channel = 'A'; - path = ahc->path; - } - found = ahc_reset_channel(ahc, channel, /*initiate reset*/TRUE); + found = ahc_reset_channel(ahc, SIM_CHANNEL(ahc, sim), + /*initiate reset*/TRUE); splx(s); if (bootverbose) { - xpt_print_path(path); + xpt_print_path(SIM_PATH(ahc, sim)); printf("SCSI bus reset delivered. " "%d SCBs aborted.\n", found); } @@ -4050,9 +4364,10 @@ 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), + ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim), + xpt_path_target_id(path), xpt_path_lun_id(path), - SIM_IS_SCSIBUS_B(ahc, sim) ? 'B' : 'A', + SIM_CHANNEL(ahc, sim), ROLE_UNKNOWN); /* @@ -4158,9 +4473,13 @@ 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) { +#if 0 + printf("Continueing Immediate Command %d:%d\n", + ccb->ccb_h.target_id, ccb->ccb_h.target_lun); +#endif + pause_sequencer(ahc); 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); @@ -4785,6 +5104,8 @@ bus_reset: struct ccb_hdr *ccbh; u_int newtimeout; + xpt_print_path(scb->ccb->ccb_h.path); + printf("Other SCB Timeout\n"); scb->flags |= SCB_OTHERTCL_TIMEOUT; newtimeout = MAX(active_scb->ccb->ccb_h.timeout, scb->ccb->ccb_h.timeout); @@ -4825,6 +5146,9 @@ bus_reset: } else { int disconnected; + if ((scb->hscb->control & TARGET_SCB) != 0) + panic("Timed-out target SCB but bus idle"); + if (bus_state != P_BUSFREE && (ahc_inb(ahc, SSTAT0) & TARGET) != 0) { /* Hung target selection. Goto busfree */ @@ -5019,9 +5343,11 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) } } - if (found) + if (found) { abort_ccb->ccb_h.status = CAM_REQ_ABORTED; - else { + xpt_done(abort_ccb); + ccb->ccb_h.status = CAM_REQ_CMP; + } else { printf("Not found\n"); ccb->ccb_h.status = CAM_PATH_INVALID; } @@ -5293,11 +5619,14 @@ ahc_reset_current_bus(struct ahc_softc *ahc) static int ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) { - u_int target, max_target; - int found; - u_int8_t sblkctl; - char cur_channel; - struct cam_path *path; + struct cam_path *path; + u_int initiator, target, max_scsiid; + u_int sblkctl; + u_int our_id; + int found; + char cur_channel; + + ahc->pending_device = NULL; pause_sequencer(ahc); /* @@ -5307,7 +5636,13 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) found = ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, channel, CAM_LUN_WILDCARD, SCB_LIST_NULL, CAM_SCSI_BUS_RESET); - path = channel == 'B' ? ahc->path_b : ahc->path; + if (channel == 'B') { + path = ahc->path_b; + our_id = ahc->our_id_b; + } else { + path = ahc->path; + our_id = ahc->our_id; + } /* Notify the XPT that a bus reset occurred */ xpt_async(AC_BUS_RESET, path, NULL); @@ -5315,16 +5650,24 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) /* * Revert to async/narrow transfers until we renegotiate. */ - max_target = (ahc->features & AHC_WIDE) ? 15 : 7; - for (target = 0; target <= max_target; target++) { - struct ahc_devinfo devinfo; + max_scsiid = (ahc->features & AHC_WIDE) ? 15 : 7; + for (target = 0; target <= max_scsiid; target++) { - ahc_compile_devinfo(&devinfo, target, CAM_LUN_WILDCARD, - channel, ROLE_UNKNOWN); - 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); + if (ahc->enabled_targets[target] == NULL) + continue; + for (initiator = 0; initiator <= max_scsiid; initiator++) { + struct ahc_devinfo devinfo; + + ahc_compile_devinfo(&devinfo, target, initiator, + CAM_LUN_WILDCARD, + channel, ROLE_UNKNOWN); + 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); + } } /* @@ -5471,37 +5814,45 @@ ahc_calc_residual(struct scb *scb) static void ahc_update_pending_syncrates(struct ahc_softc *ahc) { - /* - * Traverse the pending SCB list and ensure that all of the - * SCBs there have the proper settings. - */ struct ccb_hdr *ccbh; int pending_ccb_count; int i; u_int saved_scbptr; /* - * We were able to complete the command successfully, - * so reinstate the timeouts for all other pending - * commands. + * Traverse the pending SCB list and ensure that all of the + * SCBs there have the proper settings. */ ccbh = LIST_FIRST(&ahc->pending_ccbs); pending_ccb_count = 0; while (ccbh != NULL) { + struct ahc_devinfo devinfo; + union ccb *ccb; struct scb *pending_scb; struct hardware_scb *pending_hscb; - struct ahc_target_tinfo *tinfo; - struct ahc_devinfo devinfo; - + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int our_id, remote_id; + + ccb = (union ccb*)ccbh; pending_scb = (struct scb *)ccbh->ccb_scb_ptr; pending_hscb = pending_scb->hscb; - ahc_compile_devinfo(&devinfo, SCB_TARGET(pending_scb), + if (ccbh->func_code == XPT_CONT_TARGET_IO) { + our_id = ccb->ccb_h.target_id; + remote_id = ccb->ctio.init_id; + } else { + our_id = SCB_IS_SCSIBUS_B(pending_scb) + ? ahc->our_id_b : ahc->our_id; + remote_id = ccb->ccb_h.target_id; + } + ahc_compile_devinfo(&devinfo, our_id, remote_id, SCB_LUN(pending_scb), SCB_CHANNEL(pending_scb), ROLE_UNKNOWN); - tinfo = &ahc->transinfo[devinfo.target_offset]; + tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, + our_id, remote_id, &tstate); pending_hscb->control &= ~ULTRAENB; - if ((ahc->ultraenb & devinfo.target_mask) != 0) + if ((tstate->ultraenb & devinfo.target_mask) != 0) pending_hscb->control |= ULTRAENB; pending_hscb->scsirate = tinfo->scsirate; pending_hscb->scsioffset = tinfo->current.offset; @@ -5520,22 +5871,37 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc) ahc_outb(ahc, SCBPTR, i); scb_tag = ahc_inb(ahc, SCB_TAG); if (scb_tag != SCB_LIST_NULL) { + struct ahc_devinfo devinfo; + union ccb *ccb; struct scb *pending_scb; struct hardware_scb *pending_hscb; - struct ahc_target_tinfo *tinfo; - struct ahc_devinfo devinfo; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int our_id, remote_id; u_int control; pending_scb = ahc->scb_data->scbarray[scb_tag]; + if (pending_scb->flags == SCB_FREE) + continue; pending_hscb = pending_scb->hscb; - ahc_compile_devinfo(&devinfo, SCB_TARGET(pending_scb), + ccb = pending_scb->ccb; + if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { + our_id = ccb->ccb_h.target_id; + remote_id = ccb->ctio.init_id; + } else { + our_id = SCB_IS_SCSIBUS_B(pending_scb) + ? ahc->our_id_b : ahc->our_id; + remote_id = ccb->ccb_h.target_id; + } + ahc_compile_devinfo(&devinfo, our_id, remote_id, SCB_LUN(pending_scb), SCB_CHANNEL(pending_scb), ROLE_UNKNOWN); - tinfo = &ahc->transinfo[devinfo.target_offset]; + tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, + our_id, remote_id, &tstate); control = ahc_inb(ahc, SCB_CONTROL); control &= ~ULTRAENB; - if ((ahc->ultraenb & devinfo.target_mask) != 0) + if ((tstate->ultraenb & devinfo.target_mask) != 0) control |= ULTRAENB; ahc_outb(ahc, SCB_CONTROL, control); ahc_outb(ahc, SCB_SCSIRATE, tinfo->scsirate); diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h index e46d277e8d58..cf3037aaa07d 100644 --- a/sys/dev/aic7xxx/aic7xxx.h +++ b/sys/dev/aic7xxx/aic7xxx.h @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aic7xxx.h,v 1.4 1998/12/15 08:22:41 gibbs Exp $ + * $Id: aic7xxx.h,v 1.5 1999/01/14 06:14:15 gibbs Exp $ */ #ifndef _AIC7XXX_H_ @@ -156,7 +156,8 @@ typedef enum { * controller. */ AHC_NEWEEPROM_FMT = 0x4000, - AHC_RESOURCE_SHORTAGE = 0x8000 + AHC_RESOURCE_SHORTAGE = 0x8000, + AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */ } ahc_flag; typedef enum { @@ -277,12 +278,40 @@ struct tmode_lstate { struct ccb_hdr_slist immed_notifies; }; +#define AHC_TRANS_CUR 0x01 /* Modify current neogtiation status */ +#define AHC_TRANS_ACTIVE 0x03 /* Assume this is the active target */ +#define AHC_TRANS_GOAL 0x04 /* Modify negotiation goal */ +#define AHC_TRANS_USER 0x08 /* Modify user negotiation settings */ + +struct ahc_transinfo { + u_int8_t width; + u_int8_t period; + u_int8_t offset; +}; + +struct ahc_initiator_tinfo { + u_int8_t scsirate; + struct ahc_transinfo current; + struct ahc_transinfo goal; + struct ahc_transinfo user; +}; + /* * Per target mode enabled target state. Esentially just an array of - * pointers to lun target state. + * pointers to lun target state as well as sync/wide negotiation information + * for each initiator<->target mapping (including the mapping for when we + * are the initiator). */ struct tmode_tstate { - struct tmode_lstate* enabled_luns[8]; + struct tmode_lstate* enabled_luns[8]; + struct ahc_initiator_tinfo transinfo[16]; + + /* + * Per initiator state bitmasks. + */ + u_int16_t ultraenb; /* Using ultra sync rate */ + u_int16_t discenable; /* Disconnection allowed */ + u_int16_t tagenable; /* Tagged Queuing allowed */ }; /* @@ -356,24 +385,6 @@ struct seeprom_config { u_int16_t checksum; /* word 31 */ }; -#define AHC_TRANS_CUR 0x01 /* Modify current neogtiation status */ -#define AHC_TRANS_ACTIVE 0x03 /* Assume this is the active target */ -#define AHC_TRANS_GOAL 0x04 /* Modify negotiation goal */ -#define AHC_TRANS_USER 0x08 /* Modify user negotiation settings */ - -struct ahc_transinfo { - u_int8_t width; - u_int8_t period; - u_int8_t offset; -}; - -struct ahc_target_tinfo { - u_int8_t scsirate; - struct ahc_transinfo current; - struct ahc_transinfo goal; - struct ahc_transinfo user; -}; - struct ahc_syncrate { int sxfr_ultra2; int sxfr; @@ -405,6 +416,8 @@ struct ahc_softc { /* * Target mode related state kept on a per enabled lun basis. * Targets that are not enabled will have null entries. + * As an initiator, we keep one target entry for our initiator + * ID to store our sync/wide transfer settings. */ struct tmode_tstate* enabled_targets[16]; @@ -444,19 +457,6 @@ struct ahc_softc { u_int8_t untagged_scbs[256]; /* - * User/Current/Active Negotiation settings - */ - struct ahc_target_tinfo transinfo[16]; - - /* - * Per target state bitmasks. - */ - u_int16_t ultraenb; /* Using ultra sync rate */ - u_int16_t discenable; /* Disconnection allowed */ - u_int16_t tagenable; /* Tagged Queuing allowed */ - u_int16_t targ_msg_req; /* Need negotiation messages */ - - /* * Hooks into the XPT. */ struct cam_sim *sim; @@ -474,6 +474,9 @@ struct ahc_softc { u_int8_t our_id; u_int8_t our_id_b; + /* Targets that need negotiation messages */ + u_int16_t targ_msg_req; + /* * PCI error detection and data for running the * PCI error interrupt handler. @@ -498,6 +501,7 @@ struct ahc_softc { u_int msgout_index; /* Current index in msgout */ u_int msgin_index; /* Current index in msgin */ + /* Number of enabled target mode device on this card */ u_int enabled_luns; /* diff --git a/sys/dev/aic7xxx/aic7xxx.reg b/sys/dev/aic7xxx/aic7xxx.reg index 775c0e31086f..8a9c656a3a7a 100644 --- a/sys/dev/aic7xxx/aic7xxx.reg +++ b/sys/dev/aic7xxx/aic7xxx.reg @@ -32,7 +32,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aic7xxx.reg,v 1.11 1998/12/17 00:06:52 gibbs Exp $ + * $Id: aic7xxx.reg,v 1.12 1999/01/14 06:14:15 gibbs Exp $ */ /* @@ -882,7 +882,6 @@ scb { } SCB_CMDPTR { alias SCB_TARGET_PHASES - alias SCB_TARGET_ID /* Byte 2 */ bit TARGET_DATA_IN 0x1 /* In the second byte */ size 4 } @@ -1267,7 +1266,7 @@ scratch_ram { /* * Kernel and sequencer offsets into the queue of * incoming target mode command descriptors. The - * queue is full when the ((KERNEL_TQINPOS - TQINPOS) == 1) + * queue is full when the KERNEL_TQINPOS == TQINPOS. */ KERNEL_TQINPOS { size 1 @@ -1408,6 +1407,12 @@ const CMD_GROUP3_BYTE_DELTA -15 const CMD_GROUP4_BYTE_DELTA 4 const CMD_GROUP5_BYTE_DELTA 11 +const TCL_TARGET_SHIFT 4 +/* The update interval must be a power of 2 */ +const TQINFIFO_UPDATE_CNT 32 + +const STATUS_BUSY 0x08 +const STATUS_QUEUE_FULL 0x28 /* * Downloaded (kernel inserted) constants diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq index 5abe1b656a7f..3f23503fa85d 100644 --- a/sys/dev/aic7xxx/aic7xxx.seq +++ b/sys/dev/aic7xxx/aic7xxx.seq @@ -32,7 +32,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aic7xxx.seq,v 1.84 1999/01/14 06:14:15 gibbs Exp $ + * $Id: aic7xxx.seq,v 1.85 1999/02/11 07:10:20 gibbs Exp $ */ #include <dev/aic7xxx/aic7xxx.reg> @@ -68,8 +68,8 @@ reset: clr CCSCBCTL; } - call clear_target_state; poll_for_work: + call clear_target_state; and SXFRCTL0, ~SPIOEN; if ((ahc->features & AHC_QUEUE_REGS) == 0) { mov A, QINPOS; @@ -169,6 +169,17 @@ start_selection: mov SBLKCTL,SINDEX; /* select channel */ } initialize_scsiid: + mov SINDEX, SCSISEQ_TEMPLATE; + if ((ahc->flags & AHC_TARGETMODE) != 0) { + test SCB_CONTROL, TARGET_SCB jz . + 4; + if ((ahc->features & AHC_ULTRA2) != 0) { + mov SCSIID_ULTRA2, SCB_CMDPTR[2]; + } else { + mov SCSIID, SCB_CMDPTR[2]; + } + or SINDEX, TEMODE; + jmp initialize_scsiid_fini; + } if ((ahc->features & AHC_ULTRA2) != 0) { and A, TID, SCB_TCL; /* Get target ID */ and SCSIID_ULTRA2, OID; /* Clear old target */ @@ -178,11 +189,7 @@ initialize_scsiid: and SCSIID, OID; /* Clear old target */ or SCSIID, A; } - mov SINDEX, SCSISEQ_TEMPLATE; - if ((ahc->flags & AHC_TARGETMODE) != 0) { - test SCB_CONTROL, TARGET_SCB jz . + 2; - or SINDEX, TEMODE; - } +initialize_scsiid_fini: mov SCSISEQ, SINDEX ret; /* @@ -230,7 +237,6 @@ select_in: */ or SEQ_FLAGS, CMDPHASE_PENDING; - /* XXX If ring buffer is full, return busy or queue full */ mov A, TQINPOS; if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; @@ -251,15 +257,19 @@ select_in: } /* The Target ID we were selected at */ - if ((ahc->features & AHC_MULTI_TID) != 0) { - if ((ahc->features & AHC_CMD_CHAN) != 0) { - and CCSCBRAM, 0x0f, TARGIDIN; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + if ((ahc->features & AHC_MULTI_TID) != 0) { + and CCSCBRAM, OID, TARGIDIN; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + and CCSCBRAM, OID, SCSIID_ULTRA2; } else { - and DFDAT, 0x0f, TARGIDIN; + and CCSCBRAM, OID, SCSIID; } } else { - if ((ahc->features & AHC_CMD_CHAN) != 0) { - and CCSCBRAM, OID, SCSIID; + if ((ahc->features & AHC_MULTI_TID) != 0) { + and DFDAT, OID, TARGIDIN; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + and DFDAT, OID, SCSIID_ULTRA2; } else { and DFDAT, OID, SCSIID; } @@ -349,6 +359,16 @@ host_target_message_loop: jmp host_target_message_loop; ident_messages_done: + /* If ring buffer is full, return busy or queue full */ + mov A, KERNEL_TQINPOS; + cmp TQINPOS, A jne tqinfifo_has_space; + mvi P_STATUS|BSYO call change_phase; + cmp INITIATOR_TAG, SCB_LIST_NULL je . + 3; + mvi STATUS_QUEUE_FULL call target_outb; + jmp target_busfree_wait; + mvi STATUS_BUSY call target_outb; + jmp target_busfree_wait; +tqinfifo_has_space: /* Terminate the ident list */ if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi CCSCBRAM, SCB_LIST_NULL; @@ -450,7 +470,7 @@ target_synccmd: target_ITloop: /* * Start honoring ATN signals now that - * we properly identified ourself. + * we properly identified ourselves. */ test SCSISIGI, ATNI jnz target_mesgout; test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; @@ -491,7 +511,6 @@ target_busfree_wait: target_busfree: clr SCSISIGO; call complete_target_cmd; - call clear_target_state; jmp poll_for_work; target_cmdphase: @@ -625,7 +644,6 @@ ITloop: await_busfree: and SIMODE1, ~ENBUSFREE; - call clear_target_state; mov NONE, SCSIDATL; /* Ack the last byte */ and SXFRCTL0, ~SPIOEN; test SSTAT1,REQINIT|BUSFREE jz .; @@ -1146,14 +1164,12 @@ complete: complete_queue: mov SCB_TAG call complete_post; - -add_to_free_list: - call add_scb_to_free_list; jmp await_busfree; } complete_post: /* Post the SCBID in SINDEX and issue an interrupt */ + call add_scb_to_free_list; mov ARG_1, SINDEX; if ((ahc->features & AHC_QUEUE_REGS) != 0) { mov A, SDSCB_QOFF; |
