|
|
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 (c) 1991 NeXT Computer, Inc. All rights reserved.
26: *
27: * SCSIDiskKern.m - UNIX front end for kernel SCSIDisk device.
28: *
29: * HISTORY
30: * 30-Apr-91 Doug Mitchell at NeXT
31: * Created.
32: */
33:
34: /*
35: * Note that this file builds with KERNEL_PRIVATE and !MACH_USER_API.
36: */
37: #import <sys/systm.h> /* for nblkdev and nchrdev */
38: #import <driverkit/SCSIDisk.h>
39: #import <driverkit/kernelDiskMethods.h>
40: #import <driverkit/SCSIDiskKern.h>
41: #import <driverkit/SCSIDiskPrivate.h>
42: #import <driverkit/SCSIDiskTypes.h>
43: #import <driverkit/scsiTypes.h>
44: #import <driverkit/SCSIStructInlines.h>
45: #import <bsd/dev/scsireg.h>
46: #import <driverkit/IODiskPartition.h>
47: #import <driverkit/xpr_mi.h>
48: #import <sys/buf.h>
49: #import <sys/conf.h>
50: #import <sys/uio.h>
51: #import <bsd/dev/ldd.h>
52: #import <sys/errno.h>
53: #import <sys/proc.h>
54: #import <vm/vm_kern.h>
55: #import <sys/fcntl.h>
56: #import <bsd/dev/disk.h>
57: #import <driverkit/align.h>
58:
59: #import <kern/assert.h>
60:
61:
62: #ifdef ppc //bknight - 12/3/97 - Radar #2004660
63: #define GROK_APPLE 1
64: #endif //bknight - 12/3/97 - Radar #2004660
65:
66: // wait until 20 seconds after probe non-ready disks
67: #define MAX_DISK_PROBE_TIME 20
68:
69:
70: int sdopen(dev_t dev, int flag, int devtype, struct proc * pp);
71: int sdclose(dev_t dev, int flag, int devtype, struct proc * pp);
72: int sdread(dev_t dev, struct uio *uiop, int ioflag);
73: int sdwrite(dev_t dev, struct uio *uiop, int ioflag);
74: int sdstrategy(register struct buf *bp);
75: int sdioctl(dev_t dev,
76: u_long cmd,
77: caddr_t data,
78: int flag, struct proc *pp);
79: int sdsize(dev_t dev);
80:
81: /*
82: * dev-to-id map array. Instances of DiskObject register their IDs in
83: * this array via registerUnixDisk:.
84: */
85: static IODevAndIdInfo SCSIDiskIdMap[NUM_SD_DEV];
86:
87: /*
88: * Private per-unit data.
89: */
90: typedef struct _SCSIDisk_DataTag {
91: struct buf physbuf;
92: unsigned int maxTransfer;
93: } SCSIDisk_Data_t;
94:
95: static SCSIDisk_Data_t *SCSIDisk_dev[NUM_SD_DEV];
96:
97: /*
98: * Indices of our entries in devsw's.
99: */
100: static int sd_block_major;
101: static int sd_raw_major;
102:
103: /*
104: * prototypes for internal functions
105: */
106: static unsigned sdminphys(struct buf *bp);
107: static id sd_dev_to_id(dev_t dev);
108: static id sd_phys_dev_id(dev_t dev);
109:
110: static void sd_prevent_eject(id physicalDisk, BOOL prevent);
111:
112:
113: #ifdef DDM_DEBUG
114: static IONamedValue sdIoctlValues[] = {
115: {DKIOCSFORMAT, "DKIOCSFORMAT" },
116: {DKIOCGFORMAT, "DKIOCGFORMAT" },
117: {DKIOCGLABEL, "DKIOCGLABEL" },
118: {DKIOCSLABEL, "DKIOCSLABEL" },
119: {DKIOCEJECT, "DKIOCEJECT" },
120: {SDIOCSRQ, "SDIOCSRQ" },
121: {SDIOCGETCAP, "SDIOCGETCAP" },
122: {DKIOCINFO, "DKIOCINFO" },
123: {0, NULL }
124: };
125:
126: #endif DDM_DEBUG
127:
128: /*
129: * Initialize id map and SCSIDisk_dev. Currently invoked by SCSIDisk probe:.
130: */
131: void sd_init_idmap()
132: {
133: IODevAndIdInfo *idMap = SCSIDiskIdMap;
134: int unit;
135: struct bdevsw *bd;
136: struct cdevsw *cd;
137:
138: /*
139: * figure out our major device numbers.
140: */
141: for (bd = bdevsw; bd < &bdevsw[nblkdev]; bd++) {
142: if (bd->d_open == (int (*)())sdopen) {
143: sd_block_major = bd - bdevsw;
144: break;
145: }
146: }
147: for (cd = cdevsw; cd < &cdevsw[nchrdev]; cd++) {
148: if (cd->d_open == (int (*)())sdopen) {
149: sd_raw_major = cd - cdevsw;
150: break;
151: }
152: }
153:
154: bzero(idMap, sizeof(*idMap) * NUM_SD_DEV);
155: for(unit=0; unit<NUM_SD_DEV; unit++) {
156: idMap->rawDev = makedev(sd_raw_major, (unit << 3));
157: idMap->blockDev = makedev(sd_block_major, (unit << 3));
158: idMap++;
159: SCSIDisk_dev[unit] = IOMalloc(sizeof(SCSIDisk_Data_t));
160: SCSIDisk_dev[unit]->physbuf.b_flags = 0;
161: }
162: }
163:
164: IODevAndIdInfo *sd_idmap()
165: {
166: return SCSIDiskIdMap;
167: }
168:
169: int sdopen(dev_t dev, int flag, int devtype, struct proc *pp)
170: {
171: id diskObj;
172: BOOL prompt;
173: int err;
174: int unit;
175:
176: // UFS partition a
177: diskObj = sd_dev_to_id(dev & 0x78);
178: if( diskObj)
179: [diskObj waitForProbe:MAX_DISK_PROBE_TIME];
180:
181: diskObj = sd_dev_to_id(dev);
182: if(diskObj == nil) {
183: return(ENXIO);
184: }
185: xpr_sd("%s: sdopen\n", [diskObj name], 2,3,4,5);
186: if(flag & O_NDELAY) {
187: prompt = NO;
188: }
189: else {
190: prompt = YES;
191: }
192: if([diskObj isDiskReady:prompt]) {
193: return(ENXIO);
194: }
195:
196: /*
197: * Register this 'Unix-level open' event for IODiskPartitions.
198: */
199: if(IO_DISK_PART(dev) != SD_LIVE_PART) {
200: // If this is the first open() on a removable disk,
201: // whether block or raw, on any of the partitions,
202: // send a TEST UNIT READY to guarantee the disk is
203: // still present (isDiskReady doesn't do this). If
204: // it is, we send a PREVENT MEDIUM REMOVAL to lock
205: // down the removable disk while it is open.
206: //
207: // Note that we don't keep track of live open()'s,
208: // so we don't send TEST UNIT READY and/or PREVENT
209: // MEDIUM REMOVAL on live opens. Should not be an
210: // issue (for now).
211:
212: if ( [diskObj isRemovable] == YES &&
213: [diskObj isInstanceOpen] == NO &&
214: [diskObj isAnyOtherOpen] == NO )
215: {
216: id physDisk = sd_phys_dev_id(dev);
217: ASSERT(physDisk);
218:
219: if ( [physDisk updateReadyState] != IO_Ready )
220: {
221: [physDisk diskNotReady]; // not ready state
222: return ENXIO;
223: }
224:
225: sd_prevent_eject(physDisk, YES);
226: }
227: if(major(dev) == sd_block_major) {
228: [diskObj setBlockDeviceOpen:YES];
229: }
230: else {
231: [diskObj setRawDeviceOpen:YES];
232: }
233: }
234:
235: unit = IO_DISK_UNIT(dev);
236: #ifdef GROK_APPLE
237: if (unit >= NUM_SD_DEV)
238: unit -= NUM_SD_DEV;
239: #endif /* GROK_APPLE */
240:
241: /* We have the physical disk now so grab a maxTransfer if necessary */
242: if ( !SCSIDisk_dev[unit]->maxTransfer ) {
243: diskObj = sd_phys_dev_id(dev); /* Get the physical disk */
244: SCSIDisk_dev[unit]->maxTransfer = [[diskObj controller] maxTransfer];
245: }
246:
247: return(0);
248: } /* sdopen() */
249:
250: int sdclose(dev_t dev, int flag, int devtype, struct proc *pp)
251: {
252: id diskObj = sd_dev_to_id(dev);
253: id physDisk = sd_phys_dev_id(dev);
254:
255: if(diskObj == nil) {
256: return(ENXIO);
257: }
258: kprintf("%s: sdclose major %d minor %d\n", [diskObj name],
259: major(dev),minor(dev));
260: xpr_sd("%s: sdclose\n", [diskObj name], 2,3,4,5);
261:
262: /* Issue a Synchronize-cache operation, which will force
263: * the device to flush its cached blocks.
264: */
265: if (physDisk != nil) {
266: [physDisk synchronizeCache];
267: }
268:
269: /*
270: * bknight - 12/3/97 - 2004660
271: * This test is safe, even when IO_DISK_PART denotes an HFS partition.
272: */
273:
274: if(IO_DISK_PART(dev) == SD_LIVE_PART) {
275: return 0;
276: } else if(![diskObj isInstanceOpen]) {
277: return(ENXIO);
278: }
279:
280: /*
281: * Register this 'Unix-level close' event. We won't be called unless
282: * this is the last close.
283: */
284: if(major(dev) == sd_block_major) {
285: [diskObj setBlockDeviceOpen:NO];
286: }
287: else {
288: [diskObj setRawDeviceOpen:NO];
289: }
290:
291: // If this is the last close() on a removable disk,
292: // whether block or raw, for all of the partitions,
293: // send an ALLOW MEDIUM REMOVAL to the SCSI drive.
294: //
295: // Note that we don't keep track of live open()'s,
296: // so we don't send PREVENT/ALLOW MEDIUM REMOVAL
297: // on live opens/closes either.
298: //
299: // Note that diskObj is an IOLogicalDisk here.
300:
301: if ( [diskObj isRemovable] == YES &&
302: [diskObj isInstanceOpen] == NO && // (raw and block)
303: [diskObj isAnyOtherOpen] == NO) // (raw and block)
304: {
305: sd_prevent_eject(physDisk, NO);
306: }
307:
308: return(0);
309: } /* sdclose() */
310:
311: /*
312: * Raw I/O uses standard UNIX physio routine, resulting in async I/O requests
313: * via sdstrategy().
314: *
315: * For now, we do DMA alignment in both disk driver's phys read and
316: * physwrite as well as in the ioctl ops which do DMA. Ugh.
317: */
318: #define SD_PHYS_ALIGN 1
319: #if SD_PHYS_ALIGN
320:
321: #define FORCE_PAGE_ALIGN 1
322: #if FORCE_PAGE_ALIGN
323: int forceSdPageAlign = 0;
324: #endif FORCE_PAGE_ALIGN
325: #endif SD_PHYS_ALIGN
326:
327: int sdread(dev_t dev, struct uio *uiop, int ioflag)
328: {
329: id diskObj = sd_dev_to_id(dev);
330: int unit = IO_DISK_UNIT(dev);
331: int rtn;
332: #if SD_PHYS_ALIGN
333: void *freePtr = NULL; // memory to free
334: void *alignedPtr = NULL; // DMA target
335: int freeCnt = 0; // size to free
336: void *userPtr = NULL; // user spec'd pointer
337: BOOL didAlign = NO;
338: struct iovec *iov;
339: int userCnt = 0;
340: int userSegflg = 0;
341: IODMAAlignment dmaAlign;
342: id liveId = sd_phys_dev_id(dev);
343: #endif SD_PHYS_ALIGN
344:
345: if(diskObj == nil) {
346: return(ENXIO);
347: }
348: xpr_sd("sdread %s\n", [diskObj name], 2,3,4,5);
349:
350: /*
351: * Catch unformatted disks right now, since blockSize is zero in
352: * that case.
353: */
354: if(![diskObj isFormatted]) {
355: return EINVAL;
356: }
357:
358: #if SD_PHYS_ALIGN
359:
360: /*
361: * Note - this is temporary. We assume one vector and a well aligned
362: * byte count.
363: */
364: ASSERT(uiop->uio_iovcnt == 1);
365: iov = uiop->uio_iov;
366: [[liveId controller] getDMAAlignment:&dmaAlign];
367: #if FORCE_PAGE_ALIGN
368: if(forceSdPageAlign) {
369: dmaAlign.readStart = PAGE_SIZE;
370: }
371: #endif FORCE_PAGE_ALIGN
372: if( ( (dmaAlign.readStart > 1) &&
373: !IOIsAligned(iov->iov_base, dmaAlign.readStart)
374: ) ||
375: ( (dmaAlign.readLength > 1) &&
376: !IOIsAligned(iov->iov_len, dmaAlign.readLength)
377: )
378: #if sparc
379: || 1
380: #endif
381: ) {
382: didAlign = YES;
383: alignedPtr = [[liveId controller] allocateBufferOfLength:
384: iov->iov_len
385: actualStart:&freePtr
386: actualLength:&freeCnt];
387: userPtr = (void *)iov->iov_base;
388: iov->iov_base = (caddr_t)alignedPtr;
389: userCnt = iov->iov_len;
390:
391: /*
392: * DMA to kernel space now...
393: */
394: userSegflg = uiop->uio_segflg;
395: uiop->uio_segflg = UIO_SYSSPACE;
396: }
397: #endif SD_PHYS_ALIGN
398:
399: #ifdef GROK_APPLE
400: if (unit >= NUM_SD_DEV)
401: unit -= NUM_SD_DEV;
402: #endif /* GROK_APPLE */
403:
404: rtn = physio(sdstrategy,
405: (struct buf *) SCSIDisk_dev[unit],
406: dev,
407: B_READ,
408: sdminphys,
409: uiop,
410: [diskObj blockSize]);
411:
412: #if SD_PHYS_ALIGN
413: if(didAlign) {
414: if(userSegflg == UIO_SYSSPACE) {
415: bcopy(alignedPtr, userPtr, userCnt);
416: }
417: else {
418: copyout(alignedPtr, userPtr, userCnt);
419: }
420: IOFree(freePtr, freeCnt);
421: }
422: #endif SD_PHYS_ALIGN
423:
424: return rtn;
425:
426: } /* sdread() */
427:
428: int sdwrite(dev_t dev, struct uio *uiop, int ioflag)
429: {
430: id diskObj = sd_dev_to_id(dev);
431: int unit = IO_DISK_UNIT(dev);
432: int rtn;
433: #if SD_PHYS_ALIGN
434: void *freePtr = NULL; // memory to free
435: void *alignedPtr = NULL; // DMA target
436: int freeCnt = 0; // size to free
437: void *userPtr = NULL; // user spec'd pointer
438: BOOL didAlign = NO;
439: struct iovec *iov;
440: IODMAAlignment dmaAlign;
441: id liveId = sd_phys_dev_id(dev);
442: #endif SD_PHYS_ALIGN
443:
444: if(diskObj == nil)
445: return(ENXIO);
446: xpr_sd("sd_write %s\n", [diskObj name], 2,3,4,5);
447:
448: /*
449: * Catch unformatted disks right now, since blockSize is zero in
450: * that case.
451: */
452: if(![diskObj isFormatted]) {
453: return EINVAL;
454: }
455:
456: #if SD_PHYS_ALIGN
457:
458: /*
459: * Note - this is temporary. We assume one vector and a well aligned
460: * byte count.
461: * We force a copyin to kernel space for raw user-level I/O to
462: * ensure that rawVerify can work.
463: */
464: ASSERT(uiop->uio_iovcnt == 1);
465: iov = uiop->uio_iov;
466: [[liveId controller] getDMAAlignment:&dmaAlign];
467: #if FORCE_PAGE_ALIGN
468: if(forceSdPageAlign) {
469: dmaAlign.writeStart = PAGE_SIZE;
470: }
471: #endif FORCE_PAGE_ALIGN
472: if( ( (dmaAlign.writeStart > 1) &&
473: !IOIsAligned(iov->iov_base, dmaAlign.writeStart)
474: ) ||
475: ( (dmaAlign.writeLength > 1) &&
476: !IOIsAligned(iov->iov_len, dmaAlign.writeLength)
477: )
478: #if sparc
479: || 1
480: #endif
481: ) {
482:
483: didAlign = YES;
484: alignedPtr = [[liveId controller] allocateBufferOfLength:
485: iov->iov_len
486: actualStart:&freePtr
487: actualLength:&freeCnt];
488: userPtr = (void *)iov->iov_base;
489: iov->iov_base = (caddr_t)alignedPtr;
490: if(uiop->uio_segflg == UIO_SYSSPACE) {
491: bcopy(userPtr, alignedPtr, iov->iov_len);
492: }
493: else {
494: copyin(userPtr, alignedPtr, iov->iov_len);
495: uiop->uio_segflg = UIO_SYSSPACE;
496: }
497:
498: }
499: #endif SD_PHYS_ALIGN
500:
501: #ifdef GROK_APPLE
502: if (unit >= NUM_SD_DEV)
503: unit -= NUM_SD_DEV;
504: #endif /* GROK_APPLE */
505:
506: rtn = physio(sdstrategy,
507: (struct buf *) SCSIDisk_dev[unit],
508: dev,
509: B_WRITE,
510: sdminphys,
511: uiop,
512: [diskObj blockSize]);
513:
514: #if SD_PHYS_ALIGN
515: if(didAlign) {
516: IOFree(freePtr, freeCnt);
517: }
518: #endif SD_PHYS_ALIGN
519:
520: return rtn;
521:
522: } /* sdwrite() */
523:
524: int sdstrategy(struct buf *bp)
525: {
526: id diskObj = sd_dev_to_id(bp->b_dev);
527: u_int offset;
528: u_int bytes_req;
529: void *bufp;
530: u_int block_size;
531: IOReturn rtn;
532: vm_task_t client;
533:
534: xpr_sd("%s: sdstrategy\n", [diskObj name], 2,3,4,5);
535: if(diskObj == nil) {
536: xpr_sd("sdstrategy: bad unit\n", 1,2,3,4,5);
537: bp->b_error = ENXIO;
538: goto bad;
539: }
540: if((bp->b_flags & (B_PHYS|B_KERNSPACE)) == B_PHYS) {
541: /*
542: * Physical I/O to user space.
543: */
544: client = ((task_t)bp->b_proc->task)->map;
545: }
546: else {
547: /*
548: * Either block I/O (always kernel space) or physical I/O
549: * to kernel space (e.g., loadable file system).
550: */
551: client = kernel_map;
552: }
553: block_size = [diskObj blockSize];
554: if(block_size == 0) {
555: xpr_sd("sdstrategy %s: zero block_size\n",
556: [diskObj name], 2,3,4,5);
557: bp->b_error = ENXIO;
558: goto bad;
559: }
560: offset = bp->b_blkno;
561: bytes_req = bp->b_bcount;
562: bufp = bp->b_un.b_addr;
563: if(bp->b_flags & B_READ) {
564: rtn = [diskObj readAsyncAt:offset
565: length:bytes_req
566: buffer:bufp
567: pending:bp
568: client:client];
569: }
570: else {
571: rtn = [diskObj writeAsyncAt:offset
572: length:bytes_req
573: buffer:bufp
574: pending:bp
575: client:client];
576: }
577: if(rtn) {
578: /*
579: * Check to see if 'IODisk' object has called completeTransfer.
580: * if so then don't try to repair the bp structure just return.
581: */
582: if (bp->b_flags & B_DONE) {
583: xpr_sd("sdstrategy: COMMAND REJECT\n", 1,2,3,4,5);
584: return -1;
585: }
586: bp->b_error = [diskObj errnoFromReturn:rtn];
587: goto bad;
588: }
589: xpr_sd("sdstrategy: SUCCESS\n", 1,2,3,4,5);
590: return(0);
591:
592: bad:
593: bp->b_flags |= B_ERROR;
594: rtn = -1;
595: biodone(bp);
596: xpr_sd("sdstrategy: COMMAND REJECT\n", 1,2,3,4,5);
597: return(rtn);
598:
599: } /* sdstrategy() */
600:
601: /*
602: * Ops which are common to all IODiskPartitions are done on the raw device;
603: * SCSI-specific ioctls are done directly to the live SCSIDisk object.
604: */
605: int sdioctl(dev_t dev,
606: u_long cmd,
607: caddr_t data,
608: int flag,
609: struct proc *pp)
610: {
611: int unit = IO_DISK_UNIT(dev);
612: int part = IO_DISK_PART(dev);
613: id diskObj;
614: IODevAndIdInfo *idmap;
615: int rtn = 0;
616: IOReturn irtn = IO_R_SUCCESS;
617: char *userData = *(char **)data; // user src/dest
618: void *alignedPtr = NULL; // kernel src/des
619: unsigned alignedLength;
620: int i;
621: IOSCSIRequest scsiReq; // new style - to controller
622: struct scsi_req *srp; // old style - from caller
623: int nblk;
624: void *freeBuf;
625: int freeLength;
626:
627: xpr_sd("sdioctl: unit %d cmd %s\n", unit,
628: IOFindNameForValue(cmd, sdIoctlValues), 3,4,5);
629:
630: #ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
631:
632: /* Compensate for an HFS partition. */
633:
634: if ( ! ( unit < NUM_SD_DEV ) ) {
635: unit -= NUM_SD_DEV;
636: part += NUM_SD_PART;
637: }
638:
639: #endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
640:
641: if(!(unit < NUM_SD_DEV))
642: return (ENXIO);
643:
644: #if 0
645: if(major(dev) != sd_raw_major) {
646: xpr_sd("sdioctl: not raw device\n", 1,2,3,4,5);
647: return(ENXIO);
648: }
649: #endif
650: idmap = &SCSIDiskIdMap[unit];
651:
652: #ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
653:
654: /*
655: * Special cases for HFS partitions.
656: * DKIOCNUMBLKS - return # blocks on partition, not the whole device
657: * DKIOCSFORMAT - not permitted
658: * DKIOCGFORMAT - not permitted
659: * DKIOCGLABEL - not permitted
660: * DKIOCSLABEL - not permitted
661: */
662:
663: /* Is it an HFS partition ? */
664:
665: if ( ! ( part < NPART ) )
666: {
667: /*
668: * For an HFS partition, return the # of blocks and block
669: * size in the partition, rather than on the whole device.
670: */
671: diskObj = idmap->partitionId[part];
672: switch ( cmd )
673: {
674: case DKIOCBLKSIZE:
675: *(int *)data = [diskObj blockSize];
676: return (0);
677: break;
678:
679: case DKIOCNUMBLKS:
680: *(int *)data = [diskObj diskSize];
681: return (0);
682: break;
683:
684: case DKIOCSFORMAT:
685: case DKIOCGFORMAT:
686: case DKIOCGLABEL:
687: case DKIOCSLABEL:
688: return(EINVAL);
689: break;
690: }
691: }
692:
693: #endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
694:
695: /*
696: * Get appropriate device. Note we sometimes use the live
697: * device partition (partition 7) here even if another partition
698: * was opened; we're just directing the I/O request to the correct
699: * object.
700: *
701: * Also note that several of these ioctls can fail if not invoked
702: * upon partition0, or if any block devices are open, or if any
703: * other partitions are open. That's handled elsewhere.
704: */
705: switch (cmd) {
706: case DKIOCSFORMAT:
707: case DKIOCGFORMAT:
708: case DKIOCGLABEL:
709: case DKIOCSLABEL:
710: case DKIOCEJECT:
711: /*
712: * These must be performed on a valid raw device,
713: * but if caller asked for live device (as some disk
714: * diags are liable to do), we'll given them raw
715: * partition a.
716: */
717: {
718:
719: #ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
720:
721: /* Treat HFS partitions like the live partition, too. */
722:
723: if ( part >= SD_LIVE_PART ) {
724: part = 0;
725: }
726:
727: #else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
728:
729: if(part == SD_LIVE_PART) {
730: part = 0;
731: }
732:
733: #endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
734:
735: diskObj = idmap->partitionId[part];
736: }
737: break;
738:
739: case DKIOCGLOCATION:
740: diskObj = idmap->partitionId[part];
741: break;
742:
743: case SDIOCSRQ:
744: case SDIOCGETCAP:
745: case DKIOCINFO:
746: case DKIOCBLKSIZE:
747: case DKIOCNUMBLKS:
748: diskObj = idmap->liveId;
749: break;
750: default:
751: xpr_sd("sdioctl: BAD cmd (0x%x)\n", cmd,2,3,4,5);
752: return(EINVAL);
753: }
754: if(diskObj == nil)
755: goto nodev;
756:
757: switch (cmd) {
758: case DKIOCSFORMAT:
759: /*
760: * This can fail if block devices attached to this disk are
761: * open.
762: */
763: irtn = [diskObj setFormatted:(*(u_int *)data)];
764: break;
765:
766: case DKIOCGFORMAT:
767: {
768: *(int *)data = [diskObj isFormatted];
769: break;
770: }
771:
772: case DKIOCGLABEL:
773: {
774: struct disk_label *labelp;
775:
776: labelp = IOMalloc(sizeof(*labelp));
777: irtn = [diskObj readLabel:labelp];
778: if(irtn == IO_R_SUCCESS) {
779: *(struct disk_label *)data = *labelp;
780: }
781: IOFree(labelp, sizeof(*labelp));
782: break;
783: }
784:
785: case DKIOCSLABEL:
786: {
787: struct disk_label *labelp;
788:
789: labelp = IOMalloc(sizeof(*labelp));
790: *labelp = *(struct disk_label *)data;
791: irtn = [diskObj writeLabel:labelp];
792: IOFree(labelp, sizeof(*labelp));
793: break;
794: }
795:
796: case DKIOCINFO:
797: {
798: struct drive_info info;
799:
800: bzero(&info, sizeof(info));
801: strcpy(info.di_name, [diskObj driveName]);
802: info.di_devblklen = [diskObj blockSize];
803: info.di_maxbcount = SCSIDisk_dev[unit]->maxTransfer;
804: if(info.di_devblklen) {
805: /*
806: * Careful, blockSize might be 0 for an
807: * unformatted disk.
808: */
809: nblk = howmany(sizeof(struct disk_label),
810: info.di_devblklen);
811: for (i = 0; i < NLABELS; i++)
812: info.di_label_blkno[i] = nblk * i;
813: }
814: *(struct drive_info *)data = info;
815: break;
816: }
817:
818: case DKIOCEJECT:
819: /*
820: * This is a (legal) nop for non-removable drives. This
821: * merely accomodates a WSM quirk left over from
822: * m68k develolpment; it's handled here instead of
823: * in IODiskPartition to avoid propagating further...
824: */
825: if(![diskObj isRemovable]) {
826: break;
827: }
828: // Send an ALLOW MEDIUM REMOVAL to the SCSI drive
829: // to permit the ejection of the disk, unless we
830: // detect another active open on this disk (aside
831: // from the one issuing this eject). The [eject]
832: // method also does this check, don't worry. We
833: // just don't want to send spurious PREVENT/ALLOW
834: // commands while other folks are doing I/O.
835: //
836: // Note that on successful ejection, a 2nd ALLOW
837: // MEDIUM REMOVAL will be sent after this on the
838: // close() of this device. This is not an issue.
839:
840: if ( [diskObj isAnyOtherOpen] == NO &&
841: [diskObj isBlockDeviceOpen] == NO )
842: {
843: // Note that eject ioctls arrive on raw opens,
844: // so we only check for outstanding block opens
845: // on our device.
846: sd_prevent_eject(idmap->liveId, NO);
847:
848: // Eject the disk now.
849: irtn = [diskObj eject];
850:
851: // Send a PREVENT MEDIUM REMOVAL to the SCSI drive
852: // to re-prevent the ejection of the disk if the
853: // eject has failed for any reason.
854: if (irtn) sd_prevent_eject(idmap->liveId, YES);
855: } else {
856: irtn = [diskObj eject];
857: }
858: break;
859:
860: case DKIOCBLKSIZE:
861: *(int *)data = [diskObj blockSize];
862: break;
863:
864: case DKIOCNUMBLKS:
865: *(int *)data = [diskObj diskSize];
866: break;
867:
868: case DKIOCGLOCATION:
869: if( nil == [diskObj getDevicePath:((struct drive_location *)data)->location
870: maxLength:sizeof(((struct drive_location *)data)->location)
871: useAlias:YES] )
872: irtn = IO_R_UNSUPPORTED;
873: break;
874:
875: case SDIOCSRQ:
876:
877: srp = (struct scsi_req *)data;
878:
879: /* if user expects to do some DMA, get some well-aligned
880: * memory. Copy in the user's data if a DMA write is
881: * expected. By using allocateBufferOfLength we guarantee
882: * that there is enough space in the buffer we pass to the
883: * controller to handle end-of-buffer alignment, although
884: * we won't copy more than sr_dma_max to or from the
885: * caller.
886: */
887: if(srp->sr_dma_max != 0) {
888: IODMAAlignment dmaAlign;
889: id controller = [idmap->liveId controller];
890: unsigned alignment;
891:
892: [controller getDMAAlignment:&dmaAlign];
893: if(srp->sr_dma_dir == SR_DMA_WR) {
894: alignment = dmaAlign.writeLength;
895: }
896: else {
897: alignment = dmaAlign.readLength;
898: }
899: if(alignment > 1) {
900: alignedLength = IOAlign(unsigned,
901: srp->sr_dma_max,
902: alignment);
903: }
904: else {
905: alignedLength = srp->sr_dma_max;
906: }
907: alignedPtr = [controller
908: allocateBufferOfLength:alignedLength
909: actualStart:&freeBuf
910: actualLength:&freeLength];
911: if(srp->sr_dma_dir == SR_DMA_WR) {
912: rtn = copyin(srp->sr_addr, alignedPtr,
913: srp->sr_dma_max);
914: if(rtn) {
915: xpr_sd(" ...copyin() returned %d\n",
916: rtn, 2,3,4,5);
917: srp->sr_io_status = SR_IOST_MEMF;
918: goto err_exit;
919: }
920: }
921: } else {
922: alignedLength = 0;
923: alignedPtr = 0;
924: }
925:
926: /*
927: * Generate a contemporary version of scsi_req.
928: */
929: bzero(&scsiReq, sizeof(scsiReq));
930: scsiReq.target = [diskObj target];
931: scsiReq.lun = [diskObj lun];
932: /*
933: * Careful. this assumes that the old and new cdb structs are
934: * equivalent...
935: */
936: scsiReq.cdb = srp->sr_cdb;
937: scsiReq.read = (srp->sr_dma_dir == SR_DMA_RD) ?
938: YES : NO;
939: scsiReq.maxTransfer = alignedLength;
940: scsiReq.timeoutLength = srp->sr_ioto;
941: scsiReq.disconnect = srp->sr_discon_disable ? 0 : 1;
942: scsiReq.cmdQueueDisable = srp->sr_cmd_queue_disable;
943: scsiReq.syncDisable = srp->sr_sync_disable;
944: scsiReq.cdbLength = srp->sr_cdb_length;
945:
946: /*
947: * Go for it.
948: */
949: if(srp->sr_dma_dir == SR_DMA_WR) {
950: irtn = [diskObj sdCdbWrite:&scsiReq
951: buffer : alignedPtr
952: client : kernel_map];
953: }
954: else {
955: irtn = [diskObj sdCdbRead:&scsiReq
956: buffer : alignedPtr
957: client : kernel_map];
958: }
959:
960: /*
961: * Copy status back to user.
962: */
963: srp->sr_io_status = scsiReq.driverStatus;
964: if(srp->sr_io_status == SR_IOST_BADST) {
965: /*
966: * dmitch 9 Jun 94: Warning: this code is
967: * bogus, though benign. Lower levels will give us
968: * SR_IOST_CHKSNV or SR_IOST_CHKSV in case of
969: * STAT_CHECK.
970: */
971: if(scsiReq.scsiStatus == STAT_CHECK)
972: srp->sr_io_status = SR_IOST_CHKSNV;
973: }
974: srp->sr_scsi_status = scsiReq.scsiStatus;
975: srp->sr_dma_xfr = scsiReq.bytesTransferred;
976: if(srp->sr_dma_xfr > srp->sr_dma_max) {
977: srp->sr_dma_xfr = srp->sr_dma_max;
978: }
979: srp->sr_exec_time.tv_sec = srp->sr_exec_time.tv_usec = 0;
980:
981: /*
982: * Copy read data back to user if appropriate.
983: */
984: if((srp->sr_dma_dir == SR_DMA_RD) &&
985: (scsiReq.bytesTransferred != 0)) {
986: rtn = copyout(alignedPtr,
987: srp->sr_addr,
988: srp->sr_dma_xfr);
989: }
990: /*
991: * Copy sense data back to user if appropriate.
992: */
993: if(srp->sr_io_status == SR_IOST_CHKSV) {
994: srp->sr_esense = scsiReq.senseData;
995: }
996: err_exit:
997: if (srp->sr_dma_max != 0) {
998: IOFree(freeBuf, freeLength);
999: }
1000: break;
1001:
1002: case SDIOCGETCAP:
1003: {
1004: irtn = [diskObj updatePhysicalParameters];
1005: if(irtn)
1006: break;
1007: scsi_crp_setup((struct capacity_reply *) data,
1008: [diskObj blockSize], [diskObj diskSize] - 1);
1009: }
1010: break;
1011:
1012: default:
1013: xpr_sd("sdioctl: BAD cmd (0x%x)\n", cmd,2,3,4,5);
1014: return(EINVAL);
1015: }
1016:
1017: if(irtn)
1018: rtn = [diskObj errnoFromReturn:irtn];
1019: xpr_sd("%s sdioctl: returning %s (errno %d)\n",
1020: [diskObj name], [diskObj stringFromReturn:irtn],
1021: rtn, 4,5);
1022: return(rtn);
1023:
1024: nodev:
1025: xpr_sd("sdioctl: no such device (dev = 0x%x)\n",
1026: dev, 2,3,4,5);
1027: return(ENXIO);
1028:
1029: } /* sdioctl() */
1030:
1031: /*
1032: * Obtain physical block size.
1033: */
1034: int sdsize(dev_t dev)
1035: {
1036: id diskObj = sd_dev_to_id(dev);
1037:
1038: if(diskObj == nil) {
1039: xpr_sd("sdsize: bad unit\n", 1,2,3,4,5);
1040: return -1;
1041: }
1042: return [diskObj blockSize];
1043:
1044: }
1045:
1046: static unsigned sdminphys(struct buf *bp)
1047: {
1048: SCSIDisk_Data_t *dataBP = (SCSIDisk_Data_t *) bp;
1049:
1050: if (bp->b_bcount > dataBP->maxTransfer)
1051: bp->b_bcount = dataBP->maxTransfer;
1052: return bp->b_bcount;
1053: }
1054:
1055: /*
1056: * Map dev_t to id. A nil return indicates ENXIO.
1057: */
1058:
1059: static id sd_dev_to_id(dev_t dev)
1060: {
1061: id rtn;
1062: int unit = IO_DISK_UNIT(dev);
1063: int part = IO_DISK_PART(dev);
1064: IODevAndIdInfo * idmap;
1065:
1066: #ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
1067:
1068: if ( ! ( unit < NUM_SD_DEV ) ) {
1069: /* Modify the unit # under the assumption that it is an HFS device. */
1070:
1071: unit -= NUM_SD_DEV;
1072:
1073: /* Is it an HFS device? */
1074:
1075: if ( ! ( unit < NUM_SD_DEV ) ) {
1076: rtn = nil;
1077: goto Return;
1078: }
1079:
1080: /* Yes, it is an HFS device. */
1081:
1082: /* But it doesn't have a raw variant. */
1083:
1084: if ( major(dev) == sd_raw_major ) {
1085: rtn = nil;
1086: goto Return;
1087: }
1088:
1089: /* Modify the partition # to indicate an HFS partition and then proceed. */
1090:
1091: part += NUM_SD_PART;
1092:
1093: }
1094:
1095: #else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
1096:
1097: if((unit >= NUM_SD_DEV) || (part >= NUM_SD_PART)) {
1098: return nil;
1099: }
1100:
1101: #endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
1102:
1103: idmap = &SCSIDiskIdMap[unit];
1104:
1105: if(part == SD_LIVE_PART) {
1106: if(major(dev) == sd_block_major) {
1107: /*
1108: * Live partition on the block device not permitted.
1109: */
1110: rtn = nil;
1111: }
1112: else {
1113: rtn = idmap->liveId;
1114: }
1115: }
1116: else {
1117: rtn = idmap->partitionId[part];
1118: }
1119:
1120: Return:
1121:
1122: return rtn;
1123: }
1124:
1125: /*
1126: * Obtain the id of the physical disk assiociated with specified dev.
1127: */
1128:
1129: static id sd_phys_dev_id(dev_t dev)
1130: {
1131: int unit = IO_DISK_UNIT(dev);
1132: #ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
1133: id rtn;
1134:
1135: if ( ! ( unit < NUM_SD_DEV ) ) {
1136: /* Could it be an HFS partition? */
1137:
1138: unit -= NUM_SD_DEV;
1139:
1140: if ( ! (unit < NUM_SD_DEV) ) {
1141: rtn = nil;
1142: goto Return;
1143: }
1144:
1145: /* Yes, it is an HFS partition. Use adjusted <unit>. */
1146:
1147: }
1148:
1149: rtn = SCSIDiskIdMap[unit].liveId;
1150:
1151: Return:
1152:
1153: return rtn;
1154:
1155: #else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
1156: if(unit > NUM_SD_DEV) {
1157: return nil;
1158: }
1159: return SCSIDiskIdMap[unit].liveId;
1160: #endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
1161: }
1162:
1163: void sd_prevent_eject(id physicalDisk, BOOL prevent)
1164: {
1165: //
1166: // Sends a SCSI PREVENT/ALLOW MEDIUM REMOVAL command to the given
1167: // disk (target and lun) in order to prevent or permit the manual
1168: // ejection of removable disk(s) inside the SCSI drive.
1169: //
1170:
1171: IOSCSIRequest scsiReq;
1172:
1173: //
1174: // Set up the SCSI REQUEST structure. Note that cdbLength is an
1175: // optional field and is left as zero.
1176: //
1177:
1178: bzero(&scsiReq, sizeof(scsiReq));
1179:
1180: scsiReq.cdb.cdb_c6.c6_opcode = C60P_PREVENTALLOW;
1181: scsiReq.cdb.cdb_c6.c6_len = (prevent ? 0x01 : 0x00);
1182: scsiReq.target = [physicalDisk target];
1183: scsiReq.lun = [physicalDisk lun];
1184: scsiReq.read = YES;
1185: scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE;
1186:
1187: //
1188: // Execute the request.
1189: //
1190:
1191: [physicalDisk sdCdbRead : &scsiReq
1192: buffer : NULL
1193: client : kernel_map];
1194: }
1195:
1196: /* end of SCSIDiskKern.m */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.