| plan 9 kernel history: overview | file list | diff list |
1995/0725/pc/scsi.c (diff list | history)
| 1995/0725/sys/src/9/pc/scsi.c:1,489 – 1995/0726/sys/src/9/pc/scsi.c:1,489 (short | long | prev | next) | ||
| 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" | |
| 1995/0722 | enum { | |
| 1994/0908 | 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 | }; | |
| 1995/0722 | typedef struct { | |
| 1994/0908 | ISAConf; Scsiio io; Target target[NTarget]; } Ctlr; | |
| 1995/0723 | static Ctlr* scsi[MaxScsi]; | |
| 1994/0908 | ||
| 1995/0328 | typedef struct Link Link; | |
| 1995/0722 | 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; | |
| 1995/0725 | if(id) sprint(id, "scsi%d: unit %d", ctlr, unit); | |
| 1995/0403 | 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; | |
| 1995/0722 | cmd[4] = s? 1: 0; | |
| 1994/0908 | 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; | |
| 1995/0723 | nbytes = 8; d = scsialloc(nbytes); | |
| 1994/0908 | if(d == 0) | |
| 1995/0723 | error(Enomem); | |
| 1994/0908 | ||
| 1995/0723 | s = scsiexec(t, SCSIread, cmd, sizeof(cmd), d, &nbytes); if(s == STok) { | |
| 1995/0724 | *size = nhgetl(d+0); *bsize = nhgetl(d+4); | |
| 1994/0908 | } | |
| 1995/0723 | scsifree(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; | |
| 1995/0724 | hnputs(cmd+2, bno); | |
| 1994/0908 | cmd[4] = n; cdbsiz = 6; } else { cmd[0] = 0x2A; if(dir == SCSIread) cmd[0] = 0x28; cmd[1] = (lun<<5); | |
| 1995/0724 | hnputl(cmd+2, bno); hnputs(cmd+7, n); | |
| 1994/0908 | 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; } | |
| 1995/0722 | int scsidiskinfo(Target *t, char lun, uchar *data) { | |
| 1995/0723 | int s, nbytes; uchar cmd[10], *d; | |
| 1995/0722 | ||
| 1995/0723 | nbytes = 4; | |
| 1995/0722 | ||
| 1995/0723 | memset(cmd, 0, sizeof(cmd)); cmd[0] = 0x43; cmd[1] = lun<<5; | |
| 1995/0724 | hnputs(cmd+7, nbytes); | |
| 1995/0722 | ||
| 1995/0723 | d = scsialloc(nbytes); if(d == 0) error(Enomem); | |
| 1995/0722 | ||
| 1995/0723 | memset(d, 0, nbytes); s = scsiexec(t, SCSIread, cmd, sizeof(cmd), d, &nbytes); memmove(data, d, 4); scsifree(d); | |
| 1995/0722 | return s; } int scsitrackinfo(Target *t, char lun, int track, uchar *data) { int s, nbytes; | |
| 1995/0723 | uchar cmd[10], *d; | |
| 1995/0722 | nbytes = 12; memset(cmd, 0, sizeof(cmd)); cmd[0] = 0xe5; cmd[1] = lun<<5; cmd[5] = track; | |
| 1995/0724 | hnputs(cmd+7, nbytes); | |
| 1995/0722 | ||
| 1995/0723 | d = scsialloc(nbytes); if(d == 0) error(Enomem); memset(d, 0, nbytes); s = scsiexec(t, SCSIread, cmd, sizeof(cmd), d, &nbytes); memmove(data, d, 12); scsifree(d); | |
| 1995/0722 | return s; | |
| 1995/0723 | } int scsibufsize(Target *t, char lun, int size) { int s, nbytes; uchar cmd[6], *d; nbytes = 12; memset(cmd, 0, sizeof(cmd)); cmd[0] = 0x15; cmd[1] = lun<<5; cmd[4] = nbytes; d = scsialloc(nbytes); if(d == 0) error(Enomem); memset(d, 0, nbytes); d[3] = 8; | |
| 1995/0724 | hnputl(d+8, size); | |
| 1995/0723 | s = scsiexec(t, SCSIwrite, cmd, sizeof(cmd), d, &nbytes); scsifree(d); return s; } int | |
| 1995/0726 | scsireadcdda(Target *t, char lun, int dir, void *b, long n, long bsize, long bno) | |
| 1995/0723 | { uchar cmd[10]; int s, nbytes; memset(cmd, 0, sizeof(cmd)); cmd[0] = 0xd8; cmd[1] = (lun<<5); | |
| 1995/0724 | hnputl(cmd+2, bno); hnputl(cmd+6, n); | |
| 1995/0723 | nbytes = n*bsize; s = scsiexec(t, SCSIread, cmd, sizeof(cmd), b, &nbytes); if(s < 0) { nbytes = Nscratch; scsireqsense(t, lun, t->scratch, &nbytes, 0); return -1; } return nbytes; | |
| 1995/0722 | } | |