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