|
|
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.0 (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: /* ! 25: * Copyright 1997-1998 by Apple Computer, Inc., All rights reserved. ! 26: * Copyright 1994-1997 NeXT Software, Inc., All rights reserved. ! 27: * ! 28: * IdeDiskInternal.m - internal IDE disk methods. ! 29: * ! 30: * HISTORY ! 31: * ! 32: * 04-Mar-1996 Rakesh Dubey at NeXT ! 33: * Modified so that no memory is allocated at run-time. ! 34: * ! 35: * 07-Jul-1994 Rakesh Dubey at NeXT ! 36: * Created from original driver written by David Somayajulu. ! 37: */ ! 38: ! 39: #import <driverkit/return.h> ! 40: #import <driverkit/driverTypes.h> ! 41: #import "IdeCnt.h" ! 42: #import "IdeCntInit.h" ! 43: #import "IdeCntCmds.h" ! 44: #import "IdeDiskInternal.h" ! 45: #import "IdeKernel.h" ! 46: #import <driverkit/kernelDiskMethods.h> ! 47: #import <driverkit/generalFuncs.h> ! 48: #import <machkit/NXLock.h> ! 49: #import <driverkit/align.h> ! 50: #import <bsd/stdio.h> ! 51: #import <bsd/string.h> ! 52: ! 53: IOReturn iderToIo(ide_return_t); ! 54: ! 55: //#define DEBUG ! 56: ! 57: @implementation IdeDisk(Internal) ! 58: ! 59: /* ! 60: * Print information about the disk and fill up the ideDriveName field. ! 61: */ ! 62: -(void)printInfo:(ideIdentifyInfo_t *)ideIdentifyInfo unit:(unsigned int)unit ! 63: { ! 64: int i; ! 65: char name[50]; ! 66: char firmware[9]; ! 67: ! 68: /* ! 69: * Print drive name with firmware revision number after doing byte swaps. ! 70: */ ! 71: for (i = 0; i < 20; i++) { ! 72: name[2*i] = ideIdentifyInfo->modelNumber[2*i+1]; ! 73: name[2*i+1] = ideIdentifyInfo->modelNumber[2*i]; ! 74: } ! 75: name[40] = '\0'; ! 76: ! 77: for (i = 0; i < 4; i++) { ! 78: firmware[2*i] = ideIdentifyInfo->firmwareRevision[2*i+1]; ! 79: firmware[2*i+1] = ideIdentifyInfo->firmwareRevision[2*i]; ! 80: } ! 81: firmware[8] = '\0'; ! 82: ! 83: for (i = 38; i >= 0; i--) { ! 84: if (name[i] != ' ') ! 85: break; ! 86: } ! 87: strcpy(name+i+2, firmware); ! 88: ! 89: ! 90: IOLog("%s: %s\n", [self name], name); ! 91: ! 92: /* ! 93: * The drive name is limited to 32 characters and we don't want firmware ! 94: * version in there. ! 95: */ ! 96: name[i+1] = '\0'; name[31] = '\0'; ! 97: strcpy(_ideDriveName, name); ! 98: ! 99: /* ! 100: * Print drive geometry and how did we get it. ! 101: */ ! 102: IOLog("%s: CHS = %d/%d/%d ", ! 103: [self name], _ideInfo.cylinders, ! 104: _ideInfo.heads, _ideInfo.sectors_per_trk); ! 105: ! 106: if ([_cntrlr isDiskGeometry:unit] == YES) ! 107: IOLog("(disk geometry)\n"); ! 108: else ! 109: IOLog("(bios geometry)\n"); ! 110: ! 111: /* ! 112: * Other diagnostic information. All of this can also be obtained via ! 113: * /usr/etc/idemodes ! 114: */ ! 115: #ifdef DEBUG ! 116: IOLog("%s: PIO timing cycle: %d ns (mode %d).\n", [self name], ! 117: ideIdentifyInfo->pioDataTransferCyleTimingMode & ! 118: IDE_PIO_TIMING_MODE_MASK, ! 119: [_cntrlr getTransferModeFromCycleTime:ideIdentifyInfo ! 120: transferType:IDE_TRANSFER_PIO]); ! 121: ! 122: if (ideIdentifyInfo->capabilities & IDE_CAP_DMA_SUPPORTED) { ! 123: IOLog("%s: DMA timing cycle: %d ns (mode %d).\n", [self name], ! 124: ideIdentifyInfo->dmaDataTransferCyleTimingMode & ! 125: IDE_DMA_TIMING_MODE_MASK, ! 126: [_cntrlr getTransferModeFromCycleTime:ideIdentifyInfo ! 127: transferType:IDE_TRANSFER_SW_DMA]); ! 128: } ! 129: if (ideIdentifyInfo->capabilities & IDE_CAP_LBA_SUPPORTED) { ! 130: IOLog("%s: LBA supported.\n", [self name]); ! 131: } ! 132: if (ideIdentifyInfo->capabilities & IDE_CAP_IORDY_SUPPORTED) { ! 133: IOLog("%s: IORDY supported.\n", [self name]); ! 134: } ! 135: ! 136: if (ideIdentifyInfo->bufferType != 0) { ! 137: IOLog("%s: buffer type %d of %d sectors.\n", [self name], ! 138: ideIdentifyInfo->bufferType, ideIdentifyInfo->bufferSize); ! 139: } ! 140: #endif DEBUG ! 141: } ! 142: ! 143: /* ! 144: * Device-specific initialization. We just do enough here to do some I/O and ! 145: * to find out if the requested drive is present. This function is "reusable" ! 146: * for a given instance of IdeDisk; initResources must have been called ! 147: * exactly once prior to any use of this method. Returns YES if drive is ! 148: * present, else NO. ! 149: */ ! 150: - (BOOL)ideDiskInit:(unsigned int)diskUnit target:(unsigned int)unit ! 151: { ! 152: char dev_name[10]; ! 153: unsigned total_sectors; ! 154: ideIdentifyInfo_t *ideIdentifyInfo; ! 155: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION ! 156: int i; ! 157: ideBuf_t *ideBuf; ! 158: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION ! 159: ! 160: ! 161: queue_init(&_ioQueueDisk); ! 162: queue_init(&_ioQueueNodisk); ! 163: ! 164: ! 165: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION ! 166: ! 167: /* Set up a queue of ideBufs */ ! 168: queue_init(&_ideBufQueue); ! 169: _ideBufLock = [NXLock new]; ! 170: [_ideBufLock lock]; ! 171: ! 172: ! 173: for (i = 0; i < MAX_NUM_ATABUF; i++) { ! 174: ideBuf = &_ideBufPool[i]; ! 175: ideBuf->waitLock = [NXConditionLock alloc]; ! 176: [ideBuf->waitLock initWith:NO]; ! 177: queue_enter(&_ideBufQueue, ideBuf, ideBuf_t *, bufLink); ! 178: } ! 179: [_ideBufLock unlock]; ! 180: ! 181: ! 182: if (_ide_debug) { ! 183: IOLog("NO_ATA_RUNTIME_MEMORY_ALLOCATION\n"); ! 184: } ! 185: ! 186: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION ! 187: ! 188: _driveNum = unit; ! 189: ! 190: #ifdef DEBUG ! 191: IOLog("IDEDisk: ideDiskInit for disk %d target %d\n", diskUnit, unit); ! 192: #endif DEBUG ! 193: ! 194: /* Skip ATAPI devices. */ ! 195: if ([_cntrlr isAtapiDevice:unit] == YES) { ! 196: // IOLog("IDEDisk: disk %d is ATAPI\n", unit); ! 197: return NO; ! 198: } ! 199: ! 200: _ideInfo = [_cntrlr getIdeDriveInfo:unit]; ! 201: if (_ideInfo.type == 0) { ! 202: //IOLog("IDEDisk: Bogus info for disk %d target %d.\n", diskUnit, unit); ! 203: return NO; ! 204: } ! 205: ! 206: sprintf(dev_name, "hd%d", diskUnit); ! 207: [self setUnit:diskUnit]; ! 208: [self setName:dev_name]; ! 209: ! 210: ideIdentifyInfo = [_cntrlr getIdeIdentifyInfo:unit]; ! 211: if (ideIdentifyInfo == NULL) { ! 212: IOLog("%s: CHS = %d/%d/%d\n", ! 213: [self name], _ideInfo.cylinders, ! 214: _ideInfo.heads, _ideInfo.sectors_per_trk); ! 215: _ideDriveName[0] = '\0'; ! 216: } else { ! 217: [self printInfo:ideIdentifyInfo unit:unit]; ! 218: } ! 219: ! 220: /* ! 221: * Cache optimal data transfer command. ! 222: */ ! 223: ! 224: if ([_cntrlr isDmaSupported:unit]) { ! 225: IOLog("%s: using DMA transfers.\n", [self name]); ! 226: _ideReadCommand = IDE_READ_DMA; ! 227: _ideWriteCommand = IDE_WRITE_DMA; ! 228: } else if ([_cntrlr isMultiSectorAllowed:_driveNum]) { ! 229: IOLog("%s: using multisector (%d) transfers.\n", ! 230: [self name], [_cntrlr getMultiSectorValue:unit]); ! 231: _ideReadCommand = IDE_READ_MULTIPLE; ! 232: _ideWriteCommand = IDE_WRITE_MULTIPLE; ! 233: } else { ! 234: IOLog("%s: using single sector transfers.\n", [self name]); ! 235: _ideReadCommand = IDE_READ; ! 236: _ideWriteCommand = IDE_WRITE; ! 237: } ! 238: ! 239: if ([self initIdeDrive] != IO_R_SUCCESS) { ! 240: return NO; ! 241: } ! 242: ! 243: total_sectors = _ideInfo.total_sectors; ! 244: ! 245: [self setRemovable:NO]; ! 246: [self setBlockSize:_ideInfo.bytes_per_sector]; ! 247: [self setDiskSize:total_sectors]; ! 248: [self setFormattedInternal:YES]; ! 249: [self setLastReadyState: IO_Ready]; ! 250: ! 251: if (_ideDriveName[0] == '\0') { ! 252: sprintf(_ideDriveName, "IDE Drive Type %d", _ideInfo.type); ! 253: } ! 254: [self setDriveName:_ideDriveName]; ! 255: ! 256: [super init]; ! 257: ! 258: return YES; ! 259: } ! 260: ! 261: /* ! 262: * One-time only initialization. We have only one thread per disk since ATA ! 263: * disks do not support command queueing. ! 264: */ ! 265: #ifdef DEBUG ! 266: void *ideThreadPtr; ! 267: #endif DEBUG ! 268: ! 269: - initResources : controller ! 270: { ! 271: _cntrlr = controller; ! 272: _ioQLock = [NXConditionLock alloc]; ! 273: [_ioQLock initWith:NO_WORK_AVAILABLE]; ! 274: #ifdef DEBUG ! 275: ideThreadPtr = IOForkThread((IOThreadFunc)ideThread, self); ! 276: #else DEBUG ! 277: IOForkThread((IOThreadFunc)ideThread, self); ! 278: #endif DEBUG ! 279: return self; ! 280: } ! 281: ! 282: /* ! 283: * Free up local resources. ! 284: */ ! 285: - free ! 286: { ! 287: /* ! 288: * First kill the I/O thread, then free alloc'd instance variables. ! 289: */ ! 290: ideBuf_t *ideBuf; ! 291: int i; ! 292: ! 293: ideBuf = [self allocIdeBuf:NULL]; ! 294: ideBuf->command = IDEC_THREAD_ABORT; ! 295: ideBuf->buf = NULL; ! 296: ideBuf->needsDisk = 0; ! 297: ideBuf->oneWay = 0; ! 298: [self enqueueIdeBuf:ideBuf]; ! 299: ! 300: [self freeIdeBuf:ideBuf]; ! 301: [_ioQLock free]; ! 302: ! 303: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION ! 304: if (_ideBufLock) ! 305: [_ideBufLock free]; ! 306: ! 307: for (i = 0; i < MAX_NUM_ATABUF; i++) { ! 308: if (_ideBufPool[i].waitLock) ! 309: [_ideBufPool[i].waitLock free]; ! 310: } ! 311: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION ! 312: ! 313: return ([super free]); ! 314: } ! 315: ! 316: /* ! 317: * Allocate and free IdeBuf_t's. ! 318: */ ! 319: ! 320: #ifdef NO_ATA_RUNTIME_MEMORY_ALLOCATION ! 321: - (ideBuf_t *) allocIdeBuf:(void *)pending ! 322: { ! 323: ideBuf_t *ideBuf; ! 324: id waitLock; ! 325: ! 326: while (1) { ! 327: [_ideBufLock lock]; ! 328: if (!queue_empty(&_ideBufQueue)) ! 329: break; ! 330: [_ideBufLock unlock]; ! 331: IOSleep(10); // the system is overloaded ! 332: } ! 333: ! 334: ASSERT(queue_empty(&_ideBufQueue) != 0); ! 335: ideBuf = (ideBuf_t *) queue_first(&_ideBufQueue); ! 336: ASSERT(ideBuf != 0); ! 337: queue_remove(&_ideBufQueue, ideBuf, ideBuf_t *, bufLink); ! 338: ! 339: waitLock = ideBuf->waitLock; ! 340: bzero(ideBuf, sizeof(ideBuf_t)); ! 341: ideBuf->waitLock = waitLock; ! 342: [ideBuf->waitLock initWith:NO]; ! 343: ! 344: if (pending != NULL) ! 345: ideBuf->pending = pending; ! 346: ! 347: [_ideBufLock unlock]; ! 348: return (ideBuf); ! 349: } ! 350: ! 351: - (void)freeIdeBuf:(ideBuf_t *) ideBuf ! 352: { ! 353: [_ideBufLock lock]; ! 354: queue_enter(&_ideBufQueue, ideBuf, ideBuf_t *, bufLink); ! 355: ASSERT(queue_empty(&_ideBufQueue) != 0); ! 356: [_ideBufLock unlock]; ! 357: } ! 358: ! 359: #else NO_ATA_RUNTIME_MEMORY_ALLOCATION ! 360: ! 361: - (ideBuf_t *) allocIdeBuf:(void *)pending ! 362: { ! 363: ideBuf_t *ideBuf = IOMalloc(sizeof(ideBuf_t)); ! 364: ! 365: bzero(ideBuf, sizeof(ideBuf_t)); ! 366: if (pending == NULL) { ! 367: ideBuf->waitLock = [NXConditionLock alloc]; ! 368: [ideBuf->waitLock initWith:NO]; ! 369: } else ! 370: ideBuf->pending = pending; ! 371: return (ideBuf); ! 372: } ! 373: ! 374: - (void)freeIdeBuf:(ideBuf_t *) ideBuf ! 375: { ! 376: if (ideBuf->waitLock) { ! 377: [ideBuf->waitLock free]; ! 378: } ! 379: IOFree(ideBuf, sizeof(ideBuf_t)); ! 380: } ! 381: #endif NO_ATA_RUNTIME_MEMORY_ALLOCATION ! 382: ! 383: - (IOReturn) ideXfrIoReq:(ideIoReq_t *)ideIoReq ! 384: { ! 385: ideBuf_t *ideBuf; ! 386: IOReturn rtn; ! 387: ! 388: ideBuf = [self allocIdeBuf:NULL]; ! 389: ideBuf->command = IDEC_IOREQ; ! 390: ideBuf->ideIoReq = ideIoReq; ! 391: ideBuf->block = 0; ! 392: ideBuf->blockCnt = 0; ! 393: ideBuf->buf = 0; ! 394: ideBuf->client = 0; /* it picked up from ideIoReq */ ! 395: ideBuf->needsDisk = 1; ! 396: ideBuf->bytesXfr = 0; ! 397: ideBuf->oneWay = 0; ! 398: rtn = [self enqueueIdeBuf:ideBuf]; ! 399: [self freeIdeBuf:ideBuf]; ! 400: ! 401: return (rtn); ! 402: } ! 403: ! 404: - (IOReturn) initIdeDrive ! 405: { ! 406: IOReturn rtn; ! 407: ideBuf_t *ideBuf; ! 408: ! 409: ideBuf = [self allocIdeBuf:NULL]; ! 410: ideBuf->command = IDEC_INIT; ! 411: ideBuf->block = 0; ! 412: ideBuf->blockCnt = 0; ! 413: ideBuf->buf = 0; ! 414: ideBuf->client = 0; ! 415: ideBuf->needsDisk = 1; ! 416: ideBuf->bytesXfr = 0; ! 417: ideBuf->oneWay = 0; ! 418: rtn = [self enqueueIdeBuf:ideBuf]; ! 419: [self freeIdeBuf:ideBuf]; ! 420: ! 421: return(rtn); ! 422: } ! 423: ! 424: /* ! 425: * Common read/write routine. ! 426: */ ! 427: - (IOReturn) deviceRwCommon:(IdeCmd_t) command ! 428: block:(u_int) deviceBlock ! 429: length:(u_int) length ! 430: buffer:(void *)buffer ! 431: client:(vm_task_t) client ! 432: pending:(void *)pending ! 433: actualLength:(u_int *) actualLength ! 434: { ! 435: ideBuf_t *ideBuf; ! 436: IOReturn rtn; ! 437: u_int blocksReq; ! 438: u_int block_size; ! 439: u_int dev_size; ! 440: ! 441: rtn = [self isDiskReady:NO]; ! 442: ! 443: switch (rtn) { ! 444: case IO_R_SUCCESS: ! 445: break; ! 446: case IO_R_NO_DISK: ! 447: return (rtn); ! 448: default: ! 449: IOLog("%s deviceRwCommon: bogus return from isDiskReady (%s)\n", ! 450: [self name], [self stringFromReturn:rtn]); ! 451: return (rtn); ! 452: } ! 453: ! 454: block_size = [self blockSize]; ! 455: dev_size = [self diskSize]; ! 456: ! 457: if (length % block_size) { ! 458: return (IO_R_INVALID); ! 459: } ! 460: blocksReq = length / block_size; ! 461: if ((deviceBlock + blocksReq) > dev_size) { ! 462: if (deviceBlock >= dev_size) { ! 463: return (IO_R_INVALID_ARG); ! 464: } ! 465: blocksReq = dev_size - deviceBlock; ! 466: } ! 467: ideBuf = [self allocIdeBuf:pending]; ! 468: ideBuf->command = command; ! 469: ideBuf->block = deviceBlock; ! 470: ideBuf->blockCnt = blocksReq; ! 471: ideBuf->buf = buffer; ! 472: ideBuf->client = client; ! 473: ideBuf->needsDisk = 1; ! 474: ideBuf->bytesXfr = 0; ! 475: ideBuf->oneWay = 0; ! 476: ! 477: rtn = [self enqueueIdeBuf:ideBuf]; ! 478: ! 479: if (pending == NULL) { ! 480: /* ! 481: * Sync I/O. ! 482: */ ! 483: *actualLength = ideBuf->bytesXfr; ! 484: [self freeIdeBuf:ideBuf]; ! 485: } ! 486: return (rtn); ! 487: } ! 488: ! 489: /* ! 490: * -- Enqueue an IdeBuf_t on ioQueue<Disk,Nodisk> ! 491: * -- wake up the I/O thread ! 492: * -- wait for I/O complete (if ideBuf->pending == NULL) ! 493: * ! 494: * All I/O goes thru here; this is the last method called by exported methods ! 495: * before the I/O thread takes over. ! 496: */ ! 497: - (IOReturn) enqueueIdeBuf:(ideBuf_t *) ideBuf ! 498: { ! 499: queue_head_t *q; ! 500: ! 501: ideBuf->status = IO_R_INVALID; ! 502: [_ioQLock lock]; ! 503: if (ideBuf->needsDisk) ! 504: q = &_ioQueueDisk; ! 505: else ! 506: q = &_ioQueueNodisk; ! 507: queue_enter(q, ideBuf, ideBuf_t *, link); ! 508: [_ioQLock unlockWith:WORK_AVAILABLE]; ! 509: ! 510: if (ideBuf->pending != NULL) ! 511: return (IO_R_SUCCESS); ! 512: ! 513: /* ! 514: * Wait for I/O complete if not an async command. ! 515: */ ! 516: ! 517: if (ideBuf->oneWay) { ! 518: return IO_R_SUCCESS; ! 519: } ! 520: [ideBuf->waitLock lockWhen:YES]; ! 521: [ideBuf->waitLock unlock]; ! 522: ! 523: return (ideBuf->status); ! 524: } ! 525: ! 526: ! 527: /* ! 528: * Either wake up the thread which is waiting on the ideCmdBuf, or send an ! 529: * ioComplete back to client. ideCmdBuf->status must be valid. ! 530: */ ! 531: - (void)ideIoComplete:(ideBuf_t *) ideBuf ! 532: { ! 533: if (ideBuf->pending) { ! 534: [self completeTransfer:ideBuf->pending ! 535: withStatus:ideBuf->status ! 536: actualLength:ideBuf->bytesXfr]; ! 537: [self freeIdeBuf:ideBuf]; ! 538: } else { ! 539: /* ! 540: * Sync I/O. Just wake up the waiting thread. ! 541: */ ! 542: [ideBuf->waitLock lock]; ! 543: [ideBuf->waitLock unlockWith:YES]; ! 544: } ! 545: ! 546: } ! 547: ! 548: /* ! 549: * Main command dispatch method. ! 550: */ ! 551: - (void)ideCmdDispatch:(ideBuf_t *)ideBuf ! 552: { ! 553: IOReturn rtn = IO_R_SUCCESS; ! 554: ideBuf_t *abortBuf; ! 555: ! 556: switch (ideBuf->command) { ! 557: ! 558: case IDEC_IOREQ: ! 559: [_cntrlr ideExecuteCmd:ideBuf->ideIoReq ToDrive:_driveNum]; ! 560: ! 561: break; ! 562: ! 563: case IDEC_READ: ! 564: case IDEC_WRITE: ! 565: rtn = [self ideRwCommon:ideBuf]; ! 566: ! 567: break; ! 568: ! 569: case IDEC_ABORT: ! 570: ! 571: /* ! 572: * Each I/O pending in the needsDisk queue must be aborted. ! 573: */ ! 574: [_ioQLock lock]; ! 575: while (!queue_empty(&_ioQueueDisk)) { ! 576: abortBuf = (ideBuf_t *) queue_first(&_ioQueueDisk); ! 577: queue_remove(&_ioQueueDisk, ! 578: abortBuf, ! 579: ideBuf_t *, ! 580: link); ! 581: [_ioQLock unlock]; ! 582: abortBuf->status = IO_R_NO_DISK; ! 583: if (abortBuf->ideIoReq) ! 584: abortBuf->ideIoReq->status = IDER_VOLUNAVAIL; ! 585: [self ideIoComplete:abortBuf]; ! 586: [_ioQLock lock]; ! 587: } ! 588: [_ioQLock unlock]; ! 589: ! 590: break; ! 591: ! 592: case IDEC_THREAD_ABORT: ! 593: ! 594: /* ! 595: * First give I/O complete before we die. ! 596: */ ! 597: ideBuf->status = IO_R_SUCCESS; ! 598: [self ideIoComplete:ideBuf]; ! 599: IOExitThread(); ! 600: ! 601: case IDEC_INIT: ! 602: #if 0 ! 603: /* Called once during initialization. */ ! 604: if ([_cntrlr initIdeDriveLowLevel] == IDER_SUCCESS) ! 605: rtn = IO_R_SUCCESS; ! 606: else ! 607: rtn = IO_R_IO; ! 608: #endif 0 ! 609: rtn = IO_R_SUCCESS; ! 610: break; ! 611: ! 612: default: ! 613: IOLog("%s: Bogus ideBuf->command 0x%0x in ideCmdDispatch\n", ! 614: [self name], ideBuf->command); ! 615: IOPanic("ideThread"); ! 616: } ! 617: ! 618: /* ! 619: * I/O complete the command if appropriate. ! 620: */ ! 621: if (ideBuf->oneWay) { ! 622: ! 623: [self freeIdeBuf:ideBuf]; ! 624: ! 625: return; ! 626: } ! 627: ideBuf->status = rtn; ! 628: ! 629: [self ideIoComplete:ideBuf]; ! 630: return; ! 631: } ! 632: ! 633: /* ! 634: * Common r/w routine. The following ideBuf fields are required: ! 635: * block ! 636: * blockCnt ! 637: * buf ! 638: * client ! 639: * pending ! 640: * ! 641: * block and blockCnt are assumed to be already adjusted for overflow. ! 642: */ ! 643: - (IOReturn) ideRwCommon:(ideBuf_t *)ideBuf ! 644: { ! 645: int currentBlock = ideBuf->block; /* start block, current ! 646: * segment */ ! 647: int currentBlockCnt; /* block count, current segment */ ! 648: int blocksToGo = ideBuf->blockCnt; ! 649: char *currentBuf = ideBuf->buf; ! 650: ideIoReq_t ideIoReq; ! 651: IOReturn rtn; ! 652: unsigned int block_size = _ideInfo.bytes_per_sector; ! 653: BOOL readFlag = (ideBuf->command == IDEC_READ) ? YES : NO; ! 654: int blocksMoved; ! 655: ns_time_t start_time; ! 656: ! 657: IOGetTimestamp(&start_time); ! 658: ! 659: while (blocksToGo) { ! 660: ! 661: /* ! 662: * Set up controller command block for current segment. ! 663: */ ! 664: currentBlockCnt = ((blocksToGo > MAX_BLOCKS_PER_XFER) ? ! 665: MAX_BLOCKS_PER_XFER : blocksToGo); ! 666: ! 667: ideIoReq.cmd = readFlag ? _ideReadCommand : _ideWriteCommand; ! 668: ! 669: ideIoReq.addr = currentBuf; ! 670: ideIoReq.blkcnt = currentBlockCnt; ! 671: ideIoReq.block = currentBlock; ! 672: ! 673: /* ! 674: * Note we're compiling MACH_USER_API, hence the cast... ! 675: */ ! 676: ideIoReq.map = (struct vm_map *) ideBuf->client; ! 677: ! 678: rtn = [_cntrlr ideExecuteCmd:&ideIoReq ToDrive:_driveNum]; ! 679: ! 680: blocksMoved = ideIoReq.blocks_xfered; ! 681: blocksToGo -= blocksMoved; ! 682: currentBlock += blocksMoved; ! 683: currentBuf += ideIoReq.blocks_xfered * block_size; ! 684: ! 685: /* ! 686: * Handle errors. ! 687: */ ! 688: ! 689: if (rtn) { ! 690: /* ! 691: * This is a colossal error, which should never happen... ! 692: */ ! 693: ideIoReq.status = IDER_REJECT; ! 694: } ! 695: switch (ideIoReq.status) { ! 696: case IDER_SUCCESS: ! 697: break; ! 698: case IDER_TIMEOUT: ! 699: case IDER_MEMALLOC: ! 700: case IDER_MEMFAIL: ! 701: case IDER_REJECT: ! 702: case IDER_BADDRV: ! 703: case IDER_CMD_ERROR: ! 704: case IDER_VOLUNAVAIL: ! 705: case IDER_SPURIOUS: ! 706: goto done; ! 707: break; ! 708: default: ! 709: ! 710: /* ! 711: * Non-retriable errors. ! 712: */ ! 713: [self logRwErr:"FATAL" block:currentBlock status:ideIoReq.status ! 714: readFlag:readFlag]; ! 715: goto done; ! 716: break; ! 717: ! 718: } /* switch status */ ! 719: } /* while blocksToGo */ ! 720: done: ! 721: ! 722: /* ! 723: * Finished. Update client's status and log statistics. ! 724: */ ! 725: ideBuf->bytesXfr = (ideBuf->blockCnt - blocksToGo) * block_size; ! 726: rtn = ideBuf->status = iderToIo(ideIoReq.status); ! 727: if (ideIoReq.status != IO_R_SUCCESS) { ! 728: ! 729: if (readFlag) { ! 730: [self incrementReadErrors]; ! 731: } else { ! 732: [self incrementWriteErrors]; ! 733: } ! 734: ! 735: } else { ! 736: ns_time_t end_time; ! 737: ! 738: /* no "latency" measurement... */ ! 739: ns_time_t delta; ! 740: ! 741: IOGetTimestamp(&end_time); ! 742: delta = end_time - start_time; ! 743: if (readFlag) { ! 744: ! 745: [self addToBytesRead:ideBuf->bytesXfr ! 746: totalTime:delta ! 747: latentTime:0]; ! 748: } else { ! 749: [self addToBytesWritten:ideBuf->bytesXfr ! 750: totalTime:delta ! 751: latentTime:0]; ! 752: } ! 753: } ! 754: ! 755: return (rtn); ! 756: } ! 757: ! 758: - (void)logRwErr : (const char *)errType // e.g., "RECALIBRATING" ! 759: block : (int)block ! 760: status : (ide_return_t)status ! 761: readFlag : (BOOL)readFlag ! 762: { ! 763: ! 764: IOLog("%s: Sector %d cmd = %s; %s: %s\n", ! 765: [self name], block, readFlag ? "Read" : "Write", ! 766: IOFindNameForValue(status, iderValues), errType); ! 767: ! 768: } ! 769: ! 770: /* ! 771: * Unlock ioQLock, updating condition variable as appropriate. ! 772: */ ! 773: - (void)unlockIoQLock ! 774: { ! 775: int queue_state; ! 776: IODiskReadyState lastReady = [self lastReadyState]; ! 777: ! 778: /* ! 779: * There's still work to do when: ! 780: * -- ioQueueNodisk non-empty, or ! 781: * -- ioQueueDisk non-empty and we have a disk. ! 782: */ ! 783: ! 784: if ((!queue_empty(&_ioQueueNodisk)) || ! 785: ((!queue_empty(&_ioQueueDisk)) && (lastReady != IO_NoDisk))) { ! 786: queue_state = WORK_AVAILABLE; ! 787: } else ! 788: queue_state = NO_WORK_AVAILABLE; ! 789: [_ioQLock unlockWith:queue_state]; ! 790: } ! 791: ! 792: ! 793: /* ! 794: * I/O thread. Each one of these sits around waiting for work to do on ! 795: * ioQueue; when something appears, the thread grabs it and disptahes it. ! 796: */ ! 797: ! 798: volatile void ideThread(IdeDisk *idisk) ! 799: { ! 800: ideBuf_t *ideBuf; ! 801: queue_head_t *q; ! 802: ! 803: while (1) { ! 804: ! 805: /* ! 806: * Wait for some work to do. ! 807: */ ! 808: [idisk->_ioQLock lockWhen:WORK_AVAILABLE]; ! 809: ! 810: /* ! 811: * Service all requests which do not require a disk. ! 812: */ ! 813: q = &idisk->_ioQueueNodisk; ! 814: while (!queue_empty(q)) { ! 815: ideBuf = (ideBuf_t *) queue_first(q); ! 816: queue_remove(q, ideBuf, ideBuf_t *, link); ! 817: [idisk->_ioQLock unlock]; ! 818: ASSERT(ideBuf->needsDisk == 0); ! 819: [idisk ideCmdDispatch:ideBuf]; ! 820: [idisk->_ioQLock lock]; ! 821: } ! 822: ! 823: /* ! 824: * Now service all requests which require a disk, as long as we have ! 825: * one. ! 826: */ ! 827: ! 828: q = &idisk->_ioQueueDisk; ! 829: ASSERT([idisk lastReadyState] == IO_Ready); ! 830: while ((!queue_empty(q)) && ! 831: ([idisk lastReadyState] == IO_Ready)) { ! 832: ideBuf = (ideBuf_t *) queue_first(q); ! 833: queue_remove(q, ideBuf, ideBuf_t *, link); ! 834: [idisk->_ioQLock unlock]; ! 835: ASSERT(ideBuf->needsDisk == 1); ! 836: [idisk ideCmdDispatch:ideBuf]; ! 837: [idisk->_ioQLock lock]; ! 838: } ! 839: ! 840: [idisk unlockIoQLock]; ! 841: } ! 842: ! 843: /* NOT REACHED */ ! 844: } ! 845: ! 846: IOReturn iderToIo(ide_return_t ider) ! 847: { ! 848: switch (ider) { ! 849: case IDER_SUCCESS: ! 850: return (IO_R_SUCCESS); ! 851: case IDER_TIMEOUT: ! 852: case IDER_CNTRL_REJECT: ! 853: case IDER_CMD_ERROR: ! 854: case IDER_SPURIOUS: ! 855: return (IO_R_IO); ! 856: case IDER_MEMALLOC: ! 857: return (IO_R_NO_MEMORY); ! 858: case IDER_MEMFAIL: ! 859: return (IO_R_VM_FAILURE); ! 860: case IDER_REJECT: ! 861: return (IO_R_UNSUPPORTED); ! 862: case IDER_BADDRV: ! 863: return (IO_R_NO_DEVICE); ! 864: case IDER_VOLUNAVAIL: ! 865: return (IO_R_NO_DISK); ! 866: default: ! 867: return (IO_R_INTERNAL); ! 868: } ! 869: } ! 870: ! 871: @end ! 872:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.