|
|
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: * AtapiCntInternal.m - Implementation of ATAPI controller class. ! 29: * ! 30: * ! 31: * HISTORY ! 32: * ! 33: * 05-Mar-1996 Rakesh Dubey at NeXT ! 34: * Modified so that no memory is allocated at run-time. ! 35: * ! 36: * 21-Mar-1995 Rakesh Dubey at NeXT ! 37: * Created. ! 38: */ ! 39: ! 40: #import "IdeCnt.h" ! 41: #import "AtapiCntInternal.h" ! 42: #import <kern/assert.h> ! 43: #import <driverkit/kernelDriver.h> ! 44: #import <driverkit/interruptMsg.h> ! 45: #import <mach/mach_interface.h> ! 46: #import <driverkit/IODevice.h> ! 47: #import <machkit/NXLock.h> ! 48: #import <kernserv/prototypes.h> ! 49: ! 50: /* ! 51: * Top-level I/O thread. ! 52: */ ! 53: static volatile void atapiThread(AtapiController *atapiCnt); ! 54: ! 55: @implementation AtapiController(Internal) ! 56: ! 57: - initResources:direct ! 58: { ! 59: #ifdef NO_ATAPI_RUNTIME_MEMORY_ALLOCATION ! 60: int i; ! 61: atapiBuf_t *atapiBuf; ! 62: #endif NO_ATAPI_RUNTIME_MEMORY_ALLOCATION ! 63: ! 64: _ataController = direct; ! 65: ! 66: queue_init(&_ioQueueNodisk); ! 67: ! 68: #ifdef NO_ATAPI_RUNTIME_MEMORY_ALLOCATION ! 69: ! 70: /* Set up a queue of ideBufs */ ! 71: queue_init(&_atapiBufQueue); ! 72: _atapiBufLock = [NXLock new]; ! 73: [_atapiBufLock lock]; ! 74: ! 75: for (i = 0; i < MAX_NUM_ATAPIBUF; i++) { ! 76: atapiBuf = &_atapiBufPool[i]; ! 77: atapiBuf->waitLock = [NXConditionLock alloc]; ! 78: [atapiBuf->waitLock initWith:NO]; ! 79: queue_enter(&_atapiBufQueue, atapiBuf, atapiBuf_t *, bufLink); ! 80: } ! 81: [_atapiBufLock unlock]; ! 82: ! 83: if (_ide_debug) { ! 84: IOLog("NO_ATAPI_RUNTIME_MEMORY_ALLOCATION\n"); ! 85: } ! 86: ! 87: #endif NO_ATAPI_RUNTIME_MEMORY_ALLOCATION ! 88: ! 89: _ioQLock = [NXConditionLock alloc]; ! 90: [_ioQLock initWith:NO_WORK_AVAILABLE]; ! 91: ! 92: IOForkThread((IOThreadFunc)atapiThread, self); ! 93: ! 94: return self; ! 95: } ! 96: ! 97: /* ! 98: * Free up local resources. ! 99: */ ! 100: - free ! 101: { ! 102: /* ! 103: * First kill the I/O thread, then free alloc'd instance variables. ! 104: */ ! 105: atapiBuf_t *atapiBuf; ! 106: int i; ! 107: ! 108: atapiBuf = [self allocAtapiBuf]; ! 109: [self enqueueAtapiBuf:atapiBuf]; ! 110: ! 111: [self freeAtapiBuf:atapiBuf]; ! 112: [_ioQLock free]; ! 113: ! 114: #ifdef NO_ATAPI_RUNTIME_MEMORY_ALLOCATION ! 115: if (_atapiBufLock) ! 116: [_atapiBufLock free]; ! 117: ! 118: for (i = 0; i < MAX_NUM_ATAPIBUF; i++) { ! 119: if (_atapiBufPool[i].waitLock) ! 120: [_atapiBufPool[i].waitLock free]; ! 121: } ! 122: #endif NO_ATAPI_RUNTIME_MEMORY_ALLOCATION ! 123: ! 124: return ([super free]); ! 125: } ! 126: ! 127: /* ! 128: * Allocate and free AtapiBuf_t's. ! 129: */ ! 130: ! 131: #ifdef NO_ATAPI_RUNTIME_MEMORY_ALLOCATION ! 132: - (atapiBuf_t *) allocAtapiBuf ! 133: { ! 134: atapiBuf_t *atapiBuf; ! 135: id waitLock; ! 136: ! 137: while (1) { ! 138: [_atapiBufLock lock]; ! 139: if (!queue_empty(&_atapiBufQueue)) ! 140: break; ! 141: [_atapiBufLock unlock]; ! 142: IOSleep(20); // the system is overloaded ! 143: } ! 144: ! 145: ASSERT(queue_empty(&_atapiBufQueue) != 0); ! 146: atapiBuf = (atapiBuf_t *) queue_first(&_atapiBufQueue); ! 147: ASSERT(atapiBuf != 0); ! 148: queue_remove(&_atapiBufQueue, atapiBuf, atapiBuf_t *, bufLink); ! 149: ! 150: waitLock = atapiBuf->waitLock; ! 151: bzero(atapiBuf, sizeof(atapiBuf_t)); ! 152: atapiBuf->waitLock = waitLock; ! 153: [atapiBuf->waitLock initWith:NO]; ! 154: ! 155: [_atapiBufLock unlock]; ! 156: return (atapiBuf); ! 157: } ! 158: ! 159: - (void)freeAtapiBuf:(atapiBuf_t *) atapiBuf ! 160: { ! 161: [_atapiBufLock lock]; ! 162: queue_enter(&_atapiBufQueue, atapiBuf, atapiBuf_t *, bufLink); ! 163: ASSERT(queue_empty(&_atapiBufQueue) != 0); ! 164: [_atapiBufLock unlock]; ! 165: } ! 166: ! 167: #else NO_ATAPI_RUNTIME_MEMORY_ALLOCATION ! 168: ! 169: - (atapiBuf_t *) allocAtapiBuf ! 170: { ! 171: atapiBuf_t *atapiBuf = IOMalloc(sizeof(atapiBuf_t)); ! 172: ! 173: bzero(atapiBuf, sizeof(atapiBuf_t)); ! 174: atapiBuf->waitLock = [NXConditionLock alloc]; ! 175: [atapiBuf->waitLock initWith:NO]; ! 176: ! 177: return (atapiBuf); ! 178: } ! 179: ! 180: - (void)freeAtapiBuf:(atapiBuf_t *) atapiBuf ! 181: { ! 182: if (atapiBuf->waitLock) { ! 183: [atapiBuf->waitLock free]; ! 184: } ! 185: IOFree(atapiBuf, sizeof(atapiBuf_t)); ! 186: } ! 187: #endif NO_ATAPI_RUNTIME_MEMORY_ALLOCATION ! 188: ! 189: /* ! 190: * -- Enqueue an AtapiBuf_t on ioQueue<Disk,Nodisk> ! 191: * -- wake up the I/O thread ! 192: * -- wait for I/O complete (if atapiBuf->pending == NULL) ! 193: * ! 194: * All I/O goes thru here; this is the last method called by exported methods ! 195: * before the I/O thread takes over. ! 196: */ ! 197: - (IOReturn) enqueueAtapiBuf:(atapiBuf_t *) atapiBuf ! 198: { ! 199: queue_head_t *q; ! 200: ! 201: [_ioQLock lock]; ! 202: q = &_ioQueueNodisk; ! 203: queue_enter(q, atapiBuf, atapiBuf_t *, link); ! 204: [_ioQLock unlockWith:WORK_AVAILABLE]; ! 205: ! 206: /* ! 207: * Wait for I/O complete. ! 208: */ ! 209: [atapiBuf->waitLock lockWhen:YES]; ! 210: [atapiBuf->waitLock unlock]; ! 211: ! 212: /* FIXME: What should this value be?? */ ! 213: return (atapiBuf->status); ! 214: } ! 215: ! 216: ! 217: /* ! 218: * Either wake up the thread which is waiting on the ideCmdBuf, or send an ! 219: * ioComplete back to client. ideCmdBuf->status must be valid. ! 220: */ ! 221: - (void)atapiIoComplete:(atapiBuf_t *) atapiBuf ! 222: { ! 223: /* ! 224: * Sync I/O. Just wake up the waiting thread. ! 225: */ ! 226: [atapiBuf->waitLock lock]; ! 227: [atapiBuf->waitLock unlockWith:YES]; ! 228: } ! 229: ! 230: /* ! 231: * Main command dispatch method. ! 232: */ ! 233: - (void)atapiCmdDispatch:(atapiBuf_t *)atapiBuf ! 234: { ! 235: switch (atapiBuf->command) { ! 236: ! 237: case ATAPI_CNT_IOREQ: ! 238: atapiBuf->status = [_ataController ! 239: atapiExecuteCmd:atapiBuf->atapiIoReq ! 240: buffer:atapiBuf->buffer client:atapiBuf->client]; ! 241: break; ! 242: ! 243: case ATAPI_CNT_THREAD_ABORT: ! 244: ! 245: /* ! 246: * First give I/O complete before we die. ! 247: */ ! 248: atapiBuf->status = STAT_GOOD; ! 249: [self atapiIoComplete:atapiBuf]; ! 250: IOExitThread(); ! 251: ! 252: default: ! 253: IOLog("%s: Bogus atapiBuf->command 0x%0x in atapiCmdDispatch\n", ! 254: [self name], atapiBuf->command); ! 255: IOPanic("atapiThread"); ! 256: } ! 257: ! 258: [self atapiIoComplete:atapiBuf]; ! 259: return; ! 260: } ! 261: ! 262: /* ! 263: * Unlock ioQLock, updating condition variable as appropriate. ! 264: */ ! 265: - (void)unlockIoQLock ! 266: { ! 267: int queue_state; ! 268: ! 269: if (!queue_empty(&_ioQueueNodisk)) ! 270: queue_state = WORK_AVAILABLE; ! 271: else ! 272: queue_state = NO_WORK_AVAILABLE; ! 273: [_ioQLock unlockWith:queue_state]; ! 274: } ! 275: ! 276: ! 277: @end ! 278: ! 279: /* ! 280: * I/O thread. Each one of these sits around waiting for work to do on ! 281: * ioQueue; when something appears, the thread grabs it and disptahes it. ! 282: */ ! 283: ! 284: static volatile void ! 285: atapiThread(AtapiController *atapiCnt) ! 286: { ! 287: atapiBuf_t *atapiBuf; ! 288: queue_head_t *q; ! 289: ! 290: while (1) { ! 291: ! 292: /* ! 293: * Wait for some work to do. ! 294: */ ! 295: [atapiCnt->_ioQLock lockWhen:WORK_AVAILABLE]; ! 296: ! 297: /* ! 298: * Service all requests which do not require a disk. ! 299: */ ! 300: q = &atapiCnt->_ioQueueNodisk; ! 301: while (!queue_empty(q)) { ! 302: atapiBuf = (atapiBuf_t *) queue_first(q); ! 303: queue_remove(q, atapiBuf, atapiBuf_t *, link); ! 304: [atapiCnt->_ioQLock unlock]; ! 305: [atapiCnt atapiCmdDispatch:atapiBuf]; ! 306: [atapiCnt->_ioQLock lock]; ! 307: } ! 308: ! 309: [atapiCnt unlockIoQLock]; ! 310: } ! 311: ! 312: /* NOT REACHED */ ! 313: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.