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