|
|
1.1 ! root 1: /* ! 2: * SCSITape.m -- implementation of scsi tape driver routines ! 3: * ! 4: * HISTORY ! 5: * 31-Mar-93 Phillip Dibner at NeXT ! 6: * Created. ! 7: * ! 8: */ ! 9: ! 10: ! 11: #import <sys/errno.h> ! 12: #import <sys/types.h> ! 13: #import <sys/time.h> ! 14: #import <sys/conf.h> ! 15: #import <sys/uio.h> ! 16: #import <sys/mtio.h> ! 17: #import <bsd/dev/scsireg.h> ! 18: ! 19: #import <driverkit/scsiTypes.h> ! 20: #import <driverkit/align.h> ! 21: #import <driverkit/kernelDriver.h> ! 22: #import <driverkit/scsiTypes.h> ! 23: #import <driverkit/return.h> ! 24: #import <machkit/NXLock.h> ! 25: #import <kernserv/prototypes.h> ! 26: #import <kernserv/kern_server_types.h> ! 27: #import "SCSITape.h" ! 28: #import "SCSITapeTypes.h" ! 29: ! 30: #define DRIVE_TYPE_LENGTH 80 ! 31: ! 32: #define USE_EBD 1 /* use "even byte disconnect" rather than ! 33: * "no disconnect during data xfer" for exabyte ! 34: */ ! 35: ! 36: extern int st_devsw_init(); ! 37: ! 38: static int moveString(); /* rmv nulls & blanks from inquiry strings */ ! 39: void assign_cdb_c6s_len(); /* store length data in little-endian cdb_6s */ ! 40: void assign_msbd_numblocks(); /* store nblks in little-endian modesel bd */ ! 41: void assign_msbd_blocklength(); /* store blklen in little-endian modesel bd */ ! 42: int cdb_c6s_len_value(); /* byte swap to read length data in cdb */ ! 43: int er_info_value (); /* byte swapping for sense reply info data */ ! 44: ! 45: id stIdMap [NST]; ! 46: ! 47: @implementation SCSITape ! 48: ! 49: + (IODeviceStyle)deviceStyle ! 50: { ! 51: return IO_IndirectDevice; ! 52: } ! 53: ! 54: /* ! 55: * The protocol we need as an indirect device. ! 56: */ ! 57: static Protocol *protocols[] = { ! 58: @protocol(IOSCSIControllerExported), ! 59: nil ! 60: }; ! 61: ! 62: + (Protocol **)requiredProtocols ! 63: { ! 64: return protocols; ! 65: } ! 66: ! 67: static unsigned int tapeUnit = 0; ! 68: ! 69: + (BOOL) probe: deviceDescription ! 70: { ! 71: SCSITape *tapeId = nil; ! 72: unsigned char stTarget, stLun; ! 73: id controllerId = ! 74: [deviceDescription directDevice]; ! 75: stInitReturn_t irtn = STR_ERROR; ! 76: BOOL brtn = NO; ! 77: int major; ! 78: ! 79: /* asm volatile("int3"); */ // Early break to debugger ! 80: ! 81: if ((major = st_devsw_init()) < 0) { ! 82: return NO; ! 83: } ! 84: ! 85: for (stTarget=0; stTarget<SCSI_NTARGETS; stTarget++) { ! 86: for(stLun=0; stLun<SCSI_NLUNS; stLun++) { ! 87: ! 88: #ifdef DEBUG ! 89: IOLog ("SCSITape probe: target %d lun %d\n", stTarget, stLun); ! 90: #endif DEBUG ! 91: ! 92: if(tapeId == nil) { ! 93: /* ! 94: * Create an instance, do some basic ! 95: * initialization. Set up a default ! 96: * device name for error reporting during ! 97: * initialization. ! 98: */ ! 99: tapeId = [SCSITape alloc]; ! 100: } ! 101: ! 102: if ([controllerId reserveTarget:stTarget ! 103: lun:stLun ! 104: forOwner:tapeId]) { ! 105: /* ! 106: * Someone already has this one. ! 107: */ ! 108: continue; ! 109: } ! 110: else { ! 111: [tapeId setReservedTargetLun: YES]; ! 112: } ! 113: ! 114: #ifdef DEBUG ! 115: IOLog ("SCSITape probe: about to init\n"); ! 116: #endif DEBUG ! 117: ! 118: irtn = [tapeId initSCSITape:(int)tapeUnit ! 119: target: stTarget ! 120: lun: stLun ! 121: controller: controllerId ! 122: majorDeviceNumber: major]; ! 123: ! 124: #ifdef DEBUG ! 125: IOLog ("SCSITape probe: irtn is %d\n", irtn); ! 126: #endif DEBUG ! 127: ! 128: switch (irtn) { ! 129: case STR_GOOD: ! 130: /* ! 131: * Init'd OK - still must register device. ! 132: */ ! 133: [tapeId registerDevice]; ! 134: stIdMap [tapeUnit] = tapeId; ! 135: tapeId = nil; ! 136: tapeUnit++; ! 137: if (tapeUnit >= NST) goto done; ! 138: brtn = YES; ! 139: break; ! 140: ! 141: default: ! 142: [controllerId releaseTarget: stTarget ! 143: lun: stLun ! 144: forOwner: tapeId]; ! 145: [tapeId setReservedTargetLun: NO]; ! 146: if(irtn == STR_SELECTTO) { ! 147: /* ! 148: * Skip the rest of the luns on ! 149: * this target. ! 150: */ ! 151: goto nextTarget; ! 152: } ! 153: /* ! 154: * else try next lun. ! 155: */ ! 156: } /* switch (irtn) */ ! 157: } /* for lun */ ! 158: ! 159: nextTarget: ! 160: ! 161: continue; ! 162: } /* for target */ ! 163: ! 164: done: ! 165: /* ! 166: * Free up leftover owner and id. At this point, tapeId does NOT have ! 167: * a target/lun reserved. ! 168: */ ! 169: if(tapeId) { ! 170: [tapeId free]; ! 171: } ! 172: ! 173: return brtn; ! 174: } ! 175: ! 176: ! 177: - (stInitReturn_t) initSCSITape:(int)iunit /* IODevice unit # */ ! 178: target: (u_char) stTarget ! 179: lun: (u_char) stLun ! 180: controller: controllerId ! 181: majorDeviceNumber: (int) major ! 182: { ! 183: inquiry_reply_t inquiryData; ! 184: sc_status_t rtn; ! 185: char driveType[DRIVE_TYPE_LENGTH]; /* name from Inquiry */ ! 186: char *outp; ! 187: char deviceName[30]; ! 188: char location[IO_STRING_LENGTH]; ! 189: ! 190: ! 191: /* ! 192: * Initialize common instance variables. ! 193: */ ! 194: _controller = controllerId; ! 195: _target = stTarget; ! 196: _lun = stLun; ! 197: sprintf(deviceName, "st%d", iunit); ! 198: [self setName: deviceName]; ! 199: [self setDeviceKind:"SCSITape"]; ! 200: [self setLocation:[_controller name]]; ! 201: [self setUnit: iunit]; ! 202: ! 203: #ifdef DEBUG ! 204: IOLog ! 205: ("InitSCSITape: target %d lun %d unit %d deviceName %s location %s\n", ! 206: stTarget, stLun, iunit, deviceName, [_controller name]); ! 207: #endif DEBUG ! 208: ! 209: /* ! 210: * Resources for commands during initialization. ! 211: */ ! 212: _senseDataPtr = IOMalloc (sizeof (struct esense_reply)); ! 213: _senseDataValid = NO; ! 214: ! 215: /* ! 216: * Other instance variables ! 217: */ ! 218: _didWrite = NO; ! 219: _suppressIllegalLength = NO; ! 220: _isInitialized = NO; ! 221: _devLock = nil; // Until we know we're a tape ! 222: ! 223: /* ! 224: * Test Unit Ready to clear possible Unit Attention. Success is ! 225: * not important. ! 226: */ ! 227: [self stTestReady]; ! 228: ! 229: /* ! 230: * Try an Inquiry command. ! 231: */ ! 232: bzero(&inquiryData, sizeof(inquiry_reply_t)); ! 233: rtn = [self stInquiry:&inquiryData]; ! 234: ! 235: #ifdef DEBUG ! 236: IOLog ("InitSCSITape inquiry returned %d\n", rtn); ! 237: #endif DEBUG ! 238: ! 239: switch(rtn) { ! 240: case SR_IOST_GOOD: ! 241: break; ! 242: case SR_IOST_SELTO: ! 243: return STR_SELECTTO; ! 244: default: ! 245: return STR_ERROR; ! 246: } ! 247: ! 248: /* ! 249: * Is it a tape? ! 250: */ ! 251: if(inquiryData.ir_qual != DEVQUAL_OK || ! 252: inquiryData.ir_devicetype != DEVTYPE_TAPE) { ! 253: ! 254: #ifdef DEBUG ! 255: IOLog ("InitSCSITape: not a tape\n"); ! 256: #endif DEBUG ! 257: ! 258: return(STR_NOTATAPE); ! 259: } ! 260: ! 261: /* ! 262: * Set up resources for exclusive open. ! 263: */ ! 264: _devLock = [[NXLock alloc] init]; ! 265: _devAcquired = NO; ! 266: ! 267: /* ! 268: * Compress multiple blanks out of the vendor id and product ID. ! 269: */ ! 270: bzero (driveType, DRIVE_TYPE_LENGTH); ! 271: outp = driveType; ! 272: outp += moveString((char *)&inquiryData.ir_vendorid, ! 273: outp, ! 274: 8, ! 275: &driveType[DRIVE_TYPE_LENGTH] - outp); ! 276: if(*(outp - 1) != ' ') ! 277: *outp++ = ' '; ! 278: outp += moveString((char *)&inquiryData.ir_productid, ! 279: outp, ! 280: 16, ! 281: &driveType[DRIVE_TYPE_LENGTH] - outp); ! 282: if(*(outp - 1) != ' ') ! 283: *outp++ = ' '; ! 284: outp += moveString((char *)&inquiryData.ir_revision, ! 285: outp, ! 286: 4, ! 287: &driveType[DRIVE_TYPE_LENGTH] - outp); ! 288: *outp = '\0'; ! 289: ! 290: sprintf(location, "Target %d LUN %d at %s", _target, _lun, ! 291: [controllerId name]); ! 292: [self setLocation: location]; ! 293: IOLog("%s: %s\n", deviceName, driveType); ! 294: ! 295: ! 296: /* ! 297: * Do another Test Unit Ready to clear a possible Unit Attention ! 298: * condition. We don't care about the result. ! 299: */ ! 300: [self stTestReady]; ! 301: ! 302: /* ! 303: * Init to variable blk size. ! 304: */ ! 305: [self setBlockSize: 0]; ! 306: ! 307: /* ! 308: * Store the major number in our instance. ! 309: */ ! 310: _majorDevNum = major; ! 311: ! 312: [super init]; ! 313: _isInitialized = YES; ! 314: return(STR_GOOD); ! 315: } /* - initSCSITape: */ ! 316: ! 317: ! 318: - free ! 319: { ! 320: if (_senseDataPtr) ! 321: IOFree (_senseDataPtr, sizeof (struct esense_reply)); ! 322: if (_devLock) ! 323: [_devLock free]; ! 324: if (_reservedTargetLun) ! 325: [_controller releaseTarget: _target lun: _lun forOwner: _controller]; ! 326: return [super free]; ! 327: } ! 328: ! 329: ! 330: - (IOReturn) getIntValues: (unsigned int *)values ! 331: forParameter: (IOParameterName) parameter ! 332: count: (unsigned int *) count ! 333: { ! 334: int maxCount = *count; ! 335: ! 336: if(maxCount == 0) { ! 337: maxCount = IO_MAX_PARAMETER_ARRAY_LENGTH; ! 338: } ! 339: ! 340: if(strcmp(parameter, "IOMajorDevice") == 0) { ! 341: values [0] = [self majorDevNum]; ! 342: *count = 1; ! 343: return IO_R_SUCCESS; ! 344: } ! 345: ! 346: if (strcmp(parameter, "Unit") == 0) { ! 347: values [0] = [self unit]; ! 348: *count = 1; ! 349: return IO_R_SUCCESS; ! 350: ! 351: } ! 352: ! 353: return [super getIntValues:values ! 354: forParameter:parameter ! 355: count:&maxCount]; ! 356: } ! 357: ! 358: ! 359: ! 360: /* ! 361: * Gets and sets for instance variables. ! 362: */ ! 363: ! 364: - (int) target /* Set only during initialization */ ! 365: { ! 366: return (int) _target; ! 367: } ! 368: ! 369: - (int) lun /* Set only during initialization */ ! 370: { ! 371: return (int) _lun; ! 372: } ! 373: ! 374: - controller /* Set only during initialization */ ! 375: { ! 376: return _controller; ! 377: } ! 378: ! 379: - (BOOL) isInitialized /* Object has been initialized */ ! 380: { ! 381: return _isInitialized; ! 382: } ! 383: ! 384: - (BOOL) didWrite /* Last command was a write */ ! 385: { ! 386: return _didWrite; ! 387: } ! 388: ! 389: - (BOOL) isFixedBlock ! 390: { ! 391: if (_blockSize) { /* Zero blocksize means variable block size */ ! 392: return YES; ! 393: } else { ! 394: return NO; ! 395: } ! 396: } ! 397: ! 398: - (BOOL) senseDataValid ! 399: { ! 400: return _senseDataValid; ! 401: } ! 402: ! 403: - forceSenseDataInvalid /* for MTIOCGET and friends */ ! 404: { ! 405: _senseDataValid = NO; ! 406: return self; ! 407: } ! 408: ! 409: - (struct esense_reply *) senseDataPtr ! 410: { ! 411: return _senseDataPtr; ! 412: } ! 413: ! 414: - (int) blockSize /* Set only via setBlockSize SCSI operation */ ! 415: { ! 416: return _blockSize; ! 417: } ! 418: ! 419: - (BOOL) suppressIllegalLength ! 420: { ! 421: return _suppressIllegalLength; ! 422: } ! 423: ! 424: - setSuppressIllegalLength: (BOOL) condition ! 425: { ! 426: _suppressIllegalLength = condition; ! 427: return self; ! 428: } ! 429: ! 430: - (BOOL) ignoreCheckCondition ! 431: { ! 432: return _ignoreCheckCondition; ! 433: } ! 434: ! 435: - setIgnoreCheckCondition: (BOOL) condition ! 436: { ! 437: _ignoreCheckCondition = condition; ! 438: return self; ! 439: } ! 440: ! 441: - (int) majorDevNum ! 442: { ! 443: return _majorDevNum; ! 444: } ! 445: ! 446: - setReservedTargetLun: (BOOL) condition ! 447: { ! 448: _reservedTargetLun = condition; ! 449: return self; ! 450: } ! 451: ! 452: - (BOOL) reservedTargetLun ! 453: { ! 454: return _reservedTargetLun; ! 455: } ! 456: ! 457: - (IOReturn) acquireDevice ! 458: { ! 459: IOReturn ret = IO_R_INVALID; ! 460: ! 461: [_devLock lock]; ! 462: if (_devAcquired == YES) { ! 463: ret = IO_R_BUSY; ! 464: } else { ! 465: _devAcquired = YES; ! 466: ret = IO_R_SUCCESS; ! 467: } ! 468: [_devLock unlock]; ! 469: return ret; ! 470: } ! 471: ! 472: - (IOReturn) releaseDevice ! 473: { ! 474: [_devLock lock]; ! 475: _devAcquired = NO; ! 476: [_devLock unlock]; ! 477: return IO_R_SUCCESS; ! 478: } ! 479: ! 480: ! 481: /* ! 482: * General SCSI commands ! 483: */ ! 484: - (sc_status_t) stInquiry: (inquiry_reply_t *) inquiryReply ! 485: { ! 486: IOSCSIRequest scsiReq; ! 487: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 488: inquiry_reply_t *alignedReply; ! 489: void *freePtr; ! 490: int freeCnt; ! 491: sc_status_t rtn; ! 492: IODMAAlignment dmaAlign; ! 493: ! 494: ! 495: /* ! 496: * Get some well-aligned memory. ! 497: */ ! 498: alignedReply = [_controller ! 499: allocateBufferOfLength: sizeof(inquiry_reply_t) ! 500: actualStart:&freePtr ! 501: actualLength:&freeCnt]; ! 502: bzero(alignedReply, sizeof(inquiry_reply_t)); ! 503: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 504: scsiReq.target = _target; ! 505: scsiReq.lun = _lun; ! 506: scsiReq.read = YES; ! 507: ! 508: /* ! 509: * Get appropriate alignment from controller. ! 510: */ ! 511: [_controller getDMAAlignment:&dmaAlign]; ! 512: if(dmaAlign.readLength > 1) { ! 513: scsiReq.maxTransfer = IOAlign(int, sizeof(inquiry_reply_t), ! 514: dmaAlign.readLength); ! 515: } ! 516: else { ! 517: scsiReq.maxTransfer = sizeof(inquiry_reply_t); ! 518: } ! 519: ! 520: scsiReq.timeoutLength = ST_IOTO_NORM; ! 521: scsiReq.disconnect = 1; ! 522: ! 523: cdbp->c6_opcode = C6OP_INQUIRY; ! 524: cdbp->c6_lun = _lun; ! 525: cdbp->c6_len = sizeof(inquiry_reply_t); ! 526: ! 527: [self executeRequest: &scsiReq ! 528: buffer: alignedReply ! 529: client: IOVmTaskSelf() ! 530: senseBuf: _senseDataPtr]; ! 531: ! 532: if(scsiReq.driverStatus == SR_IOST_GOOD) { ! 533: unsigned required = (char *)(&alignedReply->ir_zero3[0]) - ! 534: (char *)(alignedReply); ! 535: if(scsiReq.bytesTransferred < required) { ! 536: IOLog("%s: bad DMA Transfer count (%d) on Inquiry\n", ! 537: [self name], scsiReq.bytesTransferred); ! 538: rtn = SR_IOST_HW; ! 539: } ! 540: else { ! 541: /* ! 542: * Copy data back to caller's struct. Zero the ! 543: * portion of alignedReply which did not get valid ! 544: * data; the last flush out of the DMA pipe could ! 545: * have written trash to it (and our caller ! 546: * expects NULL data). ! 547: */ ! 548: unsigned zeroSize; ! 549: ! 550: zeroSize = sizeof(*alignedReply) - scsiReq.bytesTransferred; ! 551: if(zeroSize) { ! 552: bzero((char *)alignedReply + scsiReq.bytesTransferred, ! 553: zeroSize); ! 554: } ! 555: *inquiryReply = *alignedReply; ! 556: rtn = scsiReq.driverStatus; ! 557: } ! 558: } ! 559: else { ! 560: rtn = scsiReq.driverStatus; ! 561: } ! 562: ! 563: IOFree(freePtr, freeCnt); ! 564: return rtn; ! 565: } /* - stInquiry: */ ! 566: ! 567: ! 568: ! 569: - (BOOL) stTestReady ! 570: { ! 571: IOSCSIRequest scsiReq; ! 572: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 573: BOOL rtn; ! 574: ! 575: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 576: scsiReq.target = _target; ! 577: scsiReq.lun = _lun; ! 578: scsiReq.timeoutLength = ST_IOTO_NORM; ! 579: scsiReq.disconnect = 1; ! 580: ! 581: cdbp->c6_opcode = C6OP_TESTRDY; ! 582: cdbp->c6_lun = _lun; ! 583: ! 584: [self executeRequest: &scsiReq ! 585: buffer: (void *) NULL ! 586: client: IOVmTaskSelf() ! 587: senseBuf: _senseDataPtr]; ! 588: ! 589: /* ! 590: * XXX Do we need to distinguish not ready from no tape? ! 591: */ ! 592: switch(scsiReq.driverStatus) { ! 593: case SR_IOST_GOOD: ! 594: rtn = YES; ! 595: break; ! 596: default: ! 597: rtn = NO; ! 598: break; ! 599: } ! 600: ! 601: return rtn; ! 602: } /* - stTestReady: */ ! 603: ! 604: ! 605: ! 606: - (sc_status_t) stCloseFile ! 607: { ! 608: IOSCSIRequest scsiReq; ! 609: cdb_6s_t *cdbp = &scsiReq.cdb.cdb_c6s; ! 610: ! 611: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 612: scsiReq.target = _target; ! 613: scsiReq.lun = _lun; ! 614: scsiReq.timeoutLength = ST_IOTO_NORM; ! 615: scsiReq.disconnect = 1; ! 616: cdbp->c6s_opcode = C6OP_WRTFM; ! 617: assign_cdb_c6s_len (cdbp, 1); /* one file mark */ ! 618: ! 619: return [self executeRequest: &scsiReq ! 620: buffer: NULL ! 621: client: IOVmTaskSelf() ! 622: senseBuf: _senseDataPtr]; ! 623: } /* - stCloseFile */ ! 624: ! 625: ! 626: - (sc_status_t) stRewind ! 627: { ! 628: IOSCSIRequest scsiReq; ! 629: cdb_6s_t *cdbp = &scsiReq.cdb.cdb_c6s; ! 630: ! 631: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 632: scsiReq.target = _target; ! 633: scsiReq.lun = _lun; ! 634: scsiReq.timeoutLength = ST_IOTO_RWD; ! 635: scsiReq.disconnect = 1; ! 636: cdbp->c6s_opcode = C6OP_REWIND; ! 637: ! 638: return [self executeRequest: &scsiReq ! 639: buffer: NULL ! 640: client: IOVmTaskSelf() ! 641: senseBuf: _senseDataPtr]; ! 642: } /* - stRewind */ ! 643: ! 644: ! 645: /* ! 646: * Get sense data. senseBuf does not have to be well aligned. ! 647: */ ! 648: - (sc_status_t) requestSense: (esense_reply_t *)senseBuf ! 649: { ! 650: IOSCSIRequest scsiReq; ! 651: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 652: esense_reply_t *alignedBuf; ! 653: void *freePtr; ! 654: int freeCnt; ! 655: sc_status_t rtn; ! 656: IODMAAlignment dmaAlign; ! 657: ! 658: alignedBuf = [_controller allocateBufferOfLength: sizeof(esense_reply_t) ! 659: actualStart: &freePtr ! 660: actualLength: &freeCnt]; ! 661: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 662: [_controller getDMAAlignment:&dmaAlign]; ! 663: ! 664: scsiReq.target = _target; ! 665: scsiReq.lun = _lun; ! 666: scsiReq.read = YES; ! 667: ! 668: if(dmaAlign.readLength > 1) { ! 669: scsiReq.maxTransfer = IOAlign(int, sizeof(esense_reply_t), ! 670: dmaAlign.readLength); ! 671: ! 672: } else { ! 673: scsiReq.maxTransfer = sizeof(esense_reply_t); ! 674: } ! 675: ! 676: scsiReq.timeoutLength = ST_IOTO_NORM; // XXX Should be ST_IOTO_SENSE?? ! 677: scsiReq.disconnect = 0; ! 678: cdbp->c6_opcode = C6OP_REQSENSE; ! 679: cdbp->c6_lun = _lun; ! 680: cdbp->c6_len = sizeof(esense_reply_t); ! 681: ! 682: rtn = [_controller executeRequest:&scsiReq ! 683: buffer:alignedBuf ! 684: client:IOVmTaskSelf()]; ! 685: if(rtn == SR_IOST_GOOD) { ! 686: *senseBuf = *alignedBuf; ! 687: _senseDataValid = YES; ! 688: } ! 689: IOFree(freePtr, freeCnt); ! 690: return rtn; ! 691: } /* - requestSense: */ ! 692: ! 693: ! 694: ! 695: ! 696: - (sc_status_t) stModeSelect: (struct modesel_parms *) modeSelectParmsPtr ! 697: { ! 698: IOSCSIRequest scsiReq; ! 699: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 700: int count = modeSelectParmsPtr->msp_bcount; ! 701: struct mode_sel_data *alignedBuf; ! 702: void *freePtr; ! 703: int freeCnt; ! 704: sc_status_t rtn; ! 705: IODMAAlignment dmaAlign; ! 706: ! 707: alignedBuf = [_controller ! 708: allocateBufferOfLength: count ! 709: actualStart: &freePtr ! 710: actualLength: &freeCnt]; ! 711: ! 712: ! 713: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 714: ! 715: scsiReq.target = _target; ! 716: scsiReq.lun = _lun; ! 717: scsiReq.read = NO; ! 718: ! 719: [_controller getDMAAlignment:&dmaAlign]; ! 720: if(dmaAlign.readLength > 1) { ! 721: scsiReq.maxTransfer = IOAlign(int, count, ! 722: dmaAlign.readLength); ! 723: ! 724: } else { ! 725: scsiReq.maxTransfer = count; ! 726: } ! 727: ! 728: scsiReq.timeoutLength = ST_IOTO_NORM; ! 729: scsiReq.disconnect = 1; ! 730: cdbp->c6_opcode = C6OP_MODESELECT; ! 731: cdbp->c6_lun = _lun; ! 732: cdbp->c6_len = count; ! 733: ! 734: bcopy (&modeSelectParmsPtr->msp_data, alignedBuf, count); ! 735: ! 736: rtn = [self executeRequest:&scsiReq ! 737: buffer:alignedBuf ! 738: client:IOVmTaskSelf() ! 739: senseBuf: _senseDataPtr]; ! 740: ! 741: IOFree(freePtr, freeCnt); ! 742: return rtn; ! 743: } /* - stModeSelect: */ ! 744: ! 745: ! 746: ! 747: ! 748: - (sc_status_t) stModeSense: (struct modesel_parms *) modeSenseParmsPtr ! 749: { ! 750: IOSCSIRequest scsiReq; ! 751: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 752: int count = modeSenseParmsPtr->msp_bcount; ! 753: struct mode_sel_data *alignedBuf; ! 754: void *freePtr; ! 755: int freeCnt; ! 756: sc_status_t rtn; ! 757: IODMAAlignment dmaAlign; ! 758: ! 759: alignedBuf = [_controller ! 760: allocateBufferOfLength: count ! 761: actualStart: &freePtr ! 762: actualLength: &freeCnt]; ! 763: ! 764: ! 765: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 766: ! 767: scsiReq.target = _target; ! 768: scsiReq.lun = _lun; ! 769: scsiReq.read = YES; ! 770: ! 771: [_controller getDMAAlignment:&dmaAlign]; ! 772: if(dmaAlign.readLength > 1) { ! 773: scsiReq.maxTransfer = IOAlign(int, count, ! 774: dmaAlign.readLength); ! 775: ! 776: } else { ! 777: scsiReq.maxTransfer = count; ! 778: } ! 779: ! 780: scsiReq.timeoutLength = ST_IOTO_NORM; ! 781: scsiReq.disconnect = 1; ! 782: cdbp->c6_opcode = C6OP_MODESENSE; ! 783: cdbp->c6_lun = _lun; ! 784: cdbp->c6_len = count; ! 785: ! 786: rtn = [self executeRequest:&scsiReq ! 787: buffer:alignedBuf ! 788: client:IOVmTaskSelf() ! 789: senseBuf: _senseDataPtr]; ! 790: ! 791: if(rtn == SR_IOST_GOOD) { ! 792: bcopy (alignedBuf, &modeSenseParmsPtr->msp_data, count); ! 793: } ! 794: ! 795: IOFree(freePtr, freeCnt); ! 796: return rtn; ! 797: } /* - stModeSense: */ ! 798: ! 799: ! 800: ! 801: - (sc_status_t) executeMTOperation: (struct mtop *) mtopp ! 802: { ! 803: IOSCSIRequest scsiReq; ! 804: cdb_6s_t *cdbp = &scsiReq.cdb.cdb_c6s; ! 805: int count; ! 806: sc_status_t rtn; ! 807: ! 808: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 809: scsiReq.target = _target; ! 810: scsiReq.lun = _lun; ! 811: scsiReq.timeoutLength = ST_IOTO_NORM; /* Some ops override this */ ! 812: scsiReq.disconnect = 1; // XXX - maybe not for all ops. ! 813: ! 814: /* ! 815: * none of these operations performs DMA. For each, just fill in ! 816: * the cdb, and pass it to the controller. ! 817: */ ! 818: ! 819: /* build a CDB */ ! 820: ! 821: switch(mtopp->mt_op) { ! 822: case MTWEOF: /* write file marks */ ! 823: cdbp->c6s_opcode = C6OP_WRTFM; ! 824: goto setcount_f; ! 825: ! 826: case MTFSF: /* space file marks forward */ ! 827: cdbp->c6s_opcode = C6OP_SPACE; ! 828: cdbp->c6s_opt = C6OPT_SPACE_FM; ! 829: scsiReq.timeoutLength = mtopp->mt_count * ST_IOTO_SPFM; ! 830: goto setcount_f; ! 831: ! 832: case MTBSF: /* space file marks backward */ ! 833: cdbp->c6s_opcode = C6OP_SPACE; ! 834: cdbp->c6s_opt = C6OPT_SPACE_FM; ! 835: scsiReq.timeoutLength = mtopp->mt_count * ST_IOTO_SPFM; ! 836: goto setcount_b; ! 837: ! 838: case MTFSR: /* space records forward */ ! 839: cdbp->c6s_opcode = C6OP_SPACE; ! 840: cdbp->c6s_opt = C6OPT_SPACE_LB; ! 841: scsiReq.timeoutLength = ST_IOTO_SPR; ! 842: setcount_f: ! 843: assign_cdb_c6s_len (cdbp, mtopp->mt_count); ! 844: break; ! 845: ! 846: case MTBSR: /* space records backward */ ! 847: cdbp->c6s_opcode = C6OP_SPACE; ! 848: cdbp->c6s_opt = C6OPT_SPACE_LB; ! 849: scsiReq.timeoutLength = ST_IOTO_SPR; ! 850: setcount_b: ! 851: count = 0 - mtopp->mt_count; ! 852: assign_cdb_c6s_len (cdbp, count); ! 853: break; ! 854: ! 855: case MTREW: /* rewind */ ! 856: cdbp->c6s_opcode = C6OP_REWIND; ! 857: scsiReq.timeoutLength = ST_IOTO_RWD; ! 858: break; ! 859: ! 860: case MTOFFL: /* set offline */ ! 861: cdbp->c6s_opcode = C6OP_STARTSTOP; ! 862: /* note load bit is 0 */ ! 863: scsiReq.timeoutLength = ST_IOTO_RWD; ! 864: break; ! 865: ! 866: case MTNOP: /* nop / get status */ ! 867: case MTCACHE: /* enable cache */ ! 868: case MTNOCACHE: /* disable cache */ ! 869: case MTRETEN: ! 870: case MTERASE: ! 871: default: ! 872: rtn = SR_IOST_CMDREJ; /* FIXME: unsupported? */ ! 873: goto out; ! 874: } ! 875: ! 876: rtn = [self executeRequest: &scsiReq ! 877: buffer: NULL ! 878: client: IOVmTaskSelf() ! 879: senseBuf: _senseDataPtr]; ! 880: out: ! 881: return rtn; ! 882: } /* - executeMTOperation: */ ! 883: ! 884: ! 885: ! 886: /* ! 887: * Set block size for SCSI tape device. ! 888: * ! 889: * blocksize == 0 --> variable ! 890: * blocksize != 0 --> fixed @ blocksize ! 891: * ! 892: * First, execute mode sense, then mode select with block length ! 893: * set to 0 (variable) or blocksize (fixed) ! 894: */ ! 895: - (IOReturn) setBlockSize: (int) blockSize ! 896: { ! 897: int rtn; ! 898: struct modesel_parms *mspp; ! 899: struct mode_sel_hdr *mshp; ! 900: ! 901: mspp = IOMalloc (sizeof(struct modesel_parms)); ! 902: mspp->msp_bcount = sizeof(struct mode_sel_hdr) + ! 903: sizeof(struct mode_sel_bd); ! 904: ! 905: if((rtn = [self stModeSense: mspp]) != SR_IOST_GOOD) { ! 906: IOFree (mspp, sizeof (struct modesel_parms)); ! 907: return [_controller returnFromScStatus: rtn]; ! 908: } ! 909: ! 910: mshp = &mspp->msp_data.msd_header; ! 911: mshp->msh_sd_length_0 = 0; ! 912: mshp-> msh_med_type = 0; ! 913: mshp-> msh_wp = 0; ! 914: mshp-> msh_bd_length = sizeof(struct mode_sel_bd); ! 915: assign_msbd_blocklength ! 916: (&mspp->msp_data.msd_blockdescript, blockSize); ! 917: assign_msbd_numblocks ! 918: (&mspp->msp_data.msd_blockdescript, 0); ! 919: ! 920: if((rtn = [self stModeSelect: mspp]) != SR_IOST_GOOD) { ! 921: IOFree (mspp, sizeof (struct modesel_parms)); ! 922: return [_controller returnFromScStatus: rtn]; ! 923: } ! 924: ! 925: _blockSize = blockSize; ! 926: ! 927: IOFree (mspp, sizeof (struct modesel_parms)); ! 928: return IO_R_SUCCESS; ! 929: } /* - setBlockSize: */ ! 930: ! 931: ! 932: ! 933: ! 934: /* ! 935: * Execute CDB. Buffer must be well aligned. If command results ! 936: * in Check Status, return the sense data in *senseBuf. ! 937: */ ! 938: - (sc_status_t) executeRequest: (IOSCSIRequest *)scsiReq ! 939: buffer:(void *) buffer /* data destination */ ! 940: client:(vm_task_t) client ! 941: senseBuf:(esense_reply_t *) senseBuf ! 942: { ! 943: sc_status_t rtn; ! 944: ! 945: _senseDataValid = NO; ! 946: ! 947: #ifdef DEBUG ! 948: IOLog("Entered SCSI Tape executeRequest: op %s, maxTransfer %d, len %d\n", ! 949: IOFindNameForValue(scsiReq->cdb.cdb_opcode, ! 950: IOSCSIOpcodeStrings), ! 951: scsiReq->maxTransfer, ! 952: (scsiReq->cdb.cdb_c6s.c6s_len2 << 16) | ! 953: (scsiReq->cdb.cdb_c6s.c6s_len1 << 8) | ! 954: (scsiReq->cdb.cdb_c6s.c6s_len0)); ! 955: #endif DEBUG ! 956: ! 957: rtn = [_controller executeRequest:scsiReq ! 958: buffer:buffer ! 959: client:client]; ! 960: ! 961: #ifdef DEBUG ! 962: IOLog ("Length %d on return from executeRequest\n", scsiReq->bytesTransferred); ! 963: #endif DEBUG ! 964: ! 965: /* ! 966: * Log error returns. ! 967: */ ! 968: if (rtn != SR_IOST_GOOD) { ! 969: /* ! 970: * If result is Check Condition, do a Request Sense, unless suppressed. ! 971: */ ! 972: if(rtn == SR_IOST_CHKSV) { ! 973: /* ! 974: * Host Adaptor already got us sense data. Give sense data ! 975: * to user and save it. ! 976: */ ! 977: *senseBuf = *_senseDataPtr = scsiReq->senseData; ! 978: _senseDataValid = YES; ! 979: } ! 980: if (((rtn == SR_IOST_CHKSNV) || (rtn == SR_IOST_CHKSV)) && ! 981: !_ignoreCheckCondition) { ! 982: if(rtn == SR_IOST_CHKSV) { ! 983: rtn = SR_IOST_GOOD; ! 984: } ! 985: else { ! 986: rtn = [self requestSense: senseBuf]; ! 987: } ! 988: if(rtn == SR_IOST_GOOD) { ! 989: /* ! 990: * If the error is a filemark, and we are reading, ! 991: * then return no error. Otherwise, return ! 992: * check sense, with valid sense data. ! 993: */ ! 994: if ((scsiReq->cdb.cdb_c6.c6_opcode == C6OP_READ) && ! 995: (senseBuf->er_filemark)) { ! 996: ! 997: /* ! 998: * Check for correct reporting of bytes transferred. ! 999: * (This works around a DPT firmware bug.) ! 1000: */ ! 1001: int transferLength = ! 1002: cdb_c6s_len_value (&scsiReq->cdb.cdb_c6s) - ! 1003: er_info_value (senseBuf); ! 1004: ! 1005: if ([self isFixedBlock]) { ! 1006: transferLength = transferLength * _blockSize; ! 1007: } ! 1008: ! 1009: if (scsiReq->bytesTransferred != transferLength) { ! 1010: #ifdef DEBUG ! 1011: IOLog ("%s: Incorrect byte count reported - " ! 1012: "corrected to %d\n", [self name], transferLength); ! 1013: #endif DEBUG ! 1014: scsiReq->bytesTransferred = transferLength; ! 1015: } ! 1016: ! 1017: rtn = SR_IOST_GOOD; ! 1018: scsiReq->driverStatus = SR_IOST_GOOD; ! 1019: ! 1020: #ifdef DEBUG ! 1021: IOLog ("execReq sense: er_filemark %d, er_badlen %d, er_sensekey %d, er_addsensecode %d, er_qualifier %d, er_info %d\n", ! 1022: senseBuf->er_filemark, senseBuf->er_badlen, senseBuf->er_sensekey, ! 1023: senseBuf->er_addsensecode, senseBuf->er_qualifier, ! 1024: er_info_value (senseBuf)); ! 1025: #endif DEBUG ! 1026: ! 1027: } ! 1028: else { ! 1029: rtn = SR_IOST_CHKSV; ! 1030: } ! 1031: } ! 1032: else { ! 1033: if (_isInitialized) { ! 1034: IOLog("%s: Request Sense on target %d lun %d " ! 1035: "failed (%s)\n", ! 1036: [self name], _target, _lun, ! 1037: IOFindNameForValue(rtn, IOScStatusStrings)); ! 1038: } ! 1039: rtn = SR_IOST_CHKSNV; ! 1040: } ! 1041: } ! 1042: ! 1043: /* ! 1044: * Log error messages, except the spate of timeouts and ! 1045: * device not ready messages during initialization. ! 1046: */ ! 1047: if (_isInitialized && ! 1048: (rtn != SR_IOST_GOOD) && ! 1049: !_ignoreCheckCondition) { ! 1050: ! 1051: IOLog("%s, target %d, lun %d: op %s returned %s\n", ! 1052: [self name], _target, _lun, ! 1053: IOFindNameForValue(scsiReq->cdb.cdb_opcode, ! 1054: IOSCSIOpcodeStrings), ! 1055: IOFindNameForValue(rtn, IOScStatusStrings)); ! 1056: ! 1057: if (rtn == SR_IOST_CHKSV) { ! 1058: IOLog (" Sense key = 0x%x Sense Code = 0x%x\n", ! 1059: senseBuf->er_sensekey, senseBuf->er_addsensecode); ! 1060: } ! 1061: } ! 1062: ! 1063: _didWrite = NO; ! 1064: } ! 1065: ! 1066: else { ! 1067: /* Remember good writes for device close */ ! 1068: if (scsiReq->cdb.cdb_opcode == C6OP_WRITE) { ! 1069: _didWrite = YES; ! 1070: } else { ! 1071: _didWrite = NO; ! 1072: } ! 1073: } ! 1074: ! 1075: return rtn; ! 1076: } /* executeRequest: */ ! 1077: ! 1078: @end ! 1079: ! 1080: /* ! 1081: * Supporting functions. ! 1082: */ ! 1083: ! 1084: /* ! 1085: * moveString is taken directly from SCSIDiskPrivate.m. ! 1086: * It's used by -initSCSITape: ! 1087: * ! 1088: * Copy inp to outp for up to inlength input characters or outlength output ! 1089: * characters. Compress multiple spaces and eliminate nulls. Returns number ! 1090: * of characters copied to outp. ! 1091: */ ! 1092: static int ! 1093: moveString(char *inp, char *outp, int inlength, int outlength) ! 1094: { ! 1095: int lastCharSpace = 0; ! 1096: char *outpStart = outp; ! 1097: ! 1098: while(inlength && outlength) { ! 1099: switch(*inp) { ! 1100: case '\0': ! 1101: inp++; ! 1102: inlength--; ! 1103: continue; ! 1104: case ' ': ! 1105: if(lastCharSpace) { ! 1106: inp++; ! 1107: inlength--; ! 1108: continue; ! 1109: } ! 1110: lastCharSpace = 1; ! 1111: goto copyit; ! 1112: default: ! 1113: lastCharSpace = 0; ! 1114: copyit: ! 1115: *outp++ = *inp++; ! 1116: inlength--; ! 1117: outlength--; ! 1118: break; ! 1119: } ! 1120: } ! 1121: return(outp - outpStart); ! 1122: } ! 1123: ! 1124: ! 1125: ! 1126: void ! 1127: assign_cdb_c6s_len (struct cdb_6s *cdbp, int length) ! 1128: { ! 1129: #if __BIG_ENDIAN__ ! 1130: #if __NATURAL_ALIGNMENT__ ! 1131: cdbp->c6s_len[0] = (length >> 16) & 0xff; ! 1132: cdbp->c6s_len[1] = (length >> 8) & 0xff; ! 1133: cdbp->c6s_len[2] = length & 0xff; ! 1134: ! 1135: #else __NATURAL_ALIGNMENT__ ! 1136: ! 1137: cdbp->c6s_len = length; ! 1138: ! 1139: #endif __NATURAL_ALIGNMENT__ ! 1140: ! 1141: ! 1142: #elif __LITTLE_ENDIAN__ ! 1143: ! 1144: cdbp->c6s_len0 = (u_char) length & 0xff; ! 1145: cdbp->c6s_len1 = (u_char) (length >> 8) & 0xff; ! 1146: cdbp->c6s_len2 = (u_char) (length >> 16) & 0xff; ! 1147: ! 1148: #endif ! 1149: ! 1150: return; ! 1151: } ! 1152: ! 1153: void ! 1154: assign_msbd_numblocks (struct mode_sel_bd *msbdp, int numblocks) ! 1155: { ! 1156: #if __BIG_ENDIAN__ ! 1157: msbdp->msbd_numblocks = numblocks; ! 1158: #elif __LITTLE_ENDIAN__ ! 1159: msbdp->msbd_numblocks0 = (u_char) numblocks & 0xff; ! 1160: msbdp->msbd_numblocks1 = (u_char) (numblocks >> 8) & 0xff; ! 1161: msbdp->msbd_numblocks2 = (u_char) (numblocks >> 16) & 0xff; ! 1162: #endif ! 1163: return; ! 1164: } ! 1165: ! 1166: void ! 1167: assign_msbd_blocklength (struct mode_sel_bd *msbdp, int length) ! 1168: { ! 1169: #if __BIG_ENDIAN__ ! 1170: msbdp->msbd_blocklength = length; ! 1171: #elif __LITTLE_ENDIAN__ ! 1172: msbdp->msbd_blocklength0 = (u_char) length & 0xff; ! 1173: msbdp->msbd_blocklength1 = (u_char) (length >> 8) & 0xff; ! 1174: msbdp->msbd_blocklength2 = (u_char) (length >> 16) & 0xff; ! 1175: #endif ! 1176: return; ! 1177: } ! 1178: ! 1179: int ! 1180: cdb_c6s_len_value (struct cdb_6s *cdbp) ! 1181: { ! 1182: #if __BIG_ENDIAN__ ! 1183: return (cdbp->c6s_len); ! 1184: #elif __LITTLE_ENDIAN__ ! 1185: return (cdbp->c6s_len0 | (cdbp->c6s_len1 << 8) | (cdbp->c6s_len2 << 16)); ! 1186: #endif ! 1187: } ! 1188: ! 1189: int ! 1190: er_info_value (struct esense_reply *esrp) ! 1191: { ! 1192: #if __BIG_ENDIAN__ ! 1193: return (esrp->er_info); ! 1194: #elif __LITTLE_ENDIAN__ ! 1195: return (esrp->er_info0 | (esrp->er_info1 << 8) | ! 1196: (esrp->er_info2 << 16) | (esrp->er_info3 << 24)); ! 1197: #endif ! 1198: } ! 1199:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.