|
|
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: /* unixDiskPrivate.m 1.0 02/07/91 (c) 1991 NeXT
25: *
26: * unixDiskPrivate.m - unixDisk Private methods.
27: *
28: * HISTORY
29: * 07-Feb-91 Doug Mitchell at NeXT
30: * Created.
31: */
32:
33: #import <bsd/sys/types.h>
34: #import <mach/cthreads.h>
35: #import <bsd/libc.h>
36: #import <bsd/sys/file.h>
37: #import <driverkit/IODevice.h>
38: #import "unixDisk.h"
39: #import "unixThread.h"
40: #import "unixDiskPrivate.h"
41: #import <bsd/dev/disk.h>
42: #import "unixDiskUxpr.h"
43: #import <errno.h>
44: #import <driverkit/generalFuncs.h>
45: #import <machkit/NXLock.h>
46:
47: @implementation unixDisk(Private)
48:
49: /*
50: * readCommon: and writeCommon: are invoked by the exported flavors of
51: * read: and write:.
52: */
53: - (IOReturn) readCommon : (u_int)block
54: length : (u_int)length
55: buffer : (void *)bufp
56: actualLength : (u_int *)actualLength /* returned */
57: pending : (void *)pending
58: caller : (id)caller
59: IOBufRtn : (IOBuf_t **)IOBufRtn
60: {
61: IOReturn mrtn;
62: IOBuf_t *IOBuf;
63: u_int block_size, dev_size;
64:
65: /*
66: * We have to 'fault in' a possible non-present disk in
67: * order to get its physical parameters...
68: */
69: mrtn = [self isDiskReady:TRUE];
70: switch(mrtn) {
71: case IO_R_SUCCESS:
72: break;
73: case IO_R_NO_DISK:
74: xpr_err("%s readCommon: disk not present\n",
75: [self name], 2,3,4,5);
76: return(mrtn);
77: default:
78: IOLog("%s readCommon: bogus return from isDiskReady"
79: " (%s)\n",
80: [self name], [self stringFromReturn:mrtn]);
81: return(mrtn);
82: }
83: if(![self isFormatted])
84: return(IO_R_UNFORMATTED);
85:
86: /*
87: * Verify legal parameters.
88: */
89: block_size = [self blockSize];
90: dev_size = [self diskSize];
91: if(block >= dev_size) {
92: xpr_ud("unixDisk readCommon: invalid "
93: "deviceBlock/byte count\n", 1,2,3,4,5);
94: return(IO_R_INVALID_ARG);
95: }
96:
97: if(length % block_size) {
98: xpr_ud("unixDisk readCommon: byteCount not block_size "
99: "multiple\n", 1,2,3,4,5);
100: return(IO_R_INVALID_ARG);
101: }
102:
103: /*
104: * Queue up an IOBuf.
105: */
106: IOBuf = [self allocIOBuf];
107: IOBuf->command = @selector(unixDeviceRead:threadNum:);
108: IOBuf->offset = block;
109: IOBuf->bytesReq = length;
110: IOBuf->buf = bufp;
111: IOBuf->bytesXfr = actualLength;
112: IOBuf->status = IO_R_INVALID; /* must be filled in by
113: * I/O thread */
114: IOBuf->pending = pending;
115: IOBuf->caller = caller;
116: IOBuf->device = self;
117: IOBuf->dirRead = 1;
118: *IOBufRtn = IOBuf;
119: if(!pending) {
120: IOBuf->wait_lock = [NXConditionLock alloc];
121: [IOBuf->wait_lock initWith:FALSE];
122: }
123: else {
124: IOBuf->wait_lock = nil;
125: }
126: [self enqueueIoBuf:IOBuf needs_disk:TRUE];
127: return(IO_R_SUCCESS);
128: }
129:
130: - (IOReturn) writeCommon : (u_int)block
131: length : (u_int)length
132: buffer : (void *)bufp
133: actualLength : (u_int *)actualLength /* returned */
134: pending : (void *)pending
135: caller : (id)caller // for DO only
136: IOBufRtn : (IOBuf_t **)IOBufRtn
137: {
138: IOReturn mrtn;
139: IOBuf_t *IOBuf;
140: u_int block_size, dev_size;
141:
142: /*
143: * We have to 'fault in' a possible non-present disk in
144: * order to get its physical parameters...
145: */
146: mrtn = [self isDiskReady:TRUE];
147: switch(mrtn) {
148: case IO_R_SUCCESS:
149: break;
150: case IO_R_NO_DISK:
151: xpr_err("%s writeCommon: disk not present\n",
152: [self name], 2,3,4,5);
153: return(mrtn);
154: default:
155: IOLog("%s writeCommon: bogus return from isDiskReady"
156: " (%s)\n",
157: [self name], [self stringFromReturn:mrtn]);
158: return(mrtn);
159: }
160:
161: /*
162: * Verify access and legal parameters.
163: */
164: if([self isWriteProtected]) {
165: return IO_R_NOT_WRITABLE;
166: }
167: block_size = [self blockSize];
168: dev_size = [self diskSize];
169: if(block >= dev_size) {
170: xpr_ud("unixDisk writeCommon: invalid "
171: "deviceBlock/byte count\n", 1,2,3,4,5);
172: return(IO_R_INVALID_ARG);
173: }
174: if(length % block_size) {
175: xpr_ud("unixDisk writeCommon: byteCount not block_size "
176: "multiple\n", 1,2,3,4,5);
177: return(IO_R_INVALID_ARG);
178: }
179:
180: /*
181: * Queue up an IOBuf.
182: */
183: IOBuf = [self allocIOBuf];
184: IOBuf->command = @selector(unixDeviceWrite:threadNum:);
185: IOBuf->offset = block;
186: IOBuf->bytesReq = length;
187: IOBuf->buf = bufp;
188: IOBuf->bytesXfr = actualLength;
189: IOBuf->status = IO_R_INVALID; /* must be filled in by
190: * I/O thread */
191: IOBuf->pending = pending;
192: IOBuf->caller = caller;
193: IOBuf->device = self;
194: IOBuf->dirRead = 1;
195: *IOBufRtn = IOBuf;
196: if(!pending) {
197: IOBuf->wait_lock = [NXConditionLock alloc];
198: [IOBuf->wait_lock initWith:FALSE];
199: }
200: else {
201: IOBuf->wait_lock = nil;
202: }
203: [self enqueueIoBuf:IOBuf needs_disk:TRUE];
204: return(IO_R_SUCCESS);
205: }
206:
207: - (IOBuf_t *)allocIOBuf
208: {
209: return(IOMalloc(sizeof(IOBuf_t)));
210: }
211:
212: - (void)freeIOBuf:(IOBuf_t *)IOBuf
213: {
214: if(IOBuf->wait_lock != nil) {
215: /*
216: * This was used for async I/O; free these resources...
217: */
218: [IOBuf->wait_lock free];
219: }
220: IOFree(IOBuf, sizeof(*IOBuf));
221: }
222:
223: /*
224: * Wakeup thread waiting on IOBuf.
225: */
226: - (void)IOBufDone : (IOBuf_t *)IOBuf
227: status : (IOReturn)status
228: {
229: [IOBuf->wait_lock lock];
230: IOBuf->status = status;
231: [IOBuf->wait_lock unlockWith:TRUE];
232: }
233:
234: /*
235: * These methods are invoked by a unix_thread; they do the actual work of
236: * reading and writing.
237: */
238: - (void)unixDeviceRead : (IOBuf_t *)IOBuf
239: threadNum:(int)threadNum
240: {
241: int rtn;
242: int position;
243: IOReturn status;
244: u_int block_size;
245:
246: xpr_uth("unix deviceRead: thread %d offset %d\n",
247: threadNum, IOBuf->offset, 3,4,5);
248:
249: /*
250: * lseek to appropriate place.
251: */
252: block_size = [self blockSize];
253: position = IOBuf->offset * block_size;
254: rtn = lseek(unix_fd[threadNum], position, L_SET);
255: if(rtn != position) {
256: xpr_uth("unixDisk deviceRead lseek(): errno %d\n", errno,
257: 2,3,4,5);
258: status = errno_to_mio(errno);
259: goto done;
260: }
261:
262: /*
263: * Go for it.
264: */
265: xpr_uth("unix deviceRead read(): thread %d offset %d\n",
266: threadNum, IOBuf->offset, 3,4,5);
267: rtn = read(unix_fd[threadNum], IOBuf->buf, IOBuf->bytesReq);
268: if(rtn > 0) {
269: *IOBuf->bytesXfr = rtn;
270: status = IO_R_SUCCESS;
271: }
272: else
273: status = errno_to_mio(errno);
274: done:
275: /*
276: * Any time we successfully complete a read or a write, we go to
277: * "formatted" state.
278: */
279: if(status == IO_R_SUCCESS)
280: [self setFormattedInternal:1];
281: if(IOBuf->pending) {
282: /*
283: * Async I/O. Notify client.
284: */
285: IOData *rdata = [[IOData alloc] initWithData:IOBuf->buf
286: size:*IOBuf->bytesXfr
287: dealloc:NO];
288:
289: [rdata setFreeFlag:NO];
290: [IOBuf->caller readIoComplete:(unsigned)IOBuf->pending
291: // ioKey
292: device:self
293: data:rdata
294: status:IOBuf->status];
295: [rdata free];
296: [self freeIOBuf:IOBuf];
297: }
298: else {
299: /*
300: * Synchronous I/O. Notify sleeping thread.
301: */
302: [self IOBufDone:IOBuf status:status];
303: }
304: xpr_uth("unixDeviceRead thread %d: DONE, status %s\n",
305: threadNum, [self stringFromReturn:IOBuf->status], 3,4,5);
306: }
307:
308: - (void)unixDeviceWrite : (IOBuf_t *)IOBuf
309: threadNum:(int)threadNum
310: {
311: int rtn;
312: int position;
313: IOReturn status;
314: u_int block_size;
315:
316: xpr_uth("unix deviceWrite: thread %d offset %d\n",
317: threadNum, IOBuf->offset, 3,4,5);
318:
319: /*
320: * lseek to appropriate place.
321: */
322: block_size = [self blockSize];
323: position = IOBuf->offset * block_size;
324: rtn = lseek(unix_fd[threadNum], position, L_SET);
325: if(rtn != position) {
326: xpr_uth("unixDisk deviceWrite lseek(): errno %d\n", errno,
327: 2,3,4,5);
328: status = errno_to_mio(errno);
329: goto done;
330: }
331:
332: /*
333: * Go for it.
334: */
335: rtn = write(unix_fd[threadNum], IOBuf->buf, IOBuf->bytesReq);
336: if(rtn > 0) {
337: *IOBuf->bytesXfr = rtn;
338: status = IO_R_SUCCESS;
339: }
340: else
341: status = errno_to_mio(errno);
342: done:
343: /*
344: * Any time we successfully complete a read or a write, we go to
345: * "formatted" state.
346: */
347: if(status == IO_R_SUCCESS)
348: [self setFormattedInternal:1];
349: if(IOBuf->pending) {
350: /*
351: * Async I/O. Notify client.
352: */
353: [IOBuf->caller writeIoComplete:(unsigned)IOBuf->pending
354: device:self
355: actualLength:*IOBuf->bytesXfr
356: status:IOBuf->status];
357: [self freeIOBuf:IOBuf];
358: }
359: else {
360: /*
361: * Synchronous I/O. Notify sleeping thread.
362: */
363: [self IOBufDone:IOBuf status:status];
364: }
365: xpr_uth("unixDeviceWrite thread %d: DONE, status %s\n",
366: threadNum, [self stringFromReturn:IOBuf->status], 3,4,5);
367: }
368:
369: - (void)deviceEject : (IOBuf_t *)IOBuf
370: threadNum:(int)threadNum
371: {
372: int rtn;
373: IOReturn status;
374:
375: xpr_uth("unixDisk deviceEject: thread %d\n", threadNum, 2,3,4,5);
376:
377: /*
378: * Wait until we're the only thread doing disk access.
379: */
380: [IOQueue.ejectLock lockWhen:1];
381: [IOQueue.ejectLock unlock];
382:
383: rtn = ioctl(unix_fd[threadNum], DKIOCEJECT, NULL);
384: if(rtn)
385: status = errno_to_mio(errno);
386: else
387: status = IO_R_SUCCESS;
388:
389: /*
390: * We go to unformatted state until we successfully complete a
391: * read or a write.
392: */
393: [self setFormattedInternal:0];
394: IOQueue.ejectPending = FALSE;
395: [self IOBufDone:IOBuf status:status];
396: xpr_uth("unixDeviceEject thread %d: DONE, status %s\n",
397: threadNum, [self stringFromReturn:IOBuf->status], 3,4,5);
398: }
399:
400: /*
401: * Requested disk is not available. ioComplete everything in this
402: * device's q_disk queue with IO_R_NO_DISK status.
403: */
404: - (void)unixDeviceAbort : (IOBuf_t *)IOBuf
405: {
406: IOBuf_t *abortBuf;
407: queue_head_t *q = &IOQueue.q_disk;
408:
409: xpr_uth("unixDeviceAbort\n", 1,2,3,4,5);
410: [IOQueue.qlock lock];
411: while(!queue_empty(q)) {
412: abortBuf = (IOBuf_t *)queue_first(q);
413: queue_remove(q, abortBuf, IOBuf_t *, ioChain);
414:
415: /*
416: * Note we don't change condition variable of qlock...
417: */
418: [IOQueue.qlock unlock];
419: xpr_uth("unixDeviceAbort: ABORTING IOBuf 0x%x\n", abortBuf,
420: 2,3,4,5);
421: [self IOBufDone:abortBuf status:IO_R_NO_DISK];
422: [IOQueue.qlock lock];
423: }
424: [IOQueue.qlock unlock];
425:
426: /*
427: * One more thing - I/O complete the abort command itself.
428: */
429: [self IOBufDone:IOBuf status:IO_R_SUCCESS];
430: }
431:
432: /*
433: * See if disk is present. If we got this far, it is; otherwise this request
434: * would have been ioComplete'd in unixDeviceAbort:.
435: */
436: - (void)deviceProbe : (IOBuf_t *)IOBuf
437: {
438: [self IOBufDone:IOBuf status:IO_R_SUCCESS];
439: }
440:
441: /*
442: * Test ready. We do this by trying to do a new open , with O_NDELAY. If that
443: * succeeds, it's ready.
444: */
445: - (void)deviceCheckReady : (IOBuf_t *)IOBuf
446: threadNum:(int)threadNum
447: {
448: int newfd;
449: IODiskReadyState *readyState = (IODiskReadyState *)IOBuf->buf;
450:
451: newfd = open(unix_name, O_RDONLY|O_NDELAY, 0);
452: if(newfd <=0) {
453: *readyState = IO_NotReady;
454: xpr_uth("deviceCheckReady: NOT READY\n", 1,2,3,4,5);
455: }
456: else {
457: *readyState = IO_Ready;
458: close(newfd);
459: xpr_uth("deviceCheckReady: READY\n", 1,2,3,4,5);
460: }
461: [self IOBufDone:IOBuf status:IO_R_SUCCESS];
462: }
463:
464: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.