|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993-1989 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: scsi.c ! 28: * Author: Alessandro Forin, Carnegie Mellon University ! 29: * Date: 9/90 ! 30: * ! 31: * Middle layer of the SCSI driver: chip independent functions ! 32: * This file contains Controller and Device-independent functions ! 33: */ ! 34: ! 35: #include <scsi.h> ! 36: ! 37: #if NSCSI > 0 ! 38: #include <platforms.h> ! 39: ! 40: #include <machine/machspl.h> /* spl definitions */ ! 41: ! 42: #include <mach/std_types.h> ! 43: #include <sys/types.h> ! 44: #include <scsi/compat_30.h> ! 45: ! 46: #include <chips/busses.h> ! 47: #include <scsi/scsi.h> ! 48: #include <scsi/scsi2.h> ! 49: #include <scsi/scsi_defs.h> ! 50: #include <machine/machspl.h> ! 51: ! 52: ! 53: ! 54: #ifdef VAXSTATION ! 55: /* We run some of this code on the interrupt stack */ ! 56: #undef spl0 ! 57: #define spl0() spl1() ! 58: #endif /*VAXSTATION*/ ! 59: ! 60: /* ! 61: * Overall driver state ! 62: */ ! 63: ! 64: target_info_t scsi_target_data[NSCSI*8]; /* per target state */ ! 65: scsi_softc_t scsi_softc_data[NSCSI]; /* per HBA state */ ! 66: scsi_softc_t *scsi_softc[NSCSI]; /* quick access&checking */ ! 67: ! 68: /* ! 69: * If a specific target should NOT be asked to go synchronous ! 70: * then its bit in this bitmap should be set. Each SCSI controller ! 71: * (Host Bus Adapter) can hold at most 8 targets --> use one ! 72: * byte per controller. A bit set to one means NO synchronous. ! 73: * Patch with adb if necessary. ! 74: */ ! 75: unsigned char scsi_no_synchronous_xfer[NSCSI]; ! 76: ! 77: /* ! 78: * For certain targets it is wise to use the long form of the ! 79: * read/write commands even if their capacity would not necessitate ! 80: * it. Same as above for usage. ! 81: */ ! 82: unsigned char scsi_use_long_form[NSCSI]; ! 83: ! 84: ! 85: /* ! 86: * Control over disconnect-reconnect mode. ! 87: */ ! 88: unsigned char scsi_might_disconnect[NSCSI] = /* do it if deemed appropriate */ ! 89: { 0xff, 0xff, 0xff, 0xff, 0xff};/* Fix by hand viz NSCSI */ ! 90: unsigned char scsi_should_disconnect[NSCSI] = /* just do it */ ! 91: { 0,}; ! 92: unsigned char scsi_initiator_id[NSCSI] = /* our id on the bus(ses) */ ! 93: { 7, 7, 7, 7, 7}; ! 94: ! 95: /* ! 96: * Miscellaneus config ! 97: */ ! 98: boolean_t scsi_exabyte_filemarks = FALSE; /* use short filemarks */ ! 99: int scsi_watchdog_period = 10; /* but exabyte needs >=30 for bspace */ ! 100: int scsi_delay_after_reset = 1000000;/* microseconds */ ! 101: boolean_t scsi_no_automatic_bbr = FALSE; /* revector bad blocks automatically */ ! 102: ! 103: #ifdef MACH_KERNEL ! 104: #else ! 105: /* This covers Exabyte's max record size */ ! 106: unsigned int scsi_per_target_virtual = 256*1024; ! 107: #endif MACH_KERNEL ! 108: ! 109: ! 110: /* ! 111: * Device-specific operations are switched off this table ! 112: */ ! 113: ! 114: extern char ! 115: *scdisk_name(), *sctape_name(), *scprt_name(), ! 116: *sccpu_name(), *scworm_name(), *sccdrom_name(), ! 117: *scscn_name(), *scmem_name(), *scjb_name(), *sccomm_name(); ! 118: extern void ! 119: sctape_optimize(); ! 120: extern scsi_ret_t ! 121: scdisk_open(), sctape_open(), sctape_close(), ! 122: sccomm_open(), sccomm_close(); ! 123: extern int ! 124: scdisk_strategy(), sctape_strategy(), sccpu_strategy(), ! 125: sccomm_strategy(); ! 126: extern void ! 127: scdisk_start(), sctape_start(), sccpu_start(), sccomm_start(); ! 128: ! 129: extern io_return_t ! 130: scdisk_set_status(), scdisk_get_status(), ! 131: sctape_set_status(), sctape_get_status(), ! 132: sccomm_set_status(), sccomm_get_status(); ! 133: ! 134: scsi_devsw_t scsi_devsw[] = { ! 135: ! 136: /* SCSI_DISK */ { scdisk_name, SCSI_OPTIMIZE_NULL, ! 137: scdisk_open, SCSI_CLOSE_NULL, ! 138: scdisk_strategy, scdisk_start, ! 139: scdisk_get_status, scdisk_set_status }, ! 140: ! 141: /* SCSI_TAPE */ { sctape_name, sctape_optimize, ! 142: sctape_open, sctape_close, ! 143: sctape_strategy, sctape_start, ! 144: sctape_get_status, sctape_set_status }, ! 145: ! 146: /* SCSI_PRINTER */ { scprt_name, SCSI_OPTIMIZE_NULL, /*XXX*/}, ! 147: ! 148: /* SCSI_CPU */ { sccpu_name, SCSI_OPTIMIZE_NULL, ! 149: SCSI_OPEN_NULL, SCSI_CLOSE_NULL, ! 150: sccpu_strategy, sccpu_start,}, ! 151: ! 152: /* SCSI_WORM */ { scworm_name, SCSI_OPTIMIZE_NULL, ! 153: scdisk_open, SCSI_CLOSE_NULL, ! 154: scdisk_strategy, scdisk_start, ! 155: scdisk_get_status, scdisk_set_status }, ! 156: ! 157: /* SCSI_CDROM */ { sccdrom_name, SCSI_OPTIMIZE_NULL, ! 158: scdisk_open, SCSI_CLOSE_NULL, ! 159: scdisk_strategy, scdisk_start, ! 160: scdisk_get_status, scdisk_set_status }, ! 161: /* scsi2 */ ! 162: /* SCSI_SCANNER */ { scscn_name, SCSI_OPTIMIZE_NULL, /*XXX*/ }, ! 163: ! 164: /* SCSI_MEMORY */ { scmem_name, SCSI_OPTIMIZE_NULL, ! 165: scdisk_open, SCSI_CLOSE_NULL, ! 166: scdisk_strategy, scdisk_start, ! 167: scdisk_get_status, scdisk_set_status }, ! 168: ! 169: /* SCSI_J_BOX */ { scjb_name, SCSI_OPTIMIZE_NULL, /*XXX*/ }, ! 170: ! 171: /* SCSI_COMM */ { sccomm_name, SCSI_OPTIMIZE_NULL, ! 172: #if (NCENDATA>0) ! 173: sccomm_open, sccomm_close, ! 174: sccomm_strategy, sccomm_start, ! 175: sccomm_get_status, sccomm_set_status ! 176: #endif ! 177: }, ! 178: 0 ! 179: }; ! 180: ! 181: /* ! 182: * Allocation routines for state structures ! 183: */ ! 184: scsi_softc_t * ! 185: scsi_master_alloc(unit, hw) ! 186: unsigned unit; ! 187: char *hw; ! 188: { ! 189: scsi_softc_t *sc; ! 190: ! 191: if (unit < NSCSI) { ! 192: sc = &scsi_softc_data[unit]; ! 193: scsi_softc[unit] = sc; ! 194: sc->masterno = unit; ! 195: sc->hw_state = hw; ! 196: return sc; ! 197: } ! 198: return 0; ! 199: } ! 200: ! 201: target_info_t * ! 202: scsi_slave_alloc(unit, slave, hw) ! 203: unsigned unit, slave; ! 204: char *hw; ! 205: { ! 206: target_info_t *tgt; ! 207: ! 208: tgt = &scsi_target_data[(unit<<3) + slave]; ! 209: tgt->hw_state = hw; ! 210: tgt->dev_ops = 0; /* later */ ! 211: tgt->target_id = slave; ! 212: tgt->masterno = unit; ! 213: tgt->block_size = 1; /* default */ ! 214: tgt->flags = TGT_ALIVE; ! 215: tgt->sync_period = 0; ! 216: tgt->sync_offset = 0; ! 217: simple_lock_init(&tgt->target_lock); ! 218: ! 219: scsi_softc[unit]->target[slave] = tgt; ! 220: return tgt; ! 221: } ! 222: ! 223: void ! 224: zero_ior( ! 225: io_req_t ior ) ! 226: { ! 227: ior->io_next = ior->io_prev = 0; ! 228: ior->io_count = 0; ! 229: ior->io_op = IO_INTERNAL; ! 230: ior->io_error = 0; ! 231: } ! 232: ! 233: /* ! 234: * Slave routine: ! 235: * See if the slave description (controller, unit, ..) ! 236: * matches one of the slaves found during probe ! 237: * ! 238: * Implementation: ! 239: * Send out an INQUIRY command to see what sort of device ! 240: * the slave is. ! 241: * Notes: ! 242: * At this time the driver is fully functional and works ! 243: * off interrupts. ! 244: * TODO: ! 245: * The SCSI2 spec says what exactly must happen: see F.2.3 ! 246: */ ! 247: int scsi_slave( ui, reg) ! 248: struct bus_device *ui; ! 249: unsigned reg; ! 250: { ! 251: scsi_softc_t *sc = scsi_softc[(unsigned char)ui->ctlr]; ! 252: target_info_t *tgt = sc->target[(unsigned char)ui->slave]; ! 253: scsi2_inquiry_data_t *inq; ! 254: int scsi_std; ! 255: int ptype, s; ! 256: ! 257: if (!tgt || !(tgt->flags & TGT_ALIVE)) ! 258: return 0; ! 259: ! 260: /* Might have scanned already */ ! 261: if (tgt->dev_ops) ! 262: goto out; ! 263: ! 264: #ifdef SCSI2 ! 265: This is what should happen: ! 266: - for all LUNs ! 267: INQUIRY ! 268: scsi_verify_state (see) ! 269: scsi_initialize (see) ! 270: #endif SCSI2 ! 271: ! 272: tgt->unit_no = ui->slave; /* incorrect, but needed early */ ! 273: ! 274: s = spl0(); /* we need interrupts */ ! 275: ! 276: if (BGET(scsi_no_synchronous_xfer,(unsigned char)sc->masterno,tgt->target_id)) ! 277: tgt->flags |= TGT_DID_SYNCH; ! 278: ! 279: /* ! 280: * Ok, it is time to see what type of device this is, ! 281: * send an INQUIRY cmd and wait till done. ! 282: * Possibly do the synch negotiation here. ! 283: */ ! 284: scsi_inquiry(tgt, SCSI_INQ_STD_DATA); ! 285: ! 286: inq = (scsi2_inquiry_data_t*)tgt->cmd_ptr; ! 287: ptype = inq->periph_type; ! 288: ! 289: switch (ptype) { ! 290: case SCSI_CDROM : ! 291: tgt->flags |= TGT_READONLY; ! 292: /* fall through */ ! 293: case SCSI_DISK : ! 294: case SCSI_TAPE : ! 295: case SCSI_PRINTER : ! 296: case SCSI_CPU : ! 297: case SCSI_WORM : ! 298: case SCSI_SCANNER : ! 299: case SCSI_MEMORY : ! 300: case SCSI_J_BOX : ! 301: case SCSI_COMM : ! 302: /* case SCSI_PREPRESS1 : reserved, really ! 303: case SCSI_PREPRESS2 : */ ! 304: tgt->dev_ops = &scsi_devsw[ptype]; ! 305: break; ! 306: default: ! 307: printf("scsi%d: %s %d (x%x). ", ui->ctlr, ! 308: "Unsupported device type at SCSI id", ui->slave, ! 309: inq->periph_type); ! 310: scsi_print_inquiry((scsi2_inquiry_data_t*)inq, ! 311: SCSI_INQ_STD_DATA, 0); ! 312: tgt->flags = 0; ! 313: splx(s); ! 314: return 0; ! 315: } ! 316: ! 317: if (inq->rmb) ! 318: tgt->flags |= TGT_REMOVABLE_MEDIA; ! 319: ! 320: /* ! 321: * Tell the user we know this target, then see if we ! 322: * can be a bit smart about it. ! 323: */ ! 324: scsi_print_inquiry((scsi2_inquiry_data_t*)inq, ! 325: SCSI_INQ_STD_DATA, tgt->tgt_name); ! 326: if (scsi_debug) ! 327: scsi_print_inquiry((scsi2_inquiry_data_t*)inq, ! 328: SCSI_INQ_STD_DATA, 0); ! 329: ! 330: /* ! 331: * The above says if it currently behaves as a scsi2, ! 332: * however scsi1 might just be the default setting. ! 333: * The spec say that even if in scsi1 mode the target ! 334: * should answer to the full scsi2 inquiry spec. ! 335: */ ! 336: scsi_std = (inq->ansi == 2 || inq->response_fmt == 2) ? 2 : 1; ! 337: #if nosey ! 338: if (scsi_std == 2) { ! 339: unsigned char supp_pages[256], i; ! 340: scsi2_impl_opdef_page_t *impl; ! 341: ! 342: scsi_inquiry(tgt, SCSI_INQ_SUPP_PAGES); ! 343: impl = (scsi2_impl_opdef_page_t *)inq; ! 344: npages = impl->page_len - 2; ! 345: bcopy(impl->supp_opdef, supp_pages, npages); ! 346: ! 347: for (i = 0; i < npages; i++) { ! 348: scsi_inquiry(tgt, supp_pages[i]); ! 349: scsi_print_inquiry(inq, supp_pages[i], 0); ! 350: } ! 351: } ! 352: ! 353: if (scsi_std == 2) { ! 354: scsi2_impl_opdef_page_t *impl; ! 355: int i; ! 356: ! 357: scsi_inquiry(tgt, SCSI_INQ_IMPL_OPDEF); ! 358: impl = (scsi2_impl_opdef_page_t *)inq; ! 359: for (i = 0; i < impl->page_len - 2; i++) ! 360: if (impl->supp_opdef[i] == SCSI2_OPDEF) { ! 361: scsi_change_definition(tgt, SCSI2_OPDEF); ! 362: /* if success .. */ ! 363: tgt->flags |= TGT_SCSI_2_MODE; ! 364: break; ! 365: } ! 366: } ! 367: #endif nosey ! 368: ! 369: splx(s); ! 370: out: ! 371: return (strcmp(ui->name, (*tgt->dev_ops->driver_name)(TRUE)) == 0); ! 372: } ! 373: ! 374: #ifdef SCSI2 ! 375: scsi_verify_state(...) ! 376: { ! 377: verify_state: send test_unit_ready up to 3 times, each time it fails ! 378: (with check condition) send a requeste_sense. It is ok to get UNIT ATTENTION ! 379: the first time only, NOT READY the second, only GOOD the last time. ! 380: If you get BUSY or RESERVATION CONFLICT retry. ! 381: } ! 382: ! 383: scsi_initialize(...) ! 384: { ! 385: ! 386: initialize: send start_unit with immed=0 (->disconnect), if fails ! 387: with check condition send requeste_sense and if "illegal request" ! 388: proceed anyways. Retry on BUSY. ! 389: Do a verify_state, then ! 390: disks: ! 391: - mode_sense (current) if ANSI2 or needed by vendor (!!!!) ! 392: and if check-condition&illegal-request goto capacity ! 393: - mode_sense (changeable) ! 394: - if needed do a mode_select (yes, 512) ! 395: - read_capacity ! 396: tapes: ! 397: ! 398: } ! 399: #endif SCSI2 ! 400: ! 401: /* ! 402: * Attach routine: ! 403: * Fill in all the relevant per-slave data and make ! 404: * the slave operational. ! 405: * ! 406: * Implementation: ! 407: * Get target's status, start the unit and then ! 408: * switch off to device-specific functions to gather ! 409: * as much info as possible about the slave. ! 410: */ ! 411: void scsi_attach(ui) ! 412: register struct bus_device *ui; ! 413: { ! 414: scsi_softc_t *sc = scsi_softc[ui->mi->unit]; ! 415: target_info_t *tgt = sc->target[(unsigned char)ui->slave]; ! 416: int i; ! 417: spl_t s; ! 418: ! 419: printf(" (%s %s) ", (*tgt->dev_ops->driver_name)(FALSE),tgt->tgt_name); ! 420: ! 421: if (tgt->flags & TGT_US) { ! 422: printf(" [this cpu]"); ! 423: return; ! 424: } ! 425: ! 426: s = spl0(); ! 427: ! 428: /* sense return from inquiry */ ! 429: scsi_request_sense(tgt, 0, 0); ! 430: ! 431: /* ! 432: * Do this twice, certain targets need it ! 433: */ ! 434: if (tgt->dev_ops != &scsi_devsw[SCSI_CPU]) { ! 435: (void) scsi_start_unit(tgt, SCSI_CMD_SS_START, 0); ! 436: i = 0; ! 437: while (scsi_start_unit(tgt, SCSI_CMD_SS_START, 0) == SCSI_RET_RETRY) { ! 438: if (i++ == 5) ! 439: printf(".. not yet online .."); ! 440: delay(1000000); ! 441: if (i == 60) { ! 442: printf(" seems hopeless."); ! 443: break; ! 444: } ! 445: } ! 446: } ! 447: ! 448: /* ! 449: * See if it is up and about ! 450: */ ! 451: scsi_test_unit_ready(tgt, 0); ! 452: ! 453: if (tgt->dev_ops->optimize != SCSI_OPTIMIZE_NULL) ! 454: (*tgt->dev_ops->optimize)(tgt); ! 455: ! 456: tgt->flags |= TGT_FULLY_PROBED; ! 457: ! 458: splx(s); ! 459: } ! 460: ! 461: /* ! 462: * Probe routine: ! 463: * See if a device answers. Used AFTER autoconf. ! 464: * ! 465: * Implementation: ! 466: * First ask the HBA to see if anyone is there at all, then ! 467: * call the scsi_slave and scsi_attach routines with a fake ui. ! 468: */ ! 469: boolean_t ! 470: scsi_probe( sc, tgt_ptr, target_id, ior) ! 471: scsi_softc_t *sc; ! 472: target_info_t **tgt_ptr; ! 473: int target_id; ! 474: io_req_t ior; ! 475: { ! 476: struct bus_device ui; ! 477: target_info_t *tgt; ! 478: ! 479: if (!sc->probe || target_id > 7 || target_id == sc->initiator_id) ! 480: return FALSE; /* sanity */ ! 481: ! 482: if (sc->target[target_id] == 0) ! 483: scsi_slave_alloc( sc->masterno, target_id, sc->hw_state); ! 484: tgt = sc->target[target_id]; ! 485: tgt->flags = 0;/* we donno yet */ ! 486: tgt->dev_ops = 0; ! 487: ! 488: /* mildly enquire */ ! 489: if (!(sc->probe)(tgt, ior)) ! 490: goto fail; ! 491: ! 492: /* There is something there, see what it is */ ! 493: bzero(&ui, sizeof(ui)); ! 494: ui.ctlr = sc->masterno; ! 495: ui.unit = ! 496: ui.slave = target_id; ! 497: ui.name = ""; ! 498: ! 499: /* this fails on the name for sure */ ! 500: (void) scsi_slave( &ui, 0 /* brrrr */); ! 501: if ((tgt->flags & TGT_ALIVE) == 0) ! 502: goto fail; ! 503: ! 504: { ! 505: struct bus_ctlr mi; ! 506: ! 507: mi.unit = sc->masterno; ! 508: ui.mi = &mi; ! 509: printf("%s at slave %d ", ! 510: (*tgt->dev_ops->driver_name)(TRUE), target_id); ! 511: scsi_attach(&ui); ! 512: } ! 513: ! 514: *tgt_ptr = tgt; ! 515: return TRUE; ! 516: fail: ! 517: tgt->flags = 0; ! 518: return FALSE; ! 519: } ! 520: ! 521: ! 522: /* ! 523: * Watchdog routine: ! 524: * Issue a SCSI bus reset if a target holds up the ! 525: * bus for too long. ! 526: * ! 527: * Implementation: ! 528: * Each HBA that wants to use this should have a ! 529: * watchdog_t structure at the head of its hardware ! 530: * descriptor. This variable is set by this periodic ! 531: * routine and reset on bus activity. If it is not reset on ! 532: * time (say some ten seconds or so) we reset the ! 533: * SCSI bus. ! 534: * NOTE: ! 535: * An HBA must be ready to accept bus reset interrupts ! 536: * properly in order to use this. ! 537: */ ! 538: void scsi_watchdog(hw) ! 539: watchdog_t *hw; ! 540: { ! 541: spl_t s = splbio(); ! 542: ! 543: switch (hw->watchdog_state) { ! 544: case SCSI_WD_EXPIRED: ! 545: ! 546: /* double check first */ ! 547: if (hw->nactive == 0) { ! 548: hw->watchdog_state = SCSI_WD_INACTIVE; ! 549: break; ! 550: } ! 551: if (scsi_debug) ! 552: printf("SCSI Watchdog expired\n"); ! 553: hw->watchdog_state = SCSI_WD_INACTIVE; ! 554: (*hw->reset)(hw); ! 555: break; ! 556: ! 557: case SCSI_WD_ACTIVE: ! 558: ! 559: hw->watchdog_state = SCSI_WD_EXPIRED; ! 560: break; ! 561: ! 562: case SCSI_WD_INACTIVE: ! 563: ! 564: break; ! 565: } ! 566: ! 567: /* do this here, fends against powered down devices */ ! 568: if (scsi_watchdog_period != 0) ! 569: timeout((int(*)())scsi_watchdog, (char*)hw, scsi_watchdog_period * hz); ! 570: ! 571: splx(s); ! 572: } ! 573: ! 574: ! 575: /* ! 576: * BusReset Notification: ! 577: * Called when the HBA sees a BusReset interrupt ! 578: * ! 579: * Implementation: ! 580: * Go through the list of targets, redo the synch ! 581: * negotiation, and restart whatever operation was ! 582: * in progress for that target. ! 583: */ ! 584: void scsi_bus_was_reset(sc) ! 585: scsi_softc_t *sc; ! 586: { ! 587: register target_info_t *tgt; ! 588: int i; ! 589: /* ! 590: * Redo the synch negotiation ! 591: */ ! 592: for (i = 0; i < 8; i++) { ! 593: io_req_t ior; ! 594: spl_t s; ! 595: ! 596: if (i == sc->initiator_id) ! 597: continue; ! 598: tgt = sc->target[i]; ! 599: if (!tgt || !(tgt->flags & TGT_ALIVE)) ! 600: continue; ! 601: ! 602: tgt->flags &= ~(TGT_DID_SYNCH|TGT_DISCONNECTED); ! 603: #if 0 ! 604: /* the standard does *not* imply this gets reset too */ ! 605: tgt->sync_period = 0; ! 606: tgt->sync_offset = 0; ! 607: #endif ! 608: ! 609: /* ! 610: * retry the synch negotiation ! 611: */ ! 612: ior = tgt->ior; ! 613: tgt->ior = 0; ! 614: printf(".. tgt %d ", tgt->target_id); ! 615: if (BGET(scsi_no_synchronous_xfer,(unsigned char)sc->masterno,tgt->target_id)) ! 616: tgt->flags |= TGT_DID_SYNCH; ! 617: else { ! 618: s = spl0(); ! 619: scsi_test_unit_ready(tgt, 0); ! 620: splx(s); ! 621: } ! 622: tgt->ior = ior; ! 623: } ! 624: ! 625: /* ! 626: * Notify each target of the accident ! 627: */ ! 628: for (i = 0; i < 8; i++) { ! 629: if (i == sc->initiator_id) ! 630: continue; ! 631: tgt = sc->target[i]; ! 632: if (!tgt) ! 633: continue; ! 634: tgt->done = SCSI_RET_ABORTED|SCSI_RET_RETRY; ! 635: if (tgt->ior) ! 636: (*tgt->dev_ops->restart)( tgt, TRUE); ! 637: } ! 638: ! 639: printf("%s", " reset complete\n"); ! 640: } ! 641: ! 642: #endif NSCSI > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.