|
|
1.1 ! root 1: /* ! 2: * io.386/ss.c ! 3: * ! 4: * Device driver for Seagate ST01/ST02 scsi host adapters. ! 5: * ! 6: * Revised: Wed May 26 16:57:51 1993 CDT ! 7: */ ! 8: ! 9: /* ! 10: * To do: ! 11: * nonzero LUN's ! 12: * start new command during disconnect ! 13: * rewrite as single state machine, instead of 7 of them ! 14: * separate SCSI layer from host-dependent stuff ! 15: */ ! 16: ! 17: /* ! 18: * Debug levels. ! 19: * DEBUG = 0 No debug output. ! 20: * DEBUG = 1 Debug output on error only. ! 21: * DEBUG = 2 Debug output on error and at other selected places. ! 22: * DEBUG = 3 Print state machine trace. ! 23: * DEBUG = 4 Print info xfer phases and msg_in values. ! 24: */ ! 25: #if (DEBUG >= 1) ! 26: static int s_id; ! 27: #define PR1(str) printf("%s%d ", str, s_id) ! 28: #else ! 29: #define PR1(str) ! 30: #endif ! 31: #if (DEBUG >= 2) ! 32: #define PR2(str) printf(str) ! 33: #else ! 34: #define PR2(str) ! 35: #endif ! 36: #if (DEBUG >= 3) ! 37: #define PR3(str) printf("%s%d ", str, s_id) ! 38: #else ! 39: #define PR3(str) ! 40: #endif ! 41: #if (DEBUG >= 4) ! 42: #define PR4(str) printf("%s%d ", str, s_id) ! 43: #else ! 44: #define PR4(str) ! 45: #endif ! 46: ! 47: /* ! 48: * Includes. ! 49: */ ! 50: #include <sys/coherent.h> ! 51: ! 52: #ifdef _I386 ! 53: #include <sys/fakeff.h> ! 54: #include <sys/dmac.h> ! 55: #endif ! 56: #include <sys/io.h> ! 57: #include <sys/sched.h> ! 58: #include <sys/uproc.h> ! 59: #include <sys/proc.h> ! 60: #include <sys/con.h> ! 61: #include <sys/stat.h> ! 62: #include <sys/devices.h> /* SCSI_MAJOR */ ! 63: #include <errno.h> ! 64: #include <sys/fdisk.h> ! 65: #include <sys/hdioctl.h> ! 66: #include <sys/buf.h> ! 67: #include <sys/scsiwork.h> ! 68: #include <sys/typed.h> ! 69: ! 70: /* ! 71: * Definitions. ! 72: * Constants. ! 73: * Macros with argument lists. ! 74: * Typedefs. ! 75: * Enums. ! 76: */ ! 77: #define SS_RAM 0x1800 /* Offset of parameter RAM */ ! 78: ! 79: /* Future Domain */ ! 80: #define FD_CSR 0x1C00 /* Offset of control/status register */ ! 81: #define FD_DAT 0x1E00 /* Offset of data port */ ! 82: ! 83: /* Seagate */ ! 84: #define SS_CSR 0x1A00 /* Offset of control/status register */ ! 85: #define SS_DAT 0x1C00 /* Offset of data port */ ! 86: ! 87: #define SS_RAM_LEN 128 /* ST0x has 128 bytes of RAM */ ! 88: #define SS_DAT_LEN 0x400 /* Byte range mapped to data port */ ! 89: #define SS_SEL_LEN 0x2000 /* Total size of memory-mapped area */ ! 90: ! 91: #define WC_ENABLE_SCSI 0x80 /* Write Control (WC) register bits */ ! 92: #define WC_ENABLE_IRPT 0x40 ! 93: #define WC_ENABLE_PRTY 0x20 ! 94: #define WC_ARBITRATE 0x10 ! 95: #define WC_ATTENTION 0x08 ! 96: #define WC_BUSY 0x04 ! 97: #define WC_SELECT 0x02 ! 98: #define WC_SCSI_RESET 0x01 ! 99: ! 100: #define RS_ARBIT_COMPL 0x80 /* Read STATUS (RS) register bits */ ! 101: #define RS_PRTY_ERROR 0x40 ! 102: #define RS_SELECT 0x20 ! 103: #define RS_REQUEST 0x10 ! 104: #define RS_CTRL_DATA 0x08 ! 105: #define RS_I_O 0x04 ! 106: #define RS_MESSAGE 0x02 ! 107: #define RS_BUSY 0x01 ! 108: ! 109: #define DEV_SCSI_ID(dev) ((dev >> 4) & 0x0007) ! 110: #define DEV_LUN(dev) ((dev >> 2) & 0x0003) ! 111: #define DEV_DRIVE(dev) ((dev >> 2) & 0x001F) ! 112: #define DEV_PARTN(dev) (dev & 0x0003) ! 113: #define DEV_SPECIAL(dev) (dev & 0x0080) ! 114: ! 115: #define HIPRI_RETRIES 5000 /* # of times to retry while hogging CPU */ ! 116: #define LOPRI_RETRIES 5 /* # of retries with sleep between tries */ ! 117: #define WHOLE_DRIVE NPARTN ! 118: #define RESET_TICKS 50 /* # of clock ticks for reset settling */ ! 119: #define LOAD_DELAY 30000 /* Loop counter during ssload() only */ ! 120: ! 121: #define BUS_FREE ((ffbyte(ss_csr) & (RS_BUSY | RS_SELECT)) == 0) ! 122: #define TGT_RSEL \ ! 123: ( (ffbyte(ss_csr) & (RS_SELECT | RS_I_O )) \ ! 124: && (ffbyte(ss_dat) & (host_id | (1<<s_id) )) ) ! 125: ! 126: #define DELAY_ARB 10 /* delays units are 10 msec (clock ticks) */ ! 127: #define DELAY_BDR 30 ! 128: #define DELAY_BSY 20 ! 129: #define DELAY_RES 50 ! 130: #define DELAY_RST 40 ! 131: ! 132: #define MAX_AVL_COUNT 100 ! 133: #define MAX_BDR_COUNT 3 ! 134: #define MAX_BSY_COUNT 3 ! 135: #define MAX_TRY_COUNT 10 ! 136: #define INL_MAX_REQ_POLL 800000L ! 137: #define WKG_MAX_REQ_POLL 20000L ! 138: ! 139: typedef enum { /* values for current driver state */ ! 140: SST_DEQUEUE =0, ! 141: SST_BUS_DEV_RESET, ! 142: SST_HIPRI_RESET, ! 143: SST_LOPRI_RESET, ! 144: SST_POLL_ARBITN, ! 145: SST_POLL_BEGIN_IO, ! 146: SST_POLL_RESELECT, ! 147: SST_REQ_SENSE, ! 148: SST_RESET_OFF ! 149: } SST_TYPE; ! 150: ! 151: typedef enum { /* values for input to recovery routine */ ! 152: RV_A_TIMEOUT, ! 153: RV_P_TIMEOUT, ! 154: RV_R_TIMEOUT, ! 155: RV_BF_TIMEOUT, ! 156: RV_CS_BUSY, ! 157: RV_CS_CHECK ! 158: } RV_TYPE; ! 159: ! 160: typedef struct ss { ! 161: ulong capacity; ! 162: ulong blocklen; ! 163: ulong bno; ! 164: int msg_in; ! 165: int dr_watch; ! 166: unchar cmdbuf[G1CMDLEN]; ! 167: int cmdlen; ! 168: int cmd_bytes_out; ! 169: int cmdstat; ! 170: BUF *bp; /* current I/O request node, or NULL */ ! 171: struct fdisk_s parmp[NPARTN+1]; ! 172: SST_TYPE state; ! 173: TIM tim; /* for target-specific timers */ ! 174: unchar avl_count; ! 175: unchar bdr_count; ! 176: unchar bsy_count; ! 177: unchar try_count; ! 178: uint busy:1; /* 1 if command uses local buffer */ ! 179: uint expired:1; /* 1 if target's timer has expired */ ! 180: uint ptab_read:1; /* 1 if partition table has been read */ ! 181: uint waiting:1; /* 1 if target timer is running */ ! 182: } ss_type; ! 183: ! 184: typedef struct { ! 185: uint ncyl; ! 186: unchar nhead; ! 187: unchar nspt; ! 188: } drv_parm_type; ! 189: ! 190: /* ! 191: * Functions. ! 192: * Import Functions. ! 193: * Export Functions. ! 194: * Local Functions. ! 195: */ ! 196: ! 197: /* functions from bufq.c */ ! 198: extern int bufq_init(); ! 199: extern void bufq_rlse(); ! 200: extern void bufq_wr_tail(); ! 201: extern BUF * bufq_rd_head(); ! 202: extern BUF * bufq_rm_head(); ! 203: ! 204: /* functions from ssas.s */ ! 205: extern void ss_get(); ! 206: extern int ss_put(); ! 207: extern int nulldev(); ! 208: extern int nonedev(); ! 209: #ifndef _I386 ! 210: extern unsigned char ffbyte(); ! 211: #endif ! 212: ! 213: static void ssopen(); /* CON functions */ ! 214: static void ssclose(); ! 215: static void ssblock(); ! 216: static void ssread(); ! 217: static void sswrite(); ! 218: static int ssioctl(); ! 219: static void sswatch(); ! 220: static void ssload(); ! 221: static void ssunload(); ! 222: ! 223: static int bus_dev_reset(); /* additional support functions */ ! 224: static int chk_reconn(); ! 225: static void do_connect(); ! 226: static void dummy_reconn(); ! 227: static int far_info_xfer(); ! 228: static int host_ident(); ! 229: static int init_call(); ! 230: static void init_pointers(); ! 231: static int inquiry(); ! 232: static int local_info_xfer(); ! 233: static int mode_sense(); ! 234: static void next_req(); ! 235: static void nonpolled(); ! 236: static int read_cap(); ! 237: static void recover(); ! 238: static int req_sense(); ! 239: static int rsel_handshake(); ! 240: static void ssdelay(); ! 241: static void ss_finished(); ! 242: static void ss_mach(); ! 243: static void set_timeout(); ! 244: static int ssinit(); ! 245: static void ssintr(); ! 246: static int start_arb(); ! 247: static void stop_timeout(); ! 248: static void tbparms(); ! 249: static unchar xpmod(); ! 250: ! 251: /* ! 252: * Global Data. ! 253: * Import Variables. ! 254: * Export Variables. ! 255: * Local Variables. ! 256: */ ! 257: ! 258: extern short n_atdr; /* set by atcount() before any load routines run */ ! 259: ! 260: CON sscon = { ! 261: DFBLK|DFCHR, /* Flags */ ! 262: SCSI_MAJOR, /* Major index */ ! 263: ssopen, /* Open */ ! 264: ssclose, /* Close */ ! 265: ssblock, /* Block */ ! 266: ssread, /* Read */ ! 267: sswrite, /* Write */ ! 268: ssioctl, /* Ioctl */ ! 269: nulldev, /* Powerfail */ ! 270: sswatch, /* Timeout */ ! 271: ssload, /* Load */ ! 272: ssunload, /* Unload */ ! 273: nulldev /* Poll */ ! 274: }; ! 275: ! 276: /* Patch these Export Variables to configure the driver. */ ! 277: /* ! 278: * In the low byte of NSDRIVE, bit n is 1 if SCSI ID n is an installed target. ! 279: * The high byte indicates which type of host adapter: ! 280: * 00 - ST01/ST02 ! 281: * 80 - TMC-845/850/860/875/885 ! 282: * 40 - TMC-840/841/880/881 ! 283: */ ! 284: uint NSDRIVE = 0x0001; ! 285: uint SS_INT = 5; /* ST0[12] use either IRQ3 or IRQ5 */ ! 286: uint SS_BASE = 0xCA00; /* Segment addr of ST0x communication area */ ! 287: ! 288: /* ncyl, nhead, nspt */ ! 289: drv_parm_type drv_parm[MAX_SCSI_ID] = { ! 290: { 0, 0, 0}, ! 291: { 0, 0, 0}, ! 292: { 0, 0, 0}, ! 293: { 0, 0, 0}, ! 294: { 0, 0, 0}, ! 295: { 0, 0, 0}, ! 296: { 0, 0, 0} ! 297: }; ! 298: ! 299: static BUF dbuf; /* For raw I/O */ ! 300: static paddr_t ss_base; /* physical address of ST0x comm area */ ! 301: static faddr_t ss_fp; /* (far *) to ST0x comm area */ ! 302: ! 303: static faddr_t ss_ram; /* (far *) to parameter RAM */ ! 304: static faddr_t ss_csr; /* (far *) to control/status */ ! 305: static faddr_t ss_dat; /* (far *) to data port */ ! 306: ! 307: static TIM delay_tim; /* needed for calls to ssdelay() */ ! 308: static int do_sst_op; /* 1 when state machine iteration continues */ ! 309: static int ss_expired; /* 1 after local timeout */ ! 310: ! 311: static uint max_req_poll; /* this changes after initialization */ ! 312: ! 313: static unchar host_id; /* Host is SCSI ID #7 for Seagate, 6 for FD */ ! 314: static unchar swap_status_bits; ! 315: ! 316: static ss_type *ss_tbl; /* points to block of "ss" structs */ ! 317: static ss_type *ss[MAX_SCSI_ID]; ! 318: ! 319: /* ! 320: * host_claimed is -1 if host is available, else it's the SCSI id of the ! 321: * target that claims the host. ! 322: * ! 323: * host is claimed at start of any of the follwoing: ! 324: * SCSI bus reset ! 325: * arbitration for block i/o request ! 326: * reselect ! 327: * ! 328: * host is released at: ! 329: * end of SCSI bus reset ! 330: * completion (successful or not) of block i/o request (ss_finished) ! 331: * disconnect <-- temporarily disabled ! 332: */ ! 333: static int host_claimed; ! 334: ! 335: /* ! 336: * ssload() - load routine. ! 337: * ! 338: * Action: The controller is reset and the interrupt vector is grabbed. ! 339: * The drive characteristics are set up at this time. ! 340: */ ! 341: static void ssload() ! 342: { ! 343: int erf = 0; /* 1 if error occurs */ ! 344: int i; ! 345: int max_id = -1; ! 346: int num_drives = 0; ! 347: int tbnum; ! 348: ! 349: ! 350: /* ! 351: * Allocate a selector to map into ST0x memory-mapped comm area. ! 352: */ ! 353: ss_base = (paddr_t)((long)(unsigned)SS_BASE << 4); ! 354: #ifdef _I386 ! 355: ss_fp = map_pv(ss_base, (fsize_t)SS_SEL_LEN); ! 356: #else /* _I386 */ ! 357: ss_fp = ptov(ss_base, (fsize_t)SS_SEL_LEN); ! 358: #endif /* _I386 */ ! 359: ss_ram = ss_fp + SS_RAM; ! 360: ! 361: /* ! 362: * Primitive test of ST0x RAM. ! 363: */ ! 364: sfword(ss_ram, 0xA55A); ! 365: sfword(ss_ram + 2, 0x3CC3); ! 366: sfword(ss_ram + SS_RAM_LEN - 4, 0xA55A); ! 367: sfword(ss_ram + SS_RAM_LEN - 2, 0x3CC3); ! 368: if (ffword(ss_ram) != 0xA55A /* fetch a "far" word */ ! 369: || ffword(ss_ram + 2) != 0x3CC3 ! 370: || ffword(ss_ram + SS_RAM_LEN - 4) != 0xA55A ! 371: || ffword(ss_ram + SS_RAM_LEN - 2) != 0x3CC3) { ! 372: printf("Error - host failed memory test\n"); ! 373: erf = 1; ! 374: } ! 375: ! 376: /* ! 377: * Set host-dependent constants. ! 378: */ ! 379: switch(NSDRIVE >> 8) { ! 380: case 0x00: /* ST01/ST02 */ ! 381: ss_csr = ss_fp + SS_CSR; ! 382: ss_dat = ss_fp + SS_DAT; ! 383: host_id = 0x80; /* host is id #7 */ ! 384: break; ! 385: case 0x80: /* TMC-845/850/860/875/885 */ ! 386: ss_csr = ss_fp + FD_CSR; ! 387: ss_dat = ss_fp + FD_DAT; ! 388: host_id = 0x40; /* host is id #6 */ ! 389: break; ! 390: case 0x40: /* TMC-840/841/880/881 */ ! 391: ss_csr = ss_fp + SS_CSR; ! 392: ss_dat = ss_fp + SS_DAT; ! 393: host_id = 0x40; /* host is id #6 */ ! 394: swap_status_bits = 1; ! 395: break; ! 396: } ! 397: NSDRIVE &= ~(uint)host_id; ! 398: ! 399: /* ! 400: * Allocate drive structs. ! 401: * ! 402: * Do a single call to kalloc() then put allocated pieces into ! 403: * array ss. ! 404: * ! 405: * First allocate and clear storage. Then hook up the pointers. ! 406: */ ! 407: if (!erf) { ! 408: for (i = 0; i < MAX_SCSI_ID; i++) ! 409: if ((NSDRIVE >> i) & 1) { ! 410: max_id = i; ! 411: num_drives++; ! 412: } ! 413: if (num_drives == 0) { ! 414: printf("Error - ss has no valid target id's\n"); ! 415: erf = 1; ! 416: } else if ((ss_tbl = kalloc(num_drives*sizeof(ss_type))) ! 417: == NULL) { ! 418: printf("Error - ss can't allocate structs\n"); ! 419: erf = 1; ! 420: } else ! 421: kclear(ss_tbl, num_drives * sizeof(ss_type)); ! 422: } ! 423: if (!erf) { ! 424: ss_type *foo = ss_tbl; ! 425: ! 426: for (i = 0; i < MAX_SCSI_ID; i++) ! 427: if ((NSDRIVE >> i) & 1) ! 428: ss[i] = foo++; ! 429: } ! 430: ! 431: /* ! 432: * Claim IRQ vector. ! 433: */ ! 434: setivec(SS_INT, ssintr); ! 435: ! 436: /* ! 437: * Initialize drives we know about (i.e. in NSDRIVE bitmap). ! 438: * ! 439: * Part of this is getting parameters from tboot, if any. ! 440: * The drive number in tboot's data block must be matched with ! 441: * the SCSI id in question. Drive numbering in tboot is assumed ! 442: * to start with any "at" drives (n_atdr counts these) ! 443: * then proceed with SCSI drives in increasing id number order. ! 444: */ ! 445: tbnum = n_atdr; /* tboot drive number for first SCSI drive */ ! 446: host_claimed = -1; ! 447: bufq_init(max_id + 1); ! 448: max_req_poll = INL_MAX_REQ_POLL; ! 449: if (!erf) { ! 450: for (i = 0; i < MAX_SCSI_ID; i++) ! 451: if ((NSDRIVE >> i) & 1) { ! 452: tbparms(tbnum, i); /* get tboot parms */ ! 453: ssinit(i); ! 454: tbnum++; ! 455: } ! 456: } ! 457: max_req_poll = WKG_MAX_REQ_POLL; ! 458: } ! 459: ! 460: /* ! 461: * ssunload() - unload routine. ! 462: */ ! 463: static void ssunload() ! 464: { ! 465: /* ! 466: * Deallocate driver heap space. ! 467: */ ! 468: if (ss_tbl) ! 469: kfree(ss_tbl); ! 470: bufq_rlse(); ! 471: ! 472: /* ! 473: * Free the ST0x selector. ! 474: */ ! 475: #ifdef _I386 ! 476: unmap_pv(ss_fp); ! 477: #else /* _I386 */ ! 478: vrelse(ss_fp); ! 479: #endif /* _I386 */ ! 480: ! 481: /* ! 482: * Release IRQ vector. ! 483: */ ! 484: clrivec(SS_INT); ! 485: } ! 486: ! 487: /* ! 488: * ssopen() ! 489: * ! 490: * Input: dev = disk device to be opened. ! 491: * mode = access mode [IPR,IPW, IPR+IPW]. ! 492: * ! 493: * Action: Validate the minor device. ! 494: * Update the paritition table if necessary. ! 495: */ ! 496: static void ssopen(dev, mode) ! 497: register dev_t dev; ! 498: { ! 499: int drive, partn; ! 500: struct fdisk_s *fdp; ! 501: ss_type * ssp; ! 502: int s_id; ! 503: unchar * msg; ! 504: ! 505: /* ! 506: * Set up local variables. ! 507: */ ! 508: drive = DEV_SCSI_ID(dev); ! 509: partn = DEV_PARTN(dev); ! 510: s_id = DEV_SCSI_ID(dev); ! 511: ssp = ss[s_id]; ! 512: fdp = ssp->parmp; ! 513: ! 514: #if (DEBUG >= 3) ! 515: devmsg(dev, "ssopen"); ! 516: #endif ! 517: ! 518: /* ! 519: * LUN must be zero. ! 520: * SCSI id must have corresponding 1 in NSDRIVE bitmapped variable. ! 521: */ ! 522: if (DEV_LUN(dev) != 0 || ((1 << drive) & NSDRIVE) == 0) { ! 523: msg = "bad LUN or SCSI id"; ! 524: u.u_error = ENXIO; ! 525: goto bad_open; ! 526: } ! 527: ! 528: /* ! 529: * If "special" bit is set, partition field must be zero. ! 530: */ ! 531: if (DEV_SPECIAL(dev) && partn != 0) { ! 532: msg = "bad special partition"; ! 533: u.u_error = ENXIO; ! 534: goto bad_open; ! 535: } ! 536: ! 537: /* ! 538: * Subscripting gimmick for partition table. ! 539: */ ! 540: if (dev & SDEV) ! 541: partn = WHOLE_DRIVE; ! 542: ! 543: /* ! 544: * If not accessing whole drive and the partition table has not ! 545: * been read yet, try to read it now. ! 546: * Do this by calling fdisk() with partition table device on the drive ! 547: * that is being accessed. ! 548: */ ! 549: if (partn != WHOLE_DRIVE && !(ssp->ptab_read)) { ! 550: int fdisk_dev; ! 551: ! 552: fdisk_dev = (dev | SDEV) & 0xfff0; ! 553: ! 554: #if (DEBUG >=3) ! 555: devmsg(fdisk_dev, "calling fdisk"); ! 556: if (fdisk(fdisk_dev, fdp)) { ! 557: int p; ! 558: ! 559: fdp[WHOLE_DRIVE].p_size = ssp->capacity; ! 560: fdp[WHOLE_DRIVE].p_base = 0; ! 561: printf("fdisk() succeeded\n"); ! 562: for (p=0; p<WHOLE_DRIVE; p++) ! 563: printf("p=%d base=%ld size=%ld\n", p, fdp[p].p_base, fdp[p].p_size); ! 564: ssp->ptab_read = 1; ! 565: } else { ! 566: printf("fdisk() failed\n"); ! 567: u.u_error = ENXIO; ! 568: goto bad_open; ! 569: } ! 570: #else ! 571: if (fdisk(fdisk_dev, fdp)) { ! 572: fdp[WHOLE_DRIVE].p_size = ssp->capacity; ! 573: fdp[WHOLE_DRIVE].p_base = 0; ! 574: ssp->ptab_read = 1; ! 575: } else { ! 576: msg = "bad partition table"; ! 577: u.u_error = ENXIO; ! 578: goto bad_open; ! 579: } ! 580: #endif ! 581: ! 582: } ! 583: ! 584: /* ! 585: * Ensure partition lies within drive boundaries and is non-zero size. ! 586: */ ! 587: if (partn != WHOLE_DRIVE ! 588: && (fdp[partn].p_base+fdp[partn].p_size) > fdp[WHOLE_DRIVE].p_size) { ! 589: msg = "partition exceeds drive capacity"; ! 590: #ifdef _I386 ! 591: u.u_error = EINVAL; ! 592: #else ! 593: u.u_error = EBADFMT; ! 594: #endif /* _I386 */ ! 595: goto bad_open; ! 596: } ! 597: ! 598: if (partn != WHOLE_DRIVE && fdp[partn].p_size == 0) { ! 599: msg = "partition not found"; ! 600: u.u_error = ENODEV; ! 601: goto bad_open; ! 602: } ! 603: ! 604: /* ! 605: * OK to open the device. ! 606: * Start watchdog timer (if not already started) for the host adapter. ! 607: */ ! 608: ++drvl[SCSI_MAJOR].d_time; ! 609: ++ssp->dr_watch; ! 610: goto end_open; ! 611: ! 612: bad_open: ! 613: devmsg(dev, msg); ! 614: end_open: ! 615: return; ! 616: } ! 617: ! 618: /* ! 619: * ssclose() ! 620: */ ! 621: static void ssclose(dev) ! 622: dev_t dev; ! 623: { ! 624: ss_type * ssp; ! 625: int s_id; ! 626: ! 627: s_id = DEV_SCSI_ID(dev); ! 628: ssp = ss[s_id]; ! 629: ! 630: /* ! 631: * Decrement the number of watchdog timer requests open for host ! 632: * adapter and for target. ! 633: */ ! 634: --drvl[SCSI_MAJOR].d_time; ! 635: --ssp->dr_watch; ! 636: ! 637: #if (DEBUG >= 3) ! 638: devmsg(dev, "ssclose"); ! 639: #endif ! 640: ! 641: } ! 642: ! 643: /* ! 644: * ssread() - read a block from the raw disk ! 645: * ! 646: * Input: dev = disk device to be written to. ! 647: * iop = pointer to source I/O structure. ! 648: * ! 649: * Action: Invoke the common raw I/O processing code. ! 650: */ ! 651: static void ssread(dev, iop) ! 652: dev_t dev; ! 653: IO *iop; ! 654: { ! 655: T_PIGGY( 0x20, printf("ssread(iop->io.vbase: %x)", iop->io.vbase); ); ! 656: ! 657: ioreq( &dbuf, iop, dev, BREAD, BFRAW|BFBLK|BFIOC ); ! 658: } ! 659: ! 660: /* ! 661: * sswrite() - write a block to the raw disk ! 662: * ! 663: * Input: dev = disk device to be written to. ! 664: * iop = pointer to source I/O structure. ! 665: * ! 666: * Action: Invoke the common raw I/O processing code. ! 667: */ ! 668: static void sswrite(dev, iop) ! 669: dev_t dev; ! 670: IO *iop; ! 671: { ! 672: T_PIGGY( 0x20, printf("sswrite(iop->io.vbase: %x)", iop->io.vbase); ); ! 673: ! 674: ioreq( &dbuf, iop, dev, BWRITE, BFRAW|BFBLK|BFIOC ); ! 675: } ! 676: ! 677: /* ! 678: * ssioctl() ! 679: * ! 680: * Input: dev = disk device to be operated on. ! 681: * cmd = input/output request to be performed. ! 682: * vec = (pointer to) optional argument. ! 683: */ ! 684: static int ssioctl(dev, cmd, vec) ! 685: register dev_t dev; ! 686: int cmd; ! 687: char * vec; ! 688: { ! 689: int ret = 0; ! 690: hdparm_t hdparm; ! 691: struct fdisk_s *fdp; ! 692: int s_id; ! 693: ss_type * ssp; ! 694: ! 695: s_id = DEV_SCSI_ID(dev); ! 696: ssp = ss[s_id]; ! 697: fdp = ssp->parmp; ! 698: ! 699: switch(cmd) { ! 700: case HDGETA: ! 701: /* ! 702: * Get hard disk attributes. ! 703: */ ! 704: PR3("HDGETA"); ! 705: fdp = ssp->parmp; ! 706: *(short *)&hdparm.landc[0] = ! 707: *(short *)&hdparm.ncyl[0] = drv_parm[s_id].ncyl; ! 708: hdparm.nhead = drv_parm[s_id].nhead; ! 709: hdparm.nspt = drv_parm[s_id].nspt; ! 710: #if (DEBUG >= 3) ! 711: printf("ncyl=%d nhead=%d nspt=%d\n", ! 712: hdparm.ncyl[0]+((int)hdparm.ncyl[1]<<8), (int)hdparm.nhead, (int)hdparm.nspt); ! 713: #endif ! 714: kucopy(&hdparm, vec, sizeof hdparm); ! 715: ret = 0; ! 716: break; ! 717: case HDSETA: ! 718: /* ! 719: * Set hard disk attributes. ! 720: */ ! 721: PR3("HDSETA"); ! 722: fdp = ssp->parmp; ! 723: ukcopy(vec, &hdparm, sizeof hdparm); ! 724: drv_parm[s_id].ncyl = *(short *)&hdparm.ncyl[0]; ! 725: drv_parm[s_id].nhead = hdparm.nhead; ! 726: drv_parm[s_id].nspt = hdparm.nspt; ! 727: #if (DEBUG >= 3) ! 728: printf("ncyl=%d nhead=%d nspt=%d\n", ! 729: hdparm.ncyl[0]+((int)hdparm.ncyl[1]<<8), (int)hdparm.nhead, (int)hdparm.nspt); ! 730: #endif ! 731: ret = 0; ! 732: break; ! 733: default: ! 734: u.u_error = EINVAL; ! 735: ret = -1; ! 736: } ! 737: ! 738: return ret; ! 739: } ! 740: ! 741: /* ! 742: * ssblock() - queue a block to the disk ! 743: * ! 744: * Input: bp = pointer to block to be queued. ! 745: * ! 746: * Action: Queue a block to the disk. ! 747: * Make sure that the transfer is within the disk partition. ! 748: */ ! 749: static void ssblock(bp) ! 750: register BUF *bp; ! 751: { ! 752: struct fdisk_s *fdp; ! 753: int partition, drive, s_id; ! 754: dev_t dev; ! 755: ss_type * ssp; ! 756: unchar * msg = NULL; ! 757: ! 758: T_PIGGY( 0x20, ! 759: printf("ssblock(bp->b_vaddr: %x, bp->b_paddr: %x)", ! 760: bp->b_vaddr, bp->b_paddr); ! 761: ); ! 762: ! 763: /* ! 764: * Set up local variables. ! 765: */ ! 766: dev = bp->b_dev; ! 767: partition = DEV_PARTN(dev); ! 768: drive = DEV_DRIVE(dev); ! 769: s_id = DEV_SCSI_ID(dev); ! 770: ssp = ss[s_id]; ! 771: if (dev & SDEV) ! 772: partition = WHOLE_DRIVE; ! 773: fdp = ssp->parmp; ! 774: ! 775: bp->b_resid = bp->b_count; ! 776: #if (DEBUG >= 2) ! 777: if (bp->b_count != BSIZE) ! 778: printf("b_count=%d ", bp->b_count); ! 779: #endif ! 780: ! 781: /* ! 782: * Range check disk region. ! 783: */ ! 784: if (!(ssp->ptab_read)) { ! 785: if ( partition == WHOLE_DRIVE ) { ! 786: #if 0 ! 787: /* Why did we only allow people to access the first block of WHOLE_DRIVE? ! 788: in cases where there was not a valid partition table? */ ! 789: if ((bp->b_bno != 0) || (bp->b_count != BSIZE)) { ! 790: msg = "invalid request"; ! 791: bp->b_flag |= BFERR; ! 792: goto bad_blk; ! 793: } ! 794: #endif ! 795: } else { ! 796: msg = "no partition table"; ! 797: bp->b_flag |= BFERR; ! 798: goto bad_blk; ! 799: } ! 800: } ! 801: ! 802: /* ! 803: * Check for read at end of partition. ! 804: * (Need to return with b_resid = BSIZE to signal end of volume.) ! 805: */ ! 806: else if ((bp->b_req == BREAD) && (bp->b_bno == fdp[partition].p_size)) { ! 807: goto bad_blk; ! 808: } ! 809: ! 810: /* ! 811: * Check for read past end of partition. ! 812: */ ! 813: else if ( (bp->b_bno + (bp->b_count/BSIZE)) ! 814: > fdp[partition].p_size ) { ! 815: msg = "partition overrun"; ! 816: bp->b_flag |= BFERR; ! 817: goto bad_blk; ! 818: } ! 819: ! 820: /* ! 821: * Fail if request is for zero bytes or is not even # of blocks. ! 822: */ ! 823: if ((bp->b_count % BSIZE) || bp->b_count == 0) { ! 824: msg = "invalid byte count"; ! 825: bp->b_flag |= BFERR; ! 826: goto bad_blk; ! 827: } ! 828: ! 829: /* ! 830: * Operation appears valid. ! 831: * Fill fields in the node and queue the request. ! 832: */ ! 833: bufq_wr_tail(s_id, bp); ! 834: ss_mach(s_id); ! 835: goto end_blk; ! 836: ! 837: /* ! 838: * Operation cannot be done. Release the kernel buffer structure. ! 839: * Value of "bp->b_flag" tells caller if error occurred. ! 840: */ ! 841: bad_blk: ! 842: if (msg) ! 843: devmsg(dev, msg); ! 844: bdone(bp); ! 845: ! 846: end_blk: ! 847: return; ! 848: } ! 849: ! 850: /* ! 851: * ssintr() - Interrupt routine. ! 852: * ! 853: * If we have been reselected by a recognized target device ! 854: * let kernel get out of interrupt mode (defer) and do SCSI ! 855: * reconnect stuff. ! 856: */ ! 857: static void ssintr() ! 858: { ! 859: int s_id; ! 860: ! 861: s_id = chk_reconn(); ! 862: if (s_id != -1) { ! 863: if (ss[s_id]->state == SST_POLL_RESELECT) ! 864: defer(ss_mach, s_id); ! 865: else ! 866: defer(dummy_reconn, s_id); ! 867: PR3("!"); ! 868: } ! 869: } ! 870: ! 871: /* ! 872: * dummy_reconn() ! 873: * ! 874: * Somehow we are in a state where the driver software does not expect ! 875: * a reconnect but a device is trying one anyway. Go thru the motions ! 876: * of reconnect because not servicing a hanging reselect seems to leave ! 877: * the target hung - in such a way that it fails to respond to reset ! 878: * messages and to reset on the SCSI bus. ! 879: */ ! 880: static void dummy_reconn(s_id) ! 881: int s_id; ! 882: { ! 883: int bus_timeout; ! 884: unchar phase_type; ! 885: int s; ! 886: int msg_in; ! 887: int cmdstat; ! 888: int xfer_good = 1; ! 889: PR1("DUM"); ! 890: if (ss[s_id]->state == SST_POLL_RESELECT) { ! 891: defer(ss_mach, s_id); ! 892: goto dum_done; ! 893: } ! 894: if (!rsel_handshake()) ! 895: goto dum_done; ! 896: ! 897: s = sphi(); ! 898: while (req_wait(&bus_timeout) && xfer_good) { ! 899: phase_type = ffbyte(ss_csr) & (RS_MESSAGE|RS_I_O|RS_CTRL_DATA); ! 900: switch (xpmod(phase_type)) { ! 901: case XP_MSG_IN: ! 902: msg_in = ffbyte(ss_dat); ! 903: switch(msg_in){ ! 904: case MSG_CMD_CMPLT: ! 905: case MSG_DISCONNECT: ! 906: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_IRPT); ! 907: break; ! 908: } ! 909: break; ! 910: case XP_MSG_OUT: ! 911: sfbyte(ss_dat, MSG_NOP); ! 912: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI); ! 913: break; ! 914: case XP_STAT_IN: ! 915: cmdstat = ffbyte(ss_dat); ! 916: break; ! 917: case XP_CMD_OUT: ! 918: case XP_DATA_OUT: ! 919: xfer_good = 0; ! 920: break; ! 921: case XP_DATA_IN: ! 922: ffbyte(ss_dat); ! 923: break; ! 924: default: ! 925: break; ! 926: } /* endswitch */ ! 927: } /* endwhile */ ! 928: spl(s); ! 929: ! 930: dum_done: ! 931: return; ! 932: } ! 933: ! 934: /* ! 935: * sswatch() ! 936: * ! 937: * Invoked once per second if any devices going through this driver are open. ! 938: * Poll for any reselect, in case interrupt got lost. ! 939: */ ! 940: static void sswatch() ! 941: { ! 942: int s_id; ! 943: ss_type * ssp; ! 944: ! 945: for (s_id = 0; s_id < MAX_SCSI_ID; s_id++) { ! 946: ssp = ss[s_id]; ! 947: if (ssp && ssp->dr_watch) ! 948: defer(ss_mach, s_id); ! 949: } /* endfor */ ! 950: } ! 951: ! 952: /* ! 953: * bus_wait() ! 954: * ! 955: * Wait for specified bit values to appear in Status Register. ! 956: * This uses a tight loop and does not expect to be interrupted. ! 957: * ! 958: * Argument "flags" is a double-byte value; the high byte is ANDed with ! 959: * status register contents, and the result is tested for equality with ! 960: * the low byte. ! 961: * ! 962: * Return 1 if values wanted appeared, 0 if timeout occurred. ! 963: */ ! 964: static int bus_wait(flags) ! 965: unsigned short flags; ! 966: { ! 967: int found, i; ! 968: unsigned char status; ! 969: ! 970: found = 0; ! 971: for ( i = 0; i < HIPRI_RETRIES; i++) { ! 972: status = ffbyte(ss_csr); ! 973: if ((status & (flags >> 8)) == (flags & 0xff)) { ! 974: found = 1; ! 975: break; ! 976: } ! 977: } ! 978: ! 979: #if (DEBUG >= 1) ! 980: if (!found) ! 981: printf("TO:f=%x s=%x ", flags, status); ! 982: #endif ! 983: ! 984: return found; ! 985: } ! 986: ! 987: /* ! 988: * ssinit() ! 989: * ! 990: * Attempt to initialize the (unique) drive with a given SCSI id. ! 991: * Assume only one drive per SCSI id, having LUN = 0. ! 992: * ! 993: * Return 1 if success, 0 if failure. ! 994: */ ! 995: static int ssinit(s_id) ! 996: int s_id; ! 997: { ! 998: int retval = 1; ! 999: unchar query_buf[MODESENSELEN]; ! 1000: ss_type * ssp = ss[s_id]; ! 1001: int dev = ((sscon.c_mind << 8) | 0x80 | (s_id << 4)); ! 1002: ! 1003: printf("SCSI ID %d LUN 0\n", s_id); ! 1004: if (retval) ! 1005: if (init_call(inquiry, s_id, query_buf)) { ! 1006: query_buf[INQUIRYLEN] = 0; ! 1007: #if (debug >= 2) ! 1008: devmsg(dev, query_buf + 8); ! 1009: #endif ! 1010: if (query_buf[0] == 0) { ! 1011: retval = 1; ! 1012: } else ! 1013: devmsg(dev, "Not Direct Access Device"); ! 1014: } else ! 1015: devmsg(dev, "Inquiry Failed"); ! 1016: ! 1017: if (retval) ! 1018: if (init_call(read_cap, s_id, query_buf)) { ! 1019: retval = 1; ! 1020: ssp->capacity = query_buf[3] | (query_buf[2] << 8) ! 1021: | (((long)(query_buf[1])) << 16) ! 1022: | (((long)(query_buf[0])) << 24); ! 1023: ssp->blocklen = query_buf[7] | (query_buf[6] << 8) ! 1024: | (((long)(query_buf[5])) << 16) ! 1025: | (((long)(query_buf[4])) << 24); ! 1026: ! 1027: printf("Capacity=%ld blocks Block length=%ld\n", ! 1028: ssp->capacity, ssp->blocklen); ! 1029: } else ! 1030: devmsg(dev, "Read Capacity Failed"); ! 1031: ! 1032: if (retval) ! 1033: if (init_call(mode_sense, s_id, query_buf)) { ! 1034: /* ! 1035: * Display physical drive parameters. ! 1036: */ ! 1037: #define FMT_PG (4+8+8+12) ! 1038: #define DDG_PG (4+8+8+12+24) ! 1039: unchar heads; ! 1040: unsigned short spt; ! 1041: ulong cyls; ! 1042: ! 1043: spt=((int)query_buf[FMT_PG+10]<<8) ! 1044: + query_buf[FMT_PG+11]; ! 1045: cyls=((int)query_buf[DDG_PG+2]<<16) ! 1046: + ((int)query_buf[DDG_PG+3]<<8) ! 1047: + query_buf[DDG_PG+4]; ! 1048: heads=query_buf[DDG_PG+5]; ! 1049: ! 1050: printf("Physical: cylinders=%ld ", cyls); ! 1051: printf("heads=%d ", heads); ! 1052: printf("spt=%d\n", spt); ! 1053: ! 1054: if (drv_parm[s_id].ncyl == 0) { ! 1055: drv_parm[s_id].ncyl = cyls; ! 1056: drv_parm[s_id].nhead = heads; ! 1057: drv_parm[s_id].nspt = spt; ! 1058: } else { ! 1059: printf("Logical: cylinders=%d ", ! 1060: drv_parm[s_id].ncyl); ! 1061: printf("heads=%d ", drv_parm[s_id].nhead); ! 1062: printf("spt=%d\n", drv_parm[s_id].nspt); ! 1063: } ! 1064: } else ! 1065: devmsg(dev, "Mode Sense Failed"); ! 1066: ! 1067: return retval; ! 1068: } ! 1069: ! 1070: /* ! 1071: * far_info_xfer() ! 1072: * ! 1073: * Do bus cycle information transfer phases. ! 1074: * This includes message in/out, command in/out, and data in/out. ! 1075: * ! 1076: * If cmdlen is nonzero, cmdbuf is an array of bytes of that length, ! 1077: * to be sent to the target. ! 1078: * ! 1079: * Return 1 if bus timeout did not occur, else 0. ! 1080: * ! 1081: * pseudocode: ! 1082: * ! 1083: * while (wait for REQ true or BUSY false on SCSI bus) ! 1084: * if (BUSY false) ! 1085: * break from while loop ! 1086: * else ! 1087: * switch (xfer phase = RS_CTRL_DATA|RS_I_O|RS_MESSAGE) ! 1088: * case XP_MSG_IN/XP_MSG_OUT/... ! 1089: * handle the indicated information transfer phase ! 1090: * endswitch ! 1091: * endif ! 1092: * endwhile ! 1093: */ ! 1094: static int far_info_xfer(s_id) ! 1095: int s_id; ! 1096: { ! 1097: int bus_timeout; ! 1098: unchar phase_type; ! 1099: unchar msg_in; ! 1100: int s; ! 1101: int bytes_to_send; ! 1102: ss_type * ssp = ss[s_id]; ! 1103: BUF * bp = ssp->bp; ! 1104: int xfer_good = 1; ! 1105: int xfer_count = bp->b_count - bp->b_resid; ! 1106: int irpts_masked; ! 1107: int block_done=0; ! 1108: ! 1109: ssp->cmd_bytes_out = 0; ! 1110: ssp->msg_in = -1; ! 1111: ! 1112: irpts_masked = 0; ! 1113: while (req_wait(&bus_timeout) && xfer_good) { ! 1114: phase_type = ffbyte(ss_csr) & (RS_MESSAGE|RS_I_O|RS_CTRL_DATA); ! 1115: if (!irpts_masked) { ! 1116: s = sphi(); ! 1117: irpts_masked = 1; ! 1118: } ! 1119: switch (xpmod(phase_type)) { ! 1120: case XP_MSG_IN: ! 1121: msg_in = ffbyte(ss_dat); ! 1122: switch(msg_in){ ! 1123: case MSG_CMD_CMPLT: ! 1124: PR4("Mcc"); ! 1125: ssp->msg_in = msg_in; ! 1126: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_IRPT); ! 1127: break; ! 1128: case MSG_DISCONNECT: ! 1129: PR4("Mdc"); ! 1130: ssp->msg_in = msg_in; ! 1131: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_IRPT); ! 1132: break; ! 1133: case MSG_SAVE_DPTR: ! 1134: PR4("Msd"); ! 1135: break; ! 1136: case MSG_RSTOR_DPTR: ! 1137: PR4("Mrd"); ! 1138: break; ! 1139: case MSG_ABORT: ! 1140: PR4("Mab"); ! 1141: break; ! 1142: case MSG_DEV_RESET: ! 1143: PR4("Mdr"); ! 1144: break; ! 1145: case MSG_IDENTIFY: ! 1146: PR4("Mmi"); ! 1147: break; ! 1148: case MSG_IDENT_DC: ! 1149: PR4("Mmd"); ! 1150: break; ! 1151: } ! 1152: break; ! 1153: case XP_MSG_OUT: ! 1154: PR4("MO"); ! 1155: /* ! 1156: * This case shouldn't happen. We weren't ! 1157: * asserting ATTENTION. Abort the bus cycle. ! 1158: */ ! 1159: sfbyte(ss_dat, MSG_NOP); ! 1160: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI); ! 1161: break; ! 1162: case XP_STAT_IN: ! 1163: PR4("SI"); ! 1164: ssp->cmdstat = ffbyte(ss_dat); ! 1165: break; ! 1166: case XP_CMD_OUT: ! 1167: /* ! 1168: * Ship out command bytes. ! 1169: * Reset SCSI bus if too many command bytes are wanted. ! 1170: */ ! 1171: bytes_to_send = ssp->cmdlen - ssp->cmd_bytes_out; ! 1172: if(bytes_to_send > 0) { ! 1173: sfbyte(ss_dat, ssp->cmdbuf[ssp->cmd_bytes_out++]); ! 1174: /* ! 1175: * If just sent last byte, allow interrupts. ! 1176: */ ! 1177: if (bytes_to_send == 1) { ! 1178: PR4("CO"); ! 1179: if (bp->b_req == BREAD) { ! 1180: if (irpts_masked) { ! 1181: spl(s); ! 1182: irpts_masked = 0; ! 1183: } ! 1184: } ! 1185: } ! 1186: } else { /* This case should not happen. */ ! 1187: xfer_good = 0; ! 1188: } ! 1189: break; ! 1190: case XP_DATA_IN: ! 1191: /* ! 1192: * If caller's buffer has room, keep incoming ! 1193: * data byte. ! 1194: */ ! 1195: if (block_done) { ! 1196: xfer_good = 0; ! 1197: PR1("Data in overrun"); ! 1198: } else if (bp->b_req != BREAD) { ! 1199: xfer_good = 0; ! 1200: } else { ! 1201: #if 0 ! 1202: int getbval; ! 1203: ! 1204: block_done=1; ! 1205: PR4("DI"); ! 1206: if(getbval = ss_getb(ss_dat, ! 1207: #ifdef _I386 ! 1208: bp->b_vaddr + xfer_count)) { ! 1209: #else ! 1210: bp->b_faddr + xfer_count)) { ! 1211: #endif /* _I386 */ ! 1212: xfer_good = 0; ! 1213: #if (DEBUG >= 1) ! 1214: printf("getb=%d ", getbval); ! 1215: #endif ! 1216: } ! 1217: #else ! 1218: block_done=1; ! 1219: #ifdef _I386 ! 1220: ! 1221: if (BSIZE != xpcopy(ss_dat, bp->b_paddr + xfer_count, ! 1222: BSIZE, SEG_386_KD|SEG_VIRT)) { ! 1223: devmsg(bp->b_dev, "XP_DATA_IN: ss_dat: %x, bp->bpaddr: %x, xfer_count: %x\n", ! 1224: ss_dat, bp->b_paddr, xfer_count); ! 1225: break; ! 1226: } ! 1227: #else ! 1228: ffcopy(ss_dat, bp->b_faddr + xfer_count, BSIZE); ! 1229: #endif /* _I386 */ ! 1230: #endif /* 0 */ ! 1231: } ! 1232: break; ! 1233: case XP_DATA_OUT: ! 1234: /* ! 1235: * Copy output buffer bytes to data register. ! 1236: */ ! 1237: if (block_done) { ! 1238: xfer_good = 0; ! 1239: PR1("Data out overrun"); ! 1240: } else if (bp->b_req != BWRITE) { ! 1241: xfer_good = 0; ! 1242: } else { ! 1243: #if 0 ! 1244: int putbval; ! 1245: block_done=1; ! 1246: PR4("DO"); ! 1247: if (putbval = ss_putb(ss_dat, ! 1248: #ifdef _I386 ! 1249: bp->b_vaddr + xfer_count)) { ! 1250: #else ! 1251: bp->b_faddr + xfer_count)) { ! 1252: #endif /* _I386 */ ! 1253: xfer_good = 0; ! 1254: #if (DEBUG >= 1) ! 1255: printf("putb=%d ", putbval); ! 1256: #endif ! 1257: } ! 1258: #else ! 1259: block_done=1; ! 1260: #ifdef _I386 ! 1261: if (BSIZE != pxcopy(bp->b_paddr + xfer_count, ss_dat, ! 1262: BSIZE, SEG_386_KD|SEG_VIRT)) { ! 1263: devmsg(bp->b_dev, "XP_DATA_OUT: bp->b_paddr: %x, xfer_count: %x, ss_dat: %x\n", ! 1264: bp->b_paddr, xfer_count, ss_dat); ! 1265: break; ! 1266: } ! 1267: ! 1268: #else ! 1269: ffcopy(bp->b_faddr + xfer_count, ss_dat, BSIZE); ! 1270: #endif /* _I386 */ ! 1271: #endif ! 1272: if (irpts_masked) { ! 1273: spl(s); ! 1274: irpts_masked = 0; ! 1275: } ! 1276: } ! 1277: break; ! 1278: default: ! 1279: break; ! 1280: } /* endswitch */ ! 1281: } ! 1282: if (irpts_masked) ! 1283: spl(s); ! 1284: ! 1285: #if (DEBUG >= 1) ! 1286: switch(ssp->cmdstat) { ! 1287: case -1: ! 1288: if (msg_in != MSG_DISCONNECT) ! 1289: printf("CS-",ssp->cmdstat); ! 1290: break; ! 1291: case CS_GOOD: ! 1292: break; ! 1293: case CS_CHECK: ! 1294: printf("CSK",ssp->cmdstat); ! 1295: break; ! 1296: case CS_BUSY: ! 1297: printf("CSY",ssp->cmdstat); ! 1298: break; ! 1299: case CS_RESERVED: ! 1300: default: ! 1301: printf("CS%x",ssp->cmdstat); ! 1302: } ! 1303: #endif ! 1304: ! 1305: return (bus_timeout) ? 0 : 1 ; ! 1306: } ! 1307: ! 1308: /* ! 1309: * req_wait() ! 1310: * ! 1311: * This routine is called at the start of each information transfer ! 1312: * phase and after the last such phase. ! 1313: * ! 1314: * It returns 1 if REQ is asserted on the SCSI bus, meaning another phase ! 1315: * may begin, and 0 otherwise. A REQ signal will not be seen if the function ! 1316: * times out or if BUSY drops. A value of 1 is written to the pointer argument ! 1317: * if timeout occurred, else 0 is written. ! 1318: */ ! 1319: static int req_wait(to_ptr) ! 1320: int *to_ptr; ! 1321: { ! 1322: int req_found; ! 1323: unsigned char status; ! 1324: ulong poll_ct; ! 1325: int s; ! 1326: ! 1327: s = splo(); ! 1328: *to_ptr = 1; ! 1329: req_found = 0; ! 1330: for (poll_ct = 0L; poll_ct < max_req_poll; poll_ct++) { ! 1331: status = ffbyte(ss_csr); ! 1332: if (status & RS_REQUEST) { ! 1333: req_found = 1; ! 1334: *to_ptr = 0; ! 1335: break; ! 1336: } else if ((status & RS_BUSY) == 0) { ! 1337: *to_ptr = 0; ! 1338: break; ! 1339: } ! 1340: } ! 1341: ! 1342: #if (DEBUG >= 1) ! 1343: if (*to_ptr) { ! 1344: printf("TX: s=%x ", status); ! 1345: } ! 1346: #endif ! 1347: ! 1348: spl(s); ! 1349: return req_found; ! 1350: } ! 1351: ! 1352: /* ! 1353: * req_sense() ! 1354: * ! 1355: * Request Sense for a device. The main reason for doing this is to ! 1356: * clear a standing Command Status of Device Check. ! 1357: * ! 1358: * Full results are discarded. Return 1 if Device returns No Sense or ! 1359: * or Unit Attention. Else return 0. ! 1360: * ! 1361: */ ! 1362: static int req_sense(s_id) ! 1363: int s_id; ! 1364: { ! 1365: unchar sense_buf[SENSELEN]; ! 1366: unchar cmdbuf[G0CMDLEN]; ! 1367: int ret = 0; ! 1368: ! 1369: cmdbuf[0] = ScmdREQUESTSENSE; ! 1370: cmdbuf[1] = 0; ! 1371: cmdbuf[2] = 0; ! 1372: cmdbuf[3] = 0; ! 1373: cmdbuf[4] = SENSELEN; ! 1374: cmdbuf[5] = 0; ! 1375: ! 1376: #if (DEBUG >= 2) ! 1377: {int i; for (i=0; i<SENSELEN; i++) sense_buf[i]=0;} ! 1378: #endif ! 1379: ! 1380: PR2("rqs:"); ! 1381: if (!start_arb()) { ! 1382: PR2("NO arb"); ! 1383: #if (DEBUG >= 2) ! 1384: printf("status=%x ", ffbyte(ss_csr)); ! 1385: #endif ! 1386: goto rqs_done; ! 1387: } ! 1388: ! 1389: if (!host_ident(s_id, 0)) { ! 1390: PR2("NO host ident"); ! 1391: #if (DEBUG >= 2) ! 1392: printf("status=%x ", ffbyte(ss_csr)); ! 1393: #endif ! 1394: goto rqs_done; ! 1395: } ! 1396: ! 1397: if(!local_info_xfer(cmdbuf, G0CMDLEN, sense_buf, SENSELEN, NULL, 0)) { ! 1398: PR2("NO local xfer"); ! 1399: goto rqs_done; ! 1400: } else { ! 1401: /* ! 1402: * Return 1 if drive responded with any of these sense keys: ! 1403: * 0x00 No Sense ! 1404: * 0x06 Unit Attention ! 1405: * 0x0B Aborted Command ! 1406: * In any of the above cases, a retry will likely succeed ! 1407: * without Buse Device Reset or SCSI Bus Reset. ! 1408: */ ! 1409: switch (sense_buf[2]) { ! 1410: case 0x00: ! 1411: case 0x06: ! 1412: case 0x0B: ! 1413: ret = 1; ! 1414: break; ! 1415: } /* endswitch */ ! 1416: } ! 1417: ! 1418: rqs_done: ! 1419: #if (DEBUG >= 2) ! 1420: { ! 1421: int i; ! 1422: ! 1423: for (i=0; i<SENSELEN;i++) ! 1424: printf("%x ", sense_buf[i]); ! 1425: printf("\n"); ! 1426: } ! 1427: #endif ! 1428: return ret; ! 1429: } ! 1430: ! 1431: /* ! 1432: * inquiry() ! 1433: * ! 1434: * Inquiry command for a device. ! 1435: * Find out if device is direct access, removable, etc. ! 1436: * ! 1437: * Put result of inquiry into supplied buffer. ! 1438: * Return 1 if command succeeds, else 0. ! 1439: */ ! 1440: static int inquiry(s_id, buf) ! 1441: int s_id; ! 1442: unchar * buf; ! 1443: { ! 1444: int ret = 0; ! 1445: unchar cmdbuf[G0CMDLEN]; ! 1446: ! 1447: cmdbuf[0] = ScmdINQUIRY; ! 1448: cmdbuf[1] = 0; ! 1449: cmdbuf[2] = 0; ! 1450: cmdbuf[3] = 0; ! 1451: cmdbuf[4] = INQUIRYLEN; ! 1452: cmdbuf[5] = 0; ! 1453: ! 1454: if (start_arb() && host_ident(s_id, 0) && ! 1455: local_info_xfer(cmdbuf, G0CMDLEN, buf, INQUIRYLEN, NULL, 0)) ! 1456: ret = 1; ! 1457: ! 1458: return ret; ! 1459: } ! 1460: ! 1461: /* ! 1462: * mode_sense() ! 1463: * ! 1464: * Mode Sense command for a device. ! 1465: * Use this to get disk parameters: ! 1466: * number of cylinders ! 1467: * number of heads ! 1468: * number of sectors per track. ! 1469: * ! 1470: * Put result of mode sense into supplied buffer. ! 1471: * Return 1 if command succeeds, else 0. ! 1472: */ ! 1473: static int mode_sense(s_id, buf) ! 1474: int s_id; ! 1475: unchar * buf; ! 1476: { ! 1477: int ret = 0; ! 1478: unchar cmdbuf[G0CMDLEN]; ! 1479: ! 1480: cmdbuf[0] = ScmdMODESENSE; ! 1481: cmdbuf[1] = 0; ! 1482: cmdbuf[2] = 0x3F; ! 1483: cmdbuf[3] = 0; ! 1484: cmdbuf[4] = MODESENSELEN; ! 1485: cmdbuf[5] = 0; ! 1486: ! 1487: if (start_arb() && host_ident(s_id, 0) && ! 1488: local_info_xfer(cmdbuf, G0CMDLEN, buf, MODESENSELEN, NULL, 0)) ! 1489: ret = 1; ! 1490: ! 1491: return ret; ! 1492: } ! 1493: ! 1494: /* ! 1495: * read_cap() ! 1496: * ! 1497: * Read Capacity command for a device. ! 1498: * ! 1499: * Return 1 if command succeeds, else 0. ! 1500: */ ! 1501: static int read_cap(s_id, buf) ! 1502: int s_id; ! 1503: unchar * buf; ! 1504: { ! 1505: int ret = 0; ! 1506: unchar cmdbuf[G1CMDLEN]; ! 1507: ! 1508: cmdbuf[0] = ScmdREADCAPACITY; ! 1509: cmdbuf[1] = 0; ! 1510: cmdbuf[2] = 0; ! 1511: cmdbuf[3] = 0; ! 1512: cmdbuf[4] = 0; ! 1513: cmdbuf[5] = 0; ! 1514: cmdbuf[6] = 0; ! 1515: cmdbuf[7] = 0; ! 1516: cmdbuf[8] = 0; ! 1517: cmdbuf[9] = 0; ! 1518: ! 1519: if (start_arb() && host_ident(s_id, 0) && ! 1520: local_info_xfer(cmdbuf, G1CMDLEN, buf, READCAPLEN, NULL, 0)) ! 1521: ret = 1; ! 1522: ! 1523: return ret; ! 1524: } ! 1525: ! 1526: /* ! 1527: * bus_dev_reset() ! 1528: * ! 1529: * Send Bus Device Reset message to the given SCSI id. ! 1530: * Return 1 if host adapter was not busy and no obvious timeouts occurred, ! 1531: * else 0. ! 1532: */ ! 1533: static int bus_dev_reset(s_id) ! 1534: { ! 1535: int bdr_ok = 1; ! 1536: int dev = ((sscon.c_mind << 8) | 0x80 | (s_id << 4)); ! 1537: ! 1538: PR1("BDR"); ! 1539: if (bdr_ok) { ! 1540: /* ! 1541: * Do ST0x arbitration. ! 1542: * ! 1543: * De-assert SCSI enable bit. ! 1544: * Write my SCSI id to port. ! 1545: * Start arbitration. ! 1546: */ ! 1547: sfbyte(ss_csr, WC_ENABLE_PRTY); ! 1548: sfbyte(ss_dat, host_id); ! 1549: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ARBITRATE); ! 1550: ! 1551: /* ! 1552: * SCSI spec says there is "no maximum" to the wait for ! 1553: * arbitration complete. ! 1554: */ ! 1555: if (!bus_wait(RS_ARBIT_COMPL << 8 | RS_ARBIT_COMPL)) { ! 1556: bdr_ok = 0; ! 1557: } ! 1558: } ! 1559: ! 1560: /* ! 1561: * Arbitration complete. Now select, with ATN to allow messages. ! 1562: */ ! 1563: if (bdr_ok) { ! 1564: sfbyte(ss_dat, host_id | (1 << s_id)); /* Write both SCSI id's */ ! 1565: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI | WC_ATTENTION | WC_SELECT); ! 1566: ! 1567: if (!bus_wait(RS_BUSY << 8 | RS_BUSY)) ! 1568: bdr_ok = 0; ! 1569: } ! 1570: ! 1571: if (bdr_ok) { ! 1572: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI | WC_ATTENTION); ! 1573: ! 1574: if (!bus_wait(((RS_REQUEST|RS_CTRL_DATA|RS_I_O|RS_MESSAGE) << 8) ! 1575: | (RS_REQUEST|RS_CTRL_DATA|RS_MESSAGE))) ! 1576: bdr_ok = 0; ! 1577: } ! 1578: ! 1579: if (bdr_ok) { ! 1580: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI); ! 1581: sfbyte(ss_dat, MSG_DEV_RESET); ! 1582: if (!bus_wait((0xFF << 8) | 0)) ! 1583: bdr_ok = 0; ! 1584: } ! 1585: ! 1586: return bdr_ok; ! 1587: } ! 1588: ! 1589: /* ! 1590: * chk_reconn() ! 1591: * ! 1592: * Check SELECT to see if any SCSI device has tried to reconnect to the host ! 1593: * adapter. Called if there is an interrupt, and by the timer in case ! 1594: * we somehow lose an interrupt. ! 1595: * ! 1596: * Return -1 if no reselect detected, or the SCSI ID of the reselecting ! 1597: * target if there is one. ! 1598: */ ! 1599: static int chk_reconn() ! 1600: { ! 1601: unchar csr, dat; ! 1602: int s_id = -1; ! 1603: ! 1604: csr = ffbyte(ss_csr); ! 1605: if (csr & (RS_SELECT | RS_I_O)) { ! 1606: dat = ffbyte(ss_dat); ! 1607: if ((dat & host_id) && (dat & NSDRIVE)) { ! 1608: dat &= ~host_id; ! 1609: s_id = 0; ! 1610: while (dat >>=1) ! 1611: s_id++; ! 1612: } ! 1613: } ! 1614: ! 1615: return s_id; ! 1616: } ! 1617: ! 1618: /* ! 1619: * ss_mach() ! 1620: * ! 1621: * Gives a distinct state machine for each target device. ! 1622: */ ! 1623: void ss_mach(s_id) ! 1624: int s_id; ! 1625: { ! 1626: ss_type * ssp = ss[s_id]; ! 1627: BUF * bp; ! 1628: ! 1629: do_sst_op = 1; /* plan to run this routine again in most cases */ ! 1630: while (do_sst_op) { ! 1631: bp = ssp->bp; /* nonpolled() below can change ssp->bp */ ! 1632: switch (ssp->state) { ! 1633: /* ! 1634: * Polling states execute whether ssp->waiting or not. ! 1635: */ ! 1636: case SST_POLL_ARBITN: ! 1637: PR3("XPAR"); ! 1638: if (ffbyte(ss_csr) & RS_ARBIT_COMPL) { ! 1639: ssp->waiting = 0; ! 1640: if (host_ident(s_id, 1)) ! 1641: do_connect(s_id); ! 1642: else ! 1643: recover(s_id, RV_P_TIMEOUT); ! 1644: } else { ! 1645: if (ssp->expired) { ! 1646: ssp->expired = 0; ! 1647: recover(s_id, RV_A_TIMEOUT); ! 1648: } else ! 1649: do_sst_op = 0; ! 1650: } ! 1651: break; ! 1652: case SST_POLL_RESELECT: ! 1653: PR3("XPRS"); ! 1654: if (TGT_RSEL) { ! 1655: ssp->waiting = 0; ! 1656: if (host_claimed == -1) ! 1657: host_claimed = s_id; ! 1658: else if (host_claimed != s_id) { ! 1659: #if (DEBUG >= 1) ! 1660: printf("%d->%d ", host_claimed, s_id); ! 1661: #endif ! 1662: } ! 1663: if (rsel_handshake()) { ! 1664: do_connect(s_id); ! 1665: } else { ! 1666: recover(s_id, RV_P_TIMEOUT); ! 1667: } ! 1668: } else { /* Reselect poll is negative */ ! 1669: if (ssp->expired) { ! 1670: ssp->expired = 0; ! 1671: recover(s_id, RV_R_TIMEOUT); ! 1672: } else ! 1673: do_sst_op = 0; ! 1674: } ! 1675: break; ! 1676: case SST_POLL_BEGIN_IO: ! 1677: PR3("XPBI"); ! 1678: if (bp == NULL) ! 1679: ssp->state = SST_DEQUEUE; ! 1680: else { ! 1681: /* ! 1682: * At this point a SCSI command is about to ! 1683: * be initiated. It may be a retry. ! 1684: */ ! 1685: if (host_claimed == -1 && BUS_FREE && BUS_FREE) { ! 1686: ssp->waiting = 0; ! 1687: init_pointers(s_id); ! 1688: if (start_arb()) { ! 1689: host_claimed = s_id; ! 1690: if (host_ident(s_id, 1)) { ! 1691: do_connect(s_id); ! 1692: } else { ! 1693: recover(s_id, RV_P_TIMEOUT); ! 1694: } ! 1695: } else { ! 1696: /* ! 1697: * If arbitration does not succeed right away, it is usually ! 1698: * because another drive is trying to reselect the host. ! 1699: */ ! 1700: set_timeout(s_id, DELAY_ARB); ! 1701: } ! 1702: } else { /* host busy or bus not free */ ! 1703: int o_id; ! 1704: ! 1705: if ((o_id = chk_reconn()) != -1) ! 1706: defer(dummy_reconn, s_id); ! 1707: ++ssp->avl_count; ! 1708: if (ssp->avl_count >= MAX_AVL_COUNT) ! 1709: recover(s_id, RV_BF_TIMEOUT); ! 1710: else ! 1711: set_timeout(s_id, DELAY_BSY); ! 1712: } ! 1713: } ! 1714: break; ! 1715: default: ! 1716: if (ssp->waiting) ! 1717: do_sst_op = 0; ! 1718: else { ! 1719: /* ! 1720: * Nonpolling states execute only if no ! 1721: * target timer is running. ! 1722: */ ! 1723: nonpolled(s_id); ! 1724: } ! 1725: } /* endswitch */ ! 1726: } /* endwhile */ ! 1727: } ! 1728: ! 1729: /* ! 1730: * nonpolled() ! 1731: * ! 1732: * Part of ss_mach() - handling of nonpolling states is taken out simply ! 1733: * for readability. ! 1734: */ ! 1735: static void nonpolled(s_id) ! 1736: int s_id; ! 1737: { ! 1738: ss_type * ssp = ss[s_id]; ! 1739: BUF * bp = ssp->bp; ! 1740: struct fdisk_s *fdp; ! 1741: int partition; ! 1742: dev_t dev; ! 1743: ! 1744: switch (ssp->state) { ! 1745: case SST_BUS_DEV_RESET: ! 1746: PR3("XBDR"); ! 1747: if (bus_dev_reset(s_id)) { ! 1748: do_sst_op = 0; ! 1749: set_timeout(s_id, DELAY_BDR); ! 1750: ssp->state = SST_REQ_SENSE; ! 1751: } else ! 1752: recover(s_id, RV_P_TIMEOUT); ! 1753: break; ! 1754: case SST_DEQUEUE: ! 1755: if(bufq_rd_head(s_id) != NULL && !ssp->busy) { ! 1756: PR3("XDQU"); ! 1757: ssp->busy = 1; ! 1758: bp = bufq_rm_head(s_id); ! 1759: ssp->bp = bp; ! 1760: dev = bp->b_dev; ! 1761: partition = DEV_PARTN(dev); ! 1762: if (dev & SDEV) ! 1763: partition = WHOLE_DRIVE; ! 1764: fdp = ssp->parmp; ! 1765: if (partition != WHOLE_DRIVE) ! 1766: ssp->bno = fdp[partition].p_base + bp->b_bno; ! 1767: else ! 1768: ssp->bno = bp->b_bno; ! 1769: if (bp->b_req == BREAD) ! 1770: ssp->cmdbuf[0] = ScmdREADEXTENDED; ! 1771: else ! 1772: ssp->cmdbuf[0] = ScmdWRITEXTENDED; ! 1773: ssp->cmdbuf[1] = 0; ! 1774: ssp->cmdbuf[2] = ssp->bno >> 24; ! 1775: ssp->cmdbuf[3] = ssp->bno >> 16; ! 1776: ssp->cmdbuf[4] = ssp->bno >> 8; ! 1777: ssp->cmdbuf[5] = ssp->bno; ! 1778: ssp->cmdbuf[6] = 0; ! 1779: ssp->cmdbuf[7] = 0; ! 1780: ssp->cmdbuf[8] = 1; ! 1781: ssp->cmdbuf[9] = 0; ! 1782: ssp->cmdlen = G1CMDLEN; ! 1783: init_pointers(s_id); ! 1784: ssp->bdr_count = 0; ! 1785: ssp->bsy_count = 0; ! 1786: ssp->try_count = 0; ! 1787: ssp->state = SST_POLL_BEGIN_IO; ! 1788: } else /* queue is empty or ssp->busy */ ! 1789: do_sst_op = 0; ! 1790: break; ! 1791: case SST_HIPRI_RESET: ! 1792: case SST_LOPRI_RESET: ! 1793: PR1("XRST"); ! 1794: /* ! 1795: * SST_LOPRI_RESET is same as SST_HIPRI_RESET for now. ! 1796: * Later, can implement a delay to allow other targets to ! 1797: * finish pending operations. ! 1798: */ ! 1799: if (host_claimed == s_id || host_claimed == -1) { ! 1800: host_claimed = s_id; ! 1801: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI | WC_SCSI_RESET); /* reset ON */ ! 1802: ssp->state = SST_RESET_OFF; ! 1803: set_timeout(s_id, DELAY_RST); ! 1804: PR1("+"); ! 1805: } else ! 1806: set_timeout(s_id, DELAY_RST); ! 1807: break; ! 1808: case SST_REQ_SENSE: ! 1809: PR1("XRQS"); ! 1810: /* ! 1811: * Come here at end of SCSI Bus reset (and at other times). ! 1812: * If we have host claimed, release it. ! 1813: */ ! 1814: if (host_claimed == s_id) ! 1815: host_claimed = -1; ! 1816: if (req_sense(s_id)) ! 1817: ssp->state = SST_POLL_BEGIN_IO; ! 1818: else ! 1819: recover(s_id, RV_P_TIMEOUT); ! 1820: break; ! 1821: case SST_RESET_OFF: ! 1822: PR3("XRFF"); ! 1823: sfbyte(ss_csr, WC_ENABLE_PRTY); /* reset OFF */ ! 1824: ssp->state = SST_REQ_SENSE; ! 1825: set_timeout(s_id, DELAY_RST); ! 1826: } /* endswitch */ ! 1827: } ! 1828: ! 1829: /* ! 1830: * start_arb() ! 1831: * ! 1832: * return 1 if host adapter returned Arbitration Complete within allotted ! 1833: * number of tries, else 0 ! 1834: */ ! 1835: static int start_arb() ! 1836: { ! 1837: int ret = 0; ! 1838: int poll_ct; ! 1839: ! 1840: sfbyte(ss_csr, WC_ENABLE_PRTY); ! 1841: sfbyte(ss_dat, host_id); ! 1842: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ARBITRATE); ! 1843: ! 1844: /* ! 1845: * SCSI spec says there is "no maximum" to the wait for arbitration ! 1846: * complete. ! 1847: */ ! 1848: for (poll_ct = 0; poll_ct < HIPRI_RETRIES; poll_ct++) { ! 1849: if (ffbyte(ss_csr) & RS_ARBIT_COMPL) { ! 1850: ret = 1; ! 1851: break; ! 1852: } else if (chk_reconn() != -1) { ! 1853: sfbyte(ss_csr, WC_ENABLE_PRTY); ! 1854: break; ! 1855: } ! 1856: } ! 1857: #if (DEBUG >= 1) ! 1858: if (!ret) ! 1859: PR1("oSA"); ! 1860: #endif ! 1861: return ret; ! 1862: } ! 1863: ! 1864: /* ! 1865: * host_ident() ! 1866: * ! 1867: * This routine is the bridge in a SCSI bus cycle between Abitration ! 1868: * Complete and the Information Transfer phases. ! 1869: * ! 1870: * return 1 if everything went ok, 0 in case of timeout ! 1871: */ ! 1872: static int host_ident(s_id, disconnect) ! 1873: int s_id; ! 1874: int disconnect; ! 1875: { ! 1876: int ret = 0; ! 1877: ! 1878: /* ! 1879: * Arbitration complete. Now select, with ATN to allow messages. ! 1880: */ ! 1881: sfbyte(ss_dat, host_id | (1 << s_id)); /* Write both SCSI id's */ ! 1882: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI | WC_ATTENTION | WC_SELECT); ! 1883: ! 1884: if (bus_wait(RS_BUSY << 8 | RS_BUSY)) { ! 1885: /* ! 1886: * Assert ATTN so target expects incoming message byte. ! 1887: */ ! 1888: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI | WC_ATTENTION); ! 1889: ! 1890: if (bus_wait(((RS_REQUEST|RS_CTRL_DATA|RS_I_O|RS_MESSAGE) << 8) ! 1891: | (RS_REQUEST|RS_CTRL_DATA|RS_MESSAGE))) { ! 1892: if (disconnect) { ! 1893: sfbyte(ss_dat, MSG_IDENT_DC); ! 1894: } else { ! 1895: sfbyte(ss_dat, MSG_IDENTIFY); ! 1896: } ! 1897: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI | WC_ENABLE_IRPT); ! 1898: ret = 1; ! 1899: } else { ! 1900: PR1("oHI2"); ! 1901: } ! 1902: } else { ! 1903: PR1("oHI1"); ! 1904: } ! 1905: return ret; ! 1906: } ! 1907: ! 1908: /* ! 1909: * rsel_handshake() ! 1910: * ! 1911: * After Reselect is detected, a couple steps are needed before entering ! 1912: * Information Transfer phases. This routine does those steps. ! 1913: * ! 1914: * return 1 if ok, 0 in case of timeout. ! 1915: */ ! 1916: static int rsel_handshake() ! 1917: { ! 1918: int ret = 0; ! 1919: ! 1920: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI | WC_BUSY); ! 1921: if (bus_wait(RS_SELECT << 8 | 0)) { ! 1922: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI); ! 1923: ret = 1; ! 1924: } ! 1925: return ret; ! 1926: } ! 1927: ! 1928: /* ! 1929: * set_timeout() ! 1930: * ! 1931: * Start a timer so as not to wait forever in case something goes wrong while ! 1932: * waiting for an event. Available delays are: ! 1933: * ! 1934: * DELAY_ARB - wait for arbitration complete ! 1935: * DELAY_BDR - allow settling time after Bus Device Reset ! 1936: * DELAY_BSY - wait for not HOST_BUSY and bus free ! 1937: * DELAY_RES - wait for reselect by target ! 1938: * DELAY_RST - allow settling times when doing SCSI Bus Reset ! 1939: * ! 1940: * Second argument is number of clock ticks to wait until timer expiration. ! 1941: */ ! 1942: static void set_timeout(s_id, delay) ! 1943: int s_id, delay; ! 1944: { ! 1945: ss_type * ssp = ss[s_id]; ! 1946: ! 1947: ssp->expired = 0; ! 1948: ssp->waiting = 1; ! 1949: do_sst_op = 0; ! 1950: timeout(&(ssp->tim), delay, stop_timeout, s_id); ! 1951: } ! 1952: ! 1953: /* ! 1954: * stop_timeout() ! 1955: * ! 1956: * Called on expiration of the timer for a given target. ! 1957: * Don't expire a timer if it's no longer active. ! 1958: */ ! 1959: static void stop_timeout(s_id) ! 1960: int s_id; ! 1961: { ! 1962: ss_type * ssp = ss[s_id]; ! 1963: ! 1964: if (ssp->waiting) { ! 1965: ssp->expired = 1; ! 1966: ssp->waiting = 0; ! 1967: } ! 1968: ss_mach(s_id); ! 1969: } ! 1970: ! 1971: /* ! 1972: * init_pointers() ! 1973: * ! 1974: * Initialize command and data pointers when starting (or restarting) ! 1975: * a block i/o command. ! 1976: */ ! 1977: static void init_pointers(s_id) ! 1978: int s_id; ! 1979: { ! 1980: ss_type * ssp = ss[s_id]; ! 1981: BUF * bp = ssp->bp; ! 1982: ! 1983: ssp->cmdstat = -1; ! 1984: ssp->cmd_bytes_out = 0; ! 1985: ssp->avl_count = 0; ! 1986: } ! 1987: ! 1988: /* ! 1989: * recover() ! 1990: * ! 1991: * This routine is called directly or indirectly from ss_mach(). It ! 1992: * determines what to do when the interface fails to behave as desired. ! 1993: * ! 1994: * Arguments are the SCSI id of the target HDC and an error type. ! 1995: * Error types are: ! 1996: * ! 1997: * RV_A_TIMEOUT (arbitration timeout) ! 1998: * Host adapter takes too long to respond with arbitration complete. ! 1999: * ! 2000: * RV_P_TIMEOUT (protocol timeout) ! 2001: * Timeout waiting for desired SCSI bus status while connected to a target. ! 2002: * ! 2003: * RV_R_TIMEOUT (reconnect timeout) ! 2004: * Timeout after target disconnects, waiting for reconnect. ! 2005: * ! 2006: * RV_BF_TIMEOUT (bus free timeout) ! 2007: * Waited too long for host not busy and BUS_FREE. ! 2008: * ! 2009: * RV_CS_BUSY (target device busy) ! 2010: * Command status returned was Busy. ! 2011: * ! 2012: * RV_CS_CHECK (target device check) ! 2013: * Command status returned was CHECK. ! 2014: * ! 2015: * Whenever an error occurs, one of the above inputs, together with the SCSI id ! 2016: * of the target, is sent to the recovery process. The recovery process in turn ! 2017: * programs the next state for the machine. ! 2018: */ ! 2019: static void recover(s_id, errtype) ! 2020: int s_id; ! 2021: RV_TYPE errtype; ! 2022: { ! 2023: ss_type * ssp = ss[s_id]; ! 2024: BUF * bp = ssp->bp; ! 2025: ! 2026: #if (DEBUG >= 1) ! 2027: int foo; ! 2028: if ((foo=chk_reconn()) != -1) ! 2029: printf("HONK%d ", foo); ! 2030: #endif ! 2031: ! 2032: ++ssp->try_count; ! 2033: if (ssp->try_count < MAX_TRY_COUNT) { ! 2034: ! 2035: switch (errtype) { ! 2036: ! 2037: case RV_CS_BUSY: ! 2038: ++ssp->bsy_count; ! 2039: if (ssp->bsy_count < MAX_BSY_COUNT) { ! 2040: ssp->state = SST_POLL_BEGIN_IO; ! 2041: set_timeout(s_id, DELAY_BSY); ! 2042: } else ! 2043: ssp->state = SST_BUS_DEV_RESET; ! 2044: break; ! 2045: ! 2046: case RV_CS_CHECK: ! 2047: ssp->state = SST_REQ_SENSE; ! 2048: break; ! 2049: ! 2050: case RV_P_TIMEOUT: ! 2051: /* fall thru */ ! 2052: case RV_R_TIMEOUT: ! 2053: ++ssp->bdr_count; ! 2054: if (ssp->bdr_count < MAX_BDR_COUNT) ! 2055: ssp->state = SST_BUS_DEV_RESET; ! 2056: else ! 2057: ssp->state = SST_LOPRI_RESET; ! 2058: break; ! 2059: ! 2060: case RV_BF_TIMEOUT: ! 2061: /* fall thru */ ! 2062: case RV_A_TIMEOUT: ! 2063: ssp->state = SST_HIPRI_RESET; ! 2064: } ! 2065: } else { /* try_count >= MAX_TRY_COUNT */ ! 2066: if (bp) { ! 2067: bp->b_flag |= BFERR; ! 2068: printf("(%d,%d): ", major(bp->b_dev), minor(bp->b_dev)); ! 2069: printf("%s error bno=%ld\n", ! 2070: (bp->b_req == BREAD) ? "read" : "write", ! 2071: bp->b_bno); ! 2072: } ! 2073: ss_finished(s_id); ! 2074: } ! 2075: } ! 2076: ! 2077: /* ! 2078: * ss_finished ! 2079: * ! 2080: * Release current i/o buffer to the O/S. ! 2081: */ ! 2082: static void ss_finished(s_id) ! 2083: int s_id; ! 2084: { ! 2085: ss_type * ssp = ss[s_id]; ! 2086: BUF * bp = ssp->bp; ! 2087: int go_again = 1; ! 2088: ! 2089: if (host_claimed == s_id) ! 2090: host_claimed = -1; ! 2091: ssp->busy = 0; ! 2092: if (bp) { ! 2093: if (!(bp->b_flag & BFERR)) ! 2094: bp->b_resid -= BSIZE; ! 2095: if ((bp->b_flag & BFERR) || bp->b_resid == 0) { ! 2096: ssp->bp = NULL; ! 2097: bdone(bp); ! 2098: go_again = 0; ! 2099: } ! 2100: } ! 2101: if (go_again) { ! 2102: ssp->state = SST_POLL_BEGIN_IO; ! 2103: ssp->bdr_count = 0; ! 2104: ssp->bsy_count = 0; ! 2105: ssp->try_count = 0; ! 2106: ! 2107: ssp->bno++; ! 2108: ssp->cmdbuf[2] = ssp->bno >> 24; ! 2109: ssp->cmdbuf[3] = ssp->bno >> 16; ! 2110: ssp->cmdbuf[4] = ssp->bno >> 8; ! 2111: ssp->cmdbuf[5] = ssp->bno; ! 2112: } else { ! 2113: /* ! 2114: * After processing a kernel i/o request, stop the ! 2115: * state machine for the current id. Then start ! 2116: * this or some other machine which has a request ! 2117: * pending. ! 2118: */ ! 2119: do_sst_op = 0; ! 2120: ssp->state = SST_DEQUEUE; ! 2121: next_req(s_id); ! 2122: } ! 2123: } ! 2124: ! 2125: /* ! 2126: * next_req() ! 2127: * ! 2128: * Given the SCSI id where an i/o request just completed, start handling ! 2129: * another i/o request - which may be for the same or other SCSI id. ! 2130: * For now, use round-robin scheduling. ! 2131: */ ! 2132: static void next_req(s_id) ! 2133: int s_id; ! 2134: { ! 2135: int next_id = s_id; ! 2136: ! 2137: while (1) { ! 2138: next_id++; ! 2139: if (next_id >= MAX_SCSI_ID) ! 2140: next_id = 0; ! 2141: if (ss[next_id] ! 2142: && (ss[next_id]->state != SST_DEQUEUE || bufq_rd_head(next_id))) { ! 2143: defer(ss_mach, next_id); ! 2144: break; ! 2145: } ! 2146: if (next_id == s_id) ! 2147: break; ! 2148: } ! 2149: } ! 2150: ! 2151: /* ! 2152: * do_connect() ! 2153: * ! 2154: * This function is called when the host is successfully connected to ! 2155: * the target. It invokes information transfer protocol and then sets ! 2156: * up some sort of recovery unless the command completed successfully ! 2157: * or there was a normal disconnect. ! 2158: */ ! 2159: static void do_connect(s_id) ! 2160: int s_id; ! 2161: { ! 2162: int result; ! 2163: ss_type * ssp = ss[s_id]; ! 2164: ! 2165: result = far_info_xfer(s_id); ! 2166: if (!result) ! 2167: recover(s_id, RV_P_TIMEOUT); ! 2168: else if (ssp->msg_in == MSG_DISCONNECT) { ! 2169: ssp->state = SST_POLL_RESELECT; ! 2170: set_timeout(s_id, DELAY_RES); ! 2171: #if 0 ! 2172: if (host_claimed == s_id) ! 2173: host_claimed = -1; ! 2174: #endif ! 2175: } else if (ssp->msg_in == MSG_CMD_CMPLT && ssp->cmdstat == CS_GOOD) ! 2176: ss_finished(s_id); ! 2177: else if (ssp->cmdstat == CS_BUSY) ! 2178: recover(s_id, RV_CS_BUSY); ! 2179: else if (ssp->cmdstat == CS_CHECK) ! 2180: recover(s_id, RV_CS_CHECK); ! 2181: else /* something else went wrong */ ! 2182: recover(s_id, RV_P_TIMEOUT); ! 2183: } ! 2184: ! 2185: /* ! 2186: * local_info_xfer() ! 2187: * ! 2188: * Do bus cycle information transfer phases. ! 2189: * Transfer is for a command which will produce local results in the driver. ! 2190: * Other ...info_xfer routine handles kernel block i/o commands. ! 2191: * ! 2192: * Return 1 if transfer succeeded, else 0. ! 2193: * ! 2194: */ ! 2195: static int local_info_xfer(cmdbuf, cmdlen, inbuf, inlen, outbuf, outlen) ! 2196: unchar * cmdbuf, * inbuf, * outbuf; ! 2197: uint cmdlen, inlen, outlen; ! 2198: { ! 2199: int bus_timeout; ! 2200: unchar phase_type; ! 2201: int s; ! 2202: int cmd_bytes_out = 0; ! 2203: int data_bytes_in = 0; ! 2204: int data_bytes_out = 0; ! 2205: int ret = 0; ! 2206: int xfer_good = 1; ! 2207: int cmdstat = -1; ! 2208: int msg_in = -1; ! 2209: #if (DEBUG >= 1) ! 2210: int x, xct=0; ! 2211: unchar xch[100]; ! 2212: #endif ! 2213: ! 2214: s = sphi(); ! 2215: while (req_wait(&bus_timeout) && xfer_good) { ! 2216: phase_type = ffbyte(ss_csr) & (RS_MESSAGE|RS_I_O|RS_CTRL_DATA); ! 2217: #if (DEBUG >= 1) ! 2218: if (xct < 100) ! 2219: xch[xct++]=phase_type; ! 2220: #endif ! 2221: switch (xpmod(phase_type)) { ! 2222: case XP_MSG_IN: ! 2223: msg_in = ffbyte(ss_dat); ! 2224: switch(msg_in){ ! 2225: case MSG_CMD_CMPLT: ! 2226: case MSG_DISCONNECT: ! 2227: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_IRPT); ! 2228: break; ! 2229: } ! 2230: break; ! 2231: case XP_MSG_OUT: ! 2232: /* ! 2233: * This case shouldn't happen. We weren't ! 2234: * asserting ATTENTION. ! 2235: */ ! 2236: sfbyte(ss_dat, MSG_NOP); ! 2237: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI); ! 2238: break; ! 2239: case XP_STAT_IN: ! 2240: cmdstat = ffbyte(ss_dat); ! 2241: break; ! 2242: case XP_CMD_OUT: ! 2243: /* ! 2244: * Ship out command bytes. ! 2245: */ ! 2246: if (cmd_bytes_out < cmdlen) { ! 2247: sfbyte(ss_dat, cmdbuf[cmd_bytes_out++]); ! 2248: #if 1 ! 2249: /* ! 2250: * If just sent last byte, allow interrupts. ! 2251: */ ! 2252: if (cmd_bytes_out == cmdlen) { ! 2253: spl(s); ! 2254: s = sphi(); ! 2255: } ! 2256: #endif ! 2257: } else { /* This case should not happen. */ ! 2258: xfer_good = 0; ! 2259: } ! 2260: break; ! 2261: case XP_DATA_IN: ! 2262: /* ! 2263: * If caller's buffer has room, keep incoming ! 2264: * data byte. Else toss it. ! 2265: */ ! 2266: if (data_bytes_in < inlen) { ! 2267: #if 0 ! 2268: do { ! 2269: inbuf[data_bytes_in++] = ffbyte(ss_dat); ! 2270: } while (data_bytes_in < inlen); ! 2271: #else ! 2272: inbuf[data_bytes_in++] = ffbyte(ss_dat); ! 2273: #endif ! 2274: } else ! 2275: xfer_good = 0; ! 2276: break; ! 2277: case XP_DATA_OUT: ! 2278: /* ! 2279: * Copy output buffer bytes to data register. ! 2280: */ ! 2281: if (data_bytes_out < outlen) { ! 2282: sfbyte(outbuf[data_bytes_out++], ss_dat); ! 2283: } else { /* This case should not happen. */ ! 2284: xfer_good = 0; ! 2285: } ! 2286: break; ! 2287: default: ! 2288: break; ! 2289: } /* endswitch */ ! 2290: } ! 2291: spl(s); ! 2292: ! 2293: if (bus_timeout) { ! 2294: PR1("oLX1"); ! 2295: } else if (!xfer_good) { ! 2296: PR1("oLX2"); ! 2297: } else if (cmdstat != CS_GOOD) { ! 2298: PR1("oLX3"); ! 2299: #if (DEBUG >= 1) ! 2300: printf("cmdstat=%x ", cmdstat); ! 2301: #endif ! 2302: } else ! 2303: ret = 1; ! 2304: #if (DEBUG >= 1) ! 2305: if (!ret) { ! 2306: printf("csr=%x ", ffbyte(ss_csr)); ! 2307: printf("xct=%d ", xct); ! 2308: for (x=0; x < xct; x++) ! 2309: printf("%x ", xch[x]); ! 2310: } ! 2311: #endif ! 2312: ! 2313: return ret; ! 2314: } ! 2315: ! 2316: /* ! 2317: * scsireset() ! 2318: * ! 2319: * Reset the SCSI bus. ! 2320: * Allow settling time when turning reset on/off. ! 2321: * Settling times were determined empirically. ! 2322: * Each tick is 10 msec. ! 2323: */ ! 2324: static void scsireset() ! 2325: { ! 2326: int s; ! 2327: ! 2328: #if (DEBUG >= 1) ! 2329: printf("scsireset "); ! 2330: #endif ! 2331: s = splo(); ! 2332: sfbyte(ss_csr, WC_ENABLE_PRTY | WC_ENABLE_SCSI | WC_SCSI_RESET); ! 2333: ssdelay(RESET_TICKS); ! 2334: sfbyte(ss_csr, WC_ENABLE_PRTY); ! 2335: ssdelay(RESET_TICKS); ! 2336: spl(s); ! 2337: } ! 2338: ! 2339: /* ! 2340: * ssdelay() ! 2341: * ! 2342: * Delay for some number of arbitrary ticks. ! 2343: * ! 2344: * Using sleep() causes a panic if this driver is linked to the kernel, ! 2345: * even though this routine is called only via ssload(). ! 2346: */ ! 2347: static void ssdelay(ticks) ! 2348: int ticks; ! 2349: { ! 2350: #if 0 ! 2351: timeout(&delay_tim, ticks, wakeup, (int)&delay_tim); ! 2352: sleep((char *)&delay_tim, CVPAUSE, IVPAUSE, SVPAUSE); ! 2353: #else ! 2354: int i, j; ! 2355: ! 2356: for (i = 0; i < ticks; i++) ! 2357: for (j = 0; j < LOAD_DELAY; j++); ! 2358: #endif ! 2359: } ! 2360: ! 2361: /* ! 2362: * init_call() ! 2363: * ! 2364: * Call SCSI command function during initialization, with error recovery. ! 2365: * If the simple command fails, try a Bus Device Reset, then SCSI Bus reset. ! 2366: */ ! 2367: static int init_call(fn, s_id, buf) ! 2368: int (*fn)(); ! 2369: int s_id; ! 2370: unchar * buf; ! 2371: { ! 2372: int ret = 1; ! 2373: int i; ! 2374: int o_id; ! 2375: int s; ! 2376: s=sphi(); ! 2377: for (i = 0; i < 2; i++) { ! 2378: o_id = chk_reconn(); ! 2379: if (o_id != -1) ! 2380: dummy_reconn(s_id); ! 2381: if ((*fn)(s_id, buf)) ! 2382: goto init_call_done; ! 2383: ! 2384: req_sense(s_id); ! 2385: if ((*fn)(s_id, buf)) ! 2386: goto init_call_done; ! 2387: ! 2388: if (bus_dev_reset(s_id)) { ! 2389: ssdelay(RESET_TICKS); ! 2390: req_sense(s_id); ! 2391: if ((*fn)(s_id, buf)) ! 2392: goto init_call_done; ! 2393: } ! 2394: ! 2395: scsireset(); ! 2396: req_sense(s_id); ! 2397: if ((*fn)(s_id, buf)) ! 2398: goto init_call_done; ! 2399: } ! 2400: ! 2401: ret = 0; ! 2402: ! 2403: init_call_done: ! 2404: spl(s); ! 2405: return ret; ! 2406: } ! 2407: ! 2408: /* ! 2409: * xpmod() ! 2410: * ! 2411: * Command/Data and Message bits are swapped on-board (outside the chip) ! 2412: * on older Future Domain host boards. ! 2413: */ ! 2414: static unchar xpmod(oldphase) ! 2415: unchar oldphase; ! 2416: { ! 2417: unchar ret = oldphase; ! 2418: ! 2419: if (swap_status_bits) { ! 2420: ret &= ~(RS_CTRL_DATA | RS_MESSAGE); ! 2421: if (oldphase & RS_MESSAGE) ! 2422: ret |= RS_CTRL_DATA; ! 2423: if (oldphase & RS_CTRL_DATA) ! 2424: ret |= RS_MESSAGE; ! 2425: } ! 2426: return ret; ! 2427: } ! 2428: ! 2429: /* ! 2430: * tbparms() ! 2431: * ! 2432: * If the drive table has already been patched for this SCSI id, do nothing. ! 2433: * Otherwise, given the real-mode drive number (tbnum) and the SCSI id (s_id), ! 2434: * look for drive parameters from tertiary boot, and copy into driver ! 2435: * data block if we find them. ! 2436: */ ! 2437: static void tbparms(tbnum, s_id) ! 2438: int tbnum, s_id; ! 2439: { ! 2440: FIFO *ffp; ! 2441: typed_space *tp; ! 2442: extern typed_space boot_gift; ! 2443: ! 2444: if (drv_parm[s_id].ncyl == 0 ! 2445: && F_NULL != (ffp = fifo_open(&boot_gift, 0))) { ! 2446: ! 2447: if (tp = fifo_read(ffp)) { ! 2448: BIOS_DISK *bdp = (BIOS_DISK *)tp->ts_data; ! 2449: if ((T_BIOS_DISK == tp->ts_type) && ! 2450: (tbnum == bdp->dp_drive) ) { ! 2451: drv_parm[s_id].ncyl = bdp->dp_cylinders; ! 2452: drv_parm[s_id].nhead = bdp->dp_heads; ! 2453: drv_parm[s_id].nspt = bdp->dp_sectors; ! 2454: } ! 2455: } ! 2456: fifo_close(ffp); ! 2457: } ! 2458: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.