URI:
       tscsi.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tscsi.c (6112B)
       ---
            1 /*
            2  * Now thread-safe.
            3  *
            4  * The codeqlock guarantees that once codes != nil, that pointer will never
            5  * change nor become invalid.
            6  *
            7  * The QLock in the Scsi structure moderates access to the raw device.
            8  * We should probably export some of the already-locked routines, but
            9  * there hasn't been a need.
           10  */
           11 
           12 #include <u.h>
           13 #include <libc.h>
           14 #include <disk.h>
           15 
           16 int scsiverbose;
           17 
           18 #define codefile "/sys/lib/scsicodes"
           19 
           20 static char *codes;
           21 static QLock codeqlock;
           22 
           23 static void
           24 getcodes(void)
           25 {
           26         Dir *d;
           27         int n, fd;
           28 
           29         if(codes != nil)
           30                 return;
           31 
           32         qlock(&codeqlock);
           33         if(codes != nil) {
           34                 qunlock(&codeqlock);
           35                 return;
           36         }
           37 
           38         if((d = dirstat(codefile)) == nil || (fd = open(codefile, OREAD)) < 0) {
           39                 qunlock(&codeqlock);
           40                 return;
           41         }
           42 
           43         codes = malloc(1+d->length+1);
           44         if(codes == nil) {
           45                 close(fd);
           46                 qunlock(&codeqlock);
           47                 free(d);
           48                 return;
           49         }
           50 
           51         codes[0] = '\n';        /* for searches */
           52         n = readn(fd, codes+1, d->length);
           53         close(fd);
           54         free(d);
           55 
           56         if(n < 0) {
           57                 free(codes);
           58                 codes = nil;
           59                 qunlock(&codeqlock);
           60                 return;
           61         }
           62         codes[n] = '\0';
           63         qunlock(&codeqlock);
           64 }
           65 
           66 char*
           67 scsierror(int asc, int ascq)
           68 {
           69         char *p, *q;
           70         static char search[32];
           71         static char buf[128];
           72 
           73         getcodes();
           74 
           75         if(codes) {
           76                 sprint(search, "\n%.2ux%.2ux ", asc, ascq);
           77                 if(p = strstr(codes, search)) {
           78                         p += 6;
           79                         if((q = strchr(p, '\n')) == nil)
           80                                 q = p+strlen(p);
           81                         snprint(buf, sizeof buf, "%.*s", (int)(q-p), p);
           82                         return buf;
           83                 }
           84 
           85                 sprint(search, "\n%.2ux00", asc);
           86                 if(p = strstr(codes, search)) {
           87                         p += 6;
           88                         if((q = strchr(p, '\n')) == nil)
           89                                 q = p+strlen(p);
           90                         snprint(buf, sizeof buf, "(ascq #%.2ux) %.*s", ascq, (int)(q-p), p);
           91                         return buf;
           92                 }
           93         }
           94 
           95         sprint(buf, "scsi #%.2ux %.2ux", asc, ascq);
           96         return buf;
           97 }
           98 
           99 
          100 static int
          101 _scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io, int dolock)
          102 {
          103         uchar resp[16];
          104         int n;
          105         long status;
          106 
          107         if(dolock)
          108                 qlock(&s->lk);
          109         if(write(s->rawfd, cmd, ccount) != ccount) {
          110                 werrstr("cmd write: %r");
          111                 if(dolock)
          112                         qunlock(&s->lk);
          113                 return -1;
          114         }
          115 
          116         switch(io){
          117         case Sread:
          118                 n = read(s->rawfd, data, dcount);
          119                 if(n < 0 && scsiverbose)
          120                         fprint(2, "dat read: %r: cmd 0x%2.2uX\n", cmd[0]);
          121                 break;
          122         case Swrite:
          123                 n = write(s->rawfd, data, dcount);
          124                 if(n != dcount && scsiverbose)
          125                         fprint(2, "dat write: %r: cmd 0x%2.2uX\n", cmd[0]);
          126                 break;
          127         default:
          128         case Snone:
          129                 n = write(s->rawfd, resp, 0);
          130                 if(n != 0 && scsiverbose)
          131                         fprint(2, "none write: %r: cmd 0x%2.2uX\n", cmd[0]);
          132                 break;
          133         }
          134 
          135         memset(resp, 0, sizeof(resp));
          136         if(read(s->rawfd, resp, sizeof(resp)) < 0) {
          137                 werrstr("resp read: %r\n");
          138                 if(dolock)
          139                         qunlock(&s->lk);
          140                 return -1;
          141         }
          142         if(dolock)
          143                 qunlock(&s->lk);
          144 
          145         resp[sizeof(resp)-1] = '\0';
          146         status = atoi((char*)resp);
          147         if(status == 0)
          148                 return n;
          149 
          150         werrstr("cmd %2.2uX: status %luX dcount %d n %d", cmd[0], status, dcount, n);
          151         return -1;
          152 }
          153 
          154 int
          155 scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io)
          156 {
          157         return _scsicmd(s, cmd, ccount, data, dcount, io, 1);
          158 }
          159 
          160 static int
          161 _scsiready(Scsi *s, int dolock)
          162 {
          163         uchar cmd[6], resp[16];
          164         int status, i;
          165 
          166         if(dolock)
          167                 qlock(&s->lk);
          168         for(i=0; i<3; i++) {
          169                 memset(cmd, 0, sizeof(cmd));
          170                 cmd[0] = 0x00;        /* unit ready */
          171                 if(write(s->rawfd, cmd, sizeof(cmd)) != sizeof(cmd)) {
          172                         if(scsiverbose)
          173                                 fprint(2, "ur cmd write: %r\n");
          174                         goto bad;
          175                 }
          176                 write(s->rawfd, resp, 0);
          177                 if(read(s->rawfd, resp, sizeof(resp)) < 0) {
          178                         if(scsiverbose)
          179                                 fprint(2, "ur resp read: %r\n");
          180                         goto bad;
          181                 }
          182                 resp[sizeof(resp)-1] = '\0';
          183                 status = atoi((char*)resp);
          184                 if(status == 0 || status == 0x02) {
          185                         if(dolock)
          186                                 qunlock(&s->lk);
          187                         return 0;
          188                 }
          189                 if(scsiverbose)
          190                         fprint(2, "target: bad status: %x\n", status);
          191         bad:;
          192         }
          193         if(dolock)
          194                 qunlock(&s->lk);
          195         return -1;
          196 }
          197 
          198 int
          199 scsiready(Scsi *s)
          200 {
          201         return _scsiready(s, 1);
          202 }
          203 
          204 int
          205 scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io)
          206 {
          207         uchar req[6], sense[255], *data;
          208         int tries, code, key, n;
          209         char *p;
          210 
          211         data = v;
          212         SET(key); SET(code);
          213         qlock(&s->lk);
          214         for(tries=0; tries<2; tries++) {
          215                 n = _scsicmd(s, cmd, ccount, data, dcount, io, 0);
          216                 if(n >= 0) {
          217                         qunlock(&s->lk);
          218                         return n;
          219                 }
          220 
          221                 /*
          222                  * request sense
          223                  */
          224                 memset(req, 0, sizeof(req));
          225                 req[0] = 0x03;
          226                 req[4] = sizeof(sense);
          227                 memset(sense, 0xFF, sizeof(sense));
          228                 if((n=_scsicmd(s, req, sizeof(req), sense, sizeof(sense), Sread, 0)) < 14)
          229                         if(scsiverbose)
          230                                 fprint(2, "reqsense scsicmd %d: %r\n", n);
          231 
          232                 if(_scsiready(s, 0) < 0)
          233                         if(scsiverbose)
          234                                 fprint(2, "unit not ready\n");
          235 
          236                 key = sense[2];
          237                 code = sense[12];
          238                 if(code == 0x17 || code == 0x18) {        /* recovered errors */
          239                         qunlock(&s->lk);
          240                         return dcount;
          241                 }
          242                 if(code == 0x28 && cmd[0] == 0x43) {        /* get info and media changed */
          243                         s->nchange++;
          244                         s->changetime = time(0);
          245                         continue;
          246                 }
          247         }
          248 
          249         /* drive not ready, or medium not present */
          250         if(cmd[0] == 0x43 && key == 2 && (code == 0x3a || code == 0x04)) {
          251                 s->changetime = 0;
          252                 qunlock(&s->lk);
          253                 return -1;
          254         }
          255         qunlock(&s->lk);
          256 
          257         if(cmd[0] == 0x43 && key == 5 && code == 0x24)        /* blank media */
          258                 return -1;
          259 
          260         p = scsierror(code, sense[13]);
          261 
          262         werrstr("cmd #%.2ux: %s", cmd[0], p);
          263 
          264         if(scsiverbose)
          265                 fprint(2, "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n", cmd[0], key, code, sense[13], p);
          266 
          267 /*        if(key == 0) */
          268 /*                return dcount; */
          269         return -1;
          270 }
          271 
          272 Scsi*
          273 openscsi(char *dev)
          274 {
          275         Scsi *s;
          276         int rawfd, ctlfd, l, n;
          277         char *name, *p, buf[512];
          278 
          279         l = strlen(dev)+1+3+1;
          280         name = malloc(l);
          281         if(name == nil)
          282                 return nil;
          283 
          284         snprint(name, l, "%s/raw", dev);
          285         if((rawfd = open(name, ORDWR)) < 0) {
          286                 free(name);
          287                 return nil;
          288         }
          289 
          290         snprint(name, l, "%s/ctl", dev);
          291         if((ctlfd = open(name, ORDWR)) < 0) {
          292                 free(name);
          293         Error:
          294                 close(rawfd);
          295                 return nil;
          296         }
          297         free(name);
          298 
          299         n = readn(ctlfd, buf, sizeof buf);
          300         close(ctlfd);
          301         if(n <= 0)
          302                 goto Error;
          303 
          304         if(strncmp(buf, "inquiry ", 8) != 0 || (p = strchr(buf, '\n')) == nil)
          305                 goto Error;
          306         *p = '\0';
          307 
          308         if((p = strdup(buf+8)) == nil)
          309                 goto Error;
          310 
          311         s = malloc(sizeof(*s));
          312         if(s == nil) {
          313         Error1:
          314                 free(p);
          315                 goto Error;
          316         }
          317         memset(s, 0, sizeof(*s));
          318 
          319         s->rawfd = rawfd;
          320         s->inquire = p;
          321         s->changetime = time(0);
          322 
          323         if(scsiready(s) < 0)
          324                 goto Error1;
          325 
          326         return s;
          327 }