summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1997-02-03 02:16:16 +0000
committergibbs <gibbs@FreeBSD.org>1997-02-03 02:16:16 +0000
commit6ed4640da220565231750fd5df08212633593f98 (patch)
tree7c5869186bf3eadf17360fbb0d63e0bf30c9bfb7 /sys
parent7ee6b3a7026d6cc577df454bad2ccc122e691e35 (diff)
downloadFreeBSD-src-6ed4640da220565231750fd5df08212633593f98.zip
FreeBSD-src-6ed4640da220565231750fd5df08212633593f98.tar.gz
White space cleanup and other cosmetic style changes.
Fix a few panics during error recovery: 1) Stupid mistake in the "no SCB match handler" where I was using the wrong variable (busy_scbid instead of scb_index). 2) Unbusy the target of an abort request if the command we are trying to abort is an untagged transaction. If we don't, we get a fatal NO_MATCH_BUSY condition which "should never happen". 3) When an abort completes, turn off ahc->in_timeout or else the next timeout will hit the protective "scb timesout again" panic. 4) Fix a typo that caused the requeued "abort" SCB to have its TAG_ENB and disconnect bits to be cleared (missing ~) so that devices would complain about overlapped commands. Be sure to turn off the unexpected busfree interrupt after we do a bus reset since we are expecting the bus to go free in that case. Return XS_TIMEOUT instead of XS_DRIVERSTUFFUP in certain scenarios. XS_TIMEOUT allows for retries, XS_DRIVERSTUFFUP does not. Allow commands with SDTR and WDTR negotiation to be tagged. The SCSI II spec says that you probably should not do this for fear of hitting bogus devices. The driver did this in the past for almost two years without any problem, and not doing it causes problems during error recovery to a tag capable device as the number of openings is higher than two and we'll start sending it tagged commands causing "overlapped commands attempted" type errors. The real fix needs to happen in the generic SCSI layer which can limit the number and type of transactions to a device during error recovery efficiently. Give ourselves at least 100ms to perform a request sense instead of relying on the original timeout to be long enough to complete this new command as well as the one that generated the condition. Removed some redundant code.
Diffstat (limited to 'sys')
-rw-r--r--sys/i386/scsi/aic7xxx.c73
-rw-r--r--sys/i386/scsi/aic7xxx.h14
2 files changed, 62 insertions, 25 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index fd00b04..da5d107 100644
--- a/sys/i386/scsi/aic7xxx.c
+++ b/sys/i386/scsi/aic7xxx.c
@@ -463,9 +463,9 @@ ahc_construct(ahc, bc, ioh, maddr, type, flags)
ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN;
ahc->pause = ahc->unpause | PAUSE;
- ahc->busreset_args.ahc = ahc;
+ ahc->busreset_args.ahc = ahc;
ahc->busreset_args.bus = 'A';
- ahc->busreset_args.ahc = ahc;
+ ahc->busreset_args.ahc = ahc;
ahc->busreset_args.bus = 'B';
#if defined(__FreeBSD__)
@@ -848,7 +848,7 @@ ahc_handle_seqint(ahc, intstat)
scb_index = busy_scbid;
if (scb_index < ahc->scb_data->numscbs) {
- scb = ahc->scb_data->scbarray[busy_scbid];
+ scb = ahc->scb_data->scbarray[scb_index];
if (scb->hscb->control & ABORT_SCB) {
sc_print_addr(scb->xs->sc_link);
@@ -1174,6 +1174,7 @@ ahc_handle_seqint(ahc, intstat)
*/
if (hscb->residual_SG_segment_count != 0)
ahc_calc_residual(scb);
+
#ifdef AHC_DEBUG
if (ahc_debug & AHC_SHOWSENSE) {
sc_print_addr(xs->sc_link);
@@ -1205,6 +1206,14 @@ ahc_handle_seqint(ahc, intstat)
scb->flags |= SCB_SENSE;
ahc_outb(ahc, RETURN_1, SEND_SENSE);
+
+ /*
+ * Ensure we have enough time to actually
+ * retrieve the sense.
+ */
+ untimeout(ahc_timeout, (caddr_t)scb);
+ timeout(ahc_timeout, (caddr_t)scb,
+ (100 * hz) / 1000);
break;
}
/*
@@ -1264,17 +1273,18 @@ ahc_handle_seqint(ahc, intstat)
}
case AWAITING_MSG:
{
- int scb_index;
+ int scb_index;
u_int8_t message_offset;
scb_index = ahc_inb(ahc, SCB_TAG);
scb = ahc->scb_data->scbarray[scb_index];
- message_offset = ahc_inb(ahc, MSG_LEN);
+
/*
* This SCB had MK_MESSAGE set in its control byte,
* informing the sequencer that we wanted to send a
* special message to this target.
*/
+ message_offset = ahc_inb(ahc, MSG_LEN);
if (scb->flags & SCB_DEVICE_RESET) {
ahc_outb(ahc, MSG0, MSG_BUS_DEV_RESET);
ahc_outb(ahc, MSG_LEN, 1);
@@ -1510,6 +1520,13 @@ ahc_handle_scsiint(ahc, intstat)
ahc_run_done_queue(ahc);
scb = NULL;
printerror = 0;
+ /*
+ * We only send these for
+ * error recovery, so if it
+ * worked, we're no longer in
+ * a timeout.
+ */
+ ahc->in_timeout = 0;
}
}
}
@@ -1525,6 +1542,7 @@ ahc_handle_scsiint(ahc, intstat)
printf("Unexpected busfree. LASTPHASE == 0x%x\n",
lastphase);
}
+ ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
ahc_outb(ahc, CLRSINT1, CLRBUSFREE);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
restart_sequencer(ahc);
@@ -1707,7 +1725,7 @@ ahc_done(ahc, scb)
if (xs->error != XS_NOERROR) {
/* Don't override the error value. */
} else if (scb->flags & SCB_ABORTED) {
- xs->error = XS_DRIVER_STUFFUP;
+ xs->error = XS_TIMEOUT;
} else if (scb->flags & SCB_SENSE)
xs->error = XS_SENSE;
if (scb->flags & SCB_SENTORDEREDTAG)
@@ -2221,7 +2239,7 @@ ahc_scsi_cmd(xs)
ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;
mask = (0x01 << (xs->sc_link->target
- | (IS_SCSIBUS_B(ahc, xs->sc_link) ? SELBUSB : 0)));
+ | (IS_SCSIBUS_B(ahc, xs->sc_link) ? SELBUSB : 0)));
SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_scsi_cmd\n"));
flags = xs->flags;
@@ -2258,8 +2276,11 @@ ahc_scsi_cmd(xs)
/*
* Put all the arguments for the xfer in the scb
*/
- if (ahc->discenable & mask)
+ if (ahc->discenable & mask) {
hscb->control |= DISCENB;
+ if (ahc->tagenable & mask)
+ hscb->control |= TAG_ENB;
+ }
if (flags & SCSI_RESET) {
scb->flags |= SCB_DEVICE_RESET|SCB_IMMED;
@@ -2277,9 +2298,6 @@ ahc_scsi_cmd(xs)
printf("Ordered Tag sent\n");
hscb->control |= MSG_ORDERED_Q_TAG;
ahc->orderedtag &= ~mask;
- } else if (hscb->control & DISCENB) {
- if (ahc->tagenable & mask)
- hscb->control |= TAG_ENB;
}
#if 0
@@ -2635,7 +2653,7 @@ ahc_poll(ahc, wait)
*/
static void
ahc_first_timeout(arg)
- void *arg;
+ void *arg;
{
timeouts_work = 1;
}
@@ -2648,10 +2666,11 @@ ahc_timeout(arg)
struct ahc_softc *ahc;
int s, found;
u_int8_t bus_state;
+ char channel;
ahc = (struct ahc_softc *)scb->xs->sc_link->adapter_softc;
- s = splbio();
+ s = splbio();
/*
* Ensure that the card doesn't do anything
@@ -2751,13 +2770,12 @@ ahc_timeout(arg)
| (ahc_inb(ahc, SEQADDR1) << 8));
/* Decide our course of action */
+ channel = (scb->hscb->tcl & SELBUSB) ? 'B': 'A';
if (scb->flags & SCB_ABORTED) {
/*
* Been down this road before.
* Do a full bus reset.
*/
- char channel = (scb->hscb->tcl & SELBUSB)
- ? 'B': 'A';
found = ahc_reset_channel(ahc, channel, XS_TIMEOUT,
/*Initiate Reset*/TRUE);
printf("%s: Issued Channel %c Bus Reset. "
@@ -2836,7 +2854,7 @@ ahc_timeout(arg)
if (disconnected) {
/* Simply set the ABORT_SCB control bit */
scb->hscb->control |= ABORT_SCB|MK_MESSAGE;
- scb->hscb->control &= DISCONNECTED;;
+ scb->hscb->control &= ~DISCONNECTED;;
scb->flags |= SCB_ABORT;
if (hscb_index != SCB_LIST_NULL) {
u_int8_t scb_control;
@@ -2847,10 +2865,20 @@ ahc_timeout(arg)
}
/*
* Actually re-queue this SCB in case we can
- * select the device before it reconnects.
+ * select the device before it reconnects. If
+ * the transaction we want to abort is not
+ * tagged, unbusy it first so that we don't
+ * get held back from sending the command.
*/
STAILQ_INSERT_HEAD(&ahc->waiting_scbs, scb,
links);
+ if ((scb->hscb->control & TAG_ENB) != 0) {
+ u_int8_t target;
+
+ target = scb->xs->sc_link->target;
+ ahc_unbusy_target(ahc, target, channel);
+ }
+
timeout(ahc_timeout, (caddr_t)scb,
(100 * hz) / 1000);
ahc_run_waiting_queue(ahc);
@@ -2923,7 +2951,7 @@ ahc_reset_device(ahc, target, channel, tag, xs_error)
for (i = 0; i < (queued - found); i++) {
saved_queue[i] = ahc_inb(ahc, QINFIFO);
scbp = ahc->scb_data->scbarray[saved_queue[i]];
- if (ahc_match_scb (scbp, target, channel, tag)) {
+ if (ahc_match_scb(scbp, target, channel, tag)) {
/*
* We found an scb that needs to be aborted.
*/
@@ -2977,7 +3005,7 @@ ahc_reset_device(ahc, target, channel, tag, xs_error)
(scbp->hscb->tcl & SELBUSB) ?
'B' : 'A');
scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE;
- scbp->xs->error |= xs_error;
+ scbp->xs->error = xs_error;
untimeout(ahc_timeout, (caddr_t)scbp);
found++;
}
@@ -3240,9 +3268,6 @@ ahc_reset_channel(ahc, channel, xs_error, initiate_reset)
offset_max = TARG_SCRATCH + 8;
}
- for (target = 0; target < maxtarget; target++)
- ahc_unbusy_target(ahc, target, channel);
-
for (; offset < offset_max; offset++) {
/*
* Revert to async/narrow transfers
@@ -3308,8 +3333,8 @@ ahc_match_scb (scb, target, channel, tag)
char channel;
u_int8_t tag;
{
- int targ = (scb->hscb->tcl >> 4) & 0x0f;
- char chan = (scb->hscb->tcl & SELBUSB) ? 'B' : 'A';
+ int targ = (scb->hscb->tcl >> 4) & 0x0f;
+ char chan = (scb->hscb->tcl & SELBUSB) ? 'B' : 'A';
int match;
match = ((chan == channel) || (channel == ALL_CHANNELS));
diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h
index e68ed23..1d857ca 100644
--- a/sys/i386/scsi/aic7xxx.h
+++ b/sys/i386/scsi/aic7xxx.h
@@ -56,7 +56,19 @@
#define stqe_next sqe_next
#endif
-#define AHC_NSEG 256 /* number of dma segments supported */
+#define AHC_NSEG 32 /* The number of dma segments supported.
+ * AHC_NSEG can be maxed out at 256 entries,
+ * but the kernel will never need to transfer
+ * such a large (1MB) request. To reduce the
+ * driver's memory consumption, we reduce the
+ * max to 32. 16 would work if all transfers
+ * are paged alined since the kernel will only
+ * generate at most a 64k transfer, but to
+ * handle non-page aligned transfers, you need
+ * 17, so we round to the next power of two
+ * to make allocating SG space easy and
+ * efficient.
+ */
#define AHC_SCB_MAX 255 /*
* Up to 255 SCBs on some types of aic7xxx
OpenPOWER on IntegriCloud