diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq index c5a1e9b79d14..e8cc5bb6a152 100644 --- a/sys/dev/aic7xxx/aic7xxx.seq +++ b/sys/dev/aic7xxx/aic7xxx.seq @@ -41,7 +41,7 @@ # ##-M######################################################################### -VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.14 1995/04/15 21:45:56 gibbs Exp $" +VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.15 1995/04/27 17:44:27 gibbs Exp $" SCBMASK = 0x1f @@ -155,6 +155,12 @@ MSG_REJECT = 0x61 # Reject message recieved BAD_STATUS = 0x71 # Bad status from target RESIDUAL = 0x81 # Residual byte count != 0 ABORT_TAG = 0x91 # Sent an ABORT_TAG message +AWAITING_MSG = 0xa1 # Kernel requested to specify + # a message to this target + # (command was null), so tell + # it that it can fill the + # message buffer. + # The host adapter card (at least the BIOS) uses 20-2f for SCSI # device information, 32-33 and 5a-5f as well. As it turns out, the @@ -179,8 +185,8 @@ ABORT_TAG = 0x91 # Sent an ABORT_TAG message # bank, so force a kernel panic if the target attempts a data in/out or # command phase instead of corrupting something. FLAGS also contains # configuration bits so that we can optimize for TWIN and WIDE controllers -# as well as the MAX_SYNC bit which we set when we want to negotiate for -# 10MHz irregardless of what the per target scratch space says. +# as well as the MAX_OFFSET bit which we set when we want to negotiate for +# maximum sync offset irregardless of what the per target scratch space says. # # Note that SG_NEXT occupies four bytes. # @@ -222,11 +228,14 @@ SCBCOUNT = 0x52 # the actual number of SCBs FLAGS = 0x53 # Device configuration flags TWIN_BUS = 0x01 WIDE_BUS = 0x02 -MAX_SYNC = 0x08 +MAX_OFFSET = 0x08 ACTIVE_MSG = 0x20 IDENTIFY_SEEN = 0x40 RESELECTED = 0x80 +MAX_OFFSET_8BIT = 0x0f +MAX_OFFSET_WIDE = 0x08 + ACTIVE_A = 0x54 ACTIVE_B = 0x55 SAVED_TCL = 0x56 # Temporary storage for the @@ -369,6 +378,17 @@ start_selection: # Messages are stored in scratch RAM starting with a flag byte (high bit # set means active message), one length byte, and then the message itself. # + + test SCBARRAY+11,0xff jnz identify # 0 Length Command? + +# The kernel has sent us an SCB with no command attached. This implies +# that the kernel wants to send a message of some sort to this target, +# so we interrupt the driver, allow it to fill the message buffer, and +# then go back into the arbitration loop + mvi INTSTAT,AWAITING_MSG + jmp poll_for_work + +identify: mov SCBARRAY+1 call disconnect # disconnect ok? and SINDEX,0x7,SCBARRAY+1 # lun @@ -682,6 +702,7 @@ clear_a: complete: mov QOUTFIFO,SCBPTR mvi INTSTAT,CMDCMPLT + test SCBARRAY+11,0xff jz start # Immediate message complete jmp p_mesgin_done # If we have a residual count, interrupt and tell the host. Other @@ -851,6 +872,10 @@ p_mesgin_done: p_busfree: mvi CLRSINT1,0x40 # CLRATNO clr SIGSTATE + +# if this is an immediate command, perform a psuedo command complete to +# notify the driver. + test SCBARRAY+11,0xff jz status_ok jmp start # Instead of a generic bcopy routine that requires an argument, we unroll @@ -1202,7 +1227,7 @@ ndx_dtr_2: mk_dtr: test SCBARRAY+0,0xc0 jz return # NEEDWDTR|NEEDSDTR test SCBARRAY+0,NEEDWDTR jnz mk_wdtr_16bit - or FLAGS, MAX_SYNC # Force an offset of 15 + or FLAGS, MAX_OFFSET # Force an offset of 15 or 8 if WIDE mk_sdtr: mvi DINDIR,1 # extended message @@ -1210,16 +1235,21 @@ mk_sdtr: mvi DINDIR,1 # SDTR code call sdtr_to_rate mov DINDIR,RETURN_1 # REQ/ACK transfer period - test FLAGS, MAX_SYNC jnz mk_sdtr_max_sync - and DINDIR,0xf,SINDIR # Sync Offset + test FLAGS, MAX_OFFSET jnz mk_sdtr_max_offset + and DINDIR,0x0f,SINDIR # Sync Offset mk_sdtr_done: add MSG_LEN,-MSG_START+0,DINDEX ret # update message length -mk_sdtr_max_sync: -# We're initiating sync negotiation, so request the max offset we can (15) - mvi DINDIR, 0x0f - xor FLAGS, MAX_SYNC +mk_sdtr_max_offset: +# We're initiating sync negotiation, so request the max offset we can (15 or 8) + xor FLAGS, MAX_OFFSET + test SCSIRATE, 0x80 jnz wmax_offset # Talking to a WIDE device? + mvi DINDIR, MAX_OFFSET_8BIT + jmp mk_sdtr_done + +wmax_offset: + mvi DINDIR, MAX_OFFSET_WIDE jmp mk_sdtr_done mk_wdtr_16bit: diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c index f8967021f300..b4bbe966231a 100644 --- a/sys/i386/scsi/aic7xxx.c +++ b/sys/i386/scsi/aic7xxx.c @@ -24,7 +24,7 @@ * * commenced: Sun Sep 27 18:14:01 PDT 1992 * - * $Id: aic7xxx.c,v 1.25 1995/05/01 18:43:14 gibbs Exp $ + * $Id: aic7xxx.c,v 1.26 1995/05/11 19:26:26 rgrimes Exp $ */ /* * TODO: @@ -56,6 +56,8 @@ #include #define KVTOPHYS(x) vtophys(x) +#define MIN(a,b) ((a < b) ? a : b) + struct ahc_data *ahcdata[NAHC]; int ahc_init __P((int unit)); @@ -356,6 +358,7 @@ struct scsi_device ahc_dev = #define BAD_STATUS 0x70 #define RESIDUAL 0x80 #define ABORT_TAG 0x90 +#define AWAITING_MSG 0xa0 #define BRKADRINT 0x08 #define SCSIINT 0x04 #define CMDCMPLT 0x02 @@ -442,6 +445,11 @@ struct scsi_device ahc_dev = */ #define HA_REJBYTE 0xc31ul +/* + * Bit vector of targets that have disconnection disabled. + */ +#define HA_DISC_DSB 0xc32ul + /* * Length of pending message */ @@ -486,6 +494,7 @@ struct scsi_device ahc_dev = #define HA_HOSTCONF 0xc5dul #define MSG_ABORT 0x06 +#define MSG_BUS_DEVICE_RESET 0x0c #define BUS_8_BIT 0x00 #define BUS_16_BIT 0x01 #define BUS_32_BIT 0x02 @@ -665,8 +674,8 @@ void ahc_scsirate(scsirate, period, offset, unit, target ) if ((ahc_syncrates[i].period - period) >= 0) { *scsirate = (ahc_syncrates[i].sxfr) | (offset & 0x0f); printf("ahc%d: target %d synchronous at %sMB/s, " - "offset = 0x%x\n", - unit, target, ahc_syncrates[i].rate, offset ); + "offset = 0x%x\n", unit, target, + ahc_syncrates[i].rate, offset ); #ifdef AHC_DEBUG #endif /* AHC_DEBUG */ return; @@ -826,6 +835,7 @@ ahcintr(unit) case MSG_SDTR: { u_char scsi_id, offset, rate, targ_scratch; + u_char maxoffset, mask; /* * Help the sequencer to translate the * negotiated transfer rate. Transfer is @@ -837,18 +847,23 @@ ahcintr(unit) /* The bottom half of SCSIXFER */ offset = inb(ACCUM + iobase); scsi_id = inb(SCSIID + iobase) >> 0x4; - ahc_scsirate(&rate, transfer, offset, unit, - scsi_id); if(inb(SBLKCTL + iobase) & 0x08) /* B channel */ scsi_id += 8; + mask = (0x01 << scsi_id); targ_scratch = inb(HA_TARG_SCRATCH + iobase + scsi_id); + if(targ_scratch & 0x80) + maxoffset = 0x08; + else + maxoffset = 0x0f; + ahc_scsirate(&rate, transfer, + MIN(offset,maxoffset), unit, scsi_id); /* Preserve the WideXfer flag */ rate |= targ_scratch & 0x80; outb(HA_TARG_SCRATCH + iobase + scsi_id, rate); outb(SCSIRATE + iobase, rate); - if( (rate & 0x7f) == 0 ) + if( (rate & 0x0f) == 0 ) { /* * The requested rate was so low @@ -862,7 +877,7 @@ ahcintr(unit) outb(HA_RETURN_1 + iobase, SEND_REJ); } /* See if we initiated Sync Negotiation */ - else if(ahc->sdtrpending & (0x01 << scsi_id)) + else if(ahc->sdtrpending & mask) { /* * Don't send an SDTR back to @@ -883,8 +898,8 @@ ahcintr(unit) /* * Negate the flags */ - ahc->needsdtr &= ~(0x01 << scsi_id); - ahc->sdtrpending &= ~(0x01 << scsi_id); + ahc->needsdtr &= ~mask; + ahc->sdtrpending &= ~mask; break; } case MSG_WDTR: @@ -918,8 +933,7 @@ ahcintr(unit) "%d using 16Bit " "transfers\n", unit, scsi_id); - scratch |= 0x88; - scratch &= 0xf8; + scratch |= 0x80; break; } } @@ -941,8 +955,7 @@ ahcintr(unit) "%d using 16Bit " "transfers\n", unit, scsi_id); - scratch |= 0x88; - scratch &= 0xf8; + scratch |= 0x80; break; } outb(HA_RETURN_1 + iobase, @@ -1201,6 +1214,28 @@ ahcintr(unit) ahc_done(unit, scb); break; } + case AWAITING_MSG: + { + int scb_index; + scb_index = inb(SCBPTR + iobase); + scb = ahc->scbarray[scb_index]; + /* + * This SCB had a zero length command, informing + * the sequencer that we wanted to send a special + * message to this target. We only do this for + * BUS_DEVICE_RESET messages currently. + */ + if(scb->flags & SCB_DEVICE_RESET) + { + outb(HA_MSG_START + iobase, + MSG_BUS_DEVICE_RESET); + outb(HA_MSG_LEN + iobase, 1); + } + else + panic("ahcintr: AWAITING_MSG for an SCB that" + "does not have a waiting message"); + break; + } default: printf("ahc: seqint, " "intstat == 0x%x, scsisigi = 0x%x\n", @@ -1278,7 +1313,7 @@ ahcintr(unit) RESTART_SEQUENCER(ahc); } - if (status & SCSIPERR) { + else if (status & SCSIPERR) { printf("ahc%d: parity error on channel %c " "target %d, lun %d\n", unit, @@ -1293,18 +1328,7 @@ ahcintr(unit) outb(CLRINT + iobase, CLRSCSIINT); scb = NULL; } - if (status & BUSFREE) { -#if 0 - /* - * Has seen busfree since selection, i.e. - * a "spurious" selection. Shouldn't happen. - */ - printf("ahc: unexpected busfree\n"); - xs->error = XS_DRIVER_STUFFUP; - outb(CLRSINT1 + iobase, BUSFREE); /* CLRBUSFREE */ -#endif - } - else { + else if (!(status & BUSFREE)) { printf("ahc%d: Unknown SCSIINT. Status = 0x%x\n", unit, status); outb(CLRSINT1 + iobase, status); @@ -1535,11 +1559,14 @@ ahc_init(unit) printf("aic7870, "); printf("%d SCBs\n", ahc->maxscbs); - if(ahc->pause & IRQMS) - printf("ahc%d: Using Level Sensitive Interrupts\n", unit); - else - printf("ahc%d: Using Edge Triggered Interrupts\n", unit); - + if(!(ahc->type & AHC_AIC7870)) { + if(ahc->pause & IRQMS) + printf("ahc%d: Using Level Sensitive Interrupts\n", + unit); + else + printf("ahc%d: Using Edge Triggered Interrupts\n", + unit); + } if(!(ahc->type & AHC_AIC7870)){ /* * The 294x cards are PCI, so we get their interrupt from the PCI @@ -1749,10 +1776,8 @@ ahc_scsi_cmd(xs) } SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb)); scb->xs = xs; - if (flags & SCSI_RESET) { - /* XXX: Needs Implementation */ - printf("ahc0: SCSI_RESET called.\n"); - } + if (flags & SCSI_RESET) + scb->flags |= SCB_DEVICE_RESET|SCB_IMMED; /* * Put all the arguments for the xfer in the scb */ @@ -1764,7 +1789,7 @@ ahc_scsi_cmd(xs) scb->control |= SCB_NEEDWDTR; ahc->wdtrpending |= mask; } - if((ahc->needsdtr & mask) && !(ahc->sdtrpending & mask)) + else if((ahc->needsdtr & mask) && !(ahc->sdtrpending & mask)) { scb->control |= SCB_NEEDSDTR; ahc->sdtrpending |= mask; @@ -1842,10 +1867,13 @@ ahc_scsi_cmd(xs) return (HAD_ERROR); } } - /* else No data xfer, use non S/G values - * the SG_segment_count and SG_list_pointer are pre-zeroed, so - * we don't have to do anything - */ + else { + /* + * No data xfer, use non S/G values + */ + scb->SG_segment_count = 0; + scb->SG_list_pointer = 0; + } /* * Usually return SUCCESSFULLY QUEUED @@ -2001,7 +2029,7 @@ ahc_get_scb(unit, flags) if (scbp) { /* Get SCB from from free list */ ahc->free_scb = scbp->next; - bzero(scbp, SCB_BZERO_SIZE); + scbp->control = 0; scbp->flags = SCB_ACTIVE; #ifdef AHC_DEBUG ahc->activescbs++; @@ -2197,7 +2225,6 @@ ahc_timeout(void *arg1) */ if (scb->flags & SCB_IMMED) { scb->xs->retries = 0; /* I MEAN IT ! */ - scb->flags |= SCB_IMMED_FAIL; ahc_done(unit, scb); splx(s); return; diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h index 81088034bc04..7fae49006963 100644 --- a/sys/i386/scsi/aic7xxx.h +++ b/sys/i386/scsi/aic7xxx.h @@ -20,7 +20,7 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: aic7xxx.h,v 1.6 1995/04/23 22:04:58 gibbs Exp $ + * $Id: aic7xxx.h,v 1.7 1995/04/27 17:47:17 gibbs Exp $ */ #ifndef _AIC7XXX_H_ @@ -112,12 +112,12 @@ struct scb { struct scb *next; /* in free list */ struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ int flags; -#define SCB_FREE 0x00 -#define SCB_ACTIVE 0x01 -#define SCB_ABORTED 0x02 -#define SCB_IMMED 0x04 -#define SCB_IMMED_FAIL 0x08 -#define SCB_SENSE 0x10 +#define SCB_FREE 0x00 +#define SCB_ACTIVE 0x01 +#define SCB_ABORTED 0x02 +#define SCB_DEVICE_RESET 0x04 +#define SCB_IMMED 0x08 +#define SCB_SENSE 0x10 int position; /* Position in scbarray */ struct ahc_dma_seg ahc_dma[AHC_NSEG] __attribute__ ((packed)); struct scsi_sense sense_cmd; /* SCSI command block */