|
|
1.1 ! root 1: /* ! 2: * This is the host adaptor specific portion of the ! 3: * Adaptec AHA154x driver. ! 4: * ! 5: * $Log: aha.c,v $ ! 6: * Revision 2.3 93/08/09 13:43:35 bin ! 7: * Kernel 82 changes ! 8: * ! 9: * Revision 2.2 93/07/26 15:27:47 nigel ! 10: * Nigel's R80 ! 11: * ! 12: * Revision 1.1 93/03/18 10:31:13 root ! 13: * r74 ! 14: * ! 15: * Revision 1.1 91/04/30 11:01:41 root ! 16: * Shipped with COH 3.1.0 ! 17: * ! 18: */ ! 19: #include <sys/coherent.h> ! 20: #include <sys/buf.h> ! 21: #include <sys/sched.h> ! 22: ! 23: #include <sys/scsiwork.h> ! 24: #include <sys/aha154x.h> ! 25: ! 26: #ifdef _I386 ! 27: extern char *palloc(); ! 28: #endif /* _I386 */ ! 29: ! 30: #ifndef _I386 ! 31: extern saddr_t sds; /* System Data Selector */ ! 32: static paddr_t sds_physical; /* as physical address */ ! 33: #endif /* _I386 */ ! 34: static short aha_i_o_base; ! 35: static char aha_loaded; /* did load() find a host adaptor? */ ! 36: static char dev_bit_map[8]; /* one byte per SCSI-ID; one bit per LUN */ ! 37: char drive_info[MAX_SCSI_ID * MAX_LUN]; /* "per drive" info/flags */ ! 38: ! 39: void aha_intr(); /* interrupt service routine */ ! 40: ! 41: #define MIN_MAILBOX 1 ! 42: int MAX_MAILBOX = { 8 }; /* tunable value */ ! 43: ! 44: static scsi_work_t *scsi_work_queue; ! 45: static mailentry *mailbox_in, *mailbox_out; ! 46: static char *aha_err_msg = { "no message" }; ! 47: ! 48: static long aha_timeout[] = { ! 49: #define TIMEOUT_PRESENT 0 ! 50: 0x30000L, ! 51: #define TIMEOUT_SENDCMD 1 ! 52: 0x10000L, ! 53: #define TIMEOUT_POLL 2 ! 54: 0x100L ! 55: }; ! 56: ! 57: /* ! 58: * NIGEL: The 'ccb_t' structure defined in <sys/aha154x.h> has data for the ! 59: * SCSI controller, at least at the base. Presumably the 'ccb_sw' member is ! 60: * not for the SCSI controller, so data after the 'cmd_status' member is ! 61: * for the driver. The 'buffer' member is not used.... ! 62: * ! 63: * Below I create a wrapper structure that separates driver-private data from ! 64: * the Adaptec 'ccb' like the original author should have written. This allows ! 65: * the 'ccb' to be threaded on a work list, and would obviate the need for the ! 66: * stupid machinery in "i386/mem_cache.c" (although not even that would be ! 67: * needed had page management been done right...) ! 68: * ! 69: * The primary motivation for this is to allow ccb's to be deallocated safely. ! 70: * The 286 version of the driver deallocated the structures in aha_process (), ! 71: * which was deferred from aha_intr (). The 4.0 version can not do that because ! 72: * due to the large size of the buffer cache a defer-table overflow might ! 73: * result. We compromise by creating a deferred work list and threading the ! 74: * ccb's on that and only deferring the 'start work' operation. Since ! 75: * aha_process () does no actual work but merely calls bdone () then frees the ! 76: * data, we create a 'free list' of ccb's and a deferred routine to free them, ! 77: * and leave aha_process () to call bdone () at interrupt level to give maximum ! 78: * throughput. ! 79: * ! 80: * You are now passing the Hack City limits. You are now in the Interdicted ! 81: * Zone. ! 82: */ ! 83: ! 84: #include <stddef.h> /* import offsetof () */ ! 85: ! 86: typedef struct driver_ccb drv_ccb_t; ! 87: ! 88: struct driver_ccb { ! 89: ccb_t aha_ccb; /* the driver CCB */ ! 90: drv_ccb_t * next; /* for threading on work list */ ! 91: }; ! 92: ! 93: static drv_ccb_t * free_list; /* ccb's to free */ ! 94: static int free_active; /* nonzero if cleanup routine active */ ! 95: ! 96: /* ! 97: * There are two low-level allocators in use, one for 3.2 and one for 4.0, ! 98: * and rather than #ifdef the usage we call them via a macro below. ! 99: */ ! 100: ! 101: #ifdef _I386 ! 102: #define AHA_ALLOC(size) palloc (size) ! 103: #define AHA_FREE(size) pfree (size) ! 104: #else ! 105: #define AHA_ALLOC(size) kalloc (size) ! 106: #define AHA_FREE(size) kfree (size) ! 107: #endif ! 108: ! 109: ! 110: /* ! 111: * Cleanup routine for free list, called via defer () from ccb_free (). ! 112: * ! 113: * Many fields of active ccb's are filled in with other dynamically allocated ! 114: * structures; this code has responsibility for freeing all of them. ! 115: */ ! 116: void ! 117: ccb_cleanup () ! 118: { ! 119: drv_ccb_t * work; ! 120: int s; ! 121: ! 122: s = sphi (); ! 123: while ((work = free_list) != NULL) { ! 124: free_list = work->next; ! 125: spl (s); ! 126: ! 127: #ifdef _I386 ! 128: /* ! 129: * The following code is insane; the DSL stuff should be part ! 130: * of this ccb system. This will be fixed when a total revamp ! 131: * of memory management occurs, and the "mem_cache.c" stuff ! 132: * gets spaced. ! 133: * ! 134: * In the original code, the ccb_forget () was done after the ! 135: * ccb was totally freed. I put it here to save conditionals. ! 136: */ ! 137: dsl_free (work->aha_ccb.dataptr); ! 138: ccb_forget (& work->aha_ccb); ! 139: #endif ! 140: ! 141: if (work->aha_ccb.ccb_sw != NULL) ! 142: AHA_FREE (work->aha_ccb.ccb_sw); ! 143: AHA_FREE (work); ! 144: ! 145: #ifdef TRACER ! 146: end_count (3); ! 147: #endif ! 148: s = sphi (); ! 149: } ! 150: ! 151: free_active = 0; /* defer () needed to reschedule */ ! 152: spl (s); ! 153: } ! 154: ! 155: ! 156: /* ! 157: * Allocate a ccb and return a pointer to it. Call from base level only. ! 158: * The scsi_work_t * value passed here is remembered so that when the ccb ! 159: * is deallocated it will be too. In addition, code in aha_process () uses ! 160: * this stored value to map back from a ccb to a buffer-cache entry. ! 161: */ ! 162: ccb_t * ! 163: ccb_alloc (sw) ! 164: scsi_work_t * sw; ! 165: { ! 166: drv_ccb_t * drvccb; ! 167: ! 168: if ((drvccb = (drv_ccb_t *) AHA_ALLOC (sizeof (* drvccb))) == NULL) ! 169: return NULL; ! 170: ! 171: #ifdef TRACER ! 172: begin_count (3); ! 173: #endif ! 174: /* ! 175: * Remember the 'sw' value. Note that this really should be put in ! 176: * our wrapper structure, but that is to be fixed later. ! 177: */ ! 178: ! 179: drvccb->aha_ccb.ccb_sw = sw; ! 180: ! 181: /* ! 182: * Return a pointer to the inner adaptec ccb. ! 183: */ ! 184: ! 185: return & drvccb->aha_ccb; ! 186: } ! 187: ! 188: ! 189: /* ! 190: * Return a ccb to the free pool. Callable from base or interrupt level. All ! 191: * the dynamically allocated member data of the ccb should be freed by this ! 192: * routine. ! 193: */ ! 194: void ! 195: ccb_free (ccb) ! 196: ccb_t * ccb; ! 197: { ! 198: int s; ! 199: drv_ccb_t * work; ! 200: ! 201: /* ! 202: * Perform a downcast from the aha_ccb to the base structure. ! 203: */ ! 204: ! 205: work = (drv_ccb_t *) ((char *) ccb - offsetof (drv_ccb_t, aha_ccb)); ! 206: ! 207: s = sphi (); ! 208: work->next = free_list; ! 209: free_list = work; ! 210: ! 211: if (free_active == 0) { ! 212: defer (ccb_cleanup, 0); ! 213: free_active = 1; ! 214: } ! 215: spl (s); ! 216: } ! 217: ! 218: ! 219: /* ! 220: * Map from a ccb to the 'scsi_work_t' that was memoized when the ccb was ! 221: * allocated. ! 222: */ ! 223: ! 224: #define ccb_to_scsiwork(ccb) (ccb->ccb_sw) ! 225: ! 226: /* ! 227: * NIGEL: Welcome back to Hack City. Beware of mutant code! ! 228: */ ! 229: ! 230: #if 0 ! 231: static ! 232: OUTB(port, value) ! 233: short port; ! 234: { printf("<O(%x,%x)>", port, value); ! 235: outb(port, value); } ! 236: INB(port) ! 237: short port; ! 238: { register int i = inb(port); ! 239: printf("<I(%x)=%x>", port, i); ! 240: return i; } ! 241: #else ! 242: #define OUTB(port, value) outb(port, value) ! 243: #define INB(port) inb(port) ! 244: #endif ! 245: ! 246: #ifdef TRACER ! 247: #define SETMSG(msg) ((void) (aha_err_msg = msg)) ! 248: ! 249: static char * ! 250: aha_last_msg() ! 251: { ! 252: return aha_err_msg; ! 253: } ! 254: ! 255: #else /* TRACER */ ! 256: ! 257: #define SETMSG(msg) ((void) 0) ! 258: static char * ! 259: aha_last_msg() ! 260: { ! 261: return "error messages not verbose"; ! 262: } ! 263: #endif /* TRACER */ ! 264: ! 265: static ! 266: int ! 267: no_mem() ! 268: { ! 269: printf("aha154x: out of kernel memory\n"); ! 270: } ! 271: ! 272: int ! 273: aha_set_base(base) ! 274: { ! 275: register int i; ! 276: ! 277: i = aha_i_o_base; ! 278: aha_i_o_base = base; ! 279: return i; ! 280: } ! 281: ! 282: int ! 283: aha_get_base() ! 284: { ! 285: return aha_i_o_base; ! 286: } ! 287: ! 288: aha_process(ccb) ! 289: ccb_t *ccb; ! 290: { ! 291: register scsi_work_t *sw; ! 292: register BUF *bp; ! 293: ! 294: #ifdef TRACER ! 295: end_count (1); ! 296: #endif ! 297: ! 298: if ((sw = ccb_to_scsiwork (ccb)) == NULL) { ! 299: #ifdef TRACER ! 300: end_count (2); ! 301: #endif ! 302: ccb->opcode = AHA_OP_INVALID; ! 303: wakeup(ccb); ! 304: return; ! 305: } ! 306: ! 307: bp = sw->sw_bp; ! 308: ! 309: if((ccb->hoststatus != 0) || (ccb->targetstatus != 0)) { ! 310: #if 0 ! 311: /* ! 312: * sw_retry is only ever set to 1, so this code was dead ! 313: * anyway, but now in the i386 system it is not legal to ! 314: * call aha_start () from interrupt level so be careful if ! 315: * you reactivate this. ! 316: */ ! 317: if(--sw->sw_retry > 0 ! 318: || (ccb->targetstatus == CHECK_TARGET_STATUS ! 319: && ccb->cmd_status[12] == SENSE_UNIT_ATTENTION)) { ! 320: int s = sphi(); ! 321: if(scsi_work_queue->sw_actf == NULL) { ! 322: ASSERT (scsi_work_queue->sw_actl == NULL); ! 323: scsi_work_queue->sw_actf = sw; ! 324: } else { ! 325: ASSERT (scsi_work_queue->sw_actl != NULL); ! 326: scsi_work_queue->sw_actl->sw_actf = sw; ! 327: } ! 328: scsi_work_queue->sw_actl = sw; ! 329: spl(s); ! 330: aha_start(); ! 331: return; ! 332: } ! 333: #endif ! 334: bp->b_flag |= BFERR; ! 335: #ifdef TRACER ! 336: aha_ccb_print (ccb); ! 337: #endif ! 338: } else { ! 339: bp->b_resid = 0; ! 340: } ! 341: ! 342: #ifdef TRACER ! 343: end_count (0); ! 344: #endif ! 345: bdone(bp); ! 346: ccb_free(ccb); ! 347: } ! 348: ! 349: static ! 350: int aha_1out(value) ! 351: { ! 352: register int i; ! 353: ! 354: while((i = INB(aha_i_o_base + AHA_STATUS) & AHA_CDOPFULL) != 0) ! 355: if((i & AHA_INVDCMD) ! 356: || (INB(aha_i_o_base+AHA_INTERRUPT) & AHA_CMD_DONE)) ! 357: return -1; ! 358: OUTB(aha_i_o_base + AHA_WRITE, value); ! 359: return 0; ! 360: } ! 361: ! 362: static ! 363: int aha_1in() ! 364: { ! 365: register int i; ! 366: ! 367: while((i = INB(aha_i_o_base + AHA_STATUS) & AHA_DIPFULL) == 0) ! 368: if((i & AHA_INVDCMD) ! 369: || (INB(aha_i_o_base+AHA_INTERRUPT) & AHA_CMD_DONE)) ! 370: return -1; ! 371: return INB(aha_i_o_base + AHA_READ) & 0xFF; ! 372: } ! 373: ! 374: static ! 375: void aha_cmd_out(value) ! 376: { ! 377: register long l; ! 378: register int i; ! 379: ! 380: for(l = aha_timeout[TIMEOUT_SENDCMD]; --l > 0;) { ! 381: if(((i=INB(aha_i_o_base + AHA_STATUS)) ! 382: & AHA_SCSIIDLE) != 0) { ! 383: aha_1out(value); ! 384: return; ! 385: } ! 386: } ! 387: SETMSG("timeout sending cmd byte"); ! 388: printf("aha154x: timeout sending cmd byte\n"); ! 389: } ! 390: ! 391: static ! 392: int aha_poll() ! 393: { ! 394: register int i; ! 395: register int l = aha_timeout[TIMEOUT_POLL]; ! 396: while((--l > 0) ! 397: && ((i = INB(aha_i_o_base + AHA_INTERRUPT)) & AHA_CMD_DONE) == 0) ! 398: ; ! 399: if(l == 0) ! 400: printf("aha154x: aha_poll timed out\n"); ! 401: ! 402: i = INB(aha_i_o_base + AHA_STATUS); ! 403: OUTB(aha_i_o_base + AHA_CONTROL, AHA_INTRRESET); ! 404: return i; ! 405: } ! 406: ! 407: static ! 408: void aha_get_data(vec, cnt) ! 409: char *vec; ! 410: int cnt; ! 411: { ! 412: while(--cnt >= 0) ! 413: *vec++ = aha_1in(); ! 414: aha_poll(); ! 415: } ! 416: ! 417: static ! 418: int aha_present() ! 419: { ! 420: long l; ! 421: ! 422: if(INB(aha_i_o_base) == 0xFF) { ! 423: SETMSG("no adapter found at io base"); ! 424: return -3; ! 425: } ! 426: for(l = aha_timeout[TIMEOUT_PRESENT]; ! 427: (--l > 0) && (INB(aha_i_o_base + AHA_STATUS) & AHA_SELFTEST);) ! 428: ; ! 429: if(l == 0) { ! 430: SETMSG("selftest not completed"); ! 431: return -1; ! 432: } ! 433: if(INB(aha_i_o_base + AHA_STATUS) & AHA_DIAGFAIL) { ! 434: SETMSG("diagnostics failed"); ! 435: return -2; ! 436: } ! 437: if(INB(aha_i_o_base + AHA_STATUS) & AHA_INITMAIL) { ! 438: SETMSG("mailbox initialization needed"); ! 439: return 1; ! 440: } ! 441: if(INB(aha_i_o_base + AHA_STATUS) & AHA_SCSIIDLE) { ! 442: SETMSG("adaptor okay, idle"); ! 443: return 0; ! 444: } ! 445: SETMSG("unknown status at start"); ! 446: return -4; ! 447: } ! 448: ! 449: void ! 450: aha_l_to_p3(value, vec) ! 451: paddr_t value; ! 452: P3 vec; ! 453: { ! 454: register int i; ! 455: ! 456: for(i = 3; --i >= 0;) { ! 457: vec[i] = value & 0xFF; ! 458: value >>= 8; ! 459: } ! 460: } ! 461: ! 462: long ! 463: aha_p3_to_l(vec) ! 464: P3 vec; ! 465: { ! 466: register int i; ! 467: register long retval; ! 468: ! 469: retval = 0; ! 470: for(i = 0; i < 3; ++i) { ! 471: retval <<= 8; ! 472: retval |= vec[i]; ! 473: } ! 474: ! 475: return(retval); ! 476: } /* aha_p3_to_l() */ ! 477: ! 478: #ifndef _I386 /* All of aha_p3_to_v(). */ ! 479: static char * ! 480: aha_p3_to_v(vec) ! 481: P3 vec; ! 482: { ! 483: paddr_t adr; ! 484: ! 485: adr = vec[0]; ! 486: adr <<= 16; ! 487: adr |= (vec[1]<<8) | vec[2]; ! 488: adr -= sds_physical; ! 489: return (char *)adr; ! 490: } ! 491: #endif /* _I386 */ ! 492: ! 493: aha_device_info() ! 494: { ! 495: register int i; ! 496: static char buf[256]; ! 497: ! 498: aha_cmd_out(AHA_DO_GET_DEVICES); ! 499: aha_get_data(&buf[0], 8); ! 500: for(i = 0; i < 8; ++i) ! 501: if(buf[i] != 0) ! 502: printf("[%d] %x ", i, buf[i]); ! 503: printf("\n"); ! 504: } ! 505: ! 506: int aha_unload(ireq) ! 507: { ! 508: /* ! 509: * we should really verify that everything ! 510: * out there gets flushed. ! 511: */ ! 512: if (!aha_loaded) ! 513: return; ! 514: if(mailbox_out) { ! 515: AHA_FREE (mailbox_out); ! 516: mailbox_out = 0; ! 517: } ! 518: clrivec(ireq); ! 519: } ! 520: ! 521: int aha_load(dma, ireq, base, head) ! 522: scsi_work_t *head; ! 523: { ! 524: register int i; ! 525: unsigned char adr[4]; ! 526: ! 527: aha_set_base(base); ! 528: if(mailbox_out == 0) { ! 529: if ((mailbox_out = ! 530: AHA_ALLOC (2 * MAX_MAILBOX * sizeof(mailentry))) == 0) { ! 531: no_mem(); ! 532: return -1; ! 533: } else { ! 534: mailbox_in = &mailbox_out[MAX_MAILBOX]; ! 535: } ! 536: } ! 537: ! 538: for(i = 0; i < MAX_MAILBOX; ++i) ! 539: mailbox_out[i].cmd = mailbox_in[i].cmd = 0; ! 540: ! 541: #ifdef _I386 ! 542: aha_l_to_p3(vtop(mailbox_out), &adr[1]); ! 543: #else /* _I386 */ ! 544: sds_physical = VTOP2(0, sds); ! 545: aha_l_to_p3(VTOP2(mailbox_out, sds), &adr[1]); ! 546: #endif /* _I386 */ ! 547: ! 548: adr[0] = MAX_MAILBOX; ! 549: ! 550: /* ! 551: * setup HW ! 552: */ ! 553: setivec(ireq, aha_intr); ! 554: ! 555: outb(0xD6, 0xC1); /* DMA is currently hard coded for */ ! 556: outb(0xD4, 0x01); /* DMA channel 5 */ ! 557: ! 558: ! 559: OUTB(aha_i_o_base+AHA_CONTROL, AHA_HARDRESET); ! 560: if (aha_present() < 0) { ! 561: printf("aha154x: initialization error or host adaptor not "); ! 562: printf("found at 0x%x\n", aha_i_o_base); ! 563: return -1; ! 564: } ! 565: aha_cmd_out(AHA_DO_MAILBOX_INIT); ! 566: for(i = 0; i < 4; ++i) ! 567: aha_1out(adr[i]); ! 568: scsi_work_queue = head; ! 569: ++aha_loaded; ! 570: return MAX_MAILBOX; ! 571: } ! 572: ! 573: aha_command(sc) ! 574: register scsi_cmd_t *sc; ! 575: { ! 576: register int i; ! 577: /* register */ ccb_t *ccb; ! 578: ! 579: short count = sc->blklen; ! 580: long block = sc->block; ! 581: ! 582: if ((ccb = ccb_alloc (NULL)) == NULL) { ! 583: no_mem(); ! 584: return -1; ! 585: } ! 586: ! 587: #ifdef _I386 ! 588: ccb->opcode = AHA_OP_SIC_SG; /* SCSI_INITIATOR*/ ! 589: #else /* _I386 */ ! 590: ccb->opcode = AHA_OP_SIC; /* SCSI_INITIATOR*/ ! 591: #endif /* _I386 */ ! 592: ccb->target = (sc->unit & 0x1C) << 3; /* SCSI ID */ ! 593: ccb->target |= sc->unit & 0x3; /* LUN */ ! 594: if((ccb->cmd_status[0] = sc->cmd) == ScmdWRITEXTENDED) { ! 595: ccb->target |= AHA_CCB_DATA_OUT; ! 596: } else { /* READEXT, READCAP, INQUIRY */ ! 597: ccb->target |= AHA_CCB_DATA_IN; ! 598: } ! 599: ccb->cmd_status[1] = 0; ! 600: ccb->cmd_status[2] = block; ! 601: ccb->cmd_status[3] = block >>16; ! 602: ccb->cmd_status[4] = block >> 8; ! 603: ccb->cmd_status[5] = block; ! 604: ccb->cmd_status[6] = 0; ! 605: ccb->cmd_status[7] = count / 512; ! 606: ccb->cmd_status[8] = count; ! 607: ccb->cmd_status[9] = 0; ! 608: ccb->cmdlen = 10; ! 609: ccb->senselen = MAX_SENSEDATA; ! 610: ! 611: #ifdef _I386 ! 612: dsl_gen(ccb->dataptr, ccb->datalen, sc->buffer, (long)sc->buflen); ! 613: aha_l_to_p3(vtop(ccb), mailbox_out[0].adr); ! 614: ccb_remember(ccb, mailbox_out[0].adr); ! 615: #else /* _I386 */ ! 616: aha_l_to_p3((long)sc->buflen, ccb->datalen); ! 617: aha_l_to_p3(sc->buffer, ccb->dataptr); ! 618: aha_l_to_p3(VTOP2(ccb, sds), mailbox_out[0].adr); ! 619: #endif /* _I386 */ ! 620: ! 621: #ifdef TRACER ! 622: begin_count (2); ! 623: #endif ! 624: mailbox_out[0].cmd = MBO_TO_START; ! 625: ! 626: /* Start the AHA-154x scanning the mailboxes. */ ! 627: aha_1out(AHA_DO_SCSI_START); ! 628: ! 629: /* Wait for this ccb to finish. */ ! 630: while(ccb->opcode != AHA_OP_INVALID) { ! 631: #ifdef _I386 ! 632: x_sleep(ccb, pridisk, slpriNoSig, "aha:ccb"); ! 633: #else ! 634: v_sleep(ccb, CVBLKIO, IVBLKIO, SVBLKIO, "aha:ccb"); ! 635: #endif ! 636: /* The AHA-154x driver is waiting for a ccb to complete. */ ! 637: } ! 638: ! 639: if((ccb->targetstatus == CHECK_TARGET_STATUS) ! 640: && (ccb->cmd_status[12] != SENSE_UNIT_ATTENTION)) { ! 641: printf("aha: SCSI ID %d LUN %d. SCSI sense =", ! 642: (sc->unit >> 2), sc->unit & 0x3); ! 643: for(i = 0; i < ccb->senselen; ++i) ! 644: printf(" %x", ccb->cmd_status[10+i]); ! 645: printf("\n"); ! 646: } ! 647: i = ccb->hoststatus | ccb->targetstatus; ! 648: ! 649: /* ! 650: * NIGEL: If you are worried that the ccb memory is not getting freed ! 651: * soon enough, add a parameter to ccb_cleanup () to flag whether it ! 652: * should clear the active flag and call it directly here. ! 653: */ ! 654: ccb_free(ccb); ! 655: ! 656: return i; ! 657: } ! 658: ! 659: ccb_t *buildccb(sw) ! 660: register scsi_work_t *sw; ! 661: { ! 662: register ccb_t *ccb; ! 663: ! 664: if ((ccb = ccb_alloc (sw)) == NULL) ! 665: return NULL; ! 666: ! 667: #ifdef _I386 ! 668: ccb->opcode = AHA_OP_SIC_SG; /* SCSI_INITIATOR*/ ! 669: #else /* _I386 */ ! 670: ccb->opcode = AHA_OP_SIC; /* SCSI_INITIATOR*/ ! 671: #endif /* _I386 */ ! 672: ! 673: ccb->target = (sw->sw_drv & 0x1C) << 3; /* SCSI ID */ ! 674: ccb->target |= (sw->sw_drv) & 0x3; /* LUN */ ! 675: if(sw->sw_bp->b_req == BREAD) { ! 676: ccb->target |= AHA_CCB_DATA_IN; ! 677: ccb->cmd_status[0] = ScmdREADEXTENDED; ! 678: } else { ! 679: ccb->target |= AHA_CCB_DATA_OUT; ! 680: ccb->cmd_status[0] = ScmdWRITEXTENDED; ! 681: } ! 682: ccb->cmd_status[1] = 0; ! 683: ccb->cmd_status[2] = 0; ! 684: ccb->cmd_status[3] = sw->sw_bno >>16; ! 685: ccb->cmd_status[4] = sw->sw_bno >> 8; ! 686: ccb->cmd_status[5] = sw->sw_bno; ! 687: ccb->cmd_status[6] = 0; ! 688: ccb->cmd_status[7] = sw->sw_bp->b_count / (512*256L); ! 689: ccb->cmd_status[8] = sw->sw_bp->b_count / 512; ! 690: ccb->cmd_status[9] = 0; ! 691: ccb->cmdlen = 10; ! 692: ccb->senselen = MAX_SENSEDATA; ! 693: ! 694: #ifdef _I386 ! 695: dsl_gen(ccb->dataptr, ccb->datalen, ! 696: sw->sw_bp->b_paddr, (long)sw->sw_bp->b_count); ! 697: #else /* _I386 */ ! 698: aha_l_to_p3((long)sw->sw_bp->b_count, ccb->datalen); ! 699: aha_l_to_p3(vtop(sw->sw_bp->b_faddr), ccb->dataptr); ! 700: #endif /* _I386 */ ! 701: /* ! 702: * The ccb's returned here are going to be freed by aha_process (). ! 703: */ ! 704: return ccb; ! 705: #if 0 ! 706: /* start of ioctl code */ ! 707: if(f == SASI_CMD_IN) ! 708: ccb->target |= AHA_CCB_DATA_IN; ! 709: else if(f == SASI_CMD_OUT) ! 710: ccb->target |= AHA_CCB_DATA_OUT; ! 711: else ! 712: ccb->target |= AHA_CCB_DATA_IN ! 713: |AHA_CCB_DATA_OUT; ! 714: #endif ! 715: } ! 716: ! 717: aha_start() ! 718: { ! 719: register int i, s, n = 0; ! 720: scsi_work_t *sw; ! 721: static char locked; ! 722: ! 723: s = sphi(); ! 724: if(locked) { ! 725: spl(s); ! 726: return; ! 727: } ! 728: ++locked; ! 729: spl(s); ! 730: ! 731: while((sw = scsi_work_queue->sw_actf) != NULL) { ! 732: for(i = MIN_MAILBOX; i < MAX_MAILBOX; ++i) ! 733: if(mailbox_out[i].cmd == MBO_IS_FREE) { ! 734: register ccb_t *ccb; ! 735: int s; ! 736: ! 737: ++n; ! 738: if ((ccb = buildccb (sw)) == NULL) { ! 739: /* ! 740: * NIGEL: Earlier kernels did not ! 741: * diagnose this! ! 742: */ ! 743: goto out_of_mem; ! 744: } ! 745: #ifdef _I386 ! 746: aha_l_to_p3(vtop(ccb), ! 747: mailbox_out[i].adr); ! 748: ccb_remember(ccb, mailbox_out[i].adr); ! 749: #else /* _I386 */ ! 750: aha_l_to_p3(VTOP2(ccb, sds), ! 751: mailbox_out[i].adr); ! 752: #endif /* _I386 */ ! 753: ! 754: #ifdef TRACER ! 755: begin_count (1); ! 756: #endif ! 757: s = sphi(); ! 758: sw = scsi_work_queue->sw_actf = sw->sw_actf; ! 759: if(sw == NULL) ! 760: scsi_work_queue->sw_actl = NULL; ! 761: spl(s); ! 762: ! 763: mailbox_out[i].cmd = MBO_TO_START; ! 764: ! 765: aha_1out(AHA_DO_SCSI_START); ! 766: ! 767: if(sw == NULL) ! 768: break; ! 769: } ! 770: if(i == MAX_MAILBOX) ! 771: break; ! 772: } ! 773: out_of_mem: ! 774: --locked; ! 775: return n; ! 776: } ! 777: ! 778: int ! 779: aha_completed() ! 780: { ! 781: register int i, n; ! 782: ! 783: for(n = 0, i = 0; i < MAX_MAILBOX; ++i) ! 784: if(mailbox_in[i].cmd != MBI_IS_FREE) { ! 785: /* ! 786: * NIGEL: Earlier kernels deferred these, but with the ! 787: * ccb_free ()/ccb_alloc () system that is no longer ! 788: * necessary in either 4.x or 3.x systems. ! 789: */ ! 790: #ifdef _I386 ! 791: aha_process(ccb_recall(mailbox_in[i].adr)); ! 792: #else /* _I386 */ ! 793: aha_process(aha_p3_to_v(mailbox_in[i].adr)); ! 794: #endif /* _I386 */ ! 795: mailbox_in[i].cmd = MBI_IS_FREE; ! 796: ++n; ! 797: } ! 798: return n; ! 799: } ! 800: ! 801: void ! 802: aha_intr() ! 803: { ! 804: register int i; ! 805: ! 806: if(((i = INB(aha_i_o_base+AHA_INTERRUPT)) & AHA_ANY_INTER) == 0) ! 807: printf("aha: spurious interrupt %x\n", i); ! 808: ! 809: switch(i & AHA_ALL_INTERRUPTS) { ! 810: case AHA_RESETED: ! 811: break; ! 812: case AHA_CMD_DONE: ! 813: break; ! 814: case AHA_MBO_EMPTY: ! 815: defer(aha_start, (char *)0); ! 816: break; ! 817: case AHA_MBI_STORED: ! 818: aha_completed(); ! 819: break; ! 820: default: ! 821: printf("aha: multiple interrupts not yet handled\n"); ! 822: } ! 823: outb(aha_i_o_base+AHA_CONTROL, AHA_INTRRESET); ! 824: } ! 825: ! 826: aha_ioctl() ! 827: { ! 828: printf("aha_ioctl: Not implemented\n"); ! 829: } ! 830: ! 831: #ifdef TRACER ! 832: static unsigned char vec[256]; ! 833: ! 834: static aha_ports_are() { ! 835: printf("aha_ports_are: %x %x %x\n", ! 836: INB(aha_i_o_base+0), ! 837: INB(aha_i_o_base+1), ! 838: INB(aha_i_o_base+2)); ! 839: } ! 840: ! 841: static aha_inquiry_is() { ! 842: printf("aha_inquiry:"); ! 843: printf("... aha_present = %d, ", aha_present()); ! 844: printf("%s\n", aha_last_msg()); ! 845: aha_cmd_out(AHA_DO_INQUIRY); ! 846: ! 847: aha_get_data(&vec[0], 4); ! 848: printf(" board id '%c'", vec[0]); ! 849: printf(", options '%c'", vec[1]); ! 850: printf(", HW '%c'", vec[2]); ! 851: printf(", FW '%c'\n", vec[3]); ! 852: } ! 853: ! 854: void aha_setup_is() { ! 855: register int i; ! 856: ! 857: printf("Setup and Data:\n"); ! 858: aha_cmd_out(AHA_DO_GET_SETUP); ! 859: aha_cmd_out(16); ! 860: aha_get_data(&vec[0], 16); ! 861: printf(" Data Xfer %s Sync (J1)\n", (vec[0]&1) ? "is" : "not"); ! 862: printf(" Parity %s Enabled (J1)\n", (vec[0]&2) ? "is" : "not"); ! 863: switch(vec[1]) { ! 864: case AHA_SPEED_5_0_MB: ! 865: printf(" 5.0 Mb/sec.\n"); break; ! 866: case AHA_SPEED_6_7_MB: ! 867: printf(" 6.7 Mb/sec.\n"); break; ! 868: case AHA_SPEED_8_0_MB: ! 869: printf(" 8.0 Mb/sec.\n"); break; ! 870: case AHA_SPEED_10_MB: ! 871: printf(" 10 Mb/sec.\n"); break; ! 872: case AHA_SPEED_5_7_MB: ! 873: printf(" 5.7 Mb/sec.\n"); break; ! 874: default: ! 875: if(vec[1] & 0x80) ! 876: printf(" Pulse Read %d, Write %d, Strobe off %d\n", ! 877: 50*(2+(vec[1]>>4)&0x7), 50*(2+(vec[1]&7)), ! 878: vec[1] & 0x80 ? 150 : 100); ! 879: } ! 880: printf(" Bus Time ON %d, OFF %d\n", vec[2], vec[3]); ! 881: printf(" %d Mailboxes at %x|%x|%x\n", vec[4], ! 882: vec[5], vec[6], vec[7]); ! 883: for(i = 0; i < 8; ++i) ! 884: if(vec[i+8]) ! 885: printf(" Target [%d] = Sync Neg %x\n", i, vec[i+8]); ! 886: } ! 887: ! 888: static aha_mailboxes_are(n, adr) ! 889: mailentry *adr; ! 890: { ! 891: register int i; ! 892: ! 893: printf("addresses for mailbox is %x:%x\n", (long)adr); ! 894: for(i = 0; i < n; ++i, ++adr) ! 895: printf(" mbo[%x] = %x %x|%x|%x\n", ! 896: i, adr->cmd, adr->adr[0], adr->adr[1], adr->adr[2]); ! 897: for(i = 0; i < n; ++i, ++adr) ! 898: printf(" mbi[%x] = %x %x|%x|%x\n", ! 899: i, adr->cmd, adr->adr[0], adr->adr[1], adr->adr[2]); ! 900: } ! 901: ! 902: void aha_status() ! 903: { ! 904: aha_ports_are(); ! 905: aha_inquiry_is(); ! 906: /* aha_devices_are(); */ /* This appears to have never existed. */ ! 907: aha_setup_is(); ! 908: aha_mailboxes_are(MAX_MAILBOX, mailbox_out); ! 909: } ! 910: ! 911: aha_ccb_print(ccb) ! 912: ccb_t *ccb; ! 913: { ! 914: register int i; ! 915: register unsigned char *cp; ! 916: ! 917: printf("aha_ccb_print(ccb: %x)", ccb); ! 918: if (0 != ccb) { ! 919: printf(", sw: %x", ccb->ccb_sw); ! 920: if (0 != ccb->ccb_sw) { ! 921: printf(", bp: %x", ccb->ccb_sw->sw_bp); ! 922: if (0 != ccb->ccb_sw->sw_bp) { ! 923: printf(", flag: %x", ! 924: ccb->ccb_sw->sw_bp->b_flag); ! 925: } ! 926: } ! 927: printf(", op %d, ", ccb->opcode); ! 928: printf("target ID=%d, ", (ccb->target>>5) & 0x7); ! 929: printf("LUN=%d, ", (ccb->target & 0x7)); ! 930: printf("dir=%s%s\n", (ccb->target&AHA_CCB_DATA_IN)?"IN":"", ! 931: (ccb->target&AHA_CCB_DATA_OUT)?"OUT":""); ! 932: printf("data len %x|%x|%x, adr %x|%x|%x\n", ! 933: ccb->datalen[0],ccb->datalen[1],ccb->datalen[2], ! 934: ccb->dataptr[0],ccb->dataptr[1],ccb->dataptr[2]); ! 935: printf("status host=%x, target=%x\n", ! 936: ccb->hoststatus, ccb->targetstatus); ! 937: printf("cmddata[%d]:", ccb->cmdlen); ! 938: for(i = 0, cp = ccb->cmd_status; i < ccb->cmdlen; ++i) ! 939: printf(" %x", *cp++); ! 940: printf("\nrequest sense[%d]:", ccb->senselen); ! 941: for(i = 0; i < ccb->senselen; ++i) ! 942: printf(" %x", *cp++); ! 943: if(i = cp[-1]) { ! 944: printf("\n + "); ! 945: while(--i >= 0) ! 946: printf(" %x", *cp++); ! 947: } ! 948: printf("\n"); ! 949: } ! 950: } ! 951: ! 952: static int _begin_count [4]; ! 953: static int _end_count [4]; ! 954: ! 955: begin_count (num) { ! 956: _begin_count [num] ++; ! 957: } ! 958: ! 959: end_count (num) { ! 960: _end_count [num] ++; ! 961: } ! 962: ! 963: void aha_mbox_status () { ! 964: int i; ! 965: scsi_work_t * sw; ! 966: static char * stats [] = { ! 967: "blocks", "adaptec transfers", "non-block commands", ! 968: "ccb allocs" ! 969: }; ! 970: ! 971: i = 0; ! 972: for (sw = scsi_work_queue->sw_actf ; sw != NULL ; sw = sw->sw_actf) ! 973: i ++; ! 974: if (i > 0) ! 975: printf ("[%d outstanding items]"); ! 976: ! 977: for (i = 0 ; i < __ARRAY_LENGTH (_begin_count) ; i ++) { ! 978: if (_begin_count [i] > _end_count [i]) ! 979: printf ("<%d unaccounted %s>", ! 980: _begin_count [i] - _end_count [i], stats [i]); ! 981: } ! 982: } ! 983: #endif /* TRACER */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.