|
|
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: * IdeKern.m - UNIX front end for kernel IDE Disk driver.
29: *
30: * HISTORY
31: * 07-Jul-1994 Rakesh Dubey at NeXT
32: * Created from original driver written by David Somayajulu.
33: * 19-Jun-97 Dieter Siegmund at Apple
34: * Updated to use the BSD4.4 ioctl interface that copies user
35: * buffer in/out of kernel automatically.
36: */
37:
38: #if (IO_DRIVERKIT_VERSION == 400)
39: #define _POSIX_SOURCE
40: #endif
41:
42: /*
43: * Note that this file builds with KERNEL_PRIVATE and !MACH_USER_API.
44: */
45: #import <sys/types.h>
46: #import <sys/ttycom.h>
47: #import <sys/ucred.h>
48: #import <driverkit/kernelDiskMethods.h>
49: #import <driverkit/generalFuncs.h>
50: #import "IdeCnt.h"
51: #import "IdeDiskInternal.h"
52: #import "IdeDisk.h"
53: #import <driverkit/kernelDriver.h>
54: #import <driverkit/IODiskPartition.h>
55: #import <sys/buf.h>
56: #import <sys/uio.h>
57: #import <bsd/dev/ldd.h>
58: #import <sys/errno.h>
59: #import <sys/proc.h>
60: #if (IO_DRIVERKIT_VERSION == 330)
61: #import <vm/vm_kern.h>
62: #endif
63: #import <sys/fcntl.h>
64: #import <sys/systm.h>
65: #import "IdeKernel.h"
66:
67: #if (IO_DRIVERKIT_VERSION != 330)
68: extern struct vm_map *kernel_map;
69: #endif
70:
71: IONamedValue iderValues[] = {
72:
73: {IDER_SUCCESS, "Success" },
74: {IDER_TIMEOUT, "Timeout occured" },
75: {IDER_MEMALLOC, "Couldn't allocate memory" },
76: {IDER_MEMFAIL, "Memory transfer error" },
77: {IDER_REJECT, "Bad field in ide_ioreq" },
78: {IDER_BADDRV, "Drive not present" },
79: {IDER_CMD_ERROR, "Command Failed" },
80: {IDER_VOLUNAVAIL, "Requested Volume not available"},
81: {IDER_SPURIOUS, "Spurious Interrupt" },
82: {IDER_CNTRL_REJECT, "Controller Reject" },
83: {0, NULL },
84: };
85:
86:
87: /*
88: * dev-to-id map array. Instances of DiskObject register their IDs in
89: * this array via registerUnixDisk:.
90: */
91: IODevAndIdInfo IdeIdMap[NUM_IDE_DEV];
92:
93: /*
94: * Private per-unit data.
95: */
96: static Ide_dev_t ide_dev[NUM_IDE_DEV] = {
97: {NULL},
98: {NULL},
99: {NULL},
100: {NULL},
101: };
102:
103: /*
104: * Indices of our entries in devsw's.
105: */
106: static int ide_block_major;
107: static int ide_raw_major;
108:
109: /*
110: * prototypes for internal functions
111: */
112: static unsigned ideminphys(struct buf *bp);
113: static id ide_dev_to_id(dev_t dev);
114:
115: /*
116: * Initialize id map and Ide_dev. Currently invoked by Ide probe:.
117: */
118: __private_extern__ void ide_init_idmap(id self)
119: {
120: IODevAndIdInfo *idMap = IdeIdMap;
121: Ide_dev_t *ide_devp = ide_dev;
122: int unit;
123:
124: /*
125: * figure out our major device numbers.
126: */
127: ide_block_major = [self blockMajor];
128: ide_raw_major = [self characterMajor];
129:
130: bzero((char *)idMap, sizeof(IODevAndIdInfo) * NUM_IDE_DEV);
131: for (unit = 0; unit < NUM_IDE_DEV; unit++) {
132: idMap->rawDev = makedev(ide_raw_major, (unit << 3));
133: idMap->blockDev = makedev(ide_block_major, (unit << 3));
134: idMap++;
135: ide_devp->physbuf = (struct buf *)IOMalloc(sizeof(struct buf));
136: ide_devp->physbuf->b_flags = 0;
137: ide_devp++;
138: }
139: }
140:
141: __private_extern__ IODevAndIdInfo *ide_idmap()
142: {
143: return IdeIdMap;
144: }
145:
146: __private_extern__ int
147: ideopen(dev_t dev, int flag, int devtype, struct proc * pp)
148: {
149: id diskObj = ide_dev_to_id(dev);
150:
151: if(diskObj == nil)
152: return(ENXIO);
153:
154: if([diskObj isDiskReady:NO])
155: return(ENXIO);
156:
157: /*
158: * Register this 'Unix-level open' event for IODiskPartitions.
159: */
160: if(IO_DISK_PART(dev) != IDE_LIVE_PART) {
161: if(major(dev) == ide_block_major) {
162: [diskObj setBlockDeviceOpen:YES];
163: }
164: else {
165: [diskObj setRawDeviceOpen:YES];
166: }
167: }
168: return(0);
169: } /* ideopen() */
170:
171: __private_extern__ int
172: ideclose(dev_t dev, int flag, int devtype, struct proc * pp)
173: {
174: id diskObj = ide_dev_to_id(dev);
175:
176: if(diskObj == nil)
177: return(ENXIO);
178: if(IO_DISK_PART(dev) == IDE_LIVE_PART) {
179: return 0;
180: } else {
181: if(![diskObj isInstanceOpen])
182: return(ENXIO);
183: }
184:
185: /*
186: * Register this 'Unix-level close' event. We won't be called unless
187: * this is the last close.
188: */
189: if(major(dev) == ide_block_major) {
190: [diskObj setBlockDeviceOpen:NO];
191: }
192: else {
193: [diskObj setRawDeviceOpen:NO];
194: }
195:
196: return(0);
197: } /* ideclose() */
198:
199: /*
200: * Raw I/O uses standard UNIX physio routine, resulting in async I/O requests
201: * via idestrategy().
202: */
203:
204: __private_extern__ int
205: ideread(dev_t dev, struct uio *uiop, int ioflag)
206: {
207: id diskObj = ide_dev_to_id(dev);
208: int unit = IO_DISK_UNIT(dev);
209: int rtn;
210:
211: if(diskObj == nil) {
212: return(ENXIO);
213: }
214:
215:
216: rtn = physio(idestrategy,
217: ide_dev[unit].physbuf,
218: dev,
219: B_READ,
220: ideminphys,
221: uiop,
222: [diskObj blockSize]);
223:
224: return rtn;
225: } /* ideread() */
226:
227: __private_extern__ int
228: idewrite(dev_t dev, struct uio *uiop, int ioflag)
229: {
230: id diskObj = ide_dev_to_id(dev);
231: int unit = IO_DISK_UNIT(dev);
232: int rtn;
233:
234: if(diskObj == nil)
235: return(ENXIO);
236:
237:
238: rtn = physio(idestrategy,
239: ide_dev[unit].physbuf,
240: dev,
241: B_WRITE,
242: ideminphys,
243: uiop,
244: [diskObj blockSize]);
245:
246: return rtn;
247: } /* idewrite() */
248:
249: __private_extern__ void
250: idestrategy(struct buf *bp)
251: {
252: id diskObj = ide_dev_to_id(bp->b_dev);
253: u_int offset;
254: u_int bytes_req;
255: void *bufp;
256: u_int block_size;
257: IOReturn rtn;
258: vm_task_t client;
259:
260: if(diskObj == nil) {
261: bp->b_error = ENXIO;
262: goto bad;
263: }
264:
265: if((bp->b_flags & (B_PHYS|B_KERNSPACE)) == B_PHYS) {
266: /*
267: * Physical I/O to user space.
268: */
269: client = IOVmTaskForBuf(bp);
270: }
271: else {
272: /*
273: * Either block I/O (always kernel space) or physical I/O
274: * to kernel space (e.g., loadable file system).
275: */
276: client = IOVmTaskSelf();
277: }
278:
279: block_size = [diskObj blockSize];
280: if (block_size == 0) {
281: bp->b_error = ENXIO;
282: goto bad;
283: }
284: offset = bp->b_blkno;
285: bytes_req = bp->b_bcount;
286: bufp = bp->b_un.b_addr;
287:
288: if (bp->b_flags & B_READ) {
289: rtn = [diskObj readAsyncAt:offset
290: length:bytes_req
291: buffer:bufp
292: pending:bp
293: client:client];
294: }
295: else {
296: rtn = [diskObj writeAsyncAt:offset
297: length:bytes_req
298: buffer:bufp
299: pending:bp
300: client:client];
301: }
302:
303: if (rtn) {
304: bp->b_error = [diskObj errnoFromReturn:rtn];
305: goto bad;
306: }
307: return;
308:
309: bad:
310: bp->b_flags |= B_ERROR;
311: biodone(bp);
312: } /* fdstrategy() */
313:
314: /*
315: * Ops which are common to all IODiskPartitions are done on the raw device;
316: * Ide-specific ioctls are done directly to the live Ide object.
317: */
318: __private_extern__ int
319: ideioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc * pp)
320: {
321: int unit = IO_DISK_UNIT(dev);
322: id diskObj;
323: IODevAndIdInfo *idmap;
324: int rtn = 0;
325: IOReturn irtn = IO_R_SUCCESS;
326: struct ucred cred;
327: u_short acflags;
328:
329: // user src/dest
330: int i;
331: int nblk;
332: ideIoReq_t *ideIoReq;
333: int error;
334: void *userPtr;
335:
336: // in ideIoReq_t
337: BOOL wrFlag = NO;
338: unsigned bSize = 0;
339: unsigned char *alignedPtr;
340:
341: if (unit > NUM_IDE_DEV)
342: return (ENXIO);
343: #if 0
344: if ((major(dev) != ide_raw_major) ||
345: (IO_DISK_PART(dev) >= NUM_IDE_PART)) {
346: return (ENXIO);
347: }
348: #endif
349:
350: idmap = &IdeIdMap[unit];
351:
352: /*
353: * First verify valid device.
354: */
355: switch (cmd) {
356: case DKIOCSFORMAT:
357: case DKIOCGFORMAT:
358: case DKIOCGLABEL:
359: case DKIOCSLABEL:
360:
361: /*
362: * Raw device, whatever the caller asked for.
363: */
364: diskObj = idmap->partitionId[0];
365: break;
366:
367: case IDEDIOCREQ:
368: case IDEDIOCINFO:
369: case DKIOCINFO:
370: case DKIOCBLKSIZE:
371: case DKIOCNUMBLKS:
372:
373: diskObj = idmap->liveId;
374: break;
375:
376: default:
377: return (EINVAL);
378: }
379: if (diskObj == nil)
380: goto nodev;
381:
382: switch (cmd) {
383: case DKIOCSFORMAT:
384:
385: /*
386: * This can fail if block devices attached to this disk are open.
387: */
388: irtn = [diskObj setFormatted:(*(u_int *) data)];
389: break;
390:
391: case DKIOCGFORMAT:
392: {
393: *(int *)data = [diskObj isFormatted];
394: break;
395: }
396:
397: case DKIOCGLABEL:
398: {
399: struct disk_label *labelp;
400:
401: labelp = (struct disk_label *)IOMalloc(sizeof(*labelp));
402: irtn = [diskObj readLabel:labelp];
403: if (irtn == IO_R_SUCCESS) {
404: *(struct disk_label *)data = *labelp;
405: }
406: IOFree(labelp, sizeof(*labelp));
407: break;
408: }
409:
410: case DKIOCSLABEL:
411: {
412: struct disk_label *labelp;
413:
414: //IOLog("DKIOCSLABEL called\n");
415:
416: labelp = (struct disk_label *)IOMalloc(sizeof(*labelp));
417: *labelp = *(struct disk_label *)data;
418: irtn = [diskObj writeLabel:labelp];
419: IOFree(labelp, sizeof(*labelp));
420: break;
421: }
422:
423: case DKIOCINFO:
424: {
425: struct drive_info info;
426:
427: bzero(&info, sizeof(info));
428: strcpy(info.di_name,[diskObj driveName]);
429: info.di_devblklen = [diskObj blockSize];
430: info.di_maxbcount = IDE_MAX_PHYS_IO;
431: if (info.di_devblklen) {
432: nblk = howmany(sizeof(struct disk_label),
433: info.di_devblklen);
434: } else {
435: nblk = 0;
436: }
437: for (i = 0; i < NLABELS; i++)
438: info.di_label_blkno[i] = nblk * i;
439: *(struct drive_info *) data = info;
440: break;
441: }
442:
443: case DKIOCBLKSIZE:
444: *(int *)data = [diskObj blockSize];
445: break;
446:
447: case DKIOCNUMBLKS:
448: *(int *)data = [diskObj diskSize];
449: break;
450:
451: case IDEDIOCREQ:
452:
453: /*
454: * Perform specified I/O.
455: */
456: ideIoReq = (ideIoReq_t *) data;
457: // if (!suser() && (ideIoReq->cmd != IDE_IDENTIFY_DRIVE))
458: if (!suser(&cred, &acflags) && (ideIoReq->cmd != IDE_IDENTIFY_DRIVE)) {
459: // return (u.u_error);
460: return (EINVAL);
461: }
462:
463: if ((ideIoReq->cmd == IDE_WRITE_DMA) ||
464: (ideIoReq->cmd == IDE_READ_DMA)) {
465: if ([[diskObj cntrlr] isDmaSupported:[diskObj driveNum]] != TRUE)
466: return (EINVAL);
467: }
468: if (ideIoReq->cmd == IDE_IDENTIFY_DRIVE)
469: ideIoReq->blkcnt = 1;
470:
471: userPtr = (void *)ideIoReq->addr;
472:
473: alignedPtr = ideIoReq->addr;
474: if ((ideIoReq->cmd == IDE_WRITE) ||
475: (ideIoReq->cmd == IDE_READ) ||
476: (ideIoReq->cmd == IDE_READ_MULTIPLE) ||
477: (ideIoReq->cmd == IDE_WRITE_MULTIPLE) ||
478: (ideIoReq->cmd == IDE_READ_DMA) ||
479: (ideIoReq->cmd == IDE_WRITE_DMA) ||
480: (ideIoReq->cmd == IDE_IDENTIFY_DRIVE)) {
481: if (ideIoReq->blkcnt != 0) {
482: bSize = [diskObj blockSize];
483: wrFlag = ((ideIoReq->cmd == IDE_WRITE) ||
484: (ideIoReq->cmd == IDE_WRITE_MULTIPLE) ||
485: (ideIoReq->cmd == IDE_WRITE_DMA));
486:
487: alignedPtr = (unsigned char *)
488: IOMalloc(ideIoReq->blkcnt * bSize);
489: if (alignedPtr == 0) {
490: ideIoReq->status = IDER_MEMALLOC;
491: return (ENOMEM);
492: }
493: if (wrFlag) {
494: error = copyin(ideIoReq->addr,
495: alignedPtr,
496: ideIoReq->blkcnt * bSize);
497: if (error) {
498: ideIoReq->status = IDER_MEMFAIL;
499: goto err_exit;
500: }
501: }
502: }
503: ideIoReq->addr = (caddr_t) alignedPtr;
504: ideIoReq->map = (struct vm_map *)IOVmTaskSelf();
505: }
506:
507:
508: [diskObj ideXfrIoReq:ideIoReq];
509:
510: /*
511: * Note if we got this far, we'll return 0; any errors are in
512: * ideIoReq->status.
513: */
514: if ((ideIoReq->cmd == IDE_WRITE) ||
515: (ideIoReq->cmd == IDE_READ) ||
516: (ideIoReq->cmd == IDE_READ_MULTIPLE) ||
517: (ideIoReq->cmd == IDE_WRITE_MULTIPLE) ||
518: (ideIoReq->cmd == IDE_READ_DMA) ||
519: (ideIoReq->cmd == IDE_WRITE_DMA) ||
520: (ideIoReq->cmd == IDE_IDENTIFY_DRIVE)) {
521:
522: ideIoReq->addr = userPtr;
523: if (((ideIoReq->cmd == IDE_READ) ||
524: (ideIoReq->cmd == IDE_READ_MULTIPLE) ||
525: (ideIoReq->cmd == IDE_IDENTIFY_DRIVE) ||
526: (ideIoReq->cmd == IDE_READ_DMA)) &&
527: (ideIoReq->blocks_xfered != 0)) {
528: error = copyout(alignedPtr,
529: userPtr,
530: ideIoReq->blocks_xfered * bSize);
531: if (error) {
532: ideIoReq->status = IDER_MEMFAIL;
533: }
534: }
535: err_exit:
536:
537: /*
538: * if we malloc'd any memory, free it.
539: */
540: if (ideIoReq->blkcnt != 0)
541: IOFree(alignedPtr, ideIoReq->blkcnt * bSize);
542: }
543: break;
544:
545: case IDEDIOCINFO:
546: {
547: ideDriveInfo_t *idep = (ideDriveInfo_t *) data;
548:
549: *idep = (ideDriveInfo_t)[diskObj ideGetDriveInfo];
550: break;
551: }
552: default:
553: return (EINVAL);
554: }
555:
556: if (irtn)
557: rtn = [diskObj errnoFromReturn:irtn];
558: return (rtn);
559:
560: nodev:
561: return (ENXIO);
562:
563: } /* ideioctl() */
564:
565: /*
566: * Obtain physical block size.
567: */
568: __private_extern__ int
569: idesize(dev_t dev)
570: {
571: id diskObj = ide_dev_to_id(dev);
572:
573: if(diskObj == nil) {
574: return -1;
575: }
576: return [diskObj blockSize];
577: }
578:
579: /*
580: * Returns block and char major nums. This is used so that the PostLoad
581: * program can create block and character nodes for IDE.
582: */
583: __private_extern__ void
584: ide_block_char_majors(int *blockmajor, int *charmajor)
585: {
586: *blockmajor = ide_block_major;
587: *charmajor = ide_raw_major;
588: }
589:
590: static unsigned ideminphys(struct buf *bp)
591: {
592: if (bp->b_bcount > IDE_MAX_PHYS_IO)
593: bp->b_bcount = IDE_MAX_PHYS_IO;
594: return(bp->b_bcount);
595: }
596:
597: /*
598: * Map dev_t to id. A nil return indicates ENXIO.
599: */
600: static id ide_dev_to_id(dev_t dev)
601: {
602: id rtn;
603: int unit = IO_DISK_UNIT(dev);
604: IODevAndIdInfo *idmap;
605: int part = IO_DISK_PART(dev);
606:
607: if((unit >= NUM_IDE_DEV) || (part >= NUM_IDE_PART)) {
608: return nil;
609: }
610: idmap = &IdeIdMap[unit];
611: if(part == IDE_LIVE_PART) {
612: if(major(dev) == ide_block_major) {
613: rtn = nil;
614: }
615: else {
616: rtn = idmap->liveId;
617: }
618: }
619: else {
620: rtn = idmap->partitionId[part];
621: }
622: return rtn;
623: }
624:
625: /* end of IdeKern.m */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.