|
|
1.1 ! root 1: /* ! 2: || dslib.c - library routines for /dev/scsi ! 3: || ! 4: || Copyright 1988, 1989, by ! 5: || Gene Dronek (Vulcan Laboratory) and ! 6: || Rich Morin (Canta Forda Computer Laboratory). ! 7: || All rights reserved. ! 8: */ ! 9: #ident "dslib.c: $Revision: 1.4 $" ! 10: ! 11: #include <stdio.h> ! 12: #include <sys/types.h> ! 13: ! 14: #include "dslib.h" ! 15: #ifdef aux ! 16: #include <sys/vio.h> ! 17: #include <sys/scsireq.h> ! 18: #endif aux ! 19: ! 20: int dsdebug=0; ! 21: long dsreqflags; /* flag bits always set by filldsreq */ ! 22: ! 23: #define min(i,j) ( (i) < (j) ? (i) : (j) ) ! 24: ! 25: ! 26: /* ! 27: || Startup/shutdown ----------------------------------------------- ! 28: */ ! 29: ! 30: static struct context *dsc[FDSIZ]; ! 31: ! 32: ! 33: /* ! 34: || dsopen - open device, set up structures ! 35: */ ! 36: ! 37: struct dsreq * ! 38: dsopen(opath, oflags) ! 39: char *opath; ! 40: int oflags; ! 41: { ! 42: ! 43: struct dsreq *dsp; ! 44: struct context *cp; ! 45: int fd; ! 46: DSDBG(fprintf(stderr,"dsopen(%s,%x) ", opath, oflags)); ! 47: ! 48: fd = open(opath, oflags); ! 49: if (fd < 0) ! 50: return NULL; /* can't open */ ! 51: if (dsc[fd] != NULL) /* already in use */ ! 52: ds_zot("dsopen: fd already in use"); ! 53: ! 54: cp = (struct context *) calloc(1, sizeof(struct context)); ! 55: if (cp == NULL) /* can't allocate */ ! 56: ds_zot("dsopen: can't allocate space"); ! 57: dsc[fd] = cp; ! 58: cp->dsc_fd = fd; ! 59: dsp = &(cp->dsc_dsreq); ! 60: ! 61: dsp->ds_flags = 0; ! 62: dsp->ds_time = 10 * 1000; /* 10 second default timeout */ ! 63: dsp->ds_private = (ulong) cp; /* pointer back to context */ ! 64: dsp->ds_cmdbuf = cp->dsc_cmd; ! 65: dsp->ds_cmdlen = sizeof cp->dsc_cmd; ! 66: dsp->ds_databuf = 0; ! 67: dsp->ds_datalen = 0; ! 68: dsp->ds_sensebuf = cp->dsc_sense; ! 69: dsp->ds_senselen = sizeof cp->dsc_sense; ! 70: DSDBG(fprintf(stderr,"=>cp %x, dsp %x\n", cp, dsp)); ! 71: return dsp; ! 72: } ! 73: ! 74: ! 75: /* ! 76: || dsclose - close device, release context struct. ! 77: */ ! 78: ! 79: dsclose(dsp) ! 80: struct dsreq *dsp; ! 81: { ! 82: int fd; ! 83: struct context *cp; ! 84: ! 85: if (dsp == NULL) ! 86: ds_zot("dsclose: dsp is NULL"); ! 87: ! 88: cp = (struct context *)dsp->ds_private; ! 89: fd = getfd(dsp); ! 90: if ( cp == NULL ) ! 91: ds_zot("dsclose: private is NULL"); ! 92: ! 93: cfree(cp); ! 94: dsc[fd] = (struct context *)NULL; ! 95: return; ! 96: } ! 97: ! 98: ! 99: /* ! 100: || Generic SCSI CCS Command functions ------------------------------------ ! 101: || ! 102: || dsp dsreq pointer ! 103: || data data buffer pointer ! 104: || datalen data buffer length ! 105: || lba logical block address ! 106: || vu vendor unique bits ! 107: */ ! 108: ! 109: /* ! 110: || testunitready00 - issue group 0 "Test Unit Ready" command (0x00) ! 111: */ ! 112: ! 113: testunitready00(dsp) ! 114: struct dsreq *dsp; ! 115: { ! 116: fillg0cmd(dsp, CMDBUF(dsp), G0_TEST, 0, 0, 0, 0, 0); ! 117: filldsreq(dsp, 0, 0, DSRQ_READ|DSRQ_SENSE); ! 118: return(doscsireq(getfd(dsp), dsp)); ! 119: } ! 120: ! 121: ! 122: /* ! 123: || requestsense03 - issue group 0 "Request Sense" command (0x03) ! 124: */ ! 125: ! 126: requestsense03(dsp, data, datalen, vu) ! 127: struct dsreq *dsp; ! 128: caddr_t data; ! 129: long datalen; ! 130: char vu; ! 131: { ! 132: fillg0cmd(dsp, CMDBUF(dsp), G0_REQU, 0, 0, 0, B1(datalen), B1(vu<<6)); ! 133: filldsreq(dsp, data, datalen, DSRQ_READ); ! 134: return(doscsireq(getfd(dsp), dsp)); ! 135: } ! 136: ! 137: ! 138: /* ! 139: || write0a - issue group 0 "Write" command (0x0a) ! 140: */ ! 141: ! 142: write0a(dsp, data, datalen, lba, vu) ! 143: struct dsreq *dsp; ! 144: caddr_t data; ! 145: long datalen, lba; ! 146: char vu; ! 147: { ! 148: fillg0cmd(dsp, CMDBUF(dsp), G0_WRIT, B3(lba), B1(datalen), B1(vu<<6)); ! 149: filldsreq(dsp, data, datalen, DSRQ_READ); ! 150: return(doscsireq(getfd(dsp), dsp)); ! 151: } ! 152: ! 153: ! 154: /* ! 155: || inquiry12 - issue group 0 "Inquiry" command (0x12) ! 156: */ ! 157: ! 158: inquiry12(dsp, data, datalen, vu) ! 159: struct dsreq *dsp; ! 160: caddr_t data; ! 161: long datalen; ! 162: char vu; ! 163: { ! 164: fillg0cmd(dsp, CMDBUF(dsp), G0_INQU, 0, 0, 0, B1(datalen), B1(vu<<6)); ! 165: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE); ! 166: return(doscsireq(getfd(dsp), dsp)); ! 167: } ! 168: ! 169: ! 170: /* ! 171: || modeselect15 - issue group 0 "Mode Select" command (0x15) ! 172: || ! 173: || save 0 - don't save saveable pages ! 174: || 1 - save saveable pages ! 175: */ ! 176: ! 177: modeselect15(dsp, data, datalen, save, vu) ! 178: struct dsreq *dsp; ! 179: caddr_t data; ! 180: long datalen; ! 181: char save, vu; ! 182: { ! 183: fillg0cmd(dsp, CMDBUF(dsp), G0_MSEL, save&1, 0, 0, B1(datalen), B1(vu<<6)); ! 184: filldsreq(dsp, data, datalen, DSRQ_WRITE|DSRQ_SENSE); ! 185: return(doscsireq(getfd(dsp), dsp)); ! 186: } ! 187: ! 188: ! 189: /* ! 190: || modesense1a - issue group 0 "Mode Sense" command (0x1a) ! 191: || ! 192: || pagectrl 0 - current values ! 193: || 1 - changeable values ! 194: || 2 - default values ! 195: || 3 - saved values ! 196: || ! 197: || pagecode 0 - vendor unique ! 198: || 1 - error recovery ! 199: || 2 - disconnect/reconnect ! 200: || 3 - direct access dev. fmt. ! 201: || 4 - rigid disk geometry ! 202: || 5 - flexible disk ! 203: || 6-9 - see specific dev. types ! 204: || 0a - implemented options ! 205: || 0b - medium types supported ! 206: || 3f - return all pages ! 207: */ ! 208: ! 209: modesense1a(dsp, data, datalen, pagectrl, pagecode, vu) ! 210: struct dsreq *dsp; ! 211: caddr_t data; ! 212: long datalen; ! 213: char pagectrl, pagecode, vu; ! 214: { ! 215: fillg0cmd(dsp, CMDBUF(dsp), G0_MSEN, 0x10, ! 216: ((pagectrl&3)<<6) | (pagecode&0x3F), ! 217: 0, B1(datalen), B1(vu<<6)); ! 218: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE); ! 219: return(doscsireq(getfd(dsp), dsp)); ! 220: } ! 221: ! 222: ! 223: /* ! 224: || senddiagnostic1d - issue group 0 "Send Diagnostic" command (0x1d) ! 225: || ! 226: || self 0 - run test, hold results ! 227: || 1 - run test, return status ! 228: || ! 229: || dofl 0 - device online ! 230: || 1 - device offline ! 231: || ! 232: || uofl 0 - unit online ! 233: || 1 - unit offline ! 234: */ ! 235: ! 236: senddiagnostic1d(dsp, data, datalen, self, dofl, uofl, vu) ! 237: struct dsreq *dsp; ! 238: caddr_t data; ! 239: long datalen; ! 240: char self, dofl, uofl, vu; ! 241: { ! 242: fillg0cmd(dsp, CMDBUF(dsp), G0_MSEN, ! 243: (self&1)<<2 | (dofl&1)<<1 | (uofl&1), ! 244: 0, B2(datalen), B1(vu<<6)); ! 245: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE); ! 246: return(doscsireq(getfd(dsp), dsp)); ! 247: } ! 248: ! 249: ! 250: /* ! 251: || readcapacity25 - issue group 1 "Read Capacity" command (0x25) ! 252: || ! 253: || pmi 0 - return last logical block, entire unit ! 254: || 1 - return last logical block, current track ! 255: */ ! 256: ! 257: readcapacity25(dsp, data, datalen, lba, pmi, vu) ! 258: struct dsreq *dsp; ! 259: caddr_t data; ! 260: long datalen, lba; ! 261: char pmi, vu; ! 262: { ! 263: fillg1cmd(dsp, CMDBUF(dsp), G1_RCAP, 0, B4(lba), 0, 0, pmi&1, B1(vu<<6)); ! 264: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE ! 265: /* |DSRQ_CTRL2 */ ); ! 266: /* dsp->ds_time = 100; /* often takes a while */ ! 267: return(doscsireq(getfd(dsp), dsp)); ! 268: } ! 269: ! 270: ! 271: /* ! 272: || readextended28 - issue group 1 "Read Extended" command (0x28) ! 273: */ ! 274: ! 275: readextended28(dsp, data, datalen, lba, vu) ! 276: struct dsreq *dsp; ! 277: caddr_t data; ! 278: long datalen, lba; ! 279: char vu; ! 280: { ! 281: fillg1cmd(dsp, CMDBUF(dsp), G1_READ, 0, B4(lba), 0, B2(datalen), B1(vu<<6)); ! 282: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE ! 283: /* |DSRQ_CTRL2 */ ); ! 284: /* dsp->ds_time = 100; /* often takes a while */ ! 285: return(doscsireq(getfd(dsp), dsp)); ! 286: } ! 287: ! 288: ! 289: /* ! 290: || writeextended2a - issue group 1 "Write Extended" command (0x2a) ! 291: */ ! 292: ! 293: writeextended2a(dsp, data, datalen, lba, vu) ! 294: struct dsreq *dsp; ! 295: caddr_t data; ! 296: long datalen, lba; ! 297: char vu; ! 298: { ! 299: fillg1cmd(dsp, CMDBUF(dsp), G1_WRIT, 0, B4(lba), 0, B2(datalen), B1(vu<<6)); ! 300: filldsreq(dsp, data, datalen, DSRQ_READ|DSRQ_SENSE ! 301: /* |DSRQ_CTRL2 */ ); ! 302: /* dsp->ds_time = 100; /* often takes a while */ ! 303: return(doscsireq(getfd(dsp), dsp)); ! 304: } ! 305: ! 306: ! 307: /* ! 308: || Support functions ---------------------------------------------------- ! 309: */ ! 310: ! 311: /* ! 312: || fillg0cmd - Fill a Group 0 command buffer ! 313: */ ! 314: ! 315: fillg0cmd(dsp, cmd, b0,b1,b2,b3,b4,b5) ! 316: struct dsreq *dsp; ! 317: uchar_t *cmd, b0,b1,b2,b3,b4,b5; ! 318: { ! 319: uchar_t *c = cmd; ! 320: DSDBG(fprintf(stderr,"fillg0cmd(%x,%x, %02x %02x %02x %02x %02x %02x)\n", ! 321: dsp, cmd, b0,b1,b2,b3,b4,b5)); ! 322: *c++ = b0, *c++ = b1, *c++ = b2, *c++ = b3, *c++ = b4, *c++ = b5; ! 323: ! 324: CMDBUF(dsp) = (caddr_t) cmd; ! 325: CMDLEN(dsp) = 6; ! 326: } ! 327: ! 328: ! 329: /* ! 330: || fillg1cmd - Fill a Group 1 command buffer ! 331: */ ! 332: ! 333: fillg1cmd(dsp, cmd, b0,b1,b2,b3,b4,b5,b6,b7,b8,b9) ! 334: struct dsreq *dsp; ! 335: uchar_t *cmd, b0,b1,b2,b3,b4,b5,b6,b7,b8,b9; ! 336: { ! 337: uchar_t *c = cmd; ! 338: DSDBG(fprintf(stderr, ! 339: "fillg1cmd(%x,%x, %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x)\n", ! 340: dsp, cmd, b0,b1,b2,b3,b4,b5,b6,b7,b8,b9)); ! 341: ! 342: *c++ = b0, *c++ = b1, *c++ = b2, *c++ = b3, *c++ = b4, *c++ = b5; ! 343: *c++ = b6, *c++ = b7, *c++ = b8, *c++ = b9; ! 344: ! 345: CMDBUF(dsp) = (caddr_t) cmd; ! 346: CMDLEN(dsp) = 10; ! 347: } ! 348: ! 349: ! 350: /* ! 351: || filldsreq - Fill a dsreq structure ! 352: */ ! 353: ! 354: filldsreq(dsp,data,datalen,flags) ! 355: struct dsreq *dsp; ! 356: uchar_t *data; ! 357: { ! 358: DSDBG(fprintf(stderr,"filldsreq(%x,%x,%d,%x) cmdlen %d\n", ! 359: dsp,data,datalen,flags,CMDLEN(dsp))); ! 360: dsp->ds_flags = flags | dsreqflags | ! 361: (((dsdebug&1) ? DSRQ_TRACE : 0) | ! 362: ((dsdebug&2) ? DSRQ_PRINT : 0)); ! 363: dsp->ds_time = 10 * 1000; /* default to 10 seconds */ ! 364: dsp->ds_link = 0; ! 365: dsp->ds_synch = 0; ! 366: dsp->ds_ret = 0; ! 367: ! 368: DATABUF(dsp) = (caddr_t) data; ! 369: DATALEN(dsp) = datalen; ! 370: } ! 371: ! 372: ! 373: /* ! 374: || bprint - print array of bytes, in hex. ! 375: */ ! 376: ! 377: #define hex(x) "0123456789ABCDEF" [ (x) & 0xF ] ! 378: ! 379: bprint(s,n,nperline,space) ! 380: char *s; ! 381: { ! 382: int i, x; ! 383: char *sp = (space) ? " ": ""; ! 384: ! 385: for(i=0;i<n;i++) { ! 386: x = s[i]; ! 387: fprintf(stderr,((i%4==3)?"%c%c%s%s":"%c%c%s"), ! 388: hex(x>>4), hex(x), sp, sp); ! 389: if ( i%nperline == (nperline - 1) ) ! 390: fprintf(stderr,"\n"); ! 391: } ! 392: if ( space ) ! 393: fprintf(stderr,"\n"); ! 394: } ! 395: ! 396: ! 397: /* ! 398: || doscsireq - issue scsi command, return status or -1 error. ! 399: */ ! 400: ! 401: doscsireq( fd, dsp) ! 402: int fd; /* ioctl file descriptor */ ! 403: struct dsreq *dsp; /* devscsi request packet */ ! 404: { ! 405: int cc; ! 406: int retries = 4; ! 407: uchar_t sbyte; ! 408: ! 409: DSDBG(fprintf(stderr,"doscsireq(%d,%x) %x ---- %s\n",fd,dsp, ! 410: (CMDBUF(dsp))[0], ! 411: ds_vtostr( (CMDBUF(dsp))[0], cmdnametab))); ! 412: ! 413: /* ! 414: * loop, issuing command ! 415: * until done, or further retry pointless ! 416: */ ! 417: ! 418: while ( --retries > 0 ) { ! 419: ! 420: caddr_t sp; ! 421: ! 422: sp = SENSEBUF(dsp); ! 423: DSDBG(fprintf(stderr,"cmdbuf = "); ! 424: bprint(CMDBUF(dsp),CMDLEN(dsp),16,1)); ! 425: if ( (dsp->ds_flags & DSRQ_WRITE) ) ! 426: DSDBG(bprint( DATABUF(dsp), min(50,DATALEN(dsp)),16,1 )); ! 427: ! 428: DSDBG(fprintf(stderr,"databuf datalen %x %d\n",DATABUF(dsp), DATALEN(dsp))); ! 429: cc = ioctl( fd, DS_ENTER, dsp); ! 430: if ( cc < 0) { ! 431: ds_panic(dsp, "cannot ioctl fd %d\n",fd); ! 432: } ! 433: ! 434: DSDBG(fprintf(stderr,"cmdlen after ioctl=%d\n",CMDLEN(dsp))); ! 435: DSDBG(fprintf(stderr,"ioctl=%d ret=%x %s", ! 436: cc, RET(dsp), ! 437: RET(dsp) ? ds_vtostr(RET(dsp),dsrtnametab) : "")); ! 438: DSDBG(if (SENSESENT(dsp)) fprintf(stderr," sensesent=%d", ! 439: SENSESENT(dsp))); ! 440: ! 441: DSDBG(fprintf(stderr, ! 442: " cmdsent=%d datasent=%d sbyte=%x %s\n", ! 443: CMDSENT(dsp), DATASENT(dsp), STATUS(dsp), ! 444: ds_vtostr(STATUS(dsp), cmdstatustab))); ! 445: DSDBG(if ( FLAGS(dsp) & DSRQ_READ ) ! 446: bprint( DATABUF(dsp), min(16*16,DATASENT(dsp)), 16,1)); ! 447: ! 448: #ifdef aux ! 449: /* ! 450: * check for AUX bus-error ! 451: * we retry with poll-dma ! 452: */ ! 453: if ( RET(dsp) == DSRT_AGAIN ) { ! 454: int n = SDC_RDPOLL|SDC_WRPOLL; ! 455: DSDBG(fprintf(stderr,"setting rd/wr-poll")); ! 456: cc = ioctl( fd, DS_SET, n); /* set bits */ ! 457: if ( cc != 0 ) ! 458: return -1; ! 459: } ! 460: #endif aux ! 461: ! 462: if ( RET(dsp) == DSRT_NOSEL ) ! 463: continue; /* retry noselect 3X */ ! 464: ! 465: /* decode sense data returned */ ! 466: if ( SENSESENT(dsp) ) { ! 467: DSDBG( ! 468: fprintf(stderr, "sense key %x - %s\n", ! 469: SENSEKEY(sp), ! 470: ds_vtostr( SENSEKEY(sp), sensekeytab)); ! 471: bprint( SENSEBUF(dsp), ! 472: min(100, SENSESENT(dsp)), ! 473: 16,1); ! 474: ); ! 475: } ! 476: DSDBG(fprintf(stderr, "sbyte %x\n", STATUS(dsp))); ! 477: ! 478: /* decode scsi command status byte */ ! 479: sbyte = STATUS(dsp); ! 480: switch (sbyte) { ! 481: case 0x08: /* BUSY */ ! 482: case 0x18: /* RESERV CONFLICT */ ! 483: sleep(2); ! 484: continue; ! 485: case 0x00: /* GOOD */ ! 486: case 0x02: /* CHECK CONDITION */ ! 487: case 0x10: /* INTERM/GOOD */ ! 488: default: ! 489: return sbyte; ! 490: } ! 491: } ! 492: return -1; /* fail retry limit */ ! 493: } ! 494: ! 495: ! 496: /* ! 497: || opttovar - lookup option in table, return var addr (NULL if fail) ! 498: */ ! 499: ! 500: int * ! 501: opttovar( ostr, table) ! 502: char *ostr; ! 503: struct opttab{ ! 504: char *opt; ! 505: int *var; ! 506: } *table; ! 507: { ! 508: register struct opttab *tp; ! 509: ! 510: for (tp=table; (tp->var); tp++) ! 511: if ( strncmp( ostr, tp->opt, 3) == 0 ) ! 512: break; ! 513: ! 514: if ( !tp->var ) ! 515: fprintf(stderr,"unknown option %s", ostr); ! 516: ! 517: return (tp->var); ! 518: } ! 519: ! 520: ! 521: /* ! 522: || ds_vtostr - lookup value in table to return string pointer ! 523: */ ! 524: ! 525: char * ! 526: ds_vtostr( v, table) ! 527: long v; ! 528: struct vtab *table; ! 529: { ! 530: register struct vtab *tp; ! 531: ! 532: for (tp=table; (tp->string); tp++) ! 533: if ( v == tp->val ) ! 534: break; ! 535: ! 536: return (tp->string) ? tp->string : ""; ! 537: } ! 538: ! 539: ! 540: /* ! 541: || ds_panic - yelp, leave... ! 542: */ ! 543: ! 544: ds_panic( fmt, v) ! 545: char *fmt; ! 546: int v; ! 547: { ! 548: extern errno; ! 549: ! 550: fprintf(stderr,fmt,v); ! 551: fprintf(stderr,"\nerrno = %d\n",errno); ! 552: exit(1); ! 553: } ! 554: ! 555: ! 556: /* ! 557: || ds_zot - go away, with a message. ! 558: */ ! 559: ! 560: ds_zot(message) ! 561: char *message; ! 562: { ! 563: fprintf(stderr, "%s\n", message); ! 564: exit(1); ! 565: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.