141480Smckusick /* 241480Smckusick * Copyright (c) 1990 The Regents of the University of California. 341480Smckusick * All rights reserved. 441480Smckusick * 541480Smckusick * This code is derived from software contributed to Berkeley by 641480Smckusick * Van Jacobson of Lawrence Berkeley Laboratory. 741480Smckusick * 841480Smckusick * %sccs.include.redist.c% 941480Smckusick * 10*45788Sbostic * @(#)scsi.c 7.3 (Berkeley) 12/16/90 1141480Smckusick */ 1241480Smckusick 1341480Smckusick /* 1441480Smckusick * HP9000/3xx 98658 SCSI host adaptor driver. 1541480Smckusick */ 1641480Smckusick #include "scsi.h" 1741480Smckusick #if NSCSI > 0 1841480Smckusick 1941480Smckusick #ifndef lint 2045514Smckusick static char rcsid[] = "$Header: scsi.c,v 1.3 90/10/10 14:55:08 mike Exp $"; 2141480Smckusick #endif 2241480Smckusick 23*45788Sbostic #include "sys/param.h" 24*45788Sbostic #include "sys/systm.h" 25*45788Sbostic #include "sys/buf.h" 2641480Smckusick #include "device.h" 27*45788Sbostic 2841480Smckusick #include "scsivar.h" 2941480Smckusick #include "scsireg.h" 3041480Smckusick #include "dmavar.h" 3141480Smckusick 32*45788Sbostic #include "../include/cpu.h" 33*45788Sbostic #include "../hp300/isr.h" 3441480Smckusick 3541480Smckusick extern void isrlink(); 3641480Smckusick extern void printf(); 3741480Smckusick extern void _insque(); 3841480Smckusick extern void _remque(); 3941480Smckusick extern void bzero(); 4041480Smckusick 4141480Smckusick int scsiinit(), scsigo(), scsiintr(), scsixfer(); 4241480Smckusick void scsistart(), scsidone(), scsifree(), scsireset(); 4341480Smckusick struct driver scsidriver = { 4441480Smckusick scsiinit, "scsi", (int (*)())scsistart, scsigo, scsiintr, 4541480Smckusick (int (*)())scsidone, 4641480Smckusick }; 4741480Smckusick 4841480Smckusick struct scsi_softc scsi_softc[NSCSI]; 4941480Smckusick struct isr scsi_isr[NSCSI]; 5041480Smckusick 5141480Smckusick int scsi_cmd_wait = 512; /* microsec wait per step of 'immediate' cmds */ 5241480Smckusick int scsi_data_wait = 512; /* wait per data in/out step */ 5341480Smckusick int scsi_nosync = 1; /* inhibit sync xfers if 1 */ 5445514Smckusick int scsi_pridma = 0; /* use "priority" dma */ 5541480Smckusick 5641480Smckusick #ifdef DEBUG 5741480Smckusick int scsi_debug = 0; 5841480Smckusick #define WAITHIST 5941480Smckusick #endif 6041480Smckusick 6141480Smckusick #ifdef WAITHIST 6245514Smckusick #define MAXWAIT 1022 6341480Smckusick u_int ixstart_wait[MAXWAIT+2]; 6441480Smckusick u_int ixin_wait[MAXWAIT+2]; 6541480Smckusick u_int ixout_wait[MAXWAIT+2]; 6641480Smckusick u_int mxin_wait[MAXWAIT+2]; 6741480Smckusick u_int cxin_wait[MAXWAIT+2]; 6841480Smckusick u_int fxfr_wait[MAXWAIT+2]; 6941480Smckusick u_int sgo_wait[MAXWAIT+2]; 7041480Smckusick #define HIST(h,w) (++h[((w)>MAXWAIT? MAXWAIT : ((w) < 0 ? -1 : (w))) + 1]); 7141480Smckusick #else 7241480Smckusick #define HIST(h,w) 7341480Smckusick #endif 7441480Smckusick 7541480Smckusick #define b_cylin b_resid 7641480Smckusick 7741480Smckusick static void 7841480Smckusick scsiabort(hs, hd, where) 7941480Smckusick register struct scsi_softc *hs; 8041480Smckusick volatile register struct scsidevice *hd; 8141480Smckusick char *where; 8241480Smckusick { 8341480Smckusick int len; 8441480Smckusick u_char junk; 8541480Smckusick 8641480Smckusick printf("scsi%d: abort from %s: phase=0x%x, ssts=0x%x, ints=0x%x\n", 8741480Smckusick hs->sc_hc->hp_unit, where, hd->scsi_psns, hd->scsi_ssts, 8841480Smckusick hd->scsi_ints); 8941480Smckusick 9041480Smckusick hd->scsi_ints = hd->scsi_ints; 9141480Smckusick hd->scsi_csr = 0; 9241480Smckusick if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0) 9341480Smckusick /* no longer connected to scsi target */ 9441480Smckusick return; 9541480Smckusick 9641480Smckusick /* get the number of bytes remaining in current xfer + fudge */ 9741480Smckusick len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl; 9841480Smckusick 9941480Smckusick /* for that many bus cycles, try to send an abort msg */ 10041480Smckusick for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) { 10141480Smckusick hd->scsi_scmd = SCMD_SET_ATN; 10241480Smckusick while ((hd->scsi_psns & PSNS_REQ) == 0) { 10341480Smckusick if (! (hd->scsi_ssts & SSTS_INITIATOR)) 10441480Smckusick goto out; 10541480Smckusick DELAY(1); 10641480Smckusick } 10741480Smckusick if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE) 10841480Smckusick hd->scsi_scmd = SCMD_RST_ATN; 10941480Smckusick hd->scsi_pctl = hd->scsi_psns & PHASE; 11041480Smckusick if (hd->scsi_psns & PHASE_IO) { 11141480Smckusick /* one of the input phases - read & discard a byte */ 11241480Smckusick hd->scsi_scmd = SCMD_SET_ACK; 11341480Smckusick if (hd->scsi_tmod == 0) 11441480Smckusick while (hd->scsi_psns & PSNS_REQ) 11541480Smckusick DELAY(1); 11641480Smckusick junk = hd->scsi_temp; 11741480Smckusick } else { 11841480Smckusick /* one of the output phases - send an abort msg */ 11941480Smckusick hd->scsi_temp = MSG_ABORT; 12041480Smckusick hd->scsi_scmd = SCMD_SET_ACK; 12141480Smckusick if (hd->scsi_tmod == 0) 12241480Smckusick while (hd->scsi_psns & PSNS_REQ) 12341480Smckusick DELAY(1); 12441480Smckusick } 12541480Smckusick hd->scsi_scmd = SCMD_RST_ACK; 12641480Smckusick } 12741480Smckusick out: 12841480Smckusick /* 12941480Smckusick * Either the abort was successful & the bus is disconnected or 13041480Smckusick * the device didn't listen. If the latter, announce the problem. 13141480Smckusick * Either way, reset the card & the SPC. 13241480Smckusick */ 13341480Smckusick if (len < 0 && hs) 13441480Smckusick printf("scsi%d: abort failed. phase=0x%x, ssts=0x%x\n", 13541480Smckusick hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts); 13641480Smckusick 13741480Smckusick if (! ((junk = hd->scsi_ints) & INTS_RESEL)) { 13841480Smckusick hd->scsi_sctl |= SCTL_CTRLRST; 13941480Smckusick DELAY(1); 14041480Smckusick hd->scsi_sctl &=~ SCTL_CTRLRST; 14141480Smckusick hd->scsi_hconf = 0; 14241480Smckusick hd->scsi_ints = hd->scsi_ints; 14341480Smckusick } 14441480Smckusick } 14541480Smckusick 14641480Smckusick int 14741480Smckusick scsiinit(hc) 14841480Smckusick register struct hp_ctlr *hc; 14941480Smckusick { 15041480Smckusick register struct scsi_softc *hs = &scsi_softc[hc->hp_unit]; 15141480Smckusick register struct scsidevice *hd = (struct scsidevice *)hc->hp_addr; 15241480Smckusick 15341480Smckusick if ((hd->scsi_id & ID_MASK) != SCSI_ID) 15441480Smckusick return(0); 15541480Smckusick hc->hp_ipl = SCSI_IPL(hd->scsi_csr); 15641480Smckusick hs->sc_hc = hc; 15741480Smckusick hs->sc_dq.dq_unit = hc->hp_unit; 15841480Smckusick hs->sc_dq.dq_driver = &scsidriver; 15941480Smckusick hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq; 16041480Smckusick scsi_isr[hc->hp_unit].isr_intr = scsiintr; 16141480Smckusick scsi_isr[hc->hp_unit].isr_ipl = hc->hp_ipl; 16241480Smckusick scsi_isr[hc->hp_unit].isr_arg = hc->hp_unit; 16341480Smckusick isrlink(&scsi_isr[hc->hp_unit]); 16441480Smckusick scsireset(hc->hp_unit); 16541480Smckusick return(1); 16641480Smckusick } 16741480Smckusick 16841480Smckusick void 16941480Smckusick scsireset(unit) 17041480Smckusick register int unit; 17141480Smckusick { 17241480Smckusick register struct scsi_softc *hs = &scsi_softc[unit]; 17341480Smckusick volatile register struct scsidevice *hd = 17441480Smckusick (struct scsidevice *)hs->sc_hc->hp_addr; 17541480Smckusick u_int i; 17641480Smckusick 17741480Smckusick if (hs->sc_flags & SCSI_ALIVE) 17841480Smckusick scsiabort(hs, hd, "reset"); 17941480Smckusick 18041480Smckusick printf("scsi%d: ", unit); 18141480Smckusick 18241480Smckusick hd->scsi_id = 0xFF; 18341480Smckusick DELAY(100); 18441480Smckusick /* 18541480Smckusick * Disable interrupts then reset the FUJI chip. 18641480Smckusick */ 18741480Smckusick hd->scsi_csr = 0; 18841480Smckusick hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST; 18941480Smckusick hd->scsi_scmd = 0; 19041480Smckusick hd->scsi_tmod = 0; 19141480Smckusick hd->scsi_pctl = 0; 19241480Smckusick hd->scsi_temp = 0; 19341480Smckusick hd->scsi_tch = 0; 19441480Smckusick hd->scsi_tcm = 0; 19541480Smckusick hd->scsi_tcl = 0; 19641480Smckusick hd->scsi_ints = 0; 19741480Smckusick 19841480Smckusick if ((hd->scsi_id & ID_WORD_DMA) == 0) { 19941480Smckusick hs->sc_flags |= SCSI_DMA32; 20041480Smckusick printf("32 bit dma, "); 20141480Smckusick } 20241480Smckusick 20341480Smckusick /* Determine Max Synchronous Transfer Rate */ 20441480Smckusick if (scsi_nosync) 20541480Smckusick i = 3; 20641480Smckusick else 20741480Smckusick i = SCSI_SYNC_XFER(hd->scsi_hconf); 20841480Smckusick switch (i) { 20941480Smckusick case 0: 21041480Smckusick hs->sc_sync = TMOD_SYNC | 0x3e; /* 250 nsecs */ 21141480Smckusick printf("250ns sync"); 21241480Smckusick break; 21341480Smckusick case 1: 21441480Smckusick hs->sc_sync = TMOD_SYNC | 0x5e; /* 375 nsecs */ 21541480Smckusick printf("375ns sync"); 21641480Smckusick break; 21741480Smckusick case 2: 21841480Smckusick hs->sc_sync = TMOD_SYNC | 0x7d; /* 500 nsecs */ 21941480Smckusick printf("500ns sync"); 22041480Smckusick break; 22141480Smckusick case 3: 22241480Smckusick hs->sc_sync = 0; 22341480Smckusick printf("async"); 22441480Smckusick break; 22541480Smckusick } 22641480Smckusick 22741480Smckusick /* 22841480Smckusick * Configure the FUJI chip with its SCSI address, all 22941480Smckusick * interrupts enabled & appropriate parity. 23041480Smckusick */ 23141480Smckusick i = (~hd->scsi_hconf) & 0x7; 23241480Smckusick hs->sc_scsi_addr = 1 << i; 23341480Smckusick hd->scsi_bdid = i; 23441480Smckusick if (hd->scsi_hconf & HCONF_PARITY) 23541480Smckusick hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | 23641480Smckusick SCTL_SEL_ENAB | SCTL_RESEL_ENAB | 23741480Smckusick SCTL_INTR_ENAB | SCTL_PARITY_ENAB; 23841480Smckusick else { 23941480Smckusick hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | 24041480Smckusick SCTL_SEL_ENAB | SCTL_RESEL_ENAB | 24141480Smckusick SCTL_INTR_ENAB; 24241480Smckusick printf(", no parity"); 24341480Smckusick } 24441480Smckusick hd->scsi_sctl &=~ SCTL_DISABLE; 24541480Smckusick 24641480Smckusick printf(", scsi id %d\n", i); 24741480Smckusick hs->sc_flags |= SCSI_ALIVE; 24841480Smckusick } 24941480Smckusick 25041480Smckusick static void 25141480Smckusick scsierror(hs, hd, ints) 25241480Smckusick register struct scsi_softc *hs; 25341480Smckusick volatile register struct scsidevice *hd; 25441480Smckusick u_char ints; 25541480Smckusick { 25641480Smckusick int unit = hs->sc_hc->hp_unit; 25741480Smckusick char *sep = ""; 25841480Smckusick 25941480Smckusick printf("scsi%d: ", unit); 26041480Smckusick if (ints & INTS_RST) { 26141480Smckusick DELAY(100); 26241480Smckusick if (hd->scsi_hconf & HCONF_SD) 26341480Smckusick printf("spurious RST interrupt"); 26441480Smckusick else 26541480Smckusick printf("hardware error - check fuse"); 26641480Smckusick sep = ", "; 26741480Smckusick } 26841480Smckusick if ((ints & INTS_HARD_ERR) || hd->scsi_serr) { 26941480Smckusick if (hd->scsi_serr & SERR_SCSI_PAR) { 27041480Smckusick printf("%sparity err", sep); 27141480Smckusick sep = ", "; 27241480Smckusick } 27341480Smckusick if (hd->scsi_serr & SERR_SPC_PAR) { 27441480Smckusick printf("%sSPC parity err", sep); 27541480Smckusick sep = ", "; 27641480Smckusick } 27741480Smckusick if (hd->scsi_serr & SERR_TC_PAR) { 27841480Smckusick printf("%sTC parity err", sep); 27941480Smckusick sep = ", "; 28041480Smckusick } 28141480Smckusick if (hd->scsi_serr & SERR_PHASE_ERR) { 28241480Smckusick printf("%sphase err", sep); 28341480Smckusick sep = ", "; 28441480Smckusick } 28541480Smckusick if (hd->scsi_serr & SERR_SHORT_XFR) { 28641480Smckusick printf("%ssync short transfer err", sep); 28741480Smckusick sep = ", "; 28841480Smckusick } 28941480Smckusick if (hd->scsi_serr & SERR_OFFSET) { 29041480Smckusick printf("%ssync offset error", sep); 29141480Smckusick sep = ", "; 29241480Smckusick } 29341480Smckusick } 29441480Smckusick if (ints & INTS_TIMEOUT) 29541480Smckusick printf("%sSPC select timeout error", sep); 29641480Smckusick if (ints & INTS_SRV_REQ) 29741480Smckusick printf("%sspurious SRV_REQ interrupt", sep); 29841480Smckusick if (ints & INTS_CMD_DONE) 29941480Smckusick printf("%sspurious CMD_DONE interrupt", sep); 30041480Smckusick if (ints & INTS_DISCON) 30141480Smckusick printf("%sspurious disconnect interrupt", sep); 30241480Smckusick if (ints & INTS_RESEL) 30341480Smckusick printf("%sspurious reselect interrupt", sep); 30441480Smckusick if (ints & INTS_SEL) 30541480Smckusick printf("%sspurious select interrupt", sep); 30641480Smckusick printf("\n"); 30741480Smckusick } 30841480Smckusick 30941480Smckusick static int 31041480Smckusick issue_select(hd, target, our_addr) 31141480Smckusick volatile register struct scsidevice *hd; 31241480Smckusick u_char target, our_addr; 31341480Smckusick { 31441480Smckusick if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY)) 31541480Smckusick return (1); 31641480Smckusick 31741480Smckusick if (hd->scsi_ints & INTS_DISCON) 31841480Smckusick hd->scsi_ints = INTS_DISCON; 31941480Smckusick 32041480Smckusick hd->scsi_pctl = 0; 32141480Smckusick hd->scsi_temp = (1 << target) | our_addr; 32241480Smckusick /* select timeout is hardcoded to 2ms */ 32341480Smckusick hd->scsi_tch = 0; 32441480Smckusick hd->scsi_tcm = 32; 32541480Smckusick hd->scsi_tcl = 4; 32641480Smckusick 32741480Smckusick hd->scsi_scmd = SCMD_SELECT; 32841480Smckusick return (0); 32941480Smckusick } 33041480Smckusick 33141480Smckusick static int 33241480Smckusick wait_for_select(hd) 33341480Smckusick volatile register struct scsidevice *hd; 33441480Smckusick { 33541480Smckusick u_char ints; 33641480Smckusick 33741480Smckusick while ((ints = hd->scsi_ints) == 0) 33841480Smckusick DELAY(1); 33941480Smckusick hd->scsi_ints = ints; 34041480Smckusick return (!(hd->scsi_ssts & SSTS_INITIATOR)); 34141480Smckusick } 34241480Smckusick 34341480Smckusick static int 34441480Smckusick ixfer_start(hd, len, phase, wait) 34541480Smckusick volatile register struct scsidevice *hd; 34641480Smckusick int len; 34741480Smckusick u_char phase; 34841480Smckusick register int wait; 34941480Smckusick { 35041480Smckusick 35141480Smckusick hd->scsi_tch = len >> 16; 35241480Smckusick hd->scsi_tcm = len >> 8; 35341480Smckusick hd->scsi_tcl = len; 35441480Smckusick hd->scsi_pctl = phase; 35541480Smckusick hd->scsi_tmod = 0; /*XXX*/ 35641480Smckusick hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; 35741480Smckusick 35841480Smckusick /* wait for xfer to start or svc_req interrupt */ 35941480Smckusick while ((hd->scsi_ssts & SSTS_BUSY) == 0) { 36041480Smckusick if (hd->scsi_ints || --wait < 0) { 36141480Smckusick #ifdef DEBUG 36241480Smckusick if (scsi_debug) 36341480Smckusick printf("ixfer_start fail: i%x, w%d\n", 36441480Smckusick hd->scsi_ints, wait); 36541480Smckusick #endif 36641480Smckusick HIST(ixstart_wait, wait) 36741480Smckusick return (0); 36841480Smckusick } 36941480Smckusick DELAY(1); 37041480Smckusick } 37141480Smckusick HIST(ixstart_wait, wait) 37241480Smckusick return (1); 37341480Smckusick } 37441480Smckusick 37541480Smckusick static int 37641480Smckusick ixfer_out(hd, len, buf) 37741480Smckusick volatile register struct scsidevice *hd; 37841480Smckusick int len; 37941480Smckusick register u_char *buf; 38041480Smckusick { 38141480Smckusick register int wait = scsi_data_wait; 38241480Smckusick 38341480Smckusick for (; len > 0; --len) { 38441480Smckusick while (hd->scsi_ssts & SSTS_DREG_FULL) { 38541480Smckusick if (hd->scsi_ints || --wait < 0) { 38641480Smckusick #ifdef DEBUG 38741480Smckusick if (scsi_debug) 38841480Smckusick printf("ixfer_out fail: l%d i%x w%d\n", 38941480Smckusick len, hd->scsi_ints, wait); 39041480Smckusick #endif 39141480Smckusick HIST(ixout_wait, wait) 39241480Smckusick return (len); 39341480Smckusick } 39441480Smckusick DELAY(1); 39541480Smckusick } 39641480Smckusick hd->scsi_dreg = *buf++; 39741480Smckusick } 39841480Smckusick HIST(ixout_wait, wait) 39941480Smckusick return (0); 40041480Smckusick } 40141480Smckusick 40241480Smckusick static void 40341480Smckusick ixfer_in(hd, len, buf) 40441480Smckusick volatile register struct scsidevice *hd; 40541480Smckusick int len; 40641480Smckusick register u_char *buf; 40741480Smckusick { 40841480Smckusick register int wait = scsi_data_wait; 40941480Smckusick 41041480Smckusick for (; len > 0; --len) { 41141480Smckusick while (hd->scsi_ssts & SSTS_DREG_EMPTY) { 41241480Smckusick if (hd->scsi_ints || --wait < 0) { 41341480Smckusick while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) { 41441480Smckusick *buf++ = hd->scsi_dreg; 41541480Smckusick --len; 41641480Smckusick } 41741480Smckusick #ifdef DEBUG 41841480Smckusick if (scsi_debug) 41941480Smckusick printf("ixfer_in fail: l%d i%x w%d\n", 42041480Smckusick len, hd->scsi_ints, wait); 42141480Smckusick #endif 42241480Smckusick HIST(ixin_wait, wait) 42341480Smckusick return; 42441480Smckusick } 42541480Smckusick DELAY(1); 42641480Smckusick } 42741480Smckusick *buf++ = hd->scsi_dreg; 42841480Smckusick } 42941480Smckusick HIST(ixin_wait, wait) 43041480Smckusick } 43141480Smckusick 43241480Smckusick static int 43341480Smckusick mxfer_in(hd, len, buf, phase) 43441480Smckusick volatile register struct scsidevice *hd; 43541480Smckusick register int len; 43641480Smckusick register u_char *buf; 43741480Smckusick register u_char phase; 43841480Smckusick { 43941480Smckusick register int wait = scsi_cmd_wait; 44041480Smckusick register int i; 44141480Smckusick 44241480Smckusick hd->scsi_tmod = 0; 44341480Smckusick for (i = 0; i < len; ++i) { 44441480Smckusick /* 44541480Smckusick * wait for the request line (which says the target 44641480Smckusick * wants to give us data). If the phase changes while 44741480Smckusick * we're waiting, we're done. 44841480Smckusick */ 44941480Smckusick while ((hd->scsi_psns & PSNS_REQ) == 0) { 45041480Smckusick if (--wait < 0) { 45141480Smckusick HIST(mxin_wait, wait) 45241480Smckusick return (-1); 45341480Smckusick } 45441480Smckusick if ((hd->scsi_psns & PHASE) != phase || 45541480Smckusick (hd->scsi_ssts & SSTS_INITIATOR) == 0) 45641480Smckusick goto out; 45741480Smckusick 45841480Smckusick DELAY(1); 45941480Smckusick } 46041480Smckusick /* 46141480Smckusick * set ack (which says we're ready for the data, wait for 46241480Smckusick * req to go away (target says data is available), grab the 46341480Smckusick * data, then reset ack (say we've got the data). 46441480Smckusick */ 46541480Smckusick hd->scsi_pctl = phase; 46641480Smckusick hd->scsi_scmd = SCMD_SET_ACK; 46741480Smckusick while (hd->scsi_psns & PSNS_REQ) { 46841480Smckusick if (--wait < 0) { 46941480Smckusick HIST(mxin_wait, wait) 47041480Smckusick return (-2); 47141480Smckusick } 47241480Smckusick DELAY(1); 47341480Smckusick } 47441480Smckusick *buf++ = hd->scsi_temp; 47541480Smckusick hd->scsi_scmd = SCMD_RST_ACK; 47641480Smckusick if (hd->scsi_psns & PSNS_ATN) 47741480Smckusick hd->scsi_scmd = SCMD_RST_ATN; 47841480Smckusick } 47941480Smckusick out: 48041480Smckusick HIST(mxin_wait, wait) 48141480Smckusick return (i); 48241480Smckusick } 48341480Smckusick 48441480Smckusick /* 48541480Smckusick * SCSI 'immediate' command: issue a command to some SCSI device 48641480Smckusick * and get back an 'immediate' response (i.e., do programmed xfer 48741480Smckusick * to get the response data). 'cbuf' is a buffer containing a scsi 48841480Smckusick * command of length clen bytes. 'buf' is a buffer of length 'len' 48941480Smckusick * bytes for data. The transfer direction is determined by the device 49041480Smckusick * (i.e., by the scsi bus data xfer phase). If 'len' is zero, the 49141480Smckusick * command must supply no data. 'xferphase' is the bus phase the 49241480Smckusick * caller expects to happen after the command is issued. It should 49341480Smckusick * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE. 49441480Smckusick */ 49541480Smckusick static int 49641480Smckusick scsiicmd(hs, target, cbuf, clen, buf, len, xferphase) 49741480Smckusick struct scsi_softc *hs; 49841480Smckusick int target; 49941480Smckusick u_char *cbuf; 50041480Smckusick int clen; 50141480Smckusick u_char *buf; 50241480Smckusick int len; 50341480Smckusick u_char xferphase; 50441480Smckusick { 50541480Smckusick volatile register struct scsidevice *hd = 50641480Smckusick (struct scsidevice *)hs->sc_hc->hp_addr; 50741480Smckusick u_char phase, ints; 50841480Smckusick register int wait; 50941480Smckusick 51041480Smckusick /* select the SCSI bus (it's an error if bus isn't free) */ 51141480Smckusick if (issue_select(hd, target, hs->sc_scsi_addr)) 51241480Smckusick return (-1); 51341480Smckusick if (wait_for_select(hd)) 51441480Smckusick return (-1); 51541480Smckusick /* 51641480Smckusick * Wait for a phase change (or error) then let the device 51741480Smckusick * sequence us through the various SCSI phases. 51841480Smckusick */ 51941480Smckusick hs->sc_stat[0] = 0xff; 52041480Smckusick hs->sc_msg[0] = 0xff; 52141480Smckusick phase = CMD_PHASE; 52241480Smckusick while (1) { 52341480Smckusick wait = scsi_cmd_wait; 52441480Smckusick switch (phase) { 52541480Smckusick 52641480Smckusick case CMD_PHASE: 52741480Smckusick if (ixfer_start(hd, clen, phase, wait)) 52841480Smckusick if (ixfer_out(hd, clen, cbuf)) 52941480Smckusick goto abort; 53041480Smckusick phase = xferphase; 53141480Smckusick break; 53241480Smckusick 53341480Smckusick case DATA_IN_PHASE: 53441480Smckusick if (len <= 0) 53541480Smckusick goto abort; 53641480Smckusick wait = scsi_data_wait; 53741480Smckusick if (ixfer_start(hd, len, phase, wait) || 53841480Smckusick !(hd->scsi_ssts & SSTS_DREG_EMPTY)) 53941480Smckusick ixfer_in(hd, len, buf); 54041480Smckusick phase = STATUS_PHASE; 54141480Smckusick break; 54241480Smckusick 54341480Smckusick case DATA_OUT_PHASE: 54441480Smckusick if (len <= 0) 54541480Smckusick goto abort; 54641480Smckusick wait = scsi_data_wait; 54741480Smckusick if (ixfer_start(hd, len, phase, wait)) { 54841480Smckusick if (ixfer_out(hd, len, buf)) 54941480Smckusick goto abort; 55041480Smckusick } 55141480Smckusick phase = STATUS_PHASE; 55241480Smckusick break; 55341480Smckusick 55441480Smckusick case STATUS_PHASE: 55541480Smckusick wait = scsi_data_wait; 55641480Smckusick if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) || 55741480Smckusick !(hd->scsi_ssts & SSTS_DREG_EMPTY)) 55841480Smckusick ixfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat); 55941480Smckusick phase = MESG_IN_PHASE; 56041480Smckusick break; 56141480Smckusick 56241480Smckusick case MESG_IN_PHASE: 56341480Smckusick if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) || 56441480Smckusick !(hd->scsi_ssts & SSTS_DREG_EMPTY)) { 56541480Smckusick ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg); 56641480Smckusick hd->scsi_scmd = SCMD_RST_ACK; 56741480Smckusick } 56841480Smckusick phase = BUS_FREE_PHASE; 56941480Smckusick break; 57041480Smckusick 57141480Smckusick case BUS_FREE_PHASE: 57241480Smckusick goto out; 57341480Smckusick 57441480Smckusick default: 57541480Smckusick printf("scsi%d: unexpected phase %d in icmd from %d\n", 57641480Smckusick hs->sc_hc->hp_unit, phase, target); 57741480Smckusick goto abort; 57841480Smckusick } 57941480Smckusick /* wait for last command to complete */ 58041480Smckusick while ((ints = hd->scsi_ints) == 0) { 58141480Smckusick if (--wait < 0) { 58241480Smckusick HIST(cxin_wait, wait) 58341480Smckusick goto abort; 58441480Smckusick } 58541480Smckusick DELAY(1); 58641480Smckusick } 58741480Smckusick HIST(cxin_wait, wait) 58841480Smckusick hd->scsi_ints = ints; 58941480Smckusick if (ints & INTS_SRV_REQ) 59041480Smckusick phase = hd->scsi_psns & PHASE; 59141480Smckusick else if (ints & INTS_DISCON) 59241480Smckusick goto out; 59341480Smckusick else if ((ints & INTS_CMD_DONE) == 0) { 59441480Smckusick scsierror(hs, hd, ints); 59541480Smckusick goto abort; 59641480Smckusick } 59741480Smckusick } 59841480Smckusick abort: 59941480Smckusick scsiabort(hs, hd, "icmd"); 60041480Smckusick out: 60141480Smckusick return (hs->sc_stat[0]); 60241480Smckusick } 60341480Smckusick 60441480Smckusick /* 60541480Smckusick * Finish SCSI xfer command: After the completion interrupt from 60641480Smckusick * a read/write operation, sequence through the final phases in 60741480Smckusick * programmed i/o. This routine is a lot like scsiicmd except we 60841480Smckusick * skip (and don't allow) the select, cmd out and data in/out phases. 60941480Smckusick */ 61041480Smckusick static void 61141480Smckusick finishxfer(hs, hd, target) 61241480Smckusick struct scsi_softc *hs; 61341480Smckusick volatile register struct scsidevice *hd; 61441480Smckusick int target; 61541480Smckusick { 61641480Smckusick u_char phase, ints; 61741480Smckusick 61841480Smckusick /* 61941480Smckusick * We specified padding xfer so we ended with either a phase 62041480Smckusick * change interrupt (normal case) or an error interrupt (handled 62141480Smckusick * elsewhere). Reset the board dma logic then try to get the 62241480Smckusick * completion status & command done msg. The reset confuses 62341480Smckusick * the SPC REQ/ACK logic so we have to do any status/msg input 62441480Smckusick * operations via 'manual xfer'. 62541480Smckusick */ 62641480Smckusick if (hd->scsi_ssts & SSTS_BUSY) { 62741480Smckusick int wait = scsi_cmd_wait; 62841480Smckusick 62941480Smckusick /* wait for dma operation to finish */ 63041480Smckusick while (hd->scsi_ssts & SSTS_BUSY) { 63141480Smckusick if (--wait < 0) { 63241480Smckusick #ifdef DEBUG 63341480Smckusick if (scsi_debug) 63441480Smckusick printf("finishxfer fail: ssts %x\n", 63541480Smckusick hd->scsi_ssts); 63641480Smckusick #endif 63741480Smckusick HIST(fxfr_wait, wait) 63841480Smckusick goto abort; 63941480Smckusick } 64041480Smckusick } 64141480Smckusick HIST(fxfr_wait, wait) 64241480Smckusick } 64341480Smckusick hd->scsi_scmd |= SCMD_PROG_XFR; 64441480Smckusick hd->scsi_sctl |= SCTL_CTRLRST; 64541480Smckusick DELAY(1); 64641480Smckusick hd->scsi_sctl &=~ SCTL_CTRLRST; 64741480Smckusick hd->scsi_hconf = 0; 64841480Smckusick hs->sc_stat[0] = 0xff; 64941480Smckusick hs->sc_msg[0] = 0xff; 65041480Smckusick hd->scsi_csr = 0; 65141480Smckusick hd->scsi_ints = ints = hd->scsi_ints; 65241480Smckusick while (1) { 65341480Smckusick phase = hd->scsi_psns & PHASE; 65441480Smckusick switch (phase) { 65541480Smckusick 65641480Smckusick case STATUS_PHASE: 65741480Smckusick if (mxfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat, 65841480Smckusick phase) <= 0) 65941480Smckusick goto abort; 66041480Smckusick break; 66141480Smckusick 66241480Smckusick case MESG_IN_PHASE: 66341480Smckusick if (mxfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg, 66441480Smckusick phase) < 0) 66541480Smckusick goto abort; 66641480Smckusick break; 66741480Smckusick 66841480Smckusick case BUS_FREE_PHASE: 66941480Smckusick return; 67041480Smckusick 67141480Smckusick default: 67241480Smckusick printf("scsi%d: unexpected phase %d in finishxfer from %d\n", 67341480Smckusick hs->sc_hc->hp_unit, phase, target); 67441480Smckusick goto abort; 67541480Smckusick } 67641480Smckusick if (ints = hd->scsi_ints) { 67741480Smckusick hd->scsi_ints = ints; 67841480Smckusick if (ints & INTS_DISCON) 67941480Smckusick return; 68041480Smckusick else if (ints & ~(INTS_SRV_REQ|INTS_CMD_DONE)) { 68141480Smckusick scsierror(hs, hd, ints); 68241480Smckusick break; 68341480Smckusick } 68441480Smckusick } 68541480Smckusick if ((hd->scsi_ssts & SSTS_INITIATOR) == 0) 68641480Smckusick return; 68741480Smckusick } 68841480Smckusick abort: 68941480Smckusick scsiabort(hs, hd, "finishxfer"); 69041480Smckusick hs->sc_stat[0] = 0xfe; 69141480Smckusick } 69241480Smckusick 69341480Smckusick int 69441480Smckusick scsi_test_unit_rdy(ctlr, slave, unit) 69541480Smckusick int ctlr, slave, unit; 69641480Smckusick { 69741480Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 69841480Smckusick static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY }; 69941480Smckusick 70041480Smckusick cdb.lun = unit; 70141480Smckusick return (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0, 70241480Smckusick STATUS_PHASE)); 70341480Smckusick } 70441480Smckusick 70541480Smckusick int 70641480Smckusick scsi_request_sense(ctlr, slave, unit, buf, len) 70741480Smckusick int ctlr, slave, unit; 70841480Smckusick u_char *buf; 70941480Smckusick unsigned len; 71041480Smckusick { 71141480Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 71241480Smckusick static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE }; 71341480Smckusick 71441480Smckusick cdb.lun = unit; 71541480Smckusick cdb.len = len; 71641480Smckusick return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE)); 71741480Smckusick } 71841480Smckusick 71941480Smckusick int 72041480Smckusick scsi_immed_command(ctlr, slave, unit, cdb, buf, len, rd) 72141480Smckusick int ctlr, slave, unit; 72241480Smckusick struct scsi_fmt_cdb *cdb; 72341480Smckusick u_char *buf; 72441480Smckusick unsigned len; 72541480Smckusick { 72641480Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 72741480Smckusick 72841480Smckusick cdb->cdb[1] |= unit << 5; 72941480Smckusick return (scsiicmd(hs, slave, cdb->cdb, cdb->len, buf, len, 73041480Smckusick rd != 0? DATA_IN_PHASE : DATA_OUT_PHASE)); 73141480Smckusick } 73241480Smckusick 73341480Smckusick /* 73441480Smckusick * The following routines are test-and-transfer i/o versions of read/write 73541480Smckusick * for things like reading disk labels and writing core dumps. The 73641480Smckusick * routine scsigo should be used for normal data transfers, NOT these 73741480Smckusick * routines. 73841480Smckusick */ 73941480Smckusick int 74041480Smckusick scsi_tt_read(ctlr, slave, unit, buf, len, blk, bshift) 74141480Smckusick int ctlr, slave, unit; 74241480Smckusick u_char *buf; 74341480Smckusick u_int len; 74441480Smckusick daddr_t blk; 74541480Smckusick int bshift; 74641480Smckusick { 74741480Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 74841480Smckusick struct scsi_cdb10 cdb; 74941480Smckusick int stat; 75041480Smckusick int old_wait = scsi_data_wait; 75141480Smckusick 75241480Smckusick scsi_data_wait = 300000; 75341480Smckusick bzero(&cdb, sizeof(cdb)); 75441480Smckusick cdb.cmd = CMD_READ_EXT; 75541480Smckusick cdb.lun = unit; 75641480Smckusick blk >>= bshift; 75741480Smckusick cdb.lbah = blk >> 24; 75841480Smckusick cdb.lbahm = blk >> 16; 75941480Smckusick cdb.lbalm = blk >> 8; 76041480Smckusick cdb.lbal = blk; 76141480Smckusick cdb.lenh = len >> (8 + DEV_BSHIFT + bshift); 76241480Smckusick cdb.lenl = len >> (DEV_BSHIFT + bshift); 76341480Smckusick stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE); 76441480Smckusick scsi_data_wait = old_wait; 76541480Smckusick return (stat); 76641480Smckusick } 76741480Smckusick 76841480Smckusick int 76941480Smckusick scsi_tt_write(ctlr, slave, unit, buf, len, blk, bshift) 77041480Smckusick int ctlr, slave, unit; 77141480Smckusick u_char *buf; 77241480Smckusick u_int len; 77341480Smckusick daddr_t blk; 77441480Smckusick int bshift; 77541480Smckusick { 77641480Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 77741480Smckusick struct scsi_cdb10 cdb; 77841480Smckusick int stat; 77941480Smckusick int old_wait = scsi_data_wait; 78041480Smckusick 78141480Smckusick scsi_data_wait = 300000; 78241480Smckusick 78341480Smckusick bzero(&cdb, sizeof(cdb)); 78441480Smckusick cdb.cmd = CMD_WRITE_EXT; 78541480Smckusick cdb.lun = unit; 78641480Smckusick blk >>= bshift; 78741480Smckusick cdb.lbah = blk >> 24; 78841480Smckusick cdb.lbahm = blk >> 16; 78941480Smckusick cdb.lbalm = blk >> 8; 79041480Smckusick cdb.lbal = blk; 79141480Smckusick cdb.lenh = len >> (8 + DEV_BSHIFT + bshift); 79241480Smckusick cdb.lenl = len >> (DEV_BSHIFT + bshift); 79341480Smckusick stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_OUT_PHASE); 79441480Smckusick scsi_data_wait = old_wait; 79541480Smckusick return (stat); 79641480Smckusick } 79741480Smckusick 79841480Smckusick int 79941480Smckusick scsireq(dq) 80041480Smckusick register struct devqueue *dq; 80141480Smckusick { 80241480Smckusick register struct devqueue *hq; 80341480Smckusick 80441480Smckusick hq = &scsi_softc[dq->dq_ctlr].sc_sq; 80541480Smckusick insque(dq, hq->dq_back); 80641480Smckusick if (dq->dq_back == hq) 80741480Smckusick return(1); 80841480Smckusick return(0); 80941480Smckusick } 81041480Smckusick 81141480Smckusick int 81241480Smckusick scsiustart(unit) 81341480Smckusick int unit; 81441480Smckusick { 81541480Smckusick register struct scsi_softc *hs = &scsi_softc[unit]; 81641480Smckusick 81741480Smckusick hs->sc_dq.dq_ctlr = DMA0 | DMA1; 81841480Smckusick if (dmareq(&hs->sc_dq)) 81941480Smckusick return(1); 82041480Smckusick return(0); 82141480Smckusick } 82241480Smckusick 82341480Smckusick void 82441480Smckusick scsistart(unit) 82541480Smckusick int unit; 82641480Smckusick { 82741480Smckusick register struct devqueue *dq; 82841480Smckusick 82941480Smckusick dq = scsi_softc[unit].sc_sq.dq_forw; 83041480Smckusick (dq->dq_driver->d_go)(dq->dq_unit); 83141480Smckusick } 83241480Smckusick 83341480Smckusick int 83441480Smckusick scsigo(ctlr, slave, unit, bp, cdb, pad) 83541480Smckusick int ctlr, slave, unit; 83641480Smckusick struct buf *bp; 83741480Smckusick struct scsi_fmt_cdb *cdb; 83841480Smckusick int pad; 83941480Smckusick { 84041480Smckusick register struct scsi_softc *hs = &scsi_softc[ctlr]; 84141480Smckusick volatile register struct scsidevice *hd = 84241480Smckusick (struct scsidevice *)hs->sc_hc->hp_addr; 84341480Smckusick int i, dmaflags; 84441480Smckusick u_char phase, ints, cmd; 84541480Smckusick 84641480Smckusick cdb->cdb[1] |= unit << 5; 84741480Smckusick 84841480Smckusick /* select the SCSI bus (it's an error if bus isn't free) */ 84941480Smckusick if (issue_select(hd, slave, hs->sc_scsi_addr) || wait_for_select(hd)) { 85041480Smckusick dmafree(&hs->sc_dq); 85141480Smckusick return (1); 85241480Smckusick } 85341480Smckusick /* 85441480Smckusick * Wait for a phase change (or error) then let the device 85541480Smckusick * sequence us through command phase (we may have to take 85641480Smckusick * a msg in/out before doing the command). If the disk has 85741480Smckusick * to do a seek, it may be a long time until we get a change 85841480Smckusick * to data phase so, in the absense of an explicit phase 85941480Smckusick * change, we assume data phase will be coming up and tell 86041480Smckusick * the SPC to start a transfer whenever it does. We'll get 86141480Smckusick * a service required interrupt later if this assumption is 86241480Smckusick * wrong. Otherwise we'll get a service required int when 86341480Smckusick * the transfer changes to status phase. 86441480Smckusick */ 86541480Smckusick phase = CMD_PHASE; 86641480Smckusick while (1) { 86741480Smckusick register int wait = scsi_cmd_wait; 86841480Smckusick 86941480Smckusick switch (phase) { 87041480Smckusick 87141480Smckusick case CMD_PHASE: 87241480Smckusick if (ixfer_start(hd, cdb->len, phase, wait)) 87341480Smckusick if (ixfer_out(hd, cdb->len, cdb->cdb)) 87441480Smckusick goto abort; 87541480Smckusick break; 87641480Smckusick 87741480Smckusick case MESG_IN_PHASE: 87841480Smckusick if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait)|| 87941480Smckusick !(hd->scsi_ssts & SSTS_DREG_EMPTY)) { 88041480Smckusick ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg); 88141480Smckusick hd->scsi_scmd = SCMD_RST_ACK; 88241480Smckusick } 88341480Smckusick phase = BUS_FREE_PHASE; 88441480Smckusick break; 88541480Smckusick 88641480Smckusick case DATA_IN_PHASE: 88741480Smckusick case DATA_OUT_PHASE: 88841480Smckusick goto out; 88941480Smckusick 89041480Smckusick default: 89141480Smckusick printf("scsi%d: unexpected phase %d in go from %d\n", 89241480Smckusick hs->sc_hc->hp_unit, phase, slave); 89341480Smckusick goto abort; 89441480Smckusick } 89541480Smckusick while ((ints = hd->scsi_ints) == 0) { 89641480Smckusick if (--wait < 0) { 89741480Smckusick HIST(sgo_wait, wait) 89841480Smckusick goto abort; 89941480Smckusick } 90041480Smckusick DELAY(1); 90141480Smckusick } 90241480Smckusick HIST(sgo_wait, wait) 90341480Smckusick hd->scsi_ints = ints; 90441480Smckusick if (ints & INTS_SRV_REQ) 90541480Smckusick phase = hd->scsi_psns & PHASE; 90641480Smckusick else if (ints & INTS_CMD_DONE) 90741480Smckusick goto out; 90841480Smckusick else { 90941480Smckusick scsierror(hs, hd, ints); 91041480Smckusick goto abort; 91141480Smckusick } 91241480Smckusick } 91341480Smckusick out: 91441480Smckusick /* 91541480Smckusick * Reset the card dma logic, setup the dma channel then 91641480Smckusick * get the dio part of the card set for a dma xfer. 91741480Smckusick */ 91841480Smckusick hd->scsi_hconf = 0; 91945514Smckusick cmd = CSR_IE; 92041480Smckusick dmaflags = DMAGO_NOINT; 92145514Smckusick if (scsi_pridma) 92245514Smckusick dmaflags |= DMAGO_PRI; 92341480Smckusick if (bp->b_flags & B_READ) 92441480Smckusick dmaflags |= DMAGO_READ; 92541480Smckusick if ((hs->sc_flags & SCSI_DMA32) && 92641480Smckusick ((int)bp->b_un.b_addr & 3) == 0 && (bp->b_bcount & 3) == 0) { 92741480Smckusick cmd |= CSR_DMA32; 92841480Smckusick dmaflags |= DMAGO_LWORD; 92941480Smckusick } else 93041480Smckusick dmaflags |= DMAGO_WORD; 93141480Smckusick dmago(hs->sc_dq.dq_ctlr, bp->b_un.b_addr, bp->b_bcount, dmaflags); 93241480Smckusick 93341480Smckusick if (bp->b_flags & B_READ) { 93441480Smckusick cmd |= CSR_DMAIN; 93541480Smckusick phase = DATA_IN_PHASE; 93641480Smckusick } else 93741480Smckusick phase = DATA_OUT_PHASE; 93845514Smckusick /* 93945514Smckusick * DMA enable bits must be set after size and direction bits. 94045514Smckusick */ 94141480Smckusick hd->scsi_csr = cmd; 94245514Smckusick hd->scsi_csr |= (CSR_DE0 << hs->sc_dq.dq_ctlr); 94341480Smckusick /* 94441480Smckusick * Setup the SPC for the transfer. We don't want to take 94541480Smckusick * first a command complete then a service required interrupt 94641480Smckusick * at the end of the transfer so we try to disable the cmd 94741480Smckusick * complete by setting the transfer counter to more bytes 94841480Smckusick * than we expect. (XXX - This strategy may have to be 94941480Smckusick * modified to deal with devices that return variable length 95041480Smckusick * blocks, e.g., some tape drives.) 95141480Smckusick */ 95241480Smckusick cmd = SCMD_XFR; 95341480Smckusick i = (unsigned)bp->b_bcount; 95441480Smckusick if (pad) { 95541480Smckusick cmd |= SCMD_PAD; 95641480Smckusick /* 95741480Smckusick * XXX - If we don't do this, the last 2 or 4 bytes 95841480Smckusick * (depending on word/lword DMA) of a read get trashed. 95941480Smckusick * It looks like it is necessary for the DMA to complete 96041480Smckusick * before the SPC goes into "pad mode"??? Note: if we 96141480Smckusick * also do this on a write, the request never completes. 96241480Smckusick */ 96341480Smckusick if (bp->b_flags & B_READ) 96441480Smckusick i += 2; 96541480Smckusick #ifdef DEBUG 96641480Smckusick hs->sc_flags |= SCSI_PAD; 96741480Smckusick if (i & 1) 96841480Smckusick printf("scsi%d: odd byte count: %d bytes @ %d\n", 96941480Smckusick ctlr, i, bp->b_cylin); 97041480Smckusick #endif 97141480Smckusick } else 97241480Smckusick i += 4; 97341480Smckusick hd->scsi_tch = i >> 16; 97441480Smckusick hd->scsi_tcm = i >> 8; 97541480Smckusick hd->scsi_tcl = i; 97641480Smckusick hd->scsi_pctl = phase; 97741480Smckusick hd->scsi_tmod = 0; 97841480Smckusick hd->scsi_scmd = cmd; 97941480Smckusick hs->sc_flags |= SCSI_IO; 98041480Smckusick return (0); 98141480Smckusick abort: 98241480Smckusick scsiabort(hs, hd, "go"); 98341480Smckusick dmafree(&hs->sc_dq); 98441480Smckusick return (1); 98541480Smckusick } 98641480Smckusick 98741480Smckusick void 98841480Smckusick scsidone(unit) 98941480Smckusick register int unit; 99041480Smckusick { 99141480Smckusick volatile register struct scsidevice *hd = 99241480Smckusick (struct scsidevice *)scsi_softc[unit].sc_hc->hp_addr; 99341480Smckusick 99445514Smckusick #ifdef DEBUG 99545514Smckusick if (scsi_debug) 99645514Smckusick printf("scsi%d: done called!\n"); 99745514Smckusick #endif 99841480Smckusick /* dma operation is done -- turn off card dma */ 99941480Smckusick hd->scsi_csr &=~ (CSR_DE1|CSR_DE0); 100041480Smckusick } 100141480Smckusick 100241480Smckusick int 100341480Smckusick scsiintr(unit) 100441480Smckusick register int unit; 100541480Smckusick { 100641480Smckusick register struct scsi_softc *hs = &scsi_softc[unit]; 100741480Smckusick volatile register struct scsidevice *hd = 100841480Smckusick (struct scsidevice *)hs->sc_hc->hp_addr; 100941480Smckusick register u_char ints; 101041480Smckusick register struct devqueue *dq; 101141480Smckusick 101241480Smckusick if ((hd->scsi_csr & (CSR_IE|CSR_IR)) != (CSR_IE|CSR_IR)) 101341480Smckusick return (0); 101441480Smckusick 101541480Smckusick ints = hd->scsi_ints; 101641480Smckusick if ((ints & INTS_SRV_REQ) && (hs->sc_flags & SCSI_IO)) { 101741480Smckusick /* 101841480Smckusick * this should be the normal i/o completion case. 101941480Smckusick * get the status & cmd complete msg then let the 102041480Smckusick * device driver look at what happened. 102141480Smckusick */ 102241480Smckusick #ifdef DEBUG 102341480Smckusick int len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | 102441480Smckusick hd->scsi_tcl; 102541480Smckusick if (!(hs->sc_flags & SCSI_PAD)) 102641480Smckusick len -= 4; 102741480Smckusick hs->sc_flags &=~ SCSI_PAD; 102841480Smckusick #endif 102941480Smckusick dq = hs->sc_sq.dq_forw; 103041480Smckusick finishxfer(hs, hd, dq->dq_unit); 103141480Smckusick hs->sc_flags &=~ SCSI_IO; 103241480Smckusick dmafree(&hs->sc_dq); 103341480Smckusick (dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat[0]); 103441480Smckusick } else { 103541480Smckusick /* Something unexpected happened -- deal with it. */ 103641480Smckusick hd->scsi_ints = ints; 103741480Smckusick hd->scsi_csr = 0; 103841480Smckusick scsierror(hs, hd, ints); 103941480Smckusick scsiabort(hs, hd, "intr"); 104041480Smckusick if (hs->sc_flags & SCSI_IO) { 104141480Smckusick hs->sc_flags &=~ SCSI_IO; 104241480Smckusick dmafree(&hs->sc_dq); 104341480Smckusick dq = hs->sc_sq.dq_forw; 104441480Smckusick (dq->dq_driver->d_intr)(dq->dq_unit, -1); 104541480Smckusick } 104641480Smckusick } 104741480Smckusick return(1); 104841480Smckusick } 104941480Smckusick 105041480Smckusick void 105141480Smckusick scsifree(dq) 105241480Smckusick register struct devqueue *dq; 105341480Smckusick { 105441480Smckusick register struct devqueue *hq; 105541480Smckusick 105641480Smckusick hq = &scsi_softc[dq->dq_ctlr].sc_sq; 105741480Smckusick remque(dq); 105841480Smckusick if ((dq = hq->dq_forw) != hq) 105941480Smckusick (dq->dq_driver->d_start)(dq->dq_unit); 106041480Smckusick } 106141480Smckusick #endif 1062