o Correct the offsets into the syncrate table for paritcular
negotiation features (DT, ULTRA2, ULTRA, FAST). The offsets where not properly updated when the DT entry was added and so the driver could attempt to negotiate a speed faster than that supported by the target device or even requested by the user via SCSI-Select settings. * o Update the target mode incoming command queue kernel index value ever 128 commands instead of 32. This means that the kernel will always try to keep its index (as seen on the card - the kernel may actually have cleared more space) 128 commands ahead of where the sequencer is adding entries. o Use the HS_MAILBOX register instead of the KERNEL_TQINPOS location in SRAM to indicate the kernel's target queue possition on Ultra2 cards. This avoids the "pause bug" on these cards and also turns out to be much more efficient. o When enabling or disabling a particular target id for target mode, make sure that the taret id in the SCSIID register does not reference an ID that is not to receive target selections. This is only an issue on chips that support the multiple target id feature where the value in SCSIID will still affect selection behavior regardless of the values in the target id bit field registers. o Remove some target mode debugging printfs. o Make sure that the sense length reported in ATIO commands is always zero. This driver does not, yet, report HBA generated sense information for accepted commands. o Honor the CAM_TIME_INFINITY and CAM_TIME_DEFAULT values for the CCB timeout field. o Make the driver compile with AHC_DEBUG again. * Noticed by: Andrew Gallatin<gallatin@cs.duke.edu>
This commit is contained in:
parent
603ed0f30d
commit
ff58fb8420
@ -259,6 +259,7 @@ 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 void ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask);
|
||||
static int ahc_handle_target_cmd(struct ahc_softc *ahc,
|
||||
struct target_cmd *cmd);
|
||||
static void ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat);
|
||||
@ -541,12 +542,22 @@ ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
|
||||
* Lazily update our position in the target mode incomming
|
||||
* command queue as seen by the sequencer.
|
||||
*/
|
||||
if ((ahc->tqinfifonext & (TQINFIFO_UPDATE_CNT-1)) == 0) {
|
||||
if (!paused)
|
||||
pause_sequencer(ahc);
|
||||
ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
|
||||
if (!paused)
|
||||
if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) {
|
||||
if ((ahc->features & AHC_HS_MAILBOX) != 0) {
|
||||
u_int hs_mailbox;
|
||||
|
||||
hs_mailbox = ahc_inb(ahc, HS_MAILBOX);
|
||||
hs_mailbox &= ~HOST_TQINPOS;
|
||||
hs_mailbox |= ahc->tqinfifonext & HOST_TQINPOS;
|
||||
ahc_outb(ahc, HS_MAILBOX, hs_mailbox);
|
||||
} else {
|
||||
if (!paused)
|
||||
pause_sequencer(ahc);
|
||||
ahc_outb(ahc, KERNEL_TQINPOS,
|
||||
ahc->tqinfifonext & HOST_TQINPOS);
|
||||
if (!paused)
|
||||
unpause_sequencer(ahc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -655,18 +666,18 @@ ahc_print_scb(struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *hscb = scb->hscb;
|
||||
|
||||
printf("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
|
||||
printf("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%x\n",
|
||||
scb,
|
||||
hscb->control,
|
||||
hscb->tcl,
|
||||
hscb->cmdlen,
|
||||
hscb->cmdpointer );
|
||||
printf(" datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
|
||||
hscb->cmdpointer);
|
||||
printf(" datlen:%d data:0x%x segs:0x%x segp:0x%x\n",
|
||||
hscb->datalen,
|
||||
hscb->data,
|
||||
hscb->SG_count,
|
||||
hscb->SG_pointer);
|
||||
printf(" sg_addr:%lx sg_len:%ld\n",
|
||||
printf(" sg_addr:%x sg_len:%d\n",
|
||||
scb->sg_list[0].addr,
|
||||
scb->sg_list[0].len);
|
||||
printf(" cdb:%x %x %x %x %x %x %x %x %x %x %x %x\n",
|
||||
@ -715,8 +726,8 @@ static const int num_phases = (sizeof(phase_table)/sizeof(phase_table[0])) - 1;
|
||||
*/
|
||||
#define AHC_SYNCRATE_DT 0
|
||||
#define AHC_SYNCRATE_ULTRA2 1
|
||||
#define AHC_SYNCRATE_ULTRA 2
|
||||
#define AHC_SYNCRATE_FAST 5
|
||||
#define AHC_SYNCRATE_ULTRA 3
|
||||
#define AHC_SYNCRATE_FAST 6
|
||||
static struct ahc_syncrate ahc_syncrates[] = {
|
||||
/* ultra2 fast/ultra period rate */
|
||||
{ 0x42, 0x000, 9, "80.0" },
|
||||
@ -1901,7 +1912,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
|
||||
ahc->enabled_luns++;
|
||||
|
||||
if ((ahc->features & AHC_MULTI_TID) != 0) {
|
||||
u_int16_t targid_mask;
|
||||
u_int targid_mask;
|
||||
|
||||
targid_mask = ahc_inb(ahc, TARGID)
|
||||
| (ahc_inb(ahc, TARGID + 1) << 8);
|
||||
@ -1909,6 +1920,8 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
|
||||
targid_mask |= target_mask;
|
||||
ahc_outb(ahc, TARGID, targid_mask);
|
||||
ahc_outb(ahc, TARGID+1, (targid_mask >> 8));
|
||||
|
||||
ahc_update_scsiid(ahc, targid_mask);
|
||||
} else {
|
||||
int our_id;
|
||||
char channel;
|
||||
@ -1964,6 +1977,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
|
||||
printf("Lun now enabled for target mode\n");
|
||||
} else {
|
||||
struct ccb_hdr *elm;
|
||||
int i, empty;
|
||||
|
||||
if (lstate == NULL) {
|
||||
ccb->ccb_h.status = CAM_LUN_INVALID;
|
||||
@ -1992,70 +2006,108 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
|
||||
ccb->ccb_h.status = CAM_REQ_INVALID;
|
||||
}
|
||||
|
||||
if (ccb->ccb_h.status == CAM_REQ_CMP) {
|
||||
int i, empty;
|
||||
if (ccb->ccb_h.status != CAM_REQ_CMP) {
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
xpt_print_path(ccb->ccb_h.path);
|
||||
printf("Target mode disabled\n");
|
||||
xpt_free_path(lstate->path);
|
||||
free(lstate, M_DEVBUF);
|
||||
xpt_print_path(ccb->ccb_h.path);
|
||||
printf("Target mode disabled\n");
|
||||
xpt_free_path(lstate->path);
|
||||
free(lstate, M_DEVBUF);
|
||||
|
||||
pause_sequencer(ahc);
|
||||
/* Can we clean up the target too? */
|
||||
if (target != CAM_TARGET_WILDCARD) {
|
||||
tstate->enabled_luns[lun] = NULL;
|
||||
ahc->enabled_luns--;
|
||||
for (empty = 1, i = 0; i < 8; i++)
|
||||
if (tstate->enabled_luns[i] != NULL) {
|
||||
empty = 0;
|
||||
break;
|
||||
}
|
||||
pause_sequencer(ahc);
|
||||
/* Can we clean up the target too? */
|
||||
if (target != CAM_TARGET_WILDCARD) {
|
||||
tstate->enabled_luns[lun] = NULL;
|
||||
ahc->enabled_luns--;
|
||||
for (empty = 1, i = 0; i < 8; i++)
|
||||
if (tstate->enabled_luns[i] != NULL) {
|
||||
empty = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (empty) {
|
||||
ahc_free_tstate(ahc, target, channel,
|
||||
/*force*/FALSE);
|
||||
if (ahc->features & AHC_MULTI_TID) {
|
||||
u_int16_t targid_mask;
|
||||
if (empty) {
|
||||
ahc_free_tstate(ahc, target, channel,
|
||||
/*force*/FALSE);
|
||||
if (ahc->features & AHC_MULTI_TID) {
|
||||
u_int targid_mask;
|
||||
|
||||
targid_mask =
|
||||
ahc_inb(ahc, TARGID)
|
||||
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));
|
||||
}
|
||||
targid_mask &= ~target_mask;
|
||||
ahc_outb(ahc, TARGID, targid_mask);
|
||||
ahc_outb(ahc, TARGID+1,
|
||||
(targid_mask >> 8));
|
||||
ahc_update_scsiid(ahc, targid_mask);
|
||||
}
|
||||
} else {
|
||||
|
||||
ahc->black_hole = NULL;
|
||||
|
||||
/*
|
||||
* We can't allow selections without
|
||||
* our black hole device.
|
||||
*/
|
||||
empty = TRUE;
|
||||
}
|
||||
if (ahc->enabled_luns == 0) {
|
||||
/* Disallow select-in */
|
||||
u_int scsiseq;
|
||||
} else {
|
||||
|
||||
scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE);
|
||||
scsiseq &= ~ENSELI;
|
||||
ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq);
|
||||
scsiseq = ahc_inb(ahc, SCSISEQ);
|
||||
scsiseq &= ~ENSELI;
|
||||
ahc_outb(ahc, SCSISEQ, scsiseq);
|
||||
}
|
||||
unpause_sequencer(ahc);
|
||||
ahc->black_hole = NULL;
|
||||
|
||||
/*
|
||||
* We can't allow selections without
|
||||
* our black hole device.
|
||||
*/
|
||||
empty = TRUE;
|
||||
}
|
||||
if (ahc->enabled_luns == 0) {
|
||||
/* Disallow select-in */
|
||||
u_int scsiseq;
|
||||
|
||||
scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE);
|
||||
scsiseq &= ~ENSELI;
|
||||
ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq);
|
||||
scsiseq = ahc_inb(ahc, SCSISEQ);
|
||||
scsiseq &= ~ENSELI;
|
||||
ahc_outb(ahc, SCSISEQ, scsiseq);
|
||||
}
|
||||
unpause_sequencer(ahc);
|
||||
splx(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask)
|
||||
{
|
||||
u_int scsiid_mask;
|
||||
u_int scsiid;
|
||||
|
||||
if ((ahc->features & AHC_MULTI_TID) == 0)
|
||||
panic("ahc_update_scsiid called on non-multitid unit\n");
|
||||
|
||||
/*
|
||||
* Since we will rely on the the TARGID mask
|
||||
* for selection enables, ensure that OID
|
||||
* in SCSIID is not set to some other ID
|
||||
* that we don't want to allow selections on.
|
||||
*/
|
||||
if ((ahc->features & AHC_ULTRA2) != 0)
|
||||
scsiid = ahc_inb(ahc, SCSIID_ULTRA2);
|
||||
else
|
||||
scsiid = ahc_inb(ahc, SCSIID);
|
||||
scsiid_mask = 0x1 << (scsiid & OID);
|
||||
if ((targid_mask & scsiid_mask) == 0) {
|
||||
u_int our_id;
|
||||
|
||||
/* ffs counts from 1 */
|
||||
our_id = ffs(targid_mask);
|
||||
if (our_id == 0)
|
||||
our_id = ahc->our_id;
|
||||
else
|
||||
our_id--;
|
||||
scsiid &= TID;
|
||||
scsiid |= our_id;
|
||||
}
|
||||
if ((ahc->features & AHC_ULTRA2) != 0)
|
||||
ahc_outb(ahc, SCSIID_ULTRA2, scsiid);
|
||||
else
|
||||
ahc_outb(ahc, SCSIID, scsiid);
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
|
||||
{
|
||||
@ -2080,23 +2132,23 @@ 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) {
|
||||
if (lstate == NULL)
|
||||
lstate = ahc->black_hole;
|
||||
atio =
|
||||
(struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios);
|
||||
} else {
|
||||
atio =
|
||||
(struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios);
|
||||
}
|
||||
|
||||
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;
|
||||
#if 0
|
||||
printf("Incoming command from %d for %d:%d%s\n",
|
||||
initiator, target, lun,
|
||||
lstate == ahc->black_hole ? "(Black Holed)" : "");
|
||||
#endif
|
||||
SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle);
|
||||
|
||||
if (lstate == ahc->black_hole) {
|
||||
@ -2109,6 +2161,7 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
|
||||
* Package it up and send it off to
|
||||
* whomever has this lun enabled.
|
||||
*/
|
||||
atio->sense_len = 0;
|
||||
atio->init_id = initiator;
|
||||
if (byte[0] != 0xFF) {
|
||||
/* Tag was included */
|
||||
@ -4122,6 +4175,11 @@ ahc_init(struct ahc_softc *ahc)
|
||||
for (i = 0; i < 256; i++)
|
||||
ahc->qoutfifo[i] = SCB_LIST_NULL;
|
||||
|
||||
if ((ahc->features & AHC_MULTI_TID) != 0) {
|
||||
ahc_outb(ahc, TARGID, 0);
|
||||
ahc_outb(ahc, TARGID + 1, 0);
|
||||
}
|
||||
|
||||
if ((ahc->flags & AHC_TARGETMODE) != 0) {
|
||||
|
||||
ahc->targetcmds = (struct target_cmd *)&ahc->untagged_scbs[256];
|
||||
@ -4130,8 +4188,9 @@ 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->tqinfifonext = 1;
|
||||
ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
|
||||
ahc_outb(ahc, TQINPOS, 0);
|
||||
ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4374,14 +4433,6 @@ ahc_init(struct ahc_softc *ahc)
|
||||
ahc_outb(ahc, QINPOS, 0);
|
||||
ahc_outb(ahc, QOUTPOS, 0);
|
||||
|
||||
#ifdef AHC_DEBUG
|
||||
if (ahc_debug & AHC_SHOWMISC)
|
||||
printf("NEEDSDTR == 0x%x\nNEEDWDTR == 0x%x\n"
|
||||
"DISCENABLE == 0x%x\nULTRAENB == 0x%x\n",
|
||||
ahc->needsdtr_orig, ahc->needwdtr_orig,
|
||||
discenable, ultraenb);
|
||||
#endif
|
||||
|
||||
/* Don't have any special messages to send to targets */
|
||||
ahc_outb(ahc, TARGET_MSG_REQUEST, 0);
|
||||
ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0);
|
||||
@ -5117,9 +5168,13 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
|
||||
scb->flags |= SCB_ACTIVE;
|
||||
ccb->ccb_h.status |= CAM_SIM_QUEUED;
|
||||
|
||||
ccb->ccb_h.timeout_ch =
|
||||
timeout(ahc_timeout, (caddr_t)scb,
|
||||
(ccb->ccb_h.timeout * hz) / 1000);
|
||||
if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
|
||||
if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT)
|
||||
ccb->ccb_h.timeout = 5 * 1000;
|
||||
ccb->ccb_h.timeout_ch =
|
||||
timeout(ahc_timeout, (caddr_t)scb,
|
||||
(ccb->ccb_h.timeout * hz) / 1000);
|
||||
}
|
||||
|
||||
if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
|
||||
#if 0
|
||||
@ -6328,7 +6383,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
|
||||
/*
|
||||
* Since we are going to restart the sequencer, avoid
|
||||
* a race in the sequencer that could cause corruption
|
||||
* of our Q pointers by starting over from index 0.
|
||||
* of our Q pointers by starting over from index 1.
|
||||
*/
|
||||
ahc->qoutfifonext = 0;
|
||||
if ((ahc->features & AHC_QUEUE_REGS) != 0)
|
||||
@ -6336,9 +6391,16 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
|
||||
else
|
||||
ahc_outb(ahc, QOUTPOS, 0);
|
||||
if ((ahc->flags & AHC_TARGETMODE) != 0) {
|
||||
ahc->tqinfifonext = 0;
|
||||
ahc->tqinfifonext = 1;
|
||||
ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
|
||||
ahc_outb(ahc, TQINPOS, 0);
|
||||
ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
|
||||
if ((ahc->features & AHC_HS_MAILBOX) != 0) {
|
||||
u_int hs_mailbox;
|
||||
|
||||
hs_mailbox = ahc_inb(ahc, HS_MAILBOX);
|
||||
hs_mailbox &= ~HOST_TQINPOS;
|
||||
ahc_outb(ahc, HS_MAILBOX, hs_mailbox);
|
||||
}
|
||||
}
|
||||
restart_needed = TRUE;
|
||||
}
|
||||
@ -6515,6 +6577,13 @@ ahc_calc_residual(struct scb *scb)
|
||||
|
||||
scb->ccb->csio.sense_resid = resid;
|
||||
}
|
||||
|
||||
#ifdef AHC_DEBUG
|
||||
if (ahc_debug & AHC_SHOWMISC) {
|
||||
xpt_print_path(scb->ccb->ccb_h.path);
|
||||
printf("Handled Residual of %d bytes\n", resid);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -6522,13 +6591,6 @@ ahc_calc_residual(struct scb *scb)
|
||||
* next consumer.
|
||||
*/
|
||||
hscb->residual_SG_count = 0;
|
||||
|
||||
#ifdef AHC_DEBUG
|
||||
if (ahc_debug & AHC_SHOWMISC) {
|
||||
sc_print_addr(xs->sc_link);
|
||||
printf("Handled Residual of %ld bytes\n" ,xs->resid);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -704,6 +704,8 @@ register HS_MAILBOX {
|
||||
address 0x086
|
||||
mask HOST_MAILBOX 0xF0
|
||||
mask SEQ_MAILBOX 0x0F
|
||||
mask HOST_REQ_INT 0x10
|
||||
mask HOST_TQINPOS 0x80 /* Boundary at either 0 or 128 */
|
||||
}
|
||||
|
||||
const HOST_MAILBOX_SHIFT 4
|
||||
@ -1465,8 +1467,6 @@ const HOST_MSG 0xff
|
||||
const CMD_GROUP_CODE_SHIFT 0x05
|
||||
|
||||
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
|
||||
|
@ -75,7 +75,7 @@ poll_for_work_loop:
|
||||
and SEQCTL, ~PAUSEDIS;
|
||||
}
|
||||
test SSTAT0, SELDO|SELDI jnz selection;
|
||||
test SCSISEQ, ENSELO jnz poll_for_work;
|
||||
test SCSISEQ, ENSELO jnz poll_for_work_loop;
|
||||
if ((ahc->features & AHC_TWIN) != 0) {
|
||||
/*
|
||||
* Twin channel devices cannot handle things like SELTO
|
||||
@ -356,7 +356,11 @@ host_target_message_loop:
|
||||
|
||||
ident_messages_done:
|
||||
/* If ring buffer is full, return busy or queue full */
|
||||
mov A, KERNEL_TQINPOS;
|
||||
if ((ahc->features & AHC_HS_MAILBOX) != 0) {
|
||||
and A, HOST_TQINPOS, HS_MAILBOX;
|
||||
} else {
|
||||
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;
|
||||
@ -424,7 +428,7 @@ initiator_reselect:
|
||||
*/
|
||||
select_out:
|
||||
/* Turn off the selection hardware */
|
||||
and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE;
|
||||
and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ;
|
||||
mvi CLRSINT0, CLRSELDO;
|
||||
mov SCBPTR, WAITING_SCBH;
|
||||
mov WAITING_SCBH,SCB_NEXT;
|
||||
|
Loading…
Reference in New Issue
Block a user