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.
This commit is contained in:
Justin T. Gibbs 2000-10-06 04:01:06 +00:00
parent 6c56727456
commit ff0c1daf6b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=66717
3 changed files with 90 additions and 70 deletions

View File

@ -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);

View File

@ -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 @@ ahc_timeout(void *arg)
/* Will clear us from the bus */
restart_sequencer(ahc);
ahc_unlock(ahc, &s);
return;
}
@ -1552,6 +1561,7 @@ ahc_timeout(void *arg)
printf("%s: Hung target selection\n",
ahc_name(ahc));
restart_sequencer(ahc);
ahc_unlock(ahc, &s);
return;
}

View File

@ -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 @@ ahc_timeout(void *arg)
/* Will clear us from the bus */
restart_sequencer(ahc);
ahc_unlock(ahc, &s);
return;
}
@ -1552,6 +1561,7 @@ ahc_timeout(void *arg)
printf("%s: Hung target selection\n",
ahc_name(ahc));
restart_sequencer(ahc);
ahc_unlock(ahc, &s);
return;
}