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