|
|
1.1 ! root 1: /*********************************************************************** ! 2: * Module: hai154x.c ! 3: * ! 4: * Host Adapter Interface routines for the Adaptec AHA154XX series ! 5: * of host adapters. ! 6: * ! 7: * Much of the information used to create this driver was obtained ! 8: * from the AHA1540B/1542B Technical Reference Manual available from ! 9: * Adaptec by phone or snail mail at: ! 10: * ! 11: * Adaptec - Literature Department ! 12: * 691 South Milpitas Blvd. ! 13: * Milpitas, CA 95035 ! 14: * (408) 945-8600 ! 15: * ! 16: * Copyright (c), 1993 Christopher Sean Hilton, All Rights Reserved. ! 17: * ! 18: * Last Modified: Sat Jul 24 08:44:54 1993 by [chris] ! 19: * ! 20: */ ! 21: ! 22: #define HA_MODULE /* Host Adaptor Module */ ! 23: #define LOUIS_HACK 1 /* defined for Louis' hacks */ ! 24: ! 25: #include <stddef.h> ! 26: #include <sys/coherent.h> ! 27: #include <sys/con.h> ! 28: #include <sys/devices.h> ! 29: #include <sys/types.h> ! 30: #include <sys/hdioctl.h> ! 31: ! 32: #include <sys/haiscsi.h> ! 33: ! 34: /* ! 35: * Configurable variables - see /etc/conf/hai/Space.c ! 36: */ ! 37: extern unsigned short AHABASE; ! 38: extern unsigned short AHAINTR; ! 39: extern unsigned short AHADMACHAN; ! 40: ! 41: extern int HAI_SD_HDS; ! 42: extern int HAI_SD_SPT; ! 43: ! 44: #define CTRLREG (AHABASE + 0) /* Control Register (Write) */ ! 45: #define HRST bit(7) /* Hard Reset */ ! 46: #define SRST bit(6) /* Soft Reset */ ! 47: #define IRST bit(5) /* Interrupt Reset */ ! 48: #define SCRST bit(4) /* SCSI Bus Reset */ ! 49: ! 50: #define STSREG (AHABASE + 0) /* Status Register (Read) */ ! 51: #define STST bit(7) /* Self Test in progress */ ! 52: #define DIAGF bit(6) /* Internal Diagnostic Failure */ ! 53: #define INIT bit(5) /* Mailbox Initialization Required */ ! 54: #define IDLE bit(4) /* SCSI Host Adapter Idle */ ! 55: #define CDF bit(3) /* Command/Data Out Port Full */ ! 56: #define DF bit(2) /* Data In Port Full */ ! 57: #define INVDCMD bit(0) /* Invalid HA Command */ ! 58: ! 59: #define CMDDATAOUT (AHABASE + 1) /* Command/Data Out (Write) */ ! 60: #define NOP 0x00 /* No Operation (really?) */ ! 61: #define MBINIT 0x01 /* Mail Box Initialization */ ! 62: #define STARTSCSI 0x02 /* Start a SCSI Command */ ! 63: #define STARTBIOS 0x03 /* Start a BIOS Command */ ! 64: #define HAINQUIRY 0x04 /* HA Inquiry */ ! 65: #define ENBLMBOA 0x05 /* Enable Mailbox Out Available Interrupt */ ! 66: #define STSELTO 0x06 /* Set Selection Timeout */ ! 67: #define SETBUSON 0x07 /* Set Bus on time */ ! 68: #define SETBUSOFF 0x08 /* Set Bus off time */ ! 69: #define SETXFER 0x09 /* Set transfer speed */ ! 70: #define RETINSTDEV 0x0a /* Return Installed Devices */ ! 71: #define RETCFGDATA 0x0b /* Return Configuration Data */ ! 72: #define ENBLTRGTMD 0x0c /* Enable Target Mode */ ! 73: #define RETSUDATA 0x0d /* Return Setup Data */ ! 74: ! 75: #define DATAIN (AHABASE + 1) ! 76: ! 77: #define INTRFLGS (AHABASE + 2) ! 78: #define ANYINTR bit(7) /* Any Interrupt */ ! 79: #define SCRD bit(3) /* SCSI Reset Detected */ ! 80: #define HACC bit(2) /* HA Command Complete */ ! 81: #define MBOA bit(1) /* MBO Empty */ ! 82: #define MBIF bit(0) /* MBI Full */ ! 83: ! 84: #define MBOFREE 0x00 /* Mailbox out is free */ ! 85: #define MBOSTART 0x01 /* Start CCB in this Mailbox */ ! 86: #define MBOABORT 0x02 /* Abort CCB in this Mailbox */ ! 87: ! 88: #define MBIFREE 0x00 /* Mailbox in is free */ ! 89: #define MBISUCCESS 0x01 /* Mailbox's CCB Completed Successfully */ ! 90: #define MBIABORTED 0x02 /* Mailbox's CCB Aborted */ ! 91: #define MBIABRTFLD 0x03 /* CCB to Abort not found */ ! 92: #define MBIERROR 0x04 /* CCB Completed with error */ ! 93: ! 94: #define TIMEOUT -1 /* Timeout from pollxxx() functions. */ ! 95: ! 96: #define ST_HAINIT 0x0001 /* Host Adapter being initialized */ ! 97: #define ST_HAIDLE 0x0002 /* Host Adapter is idle */ ! 98: ! 99: /*********************************************************************** ! 100: * Types ! 101: */ ! 102: ! 103: #pragma align 1 ! 104: ! 105: typedef union addr3_u { /* addr3_u for big/little endian conversions */ ! 106: unsigned long value; ! 107: unsigned char byteval[sizeof(unsigned long)]; ! 108: } addr3_t; ! 109: ! 110: typedef union mbo_u *mbo_p; /* Out Box to host adapter */ ! 111: ! 112: typedef union mbo_u { ! 113: unsigned char cmd; ! 114: paddr_t ccbaddr; ! 115: } mbo_t; ! 116: ! 117: typedef union mbi_u *mbi_p; /* In Box from host adapter */ ! 118: ! 119: typedef union mbi_u { ! 120: unsigned char sts; ! 121: paddr_t ccbaddr; ! 122: } mbi_t; ! 123: ! 124: typedef struct mb_s { /* Host adapter mailbox type */ ! 125: mbo_t o[MAXDEVS]; /* One out box for each device */ ! 126: mbi_t i[MAXDEVS]; /* One in box for each possible reply */ ! 127: } mb_t; ! 128: ! 129: typedef struct haccb_s *haccb_p; /* Host Adapter Command/Control Block */ ! 130: ! 131: typedef struct haccb_s { ! 132: unsigned char opcode; ! 133: unsigned char addrctrl; ! 134: unsigned char cdblen; ! 135: unsigned char senselen; ! 136: unsigned char datalen[3]; ! 137: unsigned char bufaddr[3]; ! 138: unsigned char linkaddr[3]; ! 139: unsigned char linkid; ! 140: unsigned char hoststs; ! 141: unsigned char trgtsts; ! 142: unsigned char pad[2]; ! 143: cdb_t cdb; ! 144: } haccb_t; ! 145: ! 146: typedef struct dsentry_s *dsentry_p; ! 147: ! 148: typedef struct dsentry_s { ! 149: unsigned char size[3]; ! 150: unsigned char addr[3]; ! 151: } dsentry_t; ! 152: ! 153: typedef struct dslist_s *dslist_p; ! 154: ! 155: typedef struct dslist_s { ! 156: dsentry_t entries[16]; ! 157: } dslist_t; ! 158: ! 159: #pragma align ! 160: ! 161: /*********************************************************************** ! 162: * Variables ! 163: */ ! 164: ! 165: static int hastate; /* Host Adapter State */ ! 166: static mb_t mb; /* Mailboxes for host adapter */ ! 167: static haccb_t ccb[MAXDEVS]; /* CCB's for mailboxes */ ! 168: static paddr_t ccbbase; /* ccbbase address for quick checkmail */ ! 169: static srb_p actv[MAXDEVS]; /* Active srb's for each target */ ! 170: static dslist_t ds[MAXDEVS]; /* Data segment lists one for each target */ ! 171: static unsigned chkport = 0, /* Port for chkset/ckhclr */ ! 172: chkstop = 0, /* Target value for chkset/chkclr */ ! 173: chkval = 0; /* Value in port chkset/chkclr */ ! 174: int hapresent; /* Host adapter present flag */ ! 175: ! 176: /*********************************************************************** ! 177: * Support Functions ! 178: */ ! 179: ! 180: #define min(a, b) (((a) <= (b)) ? (a) : (b)) ! 181: ! 182: /*********************************************************************** ! 183: * chkclr() -- Check port (chkport) for bits (chkstop) to be clear. ! 184: * If clear return 1 else return 0. Leave value of ! 185: * port in chkval; ! 186: */ ! 187: ! 188: static int chkclr() ! 189: ! 190: { ! 191: return ((chkval = inb(chkport)) & chkstop) == 0; ! 192: } /* chkclr() */ ! 193: ! 194: /*********************************************************************** ! 195: * chkset() -- Check port (chkport) for bits (chkstop) to be set. ! 196: * If all bits are set return 1 else return 0. Leave ! 197: * value of port in chkval. ! 198: */ ! 199: ! 200: static int chkset() ! 201: ! 202: { ! 203: return ((chkval = inb(chkport)) & chkstop) == chkstop; ! 204: } /* chkset() */ ! 205: ! 206: /*********************************************************************** ! 207: * pollclr() -- Wait usec milliseconds for bit(s) to clear in a ! 208: * port. ! 209: */ ! 210: ! 211: static int pollclr(port, bits, usec) ! 212: register unsigned port; /* port to watch */ ! 213: register unsigned bits; /* bits to watch for */ ! 214: unsigned usec; /* number of milliseconds to wait for */ ! 215: { ! 216: register s; ! 217: ! 218: s = sphi(); ! 219: chkport = port; ! 220: chkstop = bits; ! 221: busyWait(chkclr, usec); ! 222: spl(s); ! 223: ! 224: #if 1 /* DEBUG */ ! 225: if ((chkval & bits) == 0) ! 226: return chkval; ! 227: else { ! 228: printf("pollclr: <Timeout Reg: 0x%x mask 0x%x value 0x%x>\n", port, bits, chkval); ! 229: return TIMEOUT; ! 230: } ! 231: #else ! 232: return ((chkval & bits) == 0) ? chkval : TIMEOUT; ! 233: #endif ! 234: } /* pollclr() */ ! 235: ! 236: /*********************************************************************** ! 237: * pollset() -- Wait usec milliseconds for bit(s) set in a port. ! 238: */ ! 239: ! 240: static int pollset(port, bits, usec) ! 241: register unsigned port; /* port to watch */ ! 242: register unsigned bits; /* bits to watch for */ ! 243: unsigned usec; /* number of milliseconds to wait for */ ! 244: { ! 245: register s; ! 246: ! 247: s = sphi(); ! 248: chkport = port; ! 249: chkstop = bits; ! 250: busyWait(chkset, usec); ! 251: spl(s); ! 252: ! 253: #if 1 /* DEBUG */ ! 254: if ((chkval & bits) == bits) ! 255: return chkval; ! 256: else { ! 257: printf("pollset: <Timeout Reg: 0x%x mask 0x%x value 0x%x>\n", port, bits, chkval); ! 258: return TIMEOUT; ! 259: } ! 260: #else ! 261: return ((chkval & bits) == bits) ? chkval : TIMEOUT; ! 262: #endif ! 263: } /* pollset() */ ! 264: ! 265: /*********************************************************************** ! 266: * hacc() ! 267: * ! 268: * Host Adapter Command Completed - Returns 1 if last host adapter ! 269: * command completed without error. ! 270: */ ! 271: ! 272: static int hacc() ! 273: ! 274: { ! 275: register unsigned stsreg; ! 276: ! 277: #ifdef LOUIS_HACK ! 278: register unsigned louis_stsreg; ! 279: if((louis_stsreg = pollset(INTRFLGS, HACC, 350)) == TIMEOUT) ! 280: return 0; ! 281: printf("HACC - louis_stsreg: 0x%x\n", louis_stsreg); ! 282: #else ! 283: if (pollset(INTRFLGS, HACC, 350) == TIMEOUT) ! 284: return 0; ! 285: #endif ! 286: ! 287: stsreg = pollset(STSREG, IDLE, 350) & (IDLE | INIT | CDF | INVDCMD); ! 288: if (stsreg != IDLE) { ! 289: printf("Aha154x stuck - STSREG: 0x%x\n", stsreg); ! 290: return 0; ! 291: } ! 292: return 1; ! 293: } /* hacc() */ ! 294: ! 295: /*********************************************************************** ! 296: * haidle() ! 297: * ! 298: * Returns 1 if the Idle Bit is on in the adapter status register ! 299: */ ! 300: ! 301: #define haidle() (pollset(STSREG, IDLE, 350) != TIMEOUT) ! 302: ! 303: /*********************************************************************** ! 304: * gethabyte() ! 305: * ! 306: * Get a byte from the host adapter Data In register. ! 307: */ ! 308: ! 309: static int gethabyte() ! 310: ! 311: { ! 312: if (pollset(STSREG, DF, 350) == TIMEOUT) { ! 313: printf("haiscsi: <gethabyte timeout (0x%x) 0x%x 0x%x>\n", STSREG, DF, chkval); ! 314: return TIMEOUT; ! 315: } ! 316: else ! 317: return (inb(DATAIN) & 0xff); ! 318: } /* gethabyte() */ ! 319: ! 320: /*********************************************************************** ! 321: * puthabyte() ! 322: * ! 323: * Write a byte to the host adapter Command/Data Out Register. ! 324: */ ! 325: ! 326: static int puthabyte(b) ! 327: unsigned char b; ! 328: ! 329: { ! 330: if (pollclr(STSREG, CDF, 350) == TIMEOUT) ! 331: return 0; ! 332: else { ! 333: outb(CMDDATAOUT, b); ! 334: return 1; ! 335: } ! 336: } /* puthabyte() */ ! 337: ! 338: /*********************************************************************** ! 339: * is_154x() ! 340: * ! 341: * Returns a string indicating the type and revision of the AHA154x ! 342: * host adapter on the bus if it is out there. Caveat: if something ! 343: * else is out there that can respond to this message I don't know ! 344: * what will happen. ! 345: */ ! 346: ! 347: static int is_154x(haport) ! 348: unsigned haport; ! 349: { ! 350: char buf[4], ! 351: *p; ! 352: int ch, ! 353: oldhaport, ! 354: s, ! 355: r = 0; ! 356: ! 357: oldhaport = AHABASE; ! 358: s = sphi(); ! 359: AHABASE = haport; ! 360: if (haidle() && puthabyte(HAINQUIRY)) { ! 361: for (p = buf; p < buf + sizeof(buf); ++p) { ! 362: ch = gethabyte(); ! 363: if (ch == TIMEOUT) ! 364: break; ! 365: else ! 366: *p = ch; ! 367: } ! 368: if (p >= buf + sizeof(buf)) { ! 369: outb(CTRLREG, IRST); ! 370: if ((pollset(STSREG, IDLE, 350) & IDLE) == IDLE) { ! 371: if (buf[0] == '\0') { ! 372: printf("AHA-1540 with 16 Head BIOS Detected\n"); ! 373: /* SDS_HDS = 16; Should we? */ ! 374: } ! 375: r = 1; ! 376: } ! 377: } ! 378: } ! 379: AHABASE = oldhaport; ! 380: spl(s); ! 381: return r; ! 382: } /* is_154x() */ ! 383: ! 384: /*********************************************************************** ! 385: * hareset() ! 386: * ! 387: * Reset the host adapter and leave it ready for operation. ! 388: */ ! 389: ! 390: static int hareset() ! 391: ! 392: { ! 393: paddr_t mbaddr; /* Mail box array's paddr. */ ! 394: int mbiok, /* Mail box initialization proceding ok */ ! 395: stsreg, /* local copy of STSREG */ ! 396: retval, /* return value */ ! 397: s; ! 398: ! 399: retval = 0; ! 400: s = sphi(); ! 401: outb(CTRLREG, SRST); ! 402: if ((stsreg = pollclr(STSREG, STST, 350)) == TIMEOUT) ! 403: printf("AHA-154x: Reset failed, host adapter stuck.\n"); ! 404: else ! 405: #ifdef LOUIS_HACK ! 406: printf("Resetting - stsreg: 0x%x\n", stsreg); ! 407: #endif ! 408: if ((stsreg & DIAGF) || (stsreg & (INIT | IDLE)) != (INIT | IDLE)) ! 409: printf("AHA-154x: Reset/diagnostics failed.\n"); ! 410: else { ! 411: ! 412: mbaddr = vtop(&mb); ! 413: #ifdef LOUIS_HACK ! 414: printf("init commands bytes will be:\n"); ! 415: printf(" MBINIT: 0x%x, COUNT: 0x%x, ADDR_MSB: 0x%x, ADDR_2: 0x%x, ADDR_LSB: 0x%x\n", \ ! 416: MBINIT, (sizeof(mb) / (sizeof(mbo_t) + sizeof(mbi_t))), ((unsigned char *) &mbaddr)[2], \ ! 417: ((unsigned char *) &mbaddr)[1], ((unsigned char *) &mbaddr)[0]); ! 418: #endif ! 419: mbiok = 1; ! 420: mbiok &= puthabyte(MBINIT); ! 421: mbiok &= puthabyte(sizeof(mb) / (sizeof(mbo_t) + sizeof(mbi_t))); ! 422: mbiok &= puthabyte(((unsigned char *) &mbaddr)[2]); ! 423: mbiok &= puthabyte(((unsigned char *) &mbaddr)[1]); ! 424: mbiok &= puthabyte(((unsigned char *) &mbaddr)[0]); ! 425: if (!mbiok || !hacc()) ! 426: printf("AHA-154x: Mailbox initialization failed.\n"); ! 427: else ! 428: retval = 1; ! 429: } ! 430: spl(s); ! 431: return retval; ! 432: } /* hareset() */ ! 433: ! 434: /*********************************************************************** ! 435: * dmacascade() ! 436: * ! 437: * Set the selected (AHADMACHAN) dma channel to cascade mode. ! 438: */ ! 439: ! 440: static void dmacascade() ! 441: ! 442: { ! 443: int dmaporta, dmaportb, s; ! 444: ! 445: s = sphi(); ! 446: if (AHADMACHAN == 0) { ! 447: dmaporta = 0x0b; ! 448: dmaportb = 0x0a; ! 449: } else { ! 450: dmaporta = 0xd6; ! 451: dmaportb = 0xd4; ! 452: } ! 453: outb(dmaporta, 0xc0 | (AHADMACHAN & 3)); ! 454: outb(dmaportb, (AHADMACHAN & 3)); ! 455: spl(s); ! 456: } /* dmacascade() */ ! 457: ! 458: /*********************************************************************** ! 459: * checkmail() ! 460: * ! 461: * Check the incoming mailboxes for messages. Do this on any Mail ! 462: * Box In Full interrupt and before you fail a command for timeout. ! 463: * The code to determine which target device finished by tid is a ! 464: * bit tricky and relies on the following assumptions: ! 465: * ! 466: * 1) The host adapter is installed in a Intel (big-endian) ! 467: * machine. Believe it or not there is (are) non-Intel CPU ! 468: * ISA bus machines. and the one that I know of is a M68000 ! 469: * machine where this would not work. ! 470: * ! 471: * 2) The kernel's data space is physically contiguous and is ! 472: * never swapped out. ! 473: */ ! 474: ! 475: static int checkmail() ! 476: ! 477: { ! 478: static int startid = 0; ! 479: int msgs = 0; ! 480: int sts; ! 481: int s; ! 482: register int id; ! 483: register srb_p r; ! 484: register int i = startid; ! 485: ! 486: do { ! 487: if (mb. i[i]. sts != MBIFREE) { ! 488: s = sphi(); ! 489: sts = mb. i[i]. sts; ! 490: flip(mb. i[i]. ccbaddr); ! 491: id = (unsigned) ((mb. i[i]. ccbaddr & 0x00ffffffL) - ccbbase) / sizeof(haccb_t); ! 492: if (r = actv[id]) { ! 493: switch (sts) { ! 494: case MBIABRTFLD: ! 495: devmsg(r->dev, "Command 0x%x abort failed\n", r->cdb. g0. opcode); ! 496: case MBISUCCESS: ! 497: case MBIERROR: ! 498: r->status = ccb[id]. trgtsts; ! 499: break; ! 500: case MBIABORTED: ! 501: devmsg(r->dev, "Command 0x%x aborted successfully\n", r->cdb. g0. opcode); ! 502: r->status = ST_DRVABRT; ! 503: break; ! 504: default: ! 505: printf("Host Adapter Mailbox In value corrupted\n"); ! 506: break; ! 507: } ! 508: ! 509: actv[id] = NULL; ! 510: if (r->cleanup) ! 511: (*(r->cleanup))(r); ! 512: msgs |= bit(id); ! 513: } ! 514: mb. i[i]. ccbaddr = 0; ! 515: spl(s); ! 516: } ! 517: else if (msgs) ! 518: break; ! 519: i = (i + 1) & 7; ! 520: } while (i != startid); ! 521: startid = i; ! 522: ! 523: return msgs; ! 524: } /* checkmail() */ ! 525: ! 526: /*********************************************************************** ! 527: * Driver Interface Functions ! 528: */ ! 529: ! 530: /*********************************************************************** ! 531: * hatimer() ! 532: * ! 533: * Host adapter Timeout handler. ! 534: */ ! 535: ! 536: void hatimer() ! 537: ! 538: { ! 539: register int id; ! 540: register srb_p r; ! 541: register int active; ! 542: int s; ! 543: ! 544: s = sphi(); ! 545: checkmail(); /* Cleanup any missed interrupts, etc. */ ! 546: active = 0; ! 547: for (id = 0; id < MAXDEVS; ++id) { ! 548: if ((r = actv[id]) != NULL && r->timeout != 0) { ! 549: if (--r->timeout == 0) { ! 550: abortscsi(r); ! 551: r->status = ST_DRVABRT; ! 552: } ! 553: else ! 554: active = 1; ! 555: } ! 556: } ! 557: drvl[SCSIMAJOR]. d_time = active; ! 558: spl(s); ! 559: } /* hatimer() */ ! 560: ! 561: /*********************************************************************** ! 562: * haintr() ! 563: * ! 564: * SCSI interrupt handler for host adapter. ! 565: */ ! 566: ! 567: void haintr() ! 568: ! 569: { ! 570: int intrflgs; ! 571: ! 572: intrflgs = inb(INTRFLGS); ! 573: if (intrflgs & ANYINTR) ! 574: outb(CTRLREG, IRST); ! 575: ! 576: if (hastate == ST_HAINIT) ! 577: return; ! 578: if (intrflgs & MBIF) { ! 579: checkmail(); ! 580: return; ! 581: } ! 582: } /* haintr() */ ! 583: ! 584: /*********************************************************************** ! 585: * hainit() ! 586: * ! 587: * Initialize the host adapter for operation. ! 588: */ ! 589: ! 590: int hainit() ! 591: ! 592: { ! 593: register int i; ! 594: ! 595: hastate = ST_HAINIT; ! 596: hapresent = 0; ! 597: printf("Host Adapter Module: AHA-154x v1.1\n"); ! 598: if (!is_154x(AHABASE)) { ! 599: printf("hainit() failed: Adaptec AHA-154x not found.\n"); ! 600: return 0; ! 601: } ! 602: ! 603: setivec(AHAINTR, haintr); ! 604: if (!(hapresent = hareset())) { ! 605: printf("hainit() failed: Could not initialize AHA-154x at (0x%x)\n", AHABASE); ! 606: return 0; ! 607: } ! 608: ! 609: for (i = 0; i < MAXDEVS; ++i) { ! 610: actv[i] = NULL; ! 611: mb. o[i]. ccbaddr = vtop(ccb + i); ! 612: flip(mb. o[i]. ccbaddr); ! 613: mb. o[i]. cmd = MBOFREE; ! 614: } ! 615: ccbbase = vtop(ccb); ! 616: dmacascade(); ! 617: hastate = ST_HAIDLE; ! 618: return 1; ! 619: } /* hainit() */ ! 620: ! 621: /*********************************************************************** ! 622: * mkdslist() ! 623: * ! 624: * Make an Adaptec Data Segment list for a Scatter/Gather Request. ! 625: * Input: d - the memory area for the Scatter/Gather List. ! 626: * b - the bufaddr structure for the memory block. ! 627: */ ! 628: ! 629: static int mkdslist(d, b) ! 630: register dsentry_p d; ! 631: bufaddr_p b; ! 632: { ! 633: paddr_t p_start; ! 634: size_t p_size; ! 635: paddr_t p_next; ! 636: int segments = 1; ! 637: register unsigned long start; ! 638: register unsigned long end; ! 639: dsentry_p l = d; ! 640: ! 641: switch (b->space) { ! 642: case KRNL_ADDR: /* Kernal Address */ ! 643: case USER_ADDR: /* User Address (Anything goes) */ ! 644: start = b->addr. caddr; ! 645: p_start = vtop(start); ! 646: break; ! 647: case SYSGLBL_ADDR: /* System Global address (yeah) */ ! 648: start = b->addr. paddr; ! 649: p_start = P2P(start); ! 650: break; ! 651: case PHYS_ADDR: /* Physical Address - (who knows) */ ! 652: default: ! 653: return 0; ! 654: } ! 655: end = start + b->size; ! 656: p_size = min(NBPC - (p_start & (NBPC - 1)), end - start); ! 657: ! 658: for ( ; ; ) { ! 659: d->size[2] = ((unsigned char *) &p_size)[0]; ! 660: d->size[1] = ((unsigned char *) &p_size)[1]; ! 661: d->size[0] = ((unsigned char *) &p_size)[2]; ! 662: d->addr[2] = ((unsigned char *) &p_start)[0]; ! 663: d->addr[1] = ((unsigned char *) &p_start)[1]; ! 664: d->addr[0] = ((unsigned char *) &p_start)[2]; ! 665: if (start + p_size >= end) ! 666: return segments; ! 667: ! 668: p_next = (b->space == SYSGLBL_ADDR) ? P2P(start + p_size) : ! 669: vtop(start + p_size); ! 670: if (p_next == p_start + p_size) ! 671: /* Continue Last Segment */ ! 672: p_size += min(NBPC, end - start - p_size); ! 673: else { ! 674: /* Start New Segment */ ! 675: p_start = p_next; ! 676: start += p_size; ! 677: p_size = min(NBPC, end - start); ! 678: ++d; ! 679: if (++segments > (sizeof(dslist_t) / sizeof(dsentry_t))) ! 680: return 0; ! 681: } ! 682: } ! 683: } /* mkdslist() */ ! 684: ! 685: /*********************************************************************** ! 686: * startscsi() ! 687: * ! 688: * Send a SCSI CDB to a target device on the bus. ! 689: */ ! 690: ! 691: int startscsi(r) ! 692: register srb_p r; ! 693: { ! 694: register haccb_p c; ! 695: paddr_t bufaddr; ! 696: size_t datalen; ! 697: register int s; ! 698: ! 699: if (r->target >= MAXDEVS || r->lun >= MAXUNITS) { ! 700: printf("Illegal device ID: %d LUN: %d", r->target, r->lun); ! 701: return 0; ! 702: } ! 703: ! 704: ++r->tries; ! 705: if (actv[r->target]) { ! 706: devmsg(r->dev, ! 707: "Device busy: old opcode (0x%x) new opcode (0x%x)", ! 708: ccb[r->target]. cdb. g0. opcode, ! 709: r->cdb. g0. opcode); ! 710: return 0; ! 711: } ! 712: ! 713: s = sphi(); ! 714: r->status = ST_PENDING; ! 715: c = ccb + r->target; ! 716: memset(c, 0, sizeof(haccb_t)); ! 717: c->opcode = 0; /* Start SCSI CDB */ ! 718: c->addrctrl = (r->target << 5) | (r->lun & 7); ! 719: if (r->xferdir & DMAREAD) c->addrctrl |= 0x08; ! 720: if (r->xferdir & DMAWRITE) c->addrctrl |= 0x10; ! 721: c->cdblen = cpycdb(&(c->cdb), &(r->cdb)); ! 722: c->senselen = 1; ! 723: ! 724: /*********************************************************************** ! 725: * Set up the CCB's Address here. This turned out to be a bit more ! 726: * complicated than I thought it would be. ! 727: */ ! 728: ! 729: if (r->buf. space == PHYS_ADDR) { ! 730: c->datalen[0] = ((unsigned char *) &(r->buf. size))[2]; ! 731: c->datalen[1] = ((unsigned char *) &(r->buf. size))[1]; ! 732: c->datalen[2] = ((unsigned char *) &(r->buf. size))[0]; ! 733: c->bufaddr[0] = ((unsigned char *) &(r->buf. addr. paddr))[2]; ! 734: c->bufaddr[1] = ((unsigned char *) &(r->buf. addr. paddr))[1]; ! 735: c->bufaddr[2] = ((unsigned char *) &(r->buf. addr. paddr))[0]; ! 736: } ! 737: else { ! 738: datalen = mkdslist(ds[r->target]. entries, &(r->buf)); ! 739: if (datalen == 0) { ! 740: printf("SCSI ID %d - Bad Scatter/Gather list\n", r->target); ! 741: spl(s); ! 742: return 0; ! 743: } ! 744: else if (datalen == 1) ! 745: memcpy(c->datalen, ds[r->target]. entries, 6); ! 746: else { ! 747: c->opcode = 2; ! 748: bufaddr = vtop(ds[r->target]. entries); ! 749: datalen *= 6; ! 750: c->datalen[0] = ((unsigned char *) &datalen)[2]; ! 751: c->datalen[1] = ((unsigned char *) &datalen)[1]; ! 752: c->datalen[2] = ((unsigned char *) &datalen)[0]; ! 753: c->bufaddr[0] = ((unsigned char *) &bufaddr)[2]; ! 754: c->bufaddr[1] = ((unsigned char *) &bufaddr)[1]; ! 755: c->bufaddr[2] = ((unsigned char *) &bufaddr)[0]; ! 756: } ! 757: } ! 758: ! 759: mb. o[r->target]. cmd = MBOSTART; ! 760: if (puthabyte(STARTSCSI) && (inb(STSREG) & INVDCMD) == 0) { ! 761: actv[r->target] = r; ! 762: if (r->timeout) ! 763: drvl[SCSIMAJOR]. d_time = 1; ! 764: } ! 765: else { ! 766: printf("startscsi() failed: Resetting host adapter.\n"); ! 767: mb. o[r->target]. cmd = MBOFREE; ! 768: actv[r->target] = NULL; ! 769: r->status = ST_DRVABRT; ! 770: if (r->cleanup) ! 771: (*r->cleanup)(r); ! 772: hapresent = hareset(); ! 773: return 0; ! 774: } ! 775: ! 776: spl(s); ! 777: return 1; ! 778: } /* startscsi() */ ! 779: ! 780: /*********************************************************************** ! 781: * abortscsi() ! 782: * ! 783: * Abort the SCSI Command at a target device on the bus. ! 784: */ ! 785: ! 786: void abortscsi(r) ! 787: register srb_p r; ! 788: { ! 789: int s, ! 790: tries; ! 791: ! 792: printf("abortscsi(id: %d opcode: (0x%x))\n", r->target, r->cdb. g0. opcode); ! 793: s = sphi(); ! 794: r->timeout = 0; ! 795: for (tries = 10; hapresent && tries > 0; --tries) { ! 796: mb. o[r->target]. cmd = MBOABORT; ! 797: if (puthabyte(STARTSCSI) && (inb(STSREG) & INVDCMD) == 0) ! 798: break; ! 799: ! 800: printf("abortscsi(): AHA-154x Command start failed.\n"); ! 801: hapresent = hareset(); ! 802: } ! 803: ! 804: if (tries <= 0) ! 805: printf("abortscsi() failed: Cannot reach host adapter\n"); ! 806: else { ! 807: busyWait(checkmail, 1000); ! 808: ! 809: if (r->status == ST_PENDING) { ! 810: printf("abortscsi() failed: id %d\n", r->target); ! 811: resetdevice(r->target); ! 812: ! 813: actv[r->target] = NULL; ! 814: r->status = ST_DRVABRT; ! 815: if (r->cleanup) ! 816: (*r->cleanup)(r); ! 817: } ! 818: } ! 819: ! 820: spl(s); ! 821: } /* abortscsi() */ ! 822: ! 823: /*********************************************************************** ! 824: * resetdevice() ! 825: * ! 826: * Reset a SCSI target. ! 827: */ ! 828: ! 829: void resetdevice(id) ! 830: register int id; ! 831: { ! 832: register haccb_p c = &(ccb[HAI_HAID]); ! 833: int tries; ! 834: ! 835: c->opcode = 0x81; ! 836: c->addrctrl = (id << 5); ! 837: for (tries = 10; tries > 0; --tries) { ! 838: if (!hapresent) ! 839: hapresent = hareset(); ! 840: if (hapresent) { ! 841: mb. o[HAI_HAID]. cmd = MBOSTART; ! 842: if (puthabyte(STARTSCSI) && (inb(STSREG) & INVDCMD) == 0) ! 843: break; ! 844: } ! 845: } ! 846: } /* resetdevice() */ ! 847: ! 848: /*********************************************************************** ! 849: * haihdgeta() -- Get disk driver paramters. ! 850: * ! 851: * This function is provided to support the HDGETA/HDSETA I/O Controls ! 852: * so you don't need the old Adaptec SCSI driver to set up the partition ! 853: * table on initial setup. There is a catch-22 with this. You need ! 854: * to know the drive's geometry in order to set up the partition table ! 855: * but cannot get the drive's geometry until you have set up the partition ! 856: * table. We solve this by using the drive's size and then dividing ! 857: * down based upon SDS_HDS heads and SDS_SPT sectors per track. Every ! 858: * host adapter will want to do this differently. The Adaptec solution ! 859: * is the best that I've seen so far. (It allows you to use Huge (1.0 ! 860: * GB) disks under DOS without trouble. ! 861: */ ! 862: ! 863: void haihdgeta(hdp, diskcap) ! 864: register hdparm_t *hdp; ! 865: register unsigned diskcap; ! 866: { ! 867: unsigned short ncyl = (unsigned short) (diskcap / (HAI_SD_HDS * HAI_SD_SPT)), ! 868: landc = ncyl, ! 869: rwccp = 0xffff, ! 870: wpcc = 0xffff; ! 871: ! 872: memset(hdp, 0, sizeof(hdparm_t)); ! 873: *((unsigned short *) hdp->ncyl) = ncyl; ! 874: *((unsigned short *) hdp->rwccp) = rwccp; ! 875: *((unsigned short *) hdp->wpcc) = wpcc; ! 876: *((unsigned short *) hdp->landc) = landc; ! 877: ! 878: hdp->nhead = HAI_SD_HDS; ! 879: if (hdp->nhead > 8) ! 880: hdp->ctrl |= 8; ! 881: hdp->nspt = HAI_SD_SPT; ! 882: } /* haihdseta() */ ! 883: ! 884: /*********************************************************************** ! 885: * haihdseta() -- Set disk parameters in accordance with HDSETA ! 886: * I/O Control. ! 887: * ! 888: * Set the disk paramters accordingly for a request from the fdisk ! 889: * program. This call really doesn't do anything on the adaptec or ! 890: * in the SCSI driver in general because SCSI Disks use Logical Block ! 891: * addressing rather than Cylinder/Head/Track addressing found with ! 892: * less intelligent Disk drive types. What this will do is allow ! 893: * the fdisk program to work so a user can format his disk and install ! 894: * Coherent on it (A Good Thing). This boils down to a fancy way to ! 895: * patch SDS_HDS and SDS_SPT. ! 896: */ ! 897: ! 898: void haihdseta(hdp) ! 899: register hdparm_t *hdp; ! 900: { ! 901: HAI_SD_HDS = hdp->nhead; ! 902: HAI_SD_SPT = hdp->nspt; ! 903: } /* haihdseta() */ ! 904: ! 905: /* End of file */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.