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