| plan 9 kernel history: overview | file list | diff list |
1995/0513/pc/scsi.c (diff list | history)
| pc/scsi.c on 1993/0915 | ||
| 1993/0915 | #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" | |
| 1994/0908 | #include "ureg.h" | |
| 1993/0915 | #include "../port/error.h" | |
| 1994/0908 | #include "../port/netif.h" | |
| 1993/0915 | ||
| 1994/0908 | enum { Ninq = 255, Nscratch = 255, | |
| 1993/0915 | ||
| 1995/0329 | CMDtest = 0x00, | |
| 1994/0908 | CMDreqsense = 0x03, | |
| 1995/0329 | CMDread6 = 0x08, CMDwrite6 = 0x0A, | |
| 1994/0908 | CMDinquire = 0x12, | |
| 1995/0329 | CMDstart = 0x1B, CMDread10 = 0x28, CMDwrite10 = 0x2A, | |
| 1994/0908 | }; typedef struct { ISAConf; Scsiio io; Target target[NTarget]; } Ctlr; static Ctlr *scsi[MaxScsi]; | |
| 1995/0328 | typedef struct Link Link; typedef struct Link { | |
| 1994/0908 | char *type; Scsiio (*reset)(int, ISAConf*); | |
| 1995/0328 | Link* link; } Link; static Link *link; static int linkcount; | |
| 1993/0915 | void | |
| 1995/0328 | addscsilink(char *t, Scsiio (*r)(int, ISAConf*)) | |
| 1993/0915 | { | |
| 1995/0328 | Link *lp; | |
| 1994/0908 | ||
| 1995/0328 | if((lp = xalloc(sizeof(Link))) == 0) return; lp->type = t; lp->reset = r; lp->link = link; link = lp; linkcount++; | |
| 1993/0915 | } void | |
| 1994/0908 | scsireset(void) | |
| 1993/0915 | { | |
| 1994/0908 | Ctlr *ctlr; | |
| 1995/0328 | int ctlrno, t; Link *lp; | |
| 1994/0908 | for(ctlr = 0, ctlrno = 0; ctlrno < MaxScsi; ctlrno++){ if(ctlr == 0) ctlr = malloc(sizeof(Ctlr)); memset(ctlr, 0, sizeof(Ctlr)); if(isaconfig("scsi", ctlrno, ctlr) == 0) continue; | |
| 1995/0328 | for(lp = link; lp; lp = lp->link){ if(strcmp(lp->type, ctlr->type)) | |
| 1994/0908 | continue; | |
| 1995/0328 | if((ctlr->io = (*lp->reset)(ctlrno, ctlr)) == 0) | |
| 1994/0908 | break; | |
| 1995/0513 | print("scsi%d: %s: port 0x%luX irq %d", | |
| 1994/0908 | ctlrno, ctlr->type, ctlr->port, ctlr->irq, ctlr->mem, ctlr->size); | |
| 1995/0328 | if(ctlr->mem) | |
| 1995/0513 | print(" addr 0x%luX", ctlr->mem & ~KZERO); if(ctlr->size) print(" size 0x%luX", ctlr->size); | |
| 1995/0328 | print("\n"); | |
| 1994/0908 | for(t = 0; t < NTarget; t++){ ctlr->target[t].ctlrno = ctlrno; ctlr->target[t].target = t; ctlr->target[t].inq = xalloc(Ninq); ctlr->target[t].scratch = xalloc(Nscratch); } scsi[ctlrno] = ctlr; ctlr = 0; break; } } if(ctlr) free(ctlr); | |
| 1993/0915 | } | |
| 1994/0908 | int | |
| 1995/0324 | scsiexec(Target *t, int rw, uchar *cmd, int cbytes, void *data, int *dbytes) | |
| 1993/0915 | { | |
| 1995/0324 | return (*scsi[t->ctlrno]->io)(t, rw, cmd, cbytes, data, dbytes); | |
| 1994/0908 | } | |
| 1993/0915 | ||
| 1994/0908 | Target* scsiunit(int ctlr, int unit) { Target *t; if(ctlr < 0 || ctlr >= MaxScsi || scsi[ctlr] == 0) return 0; if(unit < 0 || unit >= NTarget) return 0; t = &scsi[ctlr]->target[unit]; if(t->ok == 0) return 0; return t; | |
| 1993/0915 | } | |
| 1994/0908 | static void scsiprobe(Ctlr *ctlr) | |
| 1993/0915 | { | |
| 1995/0324 | Target *t; | |
| 1994/0908 | int i, s, nbytes; for(i = 0; i < NTarget; i++) { | |
| 1995/0324 | t = &ctlr->target[i]; | |
| 1994/0908 | ||
| 1995/0404 | if(scsitest(t, 0) < 0) | |
| 1994/0908 | continue; /* * Determine if the drive exists and is not ready or * is simply not responding */ | |
| 1995/0405 | nbytes = Nscratch; s = scsireqsense(t, 0, t->scratch, &nbytes, 0); if(s != STok){ | |
| 1995/0324 | print("scsi%d: unit %d unavailable, status %d\n", t->ctlrno, i, s); | |
| 1994/0908 | continue; } /* | |
| 1995/0329 | * Inquire to find out what the device is. | |
| 1994/0908 | * Drivers then use the result to attach to targets */ | |
| 1995/0324 | memset(t->inq, 0, Ninq); | |
| 1994/0908 | nbytes = Ninq; | |
| 1995/0329 | s = scsiinquiry(t, 0, t->inq, &nbytes); | |
| 1994/0908 | if(s < 0) { | |
| 1995/0324 | print("scsi%d: unit %d inquire failed, status %d\n", t->ctlrno, i, s); | |
| 1994/0908 | continue; } | |
| 1995/0405 | print("scsi%d: unit %d: %s\n", t->ctlrno, i, t->inq+8); | |
| 1995/0324 | t->ok = 1; | |
| 1994/0908 | } | |
| 1993/0915 | } | |
| 1994/0908 | static void inventory(void) | |
| 1993/0915 | { | |
| 1994/0908 | int i; static Lock ilock; static int inited; | |
| 1993/0915 | ||
| 1994/0908 | lock(&ilock); if(inited) { unlock(&ilock); return; } inited = 1; unlock(&ilock); for(i = 0; i < MaxScsi; i++){ if(scsi[i]) scsiprobe(scsi[i]); } | |
| 1993/0915 | } | |
| 1994/0908 | int | |
| 1995/0403 | scsiinv(int devno, int *type, Target **rt, uchar **inq, char *id) | |
| 1994/0908 | { Target *t; | |
| 1995/0403 | int ctlr, *i, unit; | |
| 1993/0915 | ||
| 1994/0908 | inventory(); | |
| 1993/0915 | ||
| 1994/0908 | for(;;){ ctlr = devno/NTarget; unit = devno%NTarget; if(ctlr >= MaxScsi || scsi[ctlr] == 0) return -1; t = &scsi[ctlr]->target[unit]; devno++; | |
| 1995/0403 | if(t->ok){ for(i = type; *i >= 0; i++){ if((t->inq[0]&0x1F) != *i) continue; *rt = t; *inq = t->inq; sprint(id, "scsi%d: unit %d", ctlr, unit); return devno; } | |
| 1994/0908 | } } return -1; | |
| 1995/0404 | } int scsitest(Target *t, char lun) { uchar cmd[6]; memset(cmd, 0, sizeof(cmd)); cmd[0] = CMDtest; cmd[1] = lun<<5; return scsiexec(t, SCSIread, cmd, sizeof(cmd), 0, 0); | |
| 1994/0908 | } | |
| 1993/0915 | int | |
| 1994/0908 | scsistart(Target *t, char lun, int s) | |
| 1993/0915 | { | |
| 1994/0908 | uchar cmd[6]; memset(cmd, 0, sizeof cmd); | |
| 1995/0329 | cmd[0] = CMDstart; | |
| 1994/0908 | cmd[1] = lun<<5; cmd[4] = s ? 1 : 0; return scsiexec(t, SCSIread, cmd, sizeof(cmd), 0, 0); | |
| 1995/0329 | } int scsiinquiry(Target *t, char lun, void *data, int *datalen) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); cmd[0] = CMDinquire; cmd[1] = lun<<5; cmd[4] = *datalen; return scsiexec(t, SCSIread, cmd, sizeof(cmd), data, datalen); | |
| 1993/0915 | } | |
| 1994/0908 | int scsicap(Target *t, char lun, ulong *size, ulong *bsize) | |
| 1993/0915 | { | |
| 1994/0908 | int s, nbytes; uchar cmd[10], *d; memset(cmd, 0, sizeof(cmd)); cmd[0] = 0x25; cmd[1] = lun<<5; d = malloc(8); if(d == 0) return -1; nbytes = 8; | |
| 1995/0405 | if((s = scsiexec(t, SCSIread, cmd, sizeof(cmd), d, &nbytes)) == STok){ *size = (d[0]<<24)|(d[1]<<16)|(d[2]<<8)|(d[3]<<0); *bsize = (d[4]<<24)|(d[5]<<16)|(d[6]<<8)|(d[7]<<0); | |
| 1994/0908 | } free(d); | |
| 1995/0405 | return s; | |
| 1993/0915 | } | |
| 1994/0908 | int scsibio(Target *t, char lun, int dir, void *b, long n, long bsize, long bno) { uchar cmd[10]; int s, cdbsiz, nbytes; memset(cmd, 0, sizeof cmd); if(bno <= 0x1fffff && n < 256) { cmd[0] = 0x0A; if(dir == SCSIread) cmd[0] = 0x08; cmd[1] = (lun<<5) | bno >> 16; cmd[2] = bno >> 8; cmd[3] = bno; cmd[4] = n; cdbsiz = 6; } else { cmd[0] = 0x2A; if(dir == SCSIread) cmd[0] = 0x28; cmd[1] = (lun<<5); cmd[2] = bno >> 24; cmd[3] = bno >> 16; cmd[4] = bno >> 8; cmd[5] = bno; cmd[7] = n>>8; cmd[8] = n; cdbsiz = 10; } nbytes = n*bsize; s = scsiexec(t, dir, cmd, cdbsiz, b, &nbytes); if(s < 0) { | |
| 1995/0405 | nbytes = Nscratch; scsireqsense(t, lun, t->scratch, &nbytes, 0); | |
| 1994/0908 | return -1; } return nbytes; } static char *key[] = { "no sense", "recovered error", "not ready", "medium error", "hardware error", "illegal request", "unit attention", "data protect", "blank check", "vendor specific", "copy aborted", "aborted command", "equal", "volume overflow", "miscompare", "reserved" }; int | |
| 1995/0405 | scsireqsense(Target *t, char lun, void *data, int *nbytes, int quiet) | |
| 1994/0908 | { char *s; | |
| 1995/0405 | int status, try; | |
| 1994/0908 | uchar cmd[6], *sense; | |
| 1995/0405 | sense = malloc(*nbytes); | |
| 1994/0908 | for(try = 0; try < 5; try++) { memset(cmd, 0, sizeof(cmd)); cmd[0] = CMDreqsense; cmd[1] = lun<<5; | |
| 1995/0405 | cmd[4] = *nbytes; memset(sense, 0, *nbytes); | |
| 1994/0908 | ||
| 1995/0405 | status = scsiexec(t, SCSIread, cmd, sizeof(cmd), sense, nbytes); if(status != STok){ free(sense); return status; } *nbytes = sense[0x07]+8; memmove(data, sense, *nbytes); | |
| 1994/0908 | /* * Unit attention. We can handle that. */ | |
| 1995/0405 | if((sense[2] & 0x0F) == 0x00 || (sense[2] & 0x0F) == 0x06){ free(sense); | |
| 1994/0908 | return STok; | |
| 1995/0405 | } | |
| 1994/0908 | /* * Recovered error. Why bother telling me. */ | |
| 1995/0405 | if((sense[2] & 0x0F) == 0x01){ free(sense); | |
| 1994/0908 | return STok; | |
| 1995/0405 | } | |
| 1994/0908 | /* * Unit is becoming ready */ if(sense[12] != 0x04 || sense[13] != 0x01) break; delay(5000); } | |
| 1995/0405 | if(quiet == 0){ s = key[sense[2]&0x0F]; print("scsi%d: unit %d reqsense: '%s' code #%2.2ux #%2.2ux\n", t->ctlrno, t->target, s, sense[12], sense[13]); } free(sense); | |
| 1994/0908 | return STcheck; } | |