|
|
1.1 ! root 1: /*********************************************************************** ! 2: * Module: haiscsi.c ! 3: * ! 4: * This is the interface between the Coherent kernel, the host ! 5: * adapter module and the SCSI device modules. It's just a simple ! 6: * dispatcher that determines which routine to call based upon the ! 7: * calling device's Target ID. The target ID should be set in bits ! 8: * 4-6 of the device's minor number. ! 9: * ! 10: * Copyright (c) 1993, Christopher Sean Hilton, All Rights Reserved. ! 11: * ! 12: * Last Modified: Sat Jul 24 08:08:28 1993 by [chris] ! 13: */ ! 14: ! 15: #include <stddef.h> ! 16: #include <sys/coherent.h> ! 17: #include <sys/con.h> ! 18: #include <sys/buf.h> ! 19: #include <sys/io.h> ! 20: #include <sys/sched.h> ! 21: #include <sys/stat.h> ! 22: ! 23: #include <sys/uproc.h> ! 24: #include <errno.h> ! 25: ! 26: #include <sys/haiscsi.h> ! 27: #include <sys/haiioctl.h> ! 28: ! 29: /* ! 30: * Constants. ! 31: */ ! 32: #define GROUPMASK 0xe0 ! 33: #define GROUP0 0x00 /* SCSI-1/2 */ ! 34: #define GROUP1 0x20 /* SCSI-1/2 */ ! 35: #define GROUP2 0x40 /* SCSI-2 */ ! 36: #define GROUP5 0xa0 /* SCSI-1/2 */ ! 37: ! 38: /* Configurable variables - see /etc/conf/hai/Space.c. */ ! 39: extern int HAI_DISK; ! 40: extern int HAI_TAPE; ! 41: ! 42: extern int nonedev(); /* Set error and exit. */ ! 43: extern int nulldev(); /* Do nothing and exit. */ ! 44: ! 45: /* ! 46: * Device type entry points. ! 47: */ ! 48: extern dca_t sddca; /* Fixed disk control routines */ ! 49: extern dca_t ctdca; /* Cartridge tape control routines */ ! 50: extern dca_t haict3600; /* Cartridge tape (Tandberg TDC3600) */ ! 51: ! 52: dca_t mdca[MAXDEVS]; /* Initialized by setup_mdca(). */ ! 53: ! 54: static void scsi_open(); /* Open dispatcher */ ! 55: static void scsi_close(); /* Close dispatcher */ ! 56: static void scsi_block(); /* Block dispatcher */ ! 57: static void scsi_read(); /* Read dispatcher */ ! 58: static void scsi_write(); /* Write dispatcher */ ! 59: static void scsi_ioctl(); /* I/O Control dispatcher */ ! 60: static int scsi_load(); /* Load driver */ ! 61: static int scsi_unload(); /* Unload driver */ ! 62: ! 63: static void setup_mdca(); /* Put device handlers into SCSI id table. */ ! 64: ! 65: CON scsicon = { ! 66: DFBLK | DFCHR, ! 67: SCSIMAJOR, ! 68: scsi_open, /* Open entry point */ ! 69: scsi_close, /* Close entry point */ ! 70: scsi_block, /* Block entry point. */ ! 71: scsi_read, /* Read Entry point */ ! 72: scsi_write, /* write entry point */ ! 73: scsi_ioctl, /* IO control entry point */ ! 74: nulldev, /* No powerfail entry (yet?) */ ! 75: hatimer, /* timeout entry point */ ! 76: scsi_load, /* Load entry point */ ! 77: scsi_unload, /* Unload entry point */ ! 78: nulldev /* No poll entry yet either. */ ! 79: }; ! 80: ! 81: static char *errstr[] = { ! 82: "No sense", ! 83: "Recovered error", ! 84: "Not ready", ! 85: "Medium error", ! 86: "Hardware error", ! 87: "Illegal request", ! 88: "Unit attention", ! 89: "Data protect", ! 90: "Blank check", ! 91: "Vendor unique error", ! 92: "Copy Aborted", ! 93: "Aborted command", ! 94: "Equal", ! 95: "Volume overflow", ! 96: "Miscompare", ! 97: "Reserved" ! 98: }; ! 99: ! 100: char iofailmsg[] = "%s: status(0x%x)"; ! 101: int HAI_HAID = 7; ! 102: ! 103: extern int hapresent; /* Provided/Controled by host adapter module */ ! 104: extern dca_p mdca[MAXDEVS]; /* See haicfg.c */ ! 105: ! 106: /*********************************************************************** ! 107: * int scsi_open(dev_t dev, int mode) ! 108: * ! 109: * Open a device on the SCSI bus at target ID: tid(dev). This is ! 110: * Accomplished by calling the open routine at mdca[tid(dev)]->d_open ! 111: */ ! 112: ! 113: static void scsi_open(dev, mode) ! 114: register dev_t dev; ! 115: int mode; ! 116: { ! 117: register dca_p d = mdca[tid(dev)]; ! 118: ! 119: if (!hapresent || !d) ! 120: u. u_error = EINVAL; ! 121: else ! 122: (*(d->d_open))(dev, mode); ! 123: } /* scsi_open() */ ! 124: ! 125: /*********************************************************************** ! 126: * void scsi_close() ! 127: * ! 128: * Close entry point for all devices at major index SCSIMAJOR. ! 129: */ ! 130: ! 131: static void scsi_close(dev) ! 132: register dev_t dev; ! 133: { ! 134: register dca_p d = mdca[tid(dev)]; ! 135: ! 136: if (!hapresent || !d) ! 137: u. u_error = EINVAL; ! 138: else ! 139: (*(d->d_close))(dev); ! 140: } /* scsi_close() */ ! 141: ! 142: /*********************************************************************** ! 143: * void scsi_block() ! 144: * ! 145: * Block Entry point. ! 146: */ ! 147: ! 148: static void scsi_block(bp) ! 149: register BUF *bp; ! 150: { ! 151: register dca_p d = mdca[tid(bp->b_dev)]; ! 152: ! 153: if (!hapresent || !d) { ! 154: bp->b_resid = bp->b_count; ! 155: bp->b_flag |= BFERR; ! 156: bdone(bp); ! 157: } ! 158: else ! 159: (*(d->d_block))(bp); ! 160: } /* scsi_block() */ ! 161: ! 162: /*********************************************************************** ! 163: * void scsi_read() ! 164: * ! 165: * Read entry point. ! 166: */ ! 167: ! 168: void scsi_read(dev, iop) ! 169: register dev_t dev; ! 170: register IO *iop; ! 171: { ! 172: register dca_p d = mdca[tid(dev)]; ! 173: if (!hapresent || !d) ! 174: u. u_error = EINVAL; ! 175: else ! 176: (*(d->d_read))(dev, iop); ! 177: } /* scsi_read() */ ! 178: ! 179: /*********************************************************************** ! 180: * int scsi_write() ! 181: * ! 182: * Write entry point. ! 183: */ ! 184: ! 185: void scsi_write(dev, iop) ! 186: register dev_t dev; ! 187: IO *iop; ! 188: { ! 189: register dca_p d = mdca[tid(dev)]; ! 190: if (!hapresent || !d) ! 191: u. u_error = EINVAL; ! 192: else ! 193: (*(d->d_write))(dev, iop); ! 194: } /* scsi_write() */ ! 195: ! 196: /*********************************************************************** ! 197: * scsi_ioctl() ! 198: * ! 199: * IO Control entry point. ! 200: */ ! 201: ! 202: static void scsi_ioctl(dev, cmd, vec) ! 203: register dev_t dev; ! 204: int cmd; ! 205: char *vec; ! 206: { ! 207: register dca_p d = mdca[tid(dev)]; ! 208: ! 209: if (!hapresent || !d) ! 210: u. u_error = EINVAL; ! 211: else ! 212: (*(d->d_ioctl))(dev, cmd, vec); ! 213: } /* scsi_ioctl() */ ! 214: ! 215: /*********************************************************************** ! 216: * scsi_load() ! 217: * ! 218: * Load Entry point. ! 219: */ ! 220: ! 221: static int scsi_load() ! 222: ! 223: { ! 224: register int id; ! 225: register dca_p d; ! 226: ! 227: printf("Host Adapter Independent SCSI Driver v1.1\n"); ! 228: hainit(); ! 229: if (!hapresent) ! 230: printf("Host Adapter Initialization failed.\n"); ! 231: ! 232: setup_mdca(); ! 233: ! 234: for (id = 0; id < MAXDEVS; ++id) { ! 235: if ((d = mdca[id]) && d->d_load) { ! 236: printf("ID %d: ", id); ! 237: if (!(*(d->d_load))(id)) ! 238: printf("\tLoad() failed.\n"); ! 239: } ! 240: } ! 241: return; ! 242: } /* scsi_load() */ ! 243: ! 244: /*********************************************************************** ! 245: * scsi_unload() ! 246: * ! 247: * SCSI unload routine. ! 248: */ ! 249: ! 250: int scsi_unload() ! 251: ! 252: { ! 253: register int id; ! 254: register dca_p d; ! 255: ! 256: for (id = 0; id < MAXDEVS; ++id) ! 257: if ((d = mdca[id]) && d->d_unload) ! 258: (*(d->d_unload))(id); ! 259: } /* scsi_unload() */ ! 260: ! 261: /*********************************************************************** ! 262: * Utility Routines ! 263: */ ! 264: ! 265: /*********************************************************************** ! 266: * char *swapbytes() ! 267: * ! 268: * Swap bytes in an object from big to little endian or vice versa. ! 269: */ ! 270: ! 271: char *swapbytes(mem, size) ! 272: char *mem; ! 273: size_t size; ! 274: ! 275: { ! 276: register char *p = mem; ! 277: register char *q = p + size - 1; ! 278: ! 279: while (q > p) { ! 280: *p ^= *q; ! 281: *q ^= *p; ! 282: *p ^= *q; ! 283: p++; ! 284: q--; ! 285: } ! 286: return mem; ! 287: } /* swapbytes() */ ! 288: ! 289: /*********************************************************************** ! 290: * cpycdb() ! 291: * ! 292: * Copy a SCSI Command/Data Block. Return the number of bytes copied. ! 293: */ ! 294: ! 295: int cpycdb(dst, src) ! 296: register cdb_p dst; ! 297: register cdb_p src; ! 298: { ! 299: switch (src->g0. opcode & GROUPMASK) { ! 300: case GROUP0: ! 301: memcpy(dst, src, sizeof(g0cmd_t)); ! 302: return sizeof(g0cmd_t); ! 303: case GROUP1: ! 304: case GROUP2: ! 305: memcpy(dst, src, sizeof(g1cmd_t)); ! 306: return sizeof(g1cmd_t); ! 307: case GROUP5: ! 308: memcpy(dst, src, sizeof(g5cmd_t)); ! 309: return sizeof(g5cmd_t); ! 310: default: ! 311: return 0; ! 312: } ! 313: } /* cpycdb() */ ! 314: ! 315: /*********************************************************************** ! 316: * dumpmem() ! 317: * ! 318: * Dump memory from (p) for (s) bytes. ! 319: */ ! 320: ! 321: static char hexchars[] = "0123456789abcdef", ! 322: linebuf[] = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................\n"; ! 323: ! 324: void dumpmem(m, p, s) ! 325: char m[]; ! 326: register unsigned char *p; ! 327: register size_t s; ! 328: { ! 329: register int i; ! 330: char *l; ! 331: ! 332: if (m) ! 333: printf(m); ! 334: printf(" (0x%x)\n", (unsigned) p); ! 335: memset(linebuf, ' ', sizeof(linebuf) - 2); ! 336: linebuf[48] = '|'; ! 337: l = linebuf; ! 338: for (i = 0; i < s; ++i, ++p) { ! 339: *l++ = hexchars[(*p >> 4) & 0x0f]; ! 340: *l++ = hexchars[*p & 0x0f]; ! 341: *l++ = ' '; ! 342: linebuf[50 + (i & 15)] = (*p >= ' ' && *p <= '~') ? *p : '.'; ! 343: if ((i & 15) == 15) { ! 344: printf(linebuf); ! 345: memset(linebuf, ' ', sizeof(linebuf) - 2); ! 346: linebuf[48] = '|'; ! 347: l = linebuf; ! 348: } ! 349: } ! 350: if ((s & 15) != 0) ! 351: printf(linebuf); ! 352: } /* dumpmem() */ ! 353: ! 354: /*********************************************************************** ! 355: * scsidone() ! 356: * ! 357: * Wake up processes sleeping on SRB (r). ! 358: */ ! 359: ! 360: static int scsidone(r) ! 361: register srb_p r; ! 362: { ! 363: wakeup(&(r->status)); ! 364: } ! 365: ! 366: /*********************************************************************** ! 367: * reqsense() ! 368: * ! 369: * Issue a request sense command device loaded into the target/lun ! 370: * fields of the given srb r. Uses v_sleep(). ! 371: */ ! 372: ! 373: void reqsense(r) ! 374: register srb_p r; ! 375: { ! 376: int s; ! 377: unsigned short status; ! 378: unsigned short tries; ! 379: unsigned short timeout; ! 380: bufaddr_t buf; ! 381: unsigned short xferdir; ! 382: int (*cleanup)(); ! 383: cdb_t cdb; ! 384: ! 385: if (r->status == ST_CHKCOND) { ! 386: status = ST_CHKCOND; ! 387: tries = r->tries; ! 388: timeout = r->timeout; ! 389: memcpy(&buf, &(r->buf), sizeof(bufaddr_t)); ! 390: xferdir = r->xferdir; ! 391: cleanup = r->cleanup; ! 392: memcpy(&cdb, &(r->cdb), sizeof(cdb_t)); ! 393: ! 394: r->timeout = 4; ! 395: r->buf. space = KRNL_ADDR; ! 396: r->buf. addr. caddr = (caddr_t) r->sensebuf; ! 397: r->buf. size = sizeof(r->sensebuf); ! 398: r->xferdir = DMAREAD; ! 399: r->cleanup = &scsidone; ! 400: memset(&(r->cdb), 0, sizeof(cdb_t)); ! 401: r->cdb. g0. opcode = 0x03; ! 402: r->cdb. g0. lun_lba = (r->lun << 5); ! 403: r->cdb. g0. xfr_len = r->buf. size; ! 404: s = sphi(); ! 405: startscsi(r); ! 406: while (r->status == ST_PENDING) { ! 407: if (x_sleep(&(r->status), pritape, slpriSigCatch, "reqsense")) { ! 408: u. u_error = EINTR; ! 409: status = ST_USRABRT; ! 410: break; ! 411: } ! 412: } ! 413: spl(s); ! 414: ! 415: r->tries = tries; ! 416: r->timeout = timeout; ! 417: memcpy(&(r->buf), &buf, sizeof(bufaddr_t)); ! 418: r->xferdir = xferdir; ! 419: r->cleanup = cleanup; ! 420: memcpy(&(r->cdb), &(cdb), sizeof(cdb_t)); ! 421: r->status = status; ! 422: } ! 423: } /* reqsense() */ ! 424: ! 425: /*********************************************************************** ! 426: * doscsi() ! 427: * ! 428: * An alternative to startscsi() which handles everything including ! 429: * any request sense commands necessary if the command failed. All ! 430: * information is returned in given srb. Note: you can only use ! 431: * this routine when the u structure for a process is available (from ! 432: * an open, close, read, write, or ioctl routine). Since this calls ! 433: * sleep it will screw things up something fierce if you call it from ! 434: * a load, unload, block, timer or interrupt routine. Also note ! 435: * that some host adapters do the sense part this automatically. ! 436: */ ! 437: ! 438: void doscsi(r, retrylimit, schedPri, sleepPri, reason) ! 439: register srb_p r; ! 440: int retrylimit; ! 441: int schedPri; ! 442: int sleepPri; ! 443: char reason[]; ! 444: { ! 445: int s; ! 446: ! 447: r->cleanup = &scsidone; ! 448: for (r->tries = 0; r->tries < retrylimit; ) { ! 449: if (startscsi(r)) { ! 450: s = sphi(); ! 451: while (r->status == ST_PENDING) { ! 452: if (x_sleep(&(r->status), schedPri, sleepPri, reason)) { ! 453: abortscsi(r); ! 454: r->status = ST_USRABRT; ! 455: u. u_error = EINTR; ! 456: } ! 457: } ! 458: spl(s); ! 459: if (r->status == ST_GOOD) ! 460: return; ! 461: ! 462: if (r->status == ST_CHKCOND) ! 463: reqsense(r); ! 464: } ! 465: else ! 466: r->status = ST_TIMEOUT; ! 467: } ! 468: } /* doscsi() */ ! 469: ! 470: /*********************************************************************** ! 471: * printsense() ! 472: * ! 473: * Print out the results in the given sense buffer. This is done ! 474: * in English, almost. ! 475: */ ! 476: ! 477: void printsense(dev, msg, e) ! 478: register dev_t dev; ! 479: register char *msg; ! 480: register extsense_p e; ! 481: { ! 482: long info; ! 483: if ((e->errorcode & 0x70) != 0x70) ! 484: devmsg(dev, "%s: Bad sensekey", msg); ! 485: else { ! 486: if ((e->errorcode & 0x80) != 0x80) ! 487: devmsg(dev, ! 488: "%s: %s - key: (0x%x)", ! 489: msg, ! 490: errstr[e->sensekey & 0x0f], ! 491: (e->sensekey & 0xe0)); ! 492: else { ! 493: info = (long) e->info; ! 494: flip(info); ! 495: devmsg(dev, ! 496: "%s: %s - addr: %d key: (0x%x)", ! 497: msg, ! 498: errstr[e->sensekey & 0x0f], ! 499: info, ! 500: (e->sensekey & 0xe0)); ! 501: } ! 502: } ! 503: } /* printsense() */ ! 504: ! 505: /*********************************************************************** ! 506: * printerror() ! 507: * ! 508: * Print an error after command completion. Be silent if the command ! 509: * was aborted by the user. ! 510: */ ! 511: ! 512: int printerror(r, msg) ! 513: register srb_p r; ! 514: register char *msg; ! 515: { ! 516: if (r->status == ST_USRABRT) ! 517: return 0; ! 518: else { ! 519: if (r->status != ST_CHKCOND) ! 520: devmsg(r->dev, iofailmsg, msg, r->status); ! 521: else ! 522: printsense(r->dev, msg, r->sensebuf); ! 523: return 1; ! 524: } ! 525: } /* printerror() */ ! 526: ! 527: /*********************************************************************** ! 528: * haiioctl() -- I/O Controls common to all devices. ! 529: * ! 530: * This function provides I/O Control functions common to all SCSI ! 531: * devices. The chain of operation should be as follows: ! 532: * ! 533: * You: ! 534: * 1) Make sure that the device is in an appropriate state to ! 535: * perform the I/O Control. (It might not be a good idea to ! 536: * format the disk drive with the root partition). ! 537: * ! 538: * 2) Call haiioctl() with your srb and cmd from I/O Control. ! 539: */ ! 540: ! 541: void haiioctl(r, cmd, vec) ! 542: register srb_p r; /* Device's srb */ ! 543: register int cmd; /* Command to do */ ! 544: register char *vec; /* Additional information (if needed) */ ! 545: { ! 546: haiusercdb_t h; ! 547: ! 548: switch (cmd) { ! 549: case HAIINQUIRY: ! 550: case HAIMDSNS0: ! 551: case HAIMDSLCT0: ! 552: case HAIMDSNS2: ! 553: case HAIMDSLCT2: ! 554: u. u_error = ENXIO; ! 555: return; ! 556: case HAIUSERCDB: ! 557: if (super()) { ! 558: if (!ukcopy(vec, &h, sizeof(haiusercdb_t))) ! 559: return; ! 560: r->buf. space = USER_ADDR; ! 561: r->buf. addr. caddr = vec + sizeof(haiusercdb_t); ! 562: r->buf. size = h. buflen; ! 563: r->xferdir = h. xferdir; ! 564: r->timeout = h. timeout; ! 565: memcpy(&(r->cdb), &(h. cdb), sizeof(cdb_t)); ! 566: doscsi(r, 1, pritty, slpriSigCatch, "haiioctl"); ! 567: if (!kucopy(r->sensebuf, ((haiusercdb_p) vec)->sensebuf, SENSELEN)) ! 568: return; ! 569: } ! 570: return; ! 571: default: ! 572: u. u_error = ENXIO; ! 573: return; ! 574: } ! 575: return; ! 576: } /* haiioctl() */ ! 577: ! 578: /*********************************************************************** ! 579: * hainonblk() -- Block entry point for devices that shouldn't ! 580: * have block entry points. ! 581: * ! 582: * Since this is a multiplexing driver and some devices behind it ! 583: * will have block entry points and some shouldn't. ALL do. ! 584: */ ! 585: ! 586: void hainonblk(bp) ! 587: register BUF *bp; ! 588: { ! 589: bp->b_flag |= BFERR; ! 590: bdone(bp); ! 591: } /* hainonblk() */ ! 592: ! 593: /* ! 594: * setup_mdca ! 595: * ! 596: * Load mdca table based on globals HAI_DISK and HAI_TAPE. ! 597: */ ! 598: void ! 599: setup_mdca() ! 600: { ! 601: int id, mask; ! 602: extern dca_t sddca; ! 603: extern dca_t ctdca; ! 604: ! 605: for (id = 0; id < 8; id ++) { ! 606: mask = 1 << id; ! 607: if (HAI_DISK & mask) ! 608: mdca[id] = & sddca; ! 609: if (HAI_TAPE & mask) ! 610: mdca[id] = & ctdca; ! 611: } ! 612: } ! 613: ! 614: /* End of file */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.