|
|
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.