diff options
author | gibbs <gibbs@FreeBSD.org> | 2000-10-06 04:01:06 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 2000-10-06 04:01:06 +0000 |
commit | 1cc3d5d7b74546d67cdf228f04b3fc2d5dc6dfb4 (patch) | |
tree | 17fcaf8a3e1fa4a919079d07440bdc33add5f8b8 /sys/dev/aic7xxx | |
parent | fd275a78bd168fffc26552c4b2debf6f105a43ed (diff) | |
download | FreeBSD-src-1cc3d5d7b74546d67cdf228f04b3fc2d5dc6dfb4.zip FreeBSD-src-1cc3d5d7b74546d67cdf228f04b3fc2d5dc6dfb4.tar.gz |
Bring in a slew of fixes that were supposed to be in the last commit.
In ahc_search_qinfifo, the SEARCH_REMOVE case must also handle
an SCB that has been removed from the QINFIFO but not yet been
fully dmaed to the card.
Correct locking for ahc_get_scb() calls.
Set SCB syncrate settings in ahc_execute_scb() to avoid a race
condition that could allow a newly queued SCB to be missed
by ahc_update_pending_syncrates().
When notifying the system of transfer negotiation updates, only
set the valid bits for tagged queuing and disconnection if the
path is fully qualified. Sync/Wide settins apply to all luns
of a target, but tagged queuing and disconnection may change
on a per-lun basis.
Add missing ahc_unlock() calls in ahc_timeout() for the target
mode case.
Diffstat (limited to 'sys/dev/aic7xxx')
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.c | 4 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_freebsd.c | 78 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_osm.c | 78 |
3 files changed, 90 insertions, 70 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index cc4f9d7..0cf506d 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -4279,6 +4279,8 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, printf("Inactive SCB in qinfifo\n"); ahc_done(ahc, scb); + /* FALLTHROUGH */ + case SEARCH_REMOVE: /* * The sequencer increments its position in * the qinfifo as soon as it determines that @@ -4299,8 +4301,6 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, ahc_qinfifo_requeue(ahc, prev_scb, scb); prev_scb = scb; break; - case SEARCH_REMOVE: - break; } } else { ahc_qinfifo_requeue(ahc, prev_scb, scb); diff --git a/sys/dev/aic7xxx/aic7xxx_freebsd.c b/sys/dev/aic7xxx/aic7xxx_freebsd.c index 0cafccc..70fd7d8 100644 --- a/sys/dev/aic7xxx/aic7xxx_freebsd.c +++ b/sys/dev/aic7xxx/aic7xxx_freebsd.c @@ -424,18 +424,15 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) case XPT_SCSI_IO: /* Execute the requested I/O operation */ case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ { - struct scb *scb; - struct hardware_scb *hscb; - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - uint16_t mask; + struct scb *scb; + struct hardware_scb *hscb; /* * get an scb to use. */ + ahc_lock(ahc, &s); if ((scb = ahc_get_scb(ahc)) == NULL) { - ahc_lock(ahc, &s); ahc->flags |= AHC_RESOURCE_SHORTAGE; ahc_unlock(ahc, &s); xpt_freeze_simq(sim, /*count*/1); @@ -443,6 +440,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) xpt_done(ccb); return; } + ahc_unlock(ahc, &s); hscb = scb->hscb; @@ -461,25 +459,6 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) hscb->control = 0; hscb->scsiid = BUILD_SCSIID(ahc, sim, target_id, our_id); hscb->lun = ccb->ccb_h.target_lun; - mask = SCB_GET_TARGET_MASK(ahc, 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 ((tstate->ultraenb & mask) != 0) - hscb->control |= ULTRAENB; - - if ((tstate->discenable & mask) != 0 - && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) - hscb->control |= DISCENB; - - if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 - && (tinfo->current.width != 0 || tinfo->current.period != 0)) { - scb->flags |= SCB_NEGOTIATE; - hscb->control |= MK_MESSAGE; - } - if (ccb->ccb_h.func_code == XPT_RESET_DEV) { hscb->cdb_len = 0; scb->flags |= SCB_DEVICE_RESET; @@ -954,13 +933,18 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, cts->protocol = PROTO_SCSI; cts->transport = XPORT_SPI; - scsi->valid = CTS_SCSI_VALID_TQ; spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET | CTS_SPI_VALID_BUS_WIDTH - | CTS_SPI_VALID_DISC | CTS_SPI_VALID_PPR_OPTIONS; + if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { + scsi->valid = CTS_SCSI_VALID_TQ; + spi->valid |= CTS_SPI_VALID_DISC; + } else { + scsi->valid = 0; + } + cts->ccb_h.status = CAM_REQ_CMP; #else struct ahc_devinfo devinfo; @@ -1006,9 +990,10 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, cts->valid = CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID - | CCB_TRANS_BUS_WIDTH_VALID - | CCB_TRANS_DISC_VALID - | CCB_TRANS_TQ_VALID; + | CCB_TRANS_BUS_WIDTH_VALID; + + if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) + cts->valid |= CCB_TRANS_DISC_VALID|CCB_TRANS_TQ_VALID; cts->ccb_h.status = CAM_REQ_CMP; #endif @@ -1057,10 +1042,13 @@ static void ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, int error) { - struct scb *scb; - union ccb *ccb; - struct ahc_softc *ahc; - long s; + struct scb *scb; + union ccb *ccb; + struct ahc_softc *ahc; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int mask; + long s; scb = (struct scb *)arg; ccb = scb->io_ctx; @@ -1183,6 +1171,26 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, return; } + tinfo = ahc_fetch_transinfo(ahc, SCSIID_CHANNEL(ahc, scb->hscb->scsiid), + SCSIID_OUR_ID(scb->hscb->scsiid), + ccb->ccb_h.target_id, &tstate); + + mask = SCB_GET_TARGET_MASK(ahc, scb); + scb->hscb->scsirate = tinfo->scsirate; + scb->hscb->scsioffset = tinfo->current.offset; + if ((tstate->ultraenb & mask) != 0) + scb->hscb->control |= ULTRAENB; + + if ((tstate->discenable & mask) != 0 + && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) + scb->hscb->control |= DISCENB; + + if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 + && (tinfo->current.width != 0 || tinfo->current.period != 0)) { + scb->flags |= SCB_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } + LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); ccb->ccb_h.status |= CAM_SIM_QUEUED; @@ -1526,6 +1534,7 @@ bus_reset: /* Will clear us from the bus */ restart_sequencer(ahc); + ahc_unlock(ahc, &s); return; } @@ -1552,6 +1561,7 @@ bus_reset: printf("%s: Hung target selection\n", ahc_name(ahc)); restart_sequencer(ahc); + ahc_unlock(ahc, &s); return; } diff --git a/sys/dev/aic7xxx/aic7xxx_osm.c b/sys/dev/aic7xxx/aic7xxx_osm.c index 0cafccc..70fd7d8 100644 --- a/sys/dev/aic7xxx/aic7xxx_osm.c +++ b/sys/dev/aic7xxx/aic7xxx_osm.c @@ -424,18 +424,15 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) case XPT_SCSI_IO: /* Execute the requested I/O operation */ case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ { - struct scb *scb; - struct hardware_scb *hscb; - struct ahc_initiator_tinfo *tinfo; - struct tmode_tstate *tstate; - uint16_t mask; + struct scb *scb; + struct hardware_scb *hscb; /* * get an scb to use. */ + ahc_lock(ahc, &s); if ((scb = ahc_get_scb(ahc)) == NULL) { - ahc_lock(ahc, &s); ahc->flags |= AHC_RESOURCE_SHORTAGE; ahc_unlock(ahc, &s); xpt_freeze_simq(sim, /*count*/1); @@ -443,6 +440,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) xpt_done(ccb); return; } + ahc_unlock(ahc, &s); hscb = scb->hscb; @@ -461,25 +459,6 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) hscb->control = 0; hscb->scsiid = BUILD_SCSIID(ahc, sim, target_id, our_id); hscb->lun = ccb->ccb_h.target_lun; - mask = SCB_GET_TARGET_MASK(ahc, 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 ((tstate->ultraenb & mask) != 0) - hscb->control |= ULTRAENB; - - if ((tstate->discenable & mask) != 0 - && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) - hscb->control |= DISCENB; - - if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 - && (tinfo->current.width != 0 || tinfo->current.period != 0)) { - scb->flags |= SCB_NEGOTIATE; - hscb->control |= MK_MESSAGE; - } - if (ccb->ccb_h.func_code == XPT_RESET_DEV) { hscb->cdb_len = 0; scb->flags |= SCB_DEVICE_RESET; @@ -954,13 +933,18 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, cts->protocol = PROTO_SCSI; cts->transport = XPORT_SPI; - scsi->valid = CTS_SCSI_VALID_TQ; spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET | CTS_SPI_VALID_BUS_WIDTH - | CTS_SPI_VALID_DISC | CTS_SPI_VALID_PPR_OPTIONS; + if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { + scsi->valid = CTS_SCSI_VALID_TQ; + spi->valid |= CTS_SPI_VALID_DISC; + } else { + scsi->valid = 0; + } + cts->ccb_h.status = CAM_REQ_CMP; #else struct ahc_devinfo devinfo; @@ -1006,9 +990,10 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, cts->valid = CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID - | CCB_TRANS_BUS_WIDTH_VALID - | CCB_TRANS_DISC_VALID - | CCB_TRANS_TQ_VALID; + | CCB_TRANS_BUS_WIDTH_VALID; + + if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) + cts->valid |= CCB_TRANS_DISC_VALID|CCB_TRANS_TQ_VALID; cts->ccb_h.status = CAM_REQ_CMP; #endif @@ -1057,10 +1042,13 @@ static void ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, int error) { - struct scb *scb; - union ccb *ccb; - struct ahc_softc *ahc; - long s; + struct scb *scb; + union ccb *ccb; + struct ahc_softc *ahc; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int mask; + long s; scb = (struct scb *)arg; ccb = scb->io_ctx; @@ -1183,6 +1171,26 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, return; } + tinfo = ahc_fetch_transinfo(ahc, SCSIID_CHANNEL(ahc, scb->hscb->scsiid), + SCSIID_OUR_ID(scb->hscb->scsiid), + ccb->ccb_h.target_id, &tstate); + + mask = SCB_GET_TARGET_MASK(ahc, scb); + scb->hscb->scsirate = tinfo->scsirate; + scb->hscb->scsioffset = tinfo->current.offset; + if ((tstate->ultraenb & mask) != 0) + scb->hscb->control |= ULTRAENB; + + if ((tstate->discenable & mask) != 0 + && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0) + scb->hscb->control |= DISCENB; + + if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0 + && (tinfo->current.width != 0 || tinfo->current.period != 0)) { + scb->flags |= SCB_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } + LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); ccb->ccb_h.status |= CAM_SIM_QUEUED; @@ -1526,6 +1534,7 @@ bus_reset: /* Will clear us from the bus */ restart_sequencer(ahc); + ahc_unlock(ahc, &s); return; } @@ -1552,6 +1561,7 @@ bus_reset: printf("%s: Hung target selection\n", ahc_name(ahc)); restart_sequencer(ahc); + ahc_unlock(ahc, &s); return; } |