aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin T. Gibbs <gibbs@FreeBSD.org>1999-03-05 23:35:48 +0000
committerJustin T. Gibbs <gibbs@FreeBSD.org>1999-03-05 23:35:48 +0000
commitc562189829c1615c9ca97925efa1c799089dd024 (patch)
tree1d9ee12019fa1a107812d2b3acc62fd6fdaf3be4
parentf15aa8d8d944cf0bff05fa4da18984905b513a39 (diff)
Notes
-rw-r--r--sys/dev/aic7xxx/aic7xxx.c802
-rw-r--r--sys/dev/aic7xxx/aic7xxx.h74
-rw-r--r--sys/dev/aic7xxx/aic7xxx.reg11
-rw-r--r--sys/dev/aic7xxx/aic7xxx.seq56
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;