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