|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: /* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved. ! 25: * ! 26: * SCSIGeneric.m - Generic SCSI Driver. ! 27: * ! 28: * HISTORY ! 29: * 14-Jun-95 Doug Mitchell at NeXT ! 30: * Added SCSI-3 support. ! 31: * 19-Aug-92 Doug Mitchell at NeXT ! 32: * Created. ! 33: */ ! 34: ! 35: #import <driverkit/SCSIGeneric.h> ! 36: #import <driverkit/SCSIGenericPrivate.h> ! 37: #import <driverkit/scsiTypes.h> ! 38: #import <driverkit/return.h> ! 39: #import <driverkit/generalFuncs.h> ! 40: #import <driverkit/kernelDriver.h> ! 41: #import <machkit/NXLock.h> ! 42: #import <driverkit/xpr_mi.h> ! 43: #import <driverkit/align.h> ! 44: ! 45: /* ! 46: * Private method declarations. ! 47: */ ! 48: @interface SCSIGeneric(Private) ! 49: ! 50: - (sc_status_t)getSense : (esense_reply_t *)sense; ! 51: - (void)clearReservation; ! 52: ! 53: @end ! 54: ! 55: /* ! 56: * Public method implementation. ! 57: */ ! 58: @implementation SCSIGeneric ! 59: ! 60: + (IODeviceStyle)deviceStyle ! 61: { ! 62: return IO_IndirectDevice; ! 63: } ! 64: ! 65: /* ! 66: * The protocol we need as an indirect device. ! 67: */ ! 68: static Protocol *protocols[] = { ! 69: @protocol(IOSCSIControllerExported), ! 70: nil ! 71: }; ! 72: ! 73: + (Protocol **)requiredProtocols ! 74: { ! 75: return protocols; ! 76: } ! 77: ! 78: ! 79: - registerLoudly ! 80: { ! 81: return( nil); ! 82: } ! 83: ! 84: + (BOOL)probe : deviceDescription ! 85: { ! 86: id sgId; ! 87: int i; ! 88: id controller = [deviceDescription directDevice]; ! 89: ! 90: /* ! 91: * We only bother attaching to controller 0 at probe time. ! 92: * Clients can specify other controllers later via ! 93: * -setController:. ! 94: */ ! 95: if([controller unit] != 0) { ! 96: return NO; ! 97: } ! 98: for(i=0; i<NUM_SG_DEV; i++) { ! 99: sgId = [self alloc]; ! 100: sgIdMap[i] = sgId; ! 101: [sgId sgInit:i controller:controller]; ! 102: } ! 103: return YES; ! 104: } ! 105: ! 106: /* ! 107: * One-time only init. Returns non-zero on error. ! 108: */ ! 109: - (int)sgInit : (unsigned)unitNum ! 110: controller : controller ! 111: { ! 112: char name[20]; ! 113: ! 114: _controller = controller; ! 115: _controllerNum = 0; ! 116: _autoSense = 0; ! 117: _isReserved = 0; ! 118: _targLunValid = 0; ! 119: _openLock = [NXLock new]; ! 120: _owner = nil; ! 121: sprintf(name, "sg%d", unitNum); ! 122: [self setName:name]; ! 123: [self setDeviceKind:"SCSIGeneric"]; ! 124: [self setLocation:[controller name]]; ! 125: [self setUnit:unitNum]; ! 126: [self registerDevice]; ! 127: return 0; ! 128: } ! 129: ! 130: - (unsigned char)target ! 131: { ! 132: return (unsigned char)_target; ! 133: } ! 134: ! 135: - (unsigned char)lun ! 136: { ! 137: return (unsigned char)_lun; ! 138: } ! 139: ! 140: - (unsigned long long)SCSI3_target ! 141: { ! 142: return _target; ! 143: } ! 144: ! 145: - (unsigned long long)SCSI3_lun ! 146: { ! 147: return _lun; ! 148: } ! 149: ! 150: /* ! 151: * Acquire and release, to allow exclusive access to this device. ! 152: * ! 153: * -acquire returns non-zero if device in use, else reserves device for ! 154: * exclusive use by 'caller'. ! 155: * -release returns non-zero if device not currently in use by 'caller'. ! 156: */ ! 157: - (int)acquire : caller ! 158: { ! 159: int rtn; ! 160: ! 161: xpr_sdev("SCSIGeneric acquire\n", 1,2,3,4,5); ! 162: [_openLock lock]; ! 163: if(_owner) { ! 164: rtn = 1; ! 165: } ! 166: else { ! 167: _autoSense = 0; ! 168: _owner = caller; ! 169: rtn = 0; ! 170: } ! 171: [_openLock unlock]; ! 172: return rtn; ! 173: } ! 174: ! 175: - (int)release : caller ! 176: { ! 177: int rtn; ! 178: ! 179: xpr_sdev("SCSIGeneric release\n", 1,2,3,4,5); ! 180: [_openLock lock]; ! 181: if(caller != _owner) { ! 182: IOLog("%s: bogus close call\n", [self name]); ! 183: rtn = 1; ! 184: } ! 185: else { ! 186: /* ! 187: * Clear possible pending reservation. ! 188: */ ! 189: [self clearReservation]; ! 190: _owner = nil; ! 191: } ! 192: [_openLock unlock]; ! 193: } ! 194: ! 195: /* ! 196: * ioctl equivalents. ! 197: */ ! 198: ! 199: /* ! 200: * Set target and lun. If isRoot is true, this will succeed even if specified ! 201: * target/lun are currently reserved. otherwise, returns IO_R_BUSY if ! 202: * desired target/lun already reserved. ! 203: */ ! 204: - (IOReturn)setTarget : (unsigned char)target ! 205: lun:(unsigned char)lun ! 206: isRoot:(BOOL)isRoot ! 207: { ! 208: xpr_sdev("SCSIGeneric setTarget t %d l %d\n", target, lun, 3,4,5); ! 209: if((target >= [_controller numberOfTargets]) || (lun > SCSI_NLUNS)) { ! 210: return IO_R_INVALID_ARG; ! 211: } ! 212: ! 213: [self clearReservation]; ! 214: if([_controller reserveSCSI3Target:(unsigned long long)target ! 215: lun:(unsigned long long)lun ! 216: forOwner:self]) { ! 217: if(!isRoot) { ! 218: return IO_R_BUSY; ! 219: } ! 220: /* ! 221: * else: playing dangerously, but we'll do it... ! 222: */ ! 223: } ! 224: else { ! 225: _isReserved = 1; ! 226: } ! 227: _target = target; ! 228: _lun = lun; ! 229: _targLunValid = 1; ! 230: return IO_R_SUCCESS; ! 231: } ! 232: ! 233: - (IOReturn)setSCSI3Target : (unsigned long long)target ! 234: lun:(unsigned long long)lun ! 235: isRoot:(BOOL)isRoot ! 236: { ! 237: xpr_sdev("setSCSI3Target: t %x:%x l %x:%x\n", ! 238: (unsigned)(target >> 32), ! 239: (unsigned)target, ! 240: (unsigned)(lun >> 32), ! 241: (unsigned)lun, 5); ! 242: if((target >= [_controller numberOfTargets]) || (lun > SCSI_NLUNS)) { ! 243: return IO_R_INVALID_ARG; ! 244: } ! 245: ! 246: [self clearReservation]; ! 247: if([_controller reserveSCSI3Target:target ! 248: lun:lun ! 249: forOwner:self]) { ! 250: if(!isRoot) { ! 251: return IO_R_BUSY; ! 252: } ! 253: /* ! 254: * else: playing dangerously, but we'll do it... ! 255: */ ! 256: } ! 257: else { ! 258: _isReserved = 1; ! 259: } ! 260: _target = target; ! 261: _lun = lun; ! 262: _targLunValid = 1; ! 263: return IO_R_SUCCESS; ! 264: } ! 265: ! 266: ! 267: /* ! 268: * Select controller number. Clears pending reservation if controllerNum ! 269: * is changing. ! 270: */ ! 271: - (IOReturn)setController : (unsigned)controllerNum ! 272: { ! 273: char contrStr[10]; ! 274: IOReturn drtn; ! 275: id newController; ! 276: ! 277: if(controllerNum == _controllerNum) { ! 278: return IO_R_SUCCESS; ! 279: } ! 280: [self clearReservation]; ! 281: ! 282: /* ! 283: * Look up new controller. ! 284: */ ! 285: sprintf(contrStr, "sc%d", controllerNum); ! 286: drtn = IOGetObjectForDeviceName(contrStr, &newController); ! 287: if(drtn) { ! 288: return IO_R_NO_DEVICE; ! 289: } ! 290: _controllerNum = controllerNum; ! 291: _controller = newController; ! 292: _targLunValid = 0; ! 293: return IO_R_SUCCESS; ! 294: } ! 295: ! 296: /* ! 297: * Enable/disable 'autosense' mechanism. ! 298: */ ! 299: - (IOReturn)enableAutoSense ! 300: { ! 301: _autoSense = 1; ! 302: return IO_R_SUCCESS; ! 303: } ! 304: ! 305: - (IOReturn)disableAutoSense ! 306: { ! 307: _autoSense = 0; ! 308: return IO_R_SUCCESS; ! 309: } ! 310: ! 311: - (int)autoSense ! 312: { ! 313: return _autoSense; ! 314: } ! 315: ! 316: ! 317: /* ! 318: * Execute CDB. Buffer must be well aligned. ! 319: * *sense will contain sense data if autoSense is enabled and command ! 320: * resulted in Check status. ! 321: */ ! 322: - (sc_status_t)executeRequest : (IOSCSIRequest *)scsiReq ! 323: buffer:(void *)buffer /* data destination */ ! 324: client:(vm_task_t)client ! 325: senseBuf:(esense_reply_t *)senseBuf ! 326: { ! 327: sc_status_t rtn; ! 328: ! 329: xpr_sdev("sg executeRequest; op %s\n", ! 330: IOFindNameForValue(scsiReq->cdb.cdb_opcode, ! 331: IOSCSIOpcodeStrings),2,3,4,5); ! 332: if(!_targLunValid || ! 333: ((unsigned long long)scsiReq->target != _target) || ! 334: ((unsigned long long)scsiReq->lun != _lun)) { ! 335: rtn = SR_IOST_CMDREJ; ! 336: goto out; ! 337: } ! 338: rtn = [_controller executeRequest:scsiReq ! 339: buffer:buffer ! 340: client:client]; ! 341: ! 342: /* ! 343: * The only thing we deal with is Check Status, for which we'll do ! 344: * a Request Sense if autoSense is enabled. ! 345: */ ! 346: if(rtn == SR_IOST_CHKSV) { ! 347: /* ! 348: * Host adaptor already got us sense data. ! 349: */ ! 350: *senseBuf = scsiReq->senseData; ! 351: } ! 352: else if((rtn == SR_IOST_CHKSNV) && _autoSense) { ! 353: rtn = [self getSense:senseBuf]; ! 354: if(rtn == SR_IOST_GOOD) { ! 355: rtn = SR_IOST_CHKSV; ! 356: } ! 357: else { ! 358: IOLog("%s: Request Sense on target %d lun %d " ! 359: "failed (%s)\n", ! 360: [self name], (unsigned)_target, (unsigned)_lun, ! 361: IOFindNameForValue(rtn, IOScStatusStrings)); ! 362: rtn = SR_IOST_CHKSNV; ! 363: } ! 364: } ! 365: out: ! 366: xpr_sdev("sg executeRequest: returning %s\n", ! 367: IOFindNameForValue(rtn, IOScStatusStrings), 2,3,4,5); ! 368: return rtn; ! 369: } ! 370: ! 371: /* ! 372: * Execute CDB, SCSI-3 style. Buffer must be well aligned. ! 373: * *sense will contain sense data if autoSense is enabled and command ! 374: * resulted in Check status. ! 375: */ ! 376: - (sc_status_t)executeSCSI3Request : (IOSCSI3Request *)scsiReq ! 377: buffer : (void *)buffer /* data destination */ ! 378: client : (vm_task_t)client ! 379: senseBuf : (esense_reply_t *)senseBuf ! 380: { ! 381: sc_status_t rtn; ! 382: ! 383: xpr_sdev("sg executeSCSI3Request; op %s\n", ! 384: IOFindNameForValue(scsiReq->cdb.cdb_opcode, ! 385: IOSCSIOpcodeStrings),2,3,4,5); ! 386: if(!_targLunValid || ! 387: (scsiReq->target != _target) || ! 388: (scsiReq->lun != _lun)) { ! 389: rtn = SR_IOST_CMDREJ; ! 390: goto out; ! 391: } ! 392: rtn = [_controller executeSCSI3Request:scsiReq ! 393: buffer:buffer ! 394: client:client]; ! 395: ! 396: /* ! 397: * The only thing we deal with is Check Status, for which we'll do ! 398: * a Request Sense if autoSense is enabled. ! 399: */ ! 400: if(rtn == SR_IOST_CHKSV) { ! 401: /* ! 402: * Host adaptor already got us sense data. ! 403: */ ! 404: *senseBuf = scsiReq->senseData; ! 405: } ! 406: else if((rtn == SR_IOST_CHKSNV) && _autoSense) { ! 407: rtn = [self getSense:senseBuf]; ! 408: if(rtn == SR_IOST_GOOD) { ! 409: rtn = SR_IOST_CHKSV; ! 410: } ! 411: else { ! 412: IOLog("%s: Request Sense on target %d lun %d " ! 413: "failed (%s)\n", ! 414: [self name], (unsigned)_target, (unsigned)_lun, ! 415: IOFindNameForValue(rtn, IOScStatusStrings)); ! 416: rtn = SR_IOST_CHKSNV; ! 417: } ! 418: } ! 419: out: ! 420: xpr_sdev("sg executeSCSI3Request: returning %s\n", ! 421: IOFindNameForValue(rtn, IOScStatusStrings), 2,3,4,5); ! 422: return rtn; ! 423: } ! 424: ! 425: /* ! 426: * Reset SCSI bus. We can't authorize this; caller should ensure that ! 427: * client is root! ! 428: */ ! 429: - (sc_status_t) resetSCSIBus; ! 430: { ! 431: return [_controller resetSCSIBus]; ! 432: } ! 433: ! 434: - controller ! 435: { ! 436: return _controller; ! 437: } ! 438: ! 439: @end /* of SCSIGeneric */ ! 440: ! 441: /* ! 442: * Private methods. ! 443: */ ! 444: @implementation SCSIGeneric(Private) ! 445: ! 446: /* ! 447: * Get sense data from current target and lun. senseBuf does not have ! 448: * to be well aligned. ! 449: */ ! 450: - (sc_status_t)getSense : (esense_reply_t *)senseBuf ! 451: { ! 452: IOSCSIRequest scsiReq; ! 453: cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6; ! 454: esense_reply_t *alignedBuf; ! 455: void *freePtr; ! 456: int freeCnt; ! 457: sc_status_t rtn; ! 458: IODMAAlignment dmaAlign; ! 459: ! 460: alignedBuf = [_controller allocateBufferOfLength: ! 461: sizeof(esense_reply_t) ! 462: actualStart:&freePtr ! 463: actualLength:&freeCnt]; ! 464: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 465: [_controller getDMAAlignment:&dmaAlign]; ! 466: ! 467: scsiReq.target = _target; ! 468: scsiReq.lun = _lun; ! 469: scsiReq.read = YES; ! 470: if(dmaAlign.readLength > 1) { ! 471: scsiReq.maxTransfer = IOAlign(int, sizeof(esense_reply_t), ! 472: dmaAlign.readLength); ! 473: } else { ! 474: scsiReq.maxTransfer = sizeof(esense_reply_t); ! 475: } ! 476: scsiReq.timeoutLength = 10; ! 477: scsiReq.disconnect = 0; ! 478: cdbp->c6_opcode = C6OP_REQSENSE; ! 479: cdbp->c6_lun = _lun; ! 480: cdbp->c6_len = sizeof(esense_reply_t); ! 481: ! 482: rtn = [_controller executeRequest:&scsiReq ! 483: buffer:alignedBuf ! 484: client:IOVmTaskSelf()]; ! 485: if(rtn == SR_IOST_GOOD) { ! 486: *senseBuf = *alignedBuf; ! 487: } ! 488: IOFree(freePtr, freeCnt); ! 489: return rtn; ! 490: } ! 491: ! 492: /* ! 493: * Clear possible pending reservation, whichever style was last used. ! 494: */ ! 495: - (void)clearReservation ! 496: { ! 497: if(_isReserved) { ! 498: if(_targLunValid) { ! 499: [_controller releaseSCSI3Target:_target ! 500: lun:_lun ! 501: forOwner:self]; ! 502: _targLunValid = 0; ! 503: } ! 504: else { ! 505: IOLog("%s: clearReservation, no valid target\n", ! 506: [self name]); ! 507: } ! 508: _isReserved = 0; ! 509: } ! 510: ! 511: /* ! 512: * Note _targLunValid could have been true on entry even if ! 513: * _isReserved was false - that's the case where root set a target ! 514: * and LUN which was already reserved. ! 515: */ ! 516: _targLunValid = 0; ! 517: } ! 518: ! 519: ! 520: @end /* of SCSIGeneric(Private) */ ! 521: ! 522:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.