|
|
1.1 ! root 1: /* ! 2: * @(#)sc.c 1.1 86/02/03 Copyright (c) 1985 by Sun Microsystems, Inc. ! 3: */ ! 4: ! 5: #include <sys/param.h> ! 6: #include <sys/inode.h> ! 7: #include <sun/dklabel.h> ! 8: #include <sun/dkio.h> ! 9: #include <sys/buf.h> ! 10: #include <sundev/screg.h> ! 11: #include <sundev/sireg.h> ! 12: #include <sundev/scsi.h> ! 13: #include <machine/sunromvec.h> ! 14: #include <machine/idprom.h> ! 15: #include "saio.h" ! 16: ! 17: /* ! 18: * Low-level routines common to all devices on the SCSI bus ! 19: */ ! 20: ! 21: /* ! 22: * Interface to the routines in this module is via a second "sip" ! 23: * structure contained in the caller's local variables. ! 24: * ! 25: * This "sip" must be initialized with sip->si_boottab = scdriver ! 26: * and must then be devopen()ed before any I/O can be done. ! 27: * ! 28: * The device must be closed with devclose(). ! 29: */ ! 30: ! 31: /* How our addrs look to the SCSI DMA hardware */ ! 32: #define SCSI_DMA_ADDR(x) (((int)x)&0x000FFFFF) ! 33: ! 34: /* ! 35: * The interfaces we export ! 36: */ ! 37: extern int nullsys(); ! 38: int scopen(); ! 39: ! 40: struct boottab scdriver = ! 41: {"sd", nullsys, nullsys, scopen, nullsys, ! 42: nullsys, "", 0}; ! 43: ! 44: char seqerr_msg[] = "sequence error"; /* Saves dup copy of string */ ! 45: ! 46: /* ! 47: * Record an error message from scsi ! 48: */ ! 49: sc_error(msg) ! 50: char *msg; ! 51: { ! 52: printf("scsi: %s\n", msg); ! 53: } ! 54: ! 55: #define SCSI_MULTI_BASE 0x80000 ! 56: #define SCSI_VME_BASE 0x200000 ! 57: #define SCSI_SIZE 0x4000 /* incr to next board - OK for VME ? */ ! 58: #define SCSI_NSTD 2 /* # of standard address boards */ ! 59: ! 60: /* ! 61: * Open the SCSI host adapter. ! 62: * Note that the Multibus address and the VME address ! 63: * are totally different, although both are controller '0'. ! 64: * More fon goes here for the model 25. ! 65: */ ! 66: int ! 67: scopen(sip) ! 68: register struct saioreq *sip; ! 69: { ! 70: register struct scsi_ha_reg *har; ! 71: struct idprom id; ! 72: register int base; ! 73: enum MAPTYPES space; ! 74: char *devalloc(); ! 75: ! 76: if (idprom(IDFORM_1, &id) == IDFORM_1 && ! 77: id.id_machine == IDM_SUN2_MULTI) { ! 78: base = SCSI_MULTI_BASE; ! 79: space = MAP_MBMEM; ! 80: } else { ! 81: base = SCSI_VME_BASE; ! 82: space = MAP_VME24A16D; ! 83: } ! 84: if (sip->si_ctlr < SCSI_NSTD) ! 85: sip->si_ctlr = base + sip->si_ctlr * SCSI_SIZE; ! 86: /* now map it in */ ! 87: sip->si_devaddr = devalloc(space, sip->si_ctlr, ! 88: sizeof (struct scsi_ha_reg)); ! 89: if (sip->si_devaddr == 0) ! 90: return (-1); ! 91: ! 92: har = (struct scsi_ha_reg *) sip->si_devaddr; ! 93: har->icr = 0; ! 94: return 0; ! 95: } ! 96: ! 97: ! 98: /* ! 99: * Write a command to the SCSI bus. ! 100: * ! 101: * The supplied sip is the one opened by scopen(). ! 102: * DMA is done based on sip->si_ma and sip->si_cc. ! 103: * ! 104: * Returns -1 for error, otherwise returns the residual count not DMAed ! 105: * (zero for success). ! 106: * ! 107: * FIXME, this must be accessed via a boottab vector, ! 108: * to allow host adap to switch. ! 109: * Must pass cdb, scb in sip somewhere... ! 110: */ ! 111: int ! 112: scdoit(cdb, scb, sip) ! 113: register struct scsi_cdb *cdb; ! 114: register struct scsi_scb *scb; ! 115: register struct saioreq *sip; ! 116: { ! 117: register char *cp; ! 118: register int i, b; ! 119: register struct scsi_ha_reg *har; ! 120: ! 121: har = (struct scsi_ha_reg *) sip->si_devaddr; ! 122: ! 123: /* select controller */ ! 124: har->data = 1 << sip->si_unit; /* Set target on SCSI bus */ ! 125: ! 126: i = 100000; ! 127: for(;;) { ! 128: if ((har->icr & ICR_BUSY) == 0) { ! 129: break; ! 130: } ! 131: if (i-- <= 0) { ! 132: sc_error("bus continuously busy"); ! 133: har->icr = ICR_RESET; ! 134: DELAY(50); ! 135: har->icr = 0; ! 136: return (-1); ! 137: } ! 138: } ! 139: har->icr = ICR_SELECT; ! 140: if (sc_wait(har, ICR_BUSY) == 0) { ! 141: /* ! 142: * No response to select. Reset bus and get out. ! 143: */ ! 144: sc_error("no such controller on SCSI bus"); ! 145: har->icr = ICR_RESET; ! 146: DELAY(50); ! 147: har->icr = 0; ! 148: return (-1); ! 149: } ! 150: /* pass command */ ! 151: har->icr = ICR_WORD_MODE | ICR_DMA_ENABLE; ! 152: har->dma_addr = SCSI_DMA_ADDR(sip->si_ma); ! 153: har->dma_count = ~sip->si_cc; ! 154: cp = (char *) cdb; ! 155: for (i = 0; i < sizeof (struct scsi_cdb); i++) { ! 156: if (sc_putbyte(har, ICR_COMMAND, *cp++) == 0) { ! 157: return (-1); ! 158: } ! 159: } ! 160: /* wait for command completion */ ! 161: if (sc_wait(har, ICR_INTERRUPT_REQUEST) == 0) { ! 162: return (-1); ! 163: } ! 164: /* handle odd length dma transfer, adjust dma count */ ! 165: if (har->icr & ICR_ODD_LENGTH) { ! 166: if ((cdb->cmd == SC_REQUEST_SENSE) || (cdb->cmd == SC_READ)) { ! 167: cp = (char *)sip->si_ma + sip->si_cc - 1; ! 168: *cp = (char)har->data; ! 169: har->dma_count = ~(~har->dma_count - 1); ! 170: } else { ! 171: har->dma_count = ~(~har->dma_count + 1); ! 172: } ! 173: } ! 174: /* get status */ ! 175: cp = (char *) scb; ! 176: i = 0; ! 177: for (;;) { ! 178: b = sc_getbyte(har, ICR_STATUS); ! 179: if (b == -1) { ! 180: break; ! 181: } ! 182: if (i < STATUS_LEN) { ! 183: cp[i++] = b; ! 184: } ! 185: } ! 186: b = sc_getbyte(har, ICR_MESSAGE_IN); ! 187: if (b != SC_COMMAND_COMPLETE) { ! 188: if (b >= 0) { /* if not, sc_getbyte already printed msg */ ! 189: sc_error("invalid message"); ! 190: } ! 191: return (-1); ! 192: } ! 193: return (sip->si_cc - ~har->dma_count); ! 194: } ! 195: ! 196: ! 197: /* ! 198: * Wait for a condition on the scsi bus. ! 199: */ ! 200: int ! 201: sc_wait(har, cond) ! 202: register struct scsi_ha_reg *har; ! 203: { ! 204: register int icr, count; ! 205: ! 206: if (cond == ICR_INTERRUPT_REQUEST) { ! 207: count = 1000000; ! 208: } else { ! 209: count = 10000; ! 210: } ! 211: while (((icr = har->icr) & cond) != cond) { ! 212: if (--count <= 0) { ! 213: sc_error("timeout"); ! 214: return (0); ! 215: } ! 216: if (icr & ICR_BUS_ERROR) { ! 217: sc_error("bus error"); ! 218: return (0); ! 219: } ! 220: DELAY(5000); ! 221: } ! 222: return (1); ! 223: } ! 224: ! 225: ! 226: /* ! 227: * Put a byte into the scsi command register. ! 228: */ ! 229: int ! 230: sc_putbyte(har, bits, c) ! 231: register struct scsi_ha_reg *har; ! 232: { ! 233: if (sc_wait(har, ICR_REQUEST) == 0) { ! 234: return (0); ! 235: } ! 236: if ((har->icr & ICR_BITS) != bits) { ! 237: sc_error(seqerr_msg); ! 238: return (0); ! 239: } ! 240: har->cmd_stat = c; ! 241: return (1); ! 242: } ! 243: ! 244: ! 245: /* ! 246: * Get a byte from the scsi command/status register. ! 247: * <bits> defines the bits we want to see on in the ICR. ! 248: * If <bits> is wrong, we print a message -- unless <bits> is ICR_STATUS. ! 249: * This hack is because scdoit keeps calling getbyte until it sees a non- ! 250: * status byte; this is not an error in sequence as long as the next byte ! 251: * has MESSAGE_IN tags. FIXME. ! 252: */ ! 253: int ! 254: sc_getbyte(har, bits) ! 255: register struct scsi_ha_reg *har; ! 256: { ! 257: if (sc_wait(har, ICR_REQUEST) == 0) { ! 258: return (-1); ! 259: } ! 260: if ((har->icr & ICR_BITS) != bits) { ! 261: if (bits != ICR_STATUS) sc_error(seqerr_msg); /* Hack hack */ ! 262: return (-1); ! 263: } ! 264: return (har->cmd_stat); ! 265: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.