1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-18 15:30:21 +00:00

Keep interrupts blocked for all of isp_pci_attach. Redo DMA routines

for target mode for cleanliness and accuracy.
This commit is contained in:
Matt Jacob 2000-07-18 06:40:22 +00:00
parent 5ce6286805
commit 05fbcbb000
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=63380
2 changed files with 328 additions and 162 deletions

View File

@ -537,11 +537,12 @@ isp_pci_attach(device_t dev)
data = pci_read_config(dev, PCIR_ROMADDR, 4); data = pci_read_config(dev, PCIR_ROMADDR, 4);
data &= ~1; data &= ~1;
pci_write_config(dev, PCIR_ROMADDR, data, 4); pci_write_config(dev, PCIR_ROMADDR, data, 4);
splx(s);
if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
BUS_SPACE_MAXADDR, NULL, NULL, lim + 1, BUS_SPACE_MAXADDR, NULL, NULL, lim + 1,
255, lim, 0, &pcs->parent_dmat) != 0) { 255, lim, 0, &pcs->parent_dmat) != 0) {
splx(s);
printf("%s: could not create master dma tag\n", isp->isp_name); printf("%s: could not create master dma tag\n", isp->isp_name);
free(isp->isp_param, M_DEVBUF); free(isp->isp_param, M_DEVBUF);
free(pcs, M_DEVBUF); free(pcs, M_DEVBUF);
@ -614,7 +615,6 @@ isp_pci_attach(device_t dev)
#ifdef ISP_TARGET_MODE #ifdef ISP_TARGET_MODE
(void) getenv_int("isp_tdebug", &isp_tdebug); (void) getenv_int("isp_tdebug", &isp_tdebug);
#endif #endif
s = splbio();
if (bus_setup_intr(dev, irq, INTR_TYPE_CAM, (void (*)(void *))isp_intr, if (bus_setup_intr(dev, irq, INTR_TYPE_CAM, (void (*)(void *))isp_intr,
isp, &pcs->ih)) { isp, &pcs->ih)) {
splx(s); splx(s);
@ -622,6 +622,9 @@ isp_pci_attach(device_t dev)
goto bad; goto bad;
} }
/*
* Make sure we're in reset state.
*/
isp_reset(isp); isp_reset(isp);
if (isp->isp_state != ISP_RESETSTATE) { if (isp->isp_state != ISP_RESETSTATE) {
splx(s); splx(s);
@ -987,63 +990,87 @@ typedef struct {
* mapped and a pointer to a partially filled in already allocated request * mapped and a pointer to a partially filled in already allocated request
* queue entry. We finish the job. * queue entry. We finish the job.
*/ */
static void dma2_tgt __P((void *, bus_dma_segment_t *, int, int)); static void tdma_mk __P((void *, bus_dma_segment_t *, int, int));
static void dma2_tgt_fc __P((void *, bus_dma_segment_t *, int, int)); static void tdma_mkfc __P((void *, bus_dma_segment_t *, int, int));
static void static void
dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
{ {
mush_t *mp; mush_t *mp;
struct ccb_scsiio *csio; struct ccb_scsiio *csio;
struct isp_pcisoftc *pci; struct isp_pcisoftc *pci;
bus_dmamap_t *dp; bus_dmamap_t *dp;
u_int8_t scsi_status, send_status; u_int8_t scsi_status;
ct_entry_t *cto; ct_entry_t *cto;
u_int32_t handle; u_int32_t handle, totxfr, sflags;
int nctios; int nctios, send_status;
int32_t resid;
mp = (mush_t *) arg; mp = (mush_t *) arg;
if (error) { if (error) {
mp->error = error; mp->error = error;
return; return;
} }
csio = mp->cmd_token; csio = mp->cmd_token;
cto = mp->rq; cto = mp->rq;
cto->ct_xfrlen = 0; cto->ct_xfrlen = 0;
cto->ct_resid = 0;
cto->ct_seg_count = 0; cto->ct_seg_count = 0;
bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg)); cto->ct_header.rqs_entry_count = 1;
MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
if (nseg == 0) { if (nseg == 0) {
cto->ct_header.rqs_entry_count = 1; cto->ct_header.rqs_seqno = 1;
ISP_TDQE(mp->isp, "dma2_tgt[no data]", *mp->iptrp, cto); ISP_TDQE(mp->isp, "tdma_mk[no data]", *mp->iptrp, cto);
if (isp_tdebug) { if (isp_tdebug) {
printf("%s:CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts " printf("%s:CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts "
"0x%x res %u\n", mp->isp->isp_name, "0x%x res %d\n", mp->isp->isp_name,
csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags, csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags,
cto->ct_status, cto->ct_scsi_status, cto->ct_resid); cto->ct_status, cto->ct_scsi_status, cto->ct_resid);
} }
ISP_SWIZ_CTIO(isp, cto, cto); ISP_SWIZ_CTIO(mp->isp, cto, cto);
return; return;
} }
/*
* Save handle, and potentially any SCSI status, which
* we'll reinsert on the last CTIO we're going to send.
*/
handle = cto->ct_reserved;
cto->ct_reserved = 0;
scsi_status = cto->ct_scsi_status;
cto->ct_scsi_status = 0;
send_status = cto->ct_flags & CT_SENDSTATUS;
cto->ct_flags &= ~CT_SENDSTATUS;
nctios = nseg / ISP_RQDSEG; nctios = nseg / ISP_RQDSEG;
if (nseg % ISP_RQDSEG) { if (nseg % ISP_RQDSEG) {
nctios++; nctios++;
} }
/*
* Save handle, and potentially any SCSI status, which we'll reinsert
* on the last CTIO we're going to send.
*/
handle = cto->ct_reserved;
cto->ct_reserved = 0;
cto->ct_header.rqs_seqno = 0;
send_status = (cto->ct_flags & CT_SENDSTATUS) != 0;
if (send_status) {
sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR);
cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR);
/*
* Preserve residual.
*/
resid = cto->ct_resid;
/*
* Save actual SCSI status.
*/
scsi_status = cto->ct_scsi_status;
/*
* We can't do a status at the same time as a data CTIO, so
* we need to synthesize an extra CTIO at this level.
*/
nctios++;
} else {
sflags = scsi_status = resid = 0;
}
totxfr = cto->ct_resid = 0;
cto->ct_scsi_status = 0;
pci = (struct isp_pcisoftc *)mp->isp; pci = (struct isp_pcisoftc *)mp->isp;
dp = &pci->dmaps[isp_handle_index(handle)]; dp = &pci->dmaps[isp_handle_index(handle)];
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
@ -1054,65 +1081,104 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
while (nctios--) { while (nctios--) {
int seg, seglim; int seglim;
seglim = nseg; seglim = nseg;
if (seglim > ISP_RQDSEG) if (seglim) {
seglim = ISP_RQDSEG; int seg;
for (seg = 0; seg < seglim; seg++) { if (seglim > ISP_RQDSEG)
cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; seglim = ISP_RQDSEG;
cto->ct_dataseg[seg].ds_count = dm_segs->ds_len;
cto->ct_xfrlen += dm_segs->ds_len;
dm_segs++;
}
cto->ct_seg_count = seg; for (seg = 0; seg < seglim; seg++, nseg--) {
cto->ct_flags &= CT_DATAMASK; /*
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { * Unlike normal initiator commands, we don't
cto->ct_flags |= CT_DATA_IN; * do any swizzling here.
*/
cto->ct_dataseg[seg].ds_count = dm_segs->ds_len;
cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr;
cto->ct_xfrlen += dm_segs->ds_len;
totxfr += dm_segs->ds_len;
dm_segs++;
}
cto->ct_seg_count = seg;
} else { } else {
cto->ct_flags |= CT_DATA_OUT; /*
* This case should only happen when we're sending an
* extra CTIO with final status.
*/
if (send_status == 0) {
printf("%s: tdma_mk ran out of segments\n",
mp->isp->isp_name);
mp->error = EINVAL;
return;
}
} }
/*
* At this point, the fields ct_lun, ct_iid, ct_tagval,
* ct_tagtype, and ct_timeout have been carried over
* unchanged from what our caller had set.
*
* The dataseg fields and the seg_count fields we just got
* through setting. The data direction we've preserved all
* along and only clear it if we're now sending status.
*/
if (nctios == 0) { if (nctios == 0) {
/* /*
* We're the last in a sequence of CTIOs, so mark this * We're the last in a sequence of CTIOs, so mark
* CTIO and save the handle to the CCB such that when * this CTIO and save the handle to the CCB such that
* this CTIO completes we can free dma resources and * when this CTIO completes we can free dma resources
* do whatever else we need to do to finish the rest * and do whatever else we need to do to finish the
* of the command. * rest of the command.
*/ */
cto->ct_header.rqs_seqno = 1;
cto->ct_reserved = handle; cto->ct_reserved = handle;
cto->ct_scsi_status = scsi_status; cto->ct_header.rqs_seqno = 1;
cto->ct_flags |= send_status;
ISP_TDQE(mp->isp, "last dma2_tgt", *mp->iptrp, cto); if (send_status) {
if (isp_tdebug) { cto->ct_scsi_status = scsi_status;
printf("%s:CTIO lun %d->iid%d flgs 0x%x sts " cto->ct_flags |= sflags | CT_NO_DATA;;
"0x%x ssts 0x%x res %u\n", cto->ct_resid = resid;
mp->isp->isp_name, csio->ccb_h.target_lun,
cto->ct_iid, cto->ct_flags, cto->ct_status,
cto->ct_scsi_status, cto->ct_resid);
} }
ISP_SWIZ_CTIO(isp, cto, cto); if (isp_tdebug && send_status) {
printf("%s:CTIO lun%d for ID%d ct_flags 0x%x "
"scsi_status 0x%x res %d\n",
mp->isp->isp_name, csio->ccb_h.target_lun,
cto->ct_iid, cto->ct_flags,
cto->ct_scsi_status, cto->ct_resid);
} else if (isp_tdebug) {
printf("%s:CTIO lun%d for ID%d ct_flags 0x%x\n",
mp->isp->isp_name, csio->ccb_h.target_lun,
cto->ct_iid, cto->ct_flags);
}
ISP_TDQE(mp->isp, "last tdma_mk", *mp->iptrp, cto);
ISP_SWIZ_CTIO(mp->isp, cto, cto);
} else { } else {
ct_entry_t *octo = cto; ct_entry_t *octo = cto;
/*
* Make sure handle fields are clean
*/
cto->ct_reserved = 0; cto->ct_reserved = 0;
cto->ct_header.rqs_seqno = 0; cto->ct_header.rqs_seqno = 0;
ISP_TDQE(mp->isp, "dma2_tgt", *mp->iptrp, cto);
if (isp_tdebug) { if (isp_tdebug) {
printf("%s:CTIO lun %d->iid%d flgs 0x%x res" printf("%s:CTIO lun%d for ID%d ct_flags 0x%x\n",
" %u\n", mp->isp->isp_name, mp->isp->isp_name, csio->ccb_h.target_lun,
csio->ccb_h.target_lun, cto->ct_iid, cto->ct_iid, cto->ct_flags);
cto->ct_flags, cto->ct_resid);
} }
ISP_TDQE(mp->isp, "tdma_mk", *mp->iptrp, cto);
/*
* Get a new CTIO
*/
cto = (ct_entry_t *) cto = (ct_entry_t *)
ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
*mp->iptrp = *mp->iptrp =
ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN); ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN);
if (*mp->iptrp == mp->optr) { if (*mp->iptrp == mp->optr) {
printf("%s: Queue Overflow in dma2_tgt\n", printf("%s: Queue Overflow in tdma_mk\n",
mp->isp->isp_name); mp->isp->isp_name);
mp->error = MUSHERR_NOQENTRIES; mp->error = MUSHERR_NOQENTRIES;
return; return;
@ -1123,12 +1189,11 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
cto->ct_header.rqs_entry_count = 1; cto->ct_header.rqs_entry_count = 1;
cto->ct_header.rqs_flags = 0; cto->ct_header.rqs_flags = 0;
/* ct_header.rqs_seqno && ct_reserved filled in later */
cto->ct_lun = octo->ct_lun; cto->ct_lun = octo->ct_lun;
cto->ct_iid = octo->ct_iid; cto->ct_iid = octo->ct_iid;
cto->ct_reserved2 = octo->ct_reserved2; cto->ct_reserved2 = octo->ct_reserved2;
cto->ct_tgt = octo->ct_tgt; cto->ct_tgt = octo->ct_tgt;
cto->ct_flags = octo->ct_flags & ~CT_DATAMASK; cto->ct_flags = octo->ct_flags;
cto->ct_status = 0; cto->ct_status = 0;
cto->ct_scsi_status = 0; cto->ct_scsi_status = 0;
cto->ct_tag_val = octo->ct_tag_val; cto->ct_tag_val = octo->ct_tag_val;
@ -1137,14 +1202,18 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
cto->ct_resid = 0; cto->ct_resid = 0;
cto->ct_timeout = octo->ct_timeout; cto->ct_timeout = octo->ct_timeout;
cto->ct_seg_count = 0; cto->ct_seg_count = 0;
bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg)); MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
ISP_SWIZ_CTIO(isp, octo, octo); /*
* Now swizzle the old one for the consumption of the
* chip.
*/
ISP_SWIZ_CTIO(mp->isp, octo, octo);
} }
} }
} }
static void static void
dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
{ {
mush_t *mp; mush_t *mp;
struct ccb_scsiio *csio; struct ccb_scsiio *csio;
@ -1152,10 +1221,9 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
bus_dmamap_t *dp; bus_dmamap_t *dp;
ct2_entry_t *cto; ct2_entry_t *cto;
u_int16_t scsi_status, send_status, send_sense; u_int16_t scsi_status, send_status, send_sense;
u_int32_t handle, totxfr; u_int32_t handle, totxfr, datalen;
u_int8_t sense[QLTM_SENSELEN]; u_int8_t sense[QLTM_SENSELEN];
int nctios; int nctios;
int32_t resid;
mp = (mush_t *) arg; mp = (mush_t *) arg;
if (error) { if (error) {
@ -1174,6 +1242,7 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
return; return;
} }
cto->ct_header.rqs_entry_count = 1; cto->ct_header.rqs_entry_count = 1;
cto->ct_header.rqs_seqno = 1;
/* ct_reserved contains the handle set by caller */ /* ct_reserved contains the handle set by caller */
/* /*
* We preserve ct_lun, ct_iid, ct_rxid. We set the data * We preserve ct_lun, ct_iid, ct_rxid. We set the data
@ -1181,13 +1250,17 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
* We preserve the ct_resid and the response area. * We preserve the ct_resid and the response area.
*/ */
cto->ct_flags |= CT2_NO_DATA; cto->ct_flags |= CT2_NO_DATA;
if (cto->ct_resid > 0)
cto->ct_flags |= CT2_DATA_UNDER;
else if (cto->ct_resid < 0)
cto->ct_flags |= CT2_DATA_OVER;
cto->ct_seg_count = 0; cto->ct_seg_count = 0;
cto->ct_reloff = 0; cto->ct_reloff = 0;
ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto); ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto);
if (isp_tdebug) { if (isp_tdebug) {
scsi_status = cto->rsp.m1.ct_scsi_status; scsi_status = cto->rsp.m1.ct_scsi_status;
printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x " printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x "
"sts 0x%x ssts 0x%x res %u\n", mp->isp->isp_name, "sts 0x%x ssts 0x%x res %d\n", mp->isp->isp_name,
cto->ct_rxid, csio->ccb_h.target_lun, cto->ct_iid, cto->ct_rxid, csio->ccb_h.target_lun, cto->ct_iid,
cto->ct_flags, cto->ct_status, cto->ct_flags, cto->ct_status,
cto->rsp.m1.ct_scsi_status, cto->ct_resid); cto->rsp.m1.ct_scsi_status, cto->ct_resid);
@ -1227,9 +1300,9 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
cto->ct_flags &= ~CT2_SENDSTATUS; cto->ct_flags &= ~CT2_SENDSTATUS;
/* /*
* Preserve residual. * Preserve residual, which is actually the total count.
*/ */
resid = cto->ct_resid; datalen = cto->ct_resid;
/* /*
* Save actual SCSI status. We'll reinsert the * Save actual SCSI status. We'll reinsert the
@ -1251,7 +1324,7 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
nctios++; nctios++;
} }
} else { } else {
scsi_status = send_sense = resid = 0; scsi_status = send_sense = datalen = 0;
} }
totxfr = cto->ct_resid = 0; totxfr = cto->ct_resid = 0;
@ -1342,12 +1415,20 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
scsi_status; scsi_status;
cto->ct_flags |= CT2_SENDSTATUS; cto->ct_flags |= CT2_SENDSTATUS;
} }
cto->ct_resid = resid - totxfr; /*
* Get 'real' residual and set flags based
* on it.
*/
cto->ct_resid = datalen - totxfr;
if (cto->ct_resid > 0)
cto->ct_flags |= CT2_DATA_UNDER;
else if (cto->ct_resid < 0)
cto->ct_flags |= CT2_DATA_OVER;
} }
ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto); ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto);
if (isp_tdebug) { if (isp_tdebug) {
printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs" printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs"
"0x%x sts 0x%x ssts 0x%x res %u\n", "0x%x sts 0x%x ssts 0x%x res %d\n",
mp->isp->isp_name, cto->ct_rxid, mp->isp->isp_name, cto->ct_rxid,
csio->ccb_h.target_lun, (int) cto->ct_iid, csio->ccb_h.target_lun, (int) cto->ct_iid,
cto->ct_flags, cto->ct_status, cto->ct_flags, cto->ct_status,
@ -1564,11 +1645,12 @@ isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
#ifdef ISP_TARGET_MODE #ifdef ISP_TARGET_MODE
if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
if (IS_FC(isp)) { if (IS_FC(isp)) {
eptr = dma2_tgt_fc; eptr = tdma_mkfc;
} else { } else {
eptr = dma2_tgt; eptr = tdma_mk;
} }
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) { if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
(csio->dxfer_len == 0)) {
rq->req_seg_count = 1; rq->req_seg_count = 1;
mp = &mush; mp = &mush;
mp->isp = isp; mp->isp = isp;
@ -1590,7 +1672,8 @@ isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
* NB: that move no data. For commands that move data, * NB: that move no data. For commands that move data,
* NB: swizzling would take place in those functions. * NB: swizzling would take place in those functions.
*/ */
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) { if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
(csio->dxfer_len == 0)) {
rq->req_seg_count = 1; rq->req_seg_count = 1;
return (CMD_QUEUED); return (CMD_QUEUED);
} }

View File

@ -537,11 +537,12 @@ isp_pci_attach(device_t dev)
data = pci_read_config(dev, PCIR_ROMADDR, 4); data = pci_read_config(dev, PCIR_ROMADDR, 4);
data &= ~1; data &= ~1;
pci_write_config(dev, PCIR_ROMADDR, data, 4); pci_write_config(dev, PCIR_ROMADDR, data, 4);
splx(s);
if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
BUS_SPACE_MAXADDR, NULL, NULL, lim + 1, BUS_SPACE_MAXADDR, NULL, NULL, lim + 1,
255, lim, 0, &pcs->parent_dmat) != 0) { 255, lim, 0, &pcs->parent_dmat) != 0) {
splx(s);
printf("%s: could not create master dma tag\n", isp->isp_name); printf("%s: could not create master dma tag\n", isp->isp_name);
free(isp->isp_param, M_DEVBUF); free(isp->isp_param, M_DEVBUF);
free(pcs, M_DEVBUF); free(pcs, M_DEVBUF);
@ -614,7 +615,6 @@ isp_pci_attach(device_t dev)
#ifdef ISP_TARGET_MODE #ifdef ISP_TARGET_MODE
(void) getenv_int("isp_tdebug", &isp_tdebug); (void) getenv_int("isp_tdebug", &isp_tdebug);
#endif #endif
s = splbio();
if (bus_setup_intr(dev, irq, INTR_TYPE_CAM, (void (*)(void *))isp_intr, if (bus_setup_intr(dev, irq, INTR_TYPE_CAM, (void (*)(void *))isp_intr,
isp, &pcs->ih)) { isp, &pcs->ih)) {
splx(s); splx(s);
@ -622,6 +622,9 @@ isp_pci_attach(device_t dev)
goto bad; goto bad;
} }
/*
* Make sure we're in reset state.
*/
isp_reset(isp); isp_reset(isp);
if (isp->isp_state != ISP_RESETSTATE) { if (isp->isp_state != ISP_RESETSTATE) {
splx(s); splx(s);
@ -987,63 +990,87 @@ typedef struct {
* mapped and a pointer to a partially filled in already allocated request * mapped and a pointer to a partially filled in already allocated request
* queue entry. We finish the job. * queue entry. We finish the job.
*/ */
static void dma2_tgt __P((void *, bus_dma_segment_t *, int, int)); static void tdma_mk __P((void *, bus_dma_segment_t *, int, int));
static void dma2_tgt_fc __P((void *, bus_dma_segment_t *, int, int)); static void tdma_mkfc __P((void *, bus_dma_segment_t *, int, int));
static void static void
dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
{ {
mush_t *mp; mush_t *mp;
struct ccb_scsiio *csio; struct ccb_scsiio *csio;
struct isp_pcisoftc *pci; struct isp_pcisoftc *pci;
bus_dmamap_t *dp; bus_dmamap_t *dp;
u_int8_t scsi_status, send_status; u_int8_t scsi_status;
ct_entry_t *cto; ct_entry_t *cto;
u_int32_t handle; u_int32_t handle, totxfr, sflags;
int nctios; int nctios, send_status;
int32_t resid;
mp = (mush_t *) arg; mp = (mush_t *) arg;
if (error) { if (error) {
mp->error = error; mp->error = error;
return; return;
} }
csio = mp->cmd_token; csio = mp->cmd_token;
cto = mp->rq; cto = mp->rq;
cto->ct_xfrlen = 0; cto->ct_xfrlen = 0;
cto->ct_resid = 0;
cto->ct_seg_count = 0; cto->ct_seg_count = 0;
bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg)); cto->ct_header.rqs_entry_count = 1;
MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
if (nseg == 0) { if (nseg == 0) {
cto->ct_header.rqs_entry_count = 1; cto->ct_header.rqs_seqno = 1;
ISP_TDQE(mp->isp, "dma2_tgt[no data]", *mp->iptrp, cto); ISP_TDQE(mp->isp, "tdma_mk[no data]", *mp->iptrp, cto);
if (isp_tdebug) { if (isp_tdebug) {
printf("%s:CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts " printf("%s:CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts "
"0x%x res %u\n", mp->isp->isp_name, "0x%x res %d\n", mp->isp->isp_name,
csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags, csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags,
cto->ct_status, cto->ct_scsi_status, cto->ct_resid); cto->ct_status, cto->ct_scsi_status, cto->ct_resid);
} }
ISP_SWIZ_CTIO(isp, cto, cto); ISP_SWIZ_CTIO(mp->isp, cto, cto);
return; return;
} }
/*
* Save handle, and potentially any SCSI status, which
* we'll reinsert on the last CTIO we're going to send.
*/
handle = cto->ct_reserved;
cto->ct_reserved = 0;
scsi_status = cto->ct_scsi_status;
cto->ct_scsi_status = 0;
send_status = cto->ct_flags & CT_SENDSTATUS;
cto->ct_flags &= ~CT_SENDSTATUS;
nctios = nseg / ISP_RQDSEG; nctios = nseg / ISP_RQDSEG;
if (nseg % ISP_RQDSEG) { if (nseg % ISP_RQDSEG) {
nctios++; nctios++;
} }
/*
* Save handle, and potentially any SCSI status, which we'll reinsert
* on the last CTIO we're going to send.
*/
handle = cto->ct_reserved;
cto->ct_reserved = 0;
cto->ct_header.rqs_seqno = 0;
send_status = (cto->ct_flags & CT_SENDSTATUS) != 0;
if (send_status) {
sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR);
cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR);
/*
* Preserve residual.
*/
resid = cto->ct_resid;
/*
* Save actual SCSI status.
*/
scsi_status = cto->ct_scsi_status;
/*
* We can't do a status at the same time as a data CTIO, so
* we need to synthesize an extra CTIO at this level.
*/
nctios++;
} else {
sflags = scsi_status = resid = 0;
}
totxfr = cto->ct_resid = 0;
cto->ct_scsi_status = 0;
pci = (struct isp_pcisoftc *)mp->isp; pci = (struct isp_pcisoftc *)mp->isp;
dp = &pci->dmaps[isp_handle_index(handle)]; dp = &pci->dmaps[isp_handle_index(handle)];
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
@ -1054,65 +1081,104 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
while (nctios--) { while (nctios--) {
int seg, seglim; int seglim;
seglim = nseg; seglim = nseg;
if (seglim > ISP_RQDSEG) if (seglim) {
seglim = ISP_RQDSEG; int seg;
for (seg = 0; seg < seglim; seg++) { if (seglim > ISP_RQDSEG)
cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; seglim = ISP_RQDSEG;
cto->ct_dataseg[seg].ds_count = dm_segs->ds_len;
cto->ct_xfrlen += dm_segs->ds_len;
dm_segs++;
}
cto->ct_seg_count = seg; for (seg = 0; seg < seglim; seg++, nseg--) {
cto->ct_flags &= CT_DATAMASK; /*
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { * Unlike normal initiator commands, we don't
cto->ct_flags |= CT_DATA_IN; * do any swizzling here.
*/
cto->ct_dataseg[seg].ds_count = dm_segs->ds_len;
cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr;
cto->ct_xfrlen += dm_segs->ds_len;
totxfr += dm_segs->ds_len;
dm_segs++;
}
cto->ct_seg_count = seg;
} else { } else {
cto->ct_flags |= CT_DATA_OUT; /*
* This case should only happen when we're sending an
* extra CTIO with final status.
*/
if (send_status == 0) {
printf("%s: tdma_mk ran out of segments\n",
mp->isp->isp_name);
mp->error = EINVAL;
return;
}
} }
/*
* At this point, the fields ct_lun, ct_iid, ct_tagval,
* ct_tagtype, and ct_timeout have been carried over
* unchanged from what our caller had set.
*
* The dataseg fields and the seg_count fields we just got
* through setting. The data direction we've preserved all
* along and only clear it if we're now sending status.
*/
if (nctios == 0) { if (nctios == 0) {
/* /*
* We're the last in a sequence of CTIOs, so mark this * We're the last in a sequence of CTIOs, so mark
* CTIO and save the handle to the CCB such that when * this CTIO and save the handle to the CCB such that
* this CTIO completes we can free dma resources and * when this CTIO completes we can free dma resources
* do whatever else we need to do to finish the rest * and do whatever else we need to do to finish the
* of the command. * rest of the command.
*/ */
cto->ct_header.rqs_seqno = 1;
cto->ct_reserved = handle; cto->ct_reserved = handle;
cto->ct_scsi_status = scsi_status; cto->ct_header.rqs_seqno = 1;
cto->ct_flags |= send_status;
ISP_TDQE(mp->isp, "last dma2_tgt", *mp->iptrp, cto); if (send_status) {
if (isp_tdebug) { cto->ct_scsi_status = scsi_status;
printf("%s:CTIO lun %d->iid%d flgs 0x%x sts " cto->ct_flags |= sflags | CT_NO_DATA;;
"0x%x ssts 0x%x res %u\n", cto->ct_resid = resid;
mp->isp->isp_name, csio->ccb_h.target_lun,
cto->ct_iid, cto->ct_flags, cto->ct_status,
cto->ct_scsi_status, cto->ct_resid);
} }
ISP_SWIZ_CTIO(isp, cto, cto); if (isp_tdebug && send_status) {
printf("%s:CTIO lun%d for ID%d ct_flags 0x%x "
"scsi_status 0x%x res %d\n",
mp->isp->isp_name, csio->ccb_h.target_lun,
cto->ct_iid, cto->ct_flags,
cto->ct_scsi_status, cto->ct_resid);
} else if (isp_tdebug) {
printf("%s:CTIO lun%d for ID%d ct_flags 0x%x\n",
mp->isp->isp_name, csio->ccb_h.target_lun,
cto->ct_iid, cto->ct_flags);
}
ISP_TDQE(mp->isp, "last tdma_mk", *mp->iptrp, cto);
ISP_SWIZ_CTIO(mp->isp, cto, cto);
} else { } else {
ct_entry_t *octo = cto; ct_entry_t *octo = cto;
/*
* Make sure handle fields are clean
*/
cto->ct_reserved = 0; cto->ct_reserved = 0;
cto->ct_header.rqs_seqno = 0; cto->ct_header.rqs_seqno = 0;
ISP_TDQE(mp->isp, "dma2_tgt", *mp->iptrp, cto);
if (isp_tdebug) { if (isp_tdebug) {
printf("%s:CTIO lun %d->iid%d flgs 0x%x res" printf("%s:CTIO lun%d for ID%d ct_flags 0x%x\n",
" %u\n", mp->isp->isp_name, mp->isp->isp_name, csio->ccb_h.target_lun,
csio->ccb_h.target_lun, cto->ct_iid, cto->ct_iid, cto->ct_flags);
cto->ct_flags, cto->ct_resid);
} }
ISP_TDQE(mp->isp, "tdma_mk", *mp->iptrp, cto);
/*
* Get a new CTIO
*/
cto = (ct_entry_t *) cto = (ct_entry_t *)
ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
*mp->iptrp = *mp->iptrp =
ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN); ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN);
if (*mp->iptrp == mp->optr) { if (*mp->iptrp == mp->optr) {
printf("%s: Queue Overflow in dma2_tgt\n", printf("%s: Queue Overflow in tdma_mk\n",
mp->isp->isp_name); mp->isp->isp_name);
mp->error = MUSHERR_NOQENTRIES; mp->error = MUSHERR_NOQENTRIES;
return; return;
@ -1123,12 +1189,11 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
cto->ct_header.rqs_entry_count = 1; cto->ct_header.rqs_entry_count = 1;
cto->ct_header.rqs_flags = 0; cto->ct_header.rqs_flags = 0;
/* ct_header.rqs_seqno && ct_reserved filled in later */
cto->ct_lun = octo->ct_lun; cto->ct_lun = octo->ct_lun;
cto->ct_iid = octo->ct_iid; cto->ct_iid = octo->ct_iid;
cto->ct_reserved2 = octo->ct_reserved2; cto->ct_reserved2 = octo->ct_reserved2;
cto->ct_tgt = octo->ct_tgt; cto->ct_tgt = octo->ct_tgt;
cto->ct_flags = octo->ct_flags & ~CT_DATAMASK; cto->ct_flags = octo->ct_flags;
cto->ct_status = 0; cto->ct_status = 0;
cto->ct_scsi_status = 0; cto->ct_scsi_status = 0;
cto->ct_tag_val = octo->ct_tag_val; cto->ct_tag_val = octo->ct_tag_val;
@ -1137,14 +1202,18 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
cto->ct_resid = 0; cto->ct_resid = 0;
cto->ct_timeout = octo->ct_timeout; cto->ct_timeout = octo->ct_timeout;
cto->ct_seg_count = 0; cto->ct_seg_count = 0;
bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg)); MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
ISP_SWIZ_CTIO(isp, octo, octo); /*
* Now swizzle the old one for the consumption of the
* chip.
*/
ISP_SWIZ_CTIO(mp->isp, octo, octo);
} }
} }
} }
static void static void
dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
{ {
mush_t *mp; mush_t *mp;
struct ccb_scsiio *csio; struct ccb_scsiio *csio;
@ -1152,10 +1221,9 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
bus_dmamap_t *dp; bus_dmamap_t *dp;
ct2_entry_t *cto; ct2_entry_t *cto;
u_int16_t scsi_status, send_status, send_sense; u_int16_t scsi_status, send_status, send_sense;
u_int32_t handle, totxfr; u_int32_t handle, totxfr, datalen;
u_int8_t sense[QLTM_SENSELEN]; u_int8_t sense[QLTM_SENSELEN];
int nctios; int nctios;
int32_t resid;
mp = (mush_t *) arg; mp = (mush_t *) arg;
if (error) { if (error) {
@ -1174,6 +1242,7 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
return; return;
} }
cto->ct_header.rqs_entry_count = 1; cto->ct_header.rqs_entry_count = 1;
cto->ct_header.rqs_seqno = 1;
/* ct_reserved contains the handle set by caller */ /* ct_reserved contains the handle set by caller */
/* /*
* We preserve ct_lun, ct_iid, ct_rxid. We set the data * We preserve ct_lun, ct_iid, ct_rxid. We set the data
@ -1181,13 +1250,17 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
* We preserve the ct_resid and the response area. * We preserve the ct_resid and the response area.
*/ */
cto->ct_flags |= CT2_NO_DATA; cto->ct_flags |= CT2_NO_DATA;
if (cto->ct_resid > 0)
cto->ct_flags |= CT2_DATA_UNDER;
else if (cto->ct_resid < 0)
cto->ct_flags |= CT2_DATA_OVER;
cto->ct_seg_count = 0; cto->ct_seg_count = 0;
cto->ct_reloff = 0; cto->ct_reloff = 0;
ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto); ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto);
if (isp_tdebug) { if (isp_tdebug) {
scsi_status = cto->rsp.m1.ct_scsi_status; scsi_status = cto->rsp.m1.ct_scsi_status;
printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x " printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x "
"sts 0x%x ssts 0x%x res %u\n", mp->isp->isp_name, "sts 0x%x ssts 0x%x res %d\n", mp->isp->isp_name,
cto->ct_rxid, csio->ccb_h.target_lun, cto->ct_iid, cto->ct_rxid, csio->ccb_h.target_lun, cto->ct_iid,
cto->ct_flags, cto->ct_status, cto->ct_flags, cto->ct_status,
cto->rsp.m1.ct_scsi_status, cto->ct_resid); cto->rsp.m1.ct_scsi_status, cto->ct_resid);
@ -1227,9 +1300,9 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
cto->ct_flags &= ~CT2_SENDSTATUS; cto->ct_flags &= ~CT2_SENDSTATUS;
/* /*
* Preserve residual. * Preserve residual, which is actually the total count.
*/ */
resid = cto->ct_resid; datalen = cto->ct_resid;
/* /*
* Save actual SCSI status. We'll reinsert the * Save actual SCSI status. We'll reinsert the
@ -1251,7 +1324,7 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
nctios++; nctios++;
} }
} else { } else {
scsi_status = send_sense = resid = 0; scsi_status = send_sense = datalen = 0;
} }
totxfr = cto->ct_resid = 0; totxfr = cto->ct_resid = 0;
@ -1342,12 +1415,20 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
scsi_status; scsi_status;
cto->ct_flags |= CT2_SENDSTATUS; cto->ct_flags |= CT2_SENDSTATUS;
} }
cto->ct_resid = resid - totxfr; /*
* Get 'real' residual and set flags based
* on it.
*/
cto->ct_resid = datalen - totxfr;
if (cto->ct_resid > 0)
cto->ct_flags |= CT2_DATA_UNDER;
else if (cto->ct_resid < 0)
cto->ct_flags |= CT2_DATA_OVER;
} }
ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto); ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto);
if (isp_tdebug) { if (isp_tdebug) {
printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs" printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs"
"0x%x sts 0x%x ssts 0x%x res %u\n", "0x%x sts 0x%x ssts 0x%x res %d\n",
mp->isp->isp_name, cto->ct_rxid, mp->isp->isp_name, cto->ct_rxid,
csio->ccb_h.target_lun, (int) cto->ct_iid, csio->ccb_h.target_lun, (int) cto->ct_iid,
cto->ct_flags, cto->ct_status, cto->ct_flags, cto->ct_status,
@ -1564,11 +1645,12 @@ isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
#ifdef ISP_TARGET_MODE #ifdef ISP_TARGET_MODE
if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
if (IS_FC(isp)) { if (IS_FC(isp)) {
eptr = dma2_tgt_fc; eptr = tdma_mkfc;
} else { } else {
eptr = dma2_tgt; eptr = tdma_mk;
} }
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) { if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
(csio->dxfer_len == 0)) {
rq->req_seg_count = 1; rq->req_seg_count = 1;
mp = &mush; mp = &mush;
mp->isp = isp; mp->isp = isp;
@ -1590,7 +1672,8 @@ isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
* NB: that move no data. For commands that move data, * NB: that move no data. For commands that move data,
* NB: swizzling would take place in those functions. * NB: swizzling would take place in those functions.
*/ */
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) { if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
(csio->dxfer_len == 0)) {
rq->req_seg_count = 1; rq->req_seg_count = 1;
return (CMD_QUEUED); return (CMD_QUEUED);
} }