|
|
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) 1992 NeXT Computer, Inc. All rights reserved. ! 26: * ! 27: * SCSIGenericKern.m - UNIX front end for SCSIGeneric device. ! 28: * ! 29: * HISTORY ! 30: * 19-Aug-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/param.h> ! 38: #import <sys/proc.h> ! 39: #import <sys/user.h> ! 40: #import <bsd/dev/scsireg.h> ! 41: ! 42: #import <vm/vm_kern.h> ! 43: ! 44: #import <driverkit/SCSIGeneric.h> ! 45: #import <driverkit/SCSIGenericPrivate.h> ! 46: #import <driverkit/scsiTypes.h> ! 47: #import <driverkit/xpr_mi.h> ! 48: #import <driverkit/align.h> ! 49: #import <kernserv/ns_timer.h> ! 50: ! 51: /* ! 52: * Map minor number to an id of a SCSIGeneric instance. ! 53: */ ! 54: id sgIdMap[NUM_SG_DEV]; ! 55: ! 56: /* ! 57: * Index of our entry in cdevsw. ! 58: */ ! 59: static int sg_major; ! 60: ! 61: /* ! 62: * prototypes of static functions. ! 63: */ ! 64: static id sgDevToId(dev_t dev); ! 65: static int sg_doiocreq(id devId, scsi_req_t *srp, scsi3_req_t *s3rp); ! 66: ! 67: /* ! 68: * cdevsw callouts. ! 69: */ ! 70: ! 71: int sgopen(dev_t dev, ! 72: int oflags, ! 73: int devtype, ! 74: struct proc *pp) ! 75: { ! 76: id devId = sgDevToId(dev); ! 77: ! 78: xpr_sdev("sgopen: unit %d\n", minor(dev), 2,3,4,5); ! 79: if(devId == nil) { ! 80: return ENXIO; ! 81: } ! 82: ! 83: /* ! 84: * Note we use devId as "caller" since we're not an object; this ! 85: * works since "caller" isn't used for any authentication. ! 86: */ ! 87: if([devId acquire:devId]) { ! 88: return EBUSY; ! 89: } ! 90: else { ! 91: return 0; ! 92: } ! 93: } ! 94: ! 95: int sgclose(dev_t dev, ! 96: int fflag, ! 97: int devtype, ! 98: struct proc *pp) ! 99: { ! 100: id devId = sgDevToId(dev); ! 101: ! 102: xpr_sdev("sgclose: unit %d\n", minor(dev), 2,3,4,5); ! 103: if(devId == nil) { ! 104: return ENXIO; ! 105: } ! 106: [devId release:devId]; ! 107: } ! 108: ! 109: #define SCSI3_DEBUG 0 ! 110: ! 111: int ! 112: sgioctl(dev_t dev, ! 113: u_long cmd, /* SGIOCREQ, etc */ ! 114: caddr_t data, /* actually a ptr to scsi_req, if used */ ! 115: int flag, /* for historical reasons. Not used. */ ! 116: struct proc *p) ! 117: { ! 118: id devId = sgDevToId(dev); ! 119: ! 120: scsi_req_t *srp = (scsi_req_t *)data; ! 121: scsi_adr_t *sap = (scsi_adr_t *)data; ! 122: scsi3_req_t *s3rp = (scsi3_req_t *)data; ! 123: scsi3_adr_t *s3ap = (scsi3_adr_t *)data; ! 124: int rtn = 0; ! 125: ! 126: xpr_sdev("sgioctl: unit %d\n", minor(dev), 2,3,4,5); ! 127: if(devId == nil) { ! 128: return ENXIO; ! 129: } ! 130: switch (cmd) { ! 131: case SGIOCSTL: /* set target/lun */ ! 132: if([devId setTarget:sap->sa_target ! 133: lun:sap->sa_lun ! 134: isRoot:suser(p->p_ucred, &p->p_acflag) ? 0 : 1]) { ! 135: rtn = EACCES; ! 136: } ! 137: break; ! 138: ! 139: case SGIOCCNTR: ! 140: if([devId setController:*(int *)data]) { ! 141: rtn = ENODEV; ! 142: } ! 143: break; ! 144: ! 145: case SGIOCSTL3: /* set SCSI3 target/lun */ ! 146: #if SCSI3_DEBUG ! 147: IOLog("SGIOCSTL3: s3a_target = 0x%x:%x s3a_lun = 0x%x:%x\n", ! 148: (unsigned)(s3ap->s3a_target >> 32), ! 149: (unsigned)(s3ap->s3a_target), ! 150: (unsigned)(s3ap->s3a_lun >> 32), ! 151: (unsigned)(s3ap->s3a_lun)); ! 152: #endif SCSI3_DEBUG ! 153: if([devId setSCSI3Target:s3ap->s3a_target ! 154: lun:s3ap->s3a_lun ! 155: isRoot:suser(p->p_ucred, &p->p_acflag) ? 0 : 1]) { ! 156: rtn = EACCES; ! 157: } ! 158: break; ! 159: ! 160: case SGIOCGTL3: ! 161: s3ap->s3a_target = [devId SCSI3_target]; ! 162: s3ap->s3a_lun = [devId SCSI3_lun]; ! 163: #if SCSI3_DEBUG ! 164: IOLog("SGIOCGTL3: s3a_target = 0x%x:%x s3a_lun = 0x%x:%x\n", ! 165: (unsigned)(s3ap->s3a_target >> 32), ! 166: (unsigned)(s3ap->s3a_target), ! 167: (unsigned)(s3ap->s3a_lun >> 32), ! 168: (unsigned)(s3ap->s3a_lun)); ! 169: #endif SCSI3_DEBUG ! 170: break; ! 171: ! 172: case SGIOCREQ: ! 173: rtn = sg_doiocreq(devId, srp, NULL); ! 174: break; ! 175: ! 176: case SGIOCREQ3: ! 177: rtn = sg_doiocreq(devId, NULL, s3rp); ! 178: break; ! 179: ! 180: case SGIOCENAS: /* enable auto sense */ ! 181: if([devId enableAutoSense]) { ! 182: rtn = EINVAL; ! 183: } ! 184: break; ! 185: ! 186: case SGIOCDAS: /* disable auto sense */ ! 187: if([devId disableAutoSense]) { ! 188: rtn = EINVAL; ! 189: } ! 190: break; ! 191: ! 192: case SGIOCGAS: ! 193: *(int *)data = ([devId autoSense] ? 1 : 0); ! 194: break; ! 195: ! 196: case SGIOCMAXDMA: ! 197: *(int *)data = [[devId controller] maxTransfer]; ! 198: break; ! 199: ! 200: case SGIOCNUMTARGS: ! 201: *(int *)data = [[devId controller] numberOfTargets]; ! 202: break; ! 203: ! 204: case SGIOCRST: ! 205: #ifndef DEBUG ! 206: if (suser(p->p_ucred, &p->p_acflag)) { ! 207: /* this is too dangerous for ! 208: * the hoi polloi */ ! 209: rtn = EPERM; ! 210: break; ! 211: } ! 212: #endif DEBUG ! 213: if([devId resetSCSIBus]) { /* what could go wrong? */ ! 214: rtn = EIO; ! 215: } ! 216: break; ! 217: ! 218: default: ! 219: rtn = EINVAL; ! 220: } ! 221: xpr_sdev("sgioctl: returning %d\n", rtn, 2,3,4,5); ! 222: return rtn; ! 223: } /* sgioctl() */ ! 224: ! 225: /* ! 226: * Static functions. ! 227: */ ! 228: ! 229: /* ! 230: * Obtain id for SCSIGeneric instance associated with specified dev_t. ! 231: * A return of nil indicates ENXIO. ! 232: */ ! 233: static id sgDevToId(dev_t dev) ! 234: { ! 235: int minor = minor(dev); ! 236: ! 237: if((minor < 0) || (minor >= NUM_SG_DEV)) { ! 238: return nil; ! 239: } ! 240: return sgIdMap[minor]; ! 241: } ! 242: ! 243: /* ! 244: * Execute one scsi_req. Called from client's task context. Returns an errno. ! 245: * Exactly one of srp and s3rp must be non-NULL. ! 246: */ ! 247: ! 248: /* ! 249: * FIXME - DMA to non-page-aligned user memory doesn't work. There ! 250: * is data corruption on read operations;l the corruption occurs on page ! 251: * boundaries. ! 252: */ ! 253: #define FORCE_PAGE_ALIGN 1 ! 254: #if FORCE_PAGE_ALIGN ! 255: int forcePageAlign = 1; ! 256: #endif FORCE_PAGE_ALIGN ! 257: ! 258: static int sg_doiocreq(id devId, scsi_req_t *srp, scsi3_req_t *s3rp) ! 259: { ! 260: void *alignedPtr; ! 261: unsigned alignedLen = 0; ! 262: void *freePtr; ! 263: unsigned freeLen; ! 264: BOOL didAlign = NO; ! 265: vm_task_t client = NULL; ! 266: int rtn = 0; ! 267: sc_status_t srtn; ! 268: int dma_max; ! 269: sc_dma_dir_t dma_dir; ! 270: caddr_t dma_addr; ! 271: unsigned bytesTransferred; ! 272: ! 273: if(srp) { ! 274: dma_max = srp->sr_dma_max; ! 275: dma_dir = srp->sr_dma_dir; ! 276: dma_addr = srp->sr_addr; ! 277: } ! 278: else if(s3rp) { ! 279: dma_max = s3rp->s3r_dma_max; ! 280: dma_dir = s3rp->s3r_dma_dir; ! 281: dma_addr = s3rp->s3r_addr; ! 282: } ! 283: else { ! 284: IOPanic("sg_doiocreq: no scsi_req ptr"); ! 285: } ! 286: if(dma_max > [[devId controller] maxTransfer]) { ! 287: return EINVAL; ! 288: } ! 289: ! 290: /* Get some well-aligned memory if necessary. By using ! 291: * allocateBufferOfLength we guarantee that there is enough space ! 292: * in the buffer we pass to the controller to handle ! 293: * end-of-buffer alignment, although we won't copy more ! 294: * than sr_dma_max to or from the caller. ! 295: */ ! 296: if(dma_max != 0) { ! 297: ! 298: IODMAAlignment dmaAlign; ! 299: id controller = [devId controller]; ! 300: unsigned alignLength; ! 301: unsigned alignStart; ! 302: ! 303: /* ! 304: * Get appropriate alignment from controller. ! 305: */ ! 306: [controller getDMAAlignment:&dmaAlign]; ! 307: if(dma_dir == SR_DMA_WR) { ! 308: alignLength = dmaAlign.writeLength; ! 309: alignStart = dmaAlign.writeStart; ! 310: } ! 311: else { ! 312: alignLength = dmaAlign.readLength; ! 313: alignStart = dmaAlign.readStart; ! 314: } ! 315: #if FORCE_PAGE_ALIGN ! 316: if(forcePageAlign) { ! 317: alignStart = PAGE_SIZE; ! 318: } ! 319: #endif FORCE_PAGE_ALIGN ! 320: if (1) { /* XXX fix the well aligned case for 3.3 */ ! 321: ! 322: /* ! 323: * DMA from kernel memory, we allocate and copy. ! 324: */ ! 325: ! 326: didAlign = YES; ! 327: client = kernel_map; ! 328: ! 329: if(alignLength > 1) { ! 330: alignedLen = IOAlign(unsigned, ! 331: dma_max, ! 332: alignLength); ! 333: } ! 334: else { ! 335: alignedLen = dma_max; ! 336: } ! 337: alignedPtr = [controller allocateBufferOfLength: ! 338: dma_max ! 339: actualStart:&freePtr ! 340: actualLength:&freeLen]; ! 341: if(dma_dir == SR_DMA_WR) { ! 342: rtn = copyin(dma_addr, alignedPtr, dma_max); ! 343: if(rtn) { ! 344: xpr_sd(" ...copyin() returned %d\n", ! 345: rtn, 2,3,4,5); ! 346: rtn = EFAULT; ! 347: goto err_exit; ! 348: } ! 349: } ! 350: } ! 351: else { ! 352: /* ! 353: * Well-aligned buffer, DMA directly to/from user ! 354: * space. ! 355: */ ! 356: alignedLen = dma_max; ! 357: alignedPtr = dma_addr; ! 358: client = current_task()->map; ! 359: didAlign = NO; ! 360: } ! 361: ! 362: } else { ! 363: alignedPtr = dma_addr; ! 364: } ! 365: ! 366: ! 367: /* ! 368: * Generate a contemporary version of scsi_req. ! 369: */ ! 370: if(srp) { ! 371: IOSCSIRequest scsiReq; ! 372: unsigned long long addr; ! 373: ! 374: bzero(&scsiReq, sizeof(scsiReq)); ! 375: addr = [devId SCSI3_target]; ! 376: ! 377: /* ! 378: * Can only deal with SCSI-2 style addressing ! 379: * (32 targets, 8 LUNs). ! 380: */ ! 381: if(addr >= SCSI3_NTARGETS) { ! 382: rtn = EINVAL; ! 383: goto err_exit; ! 384: } ! 385: scsiReq.target = (unsigned char)addr; ! 386: addr = [devId SCSI3_lun]; ! 387: if(addr >= SCSI_NLUNS) { ! 388: rtn = EINVAL; ! 389: goto err_exit; ! 390: } ! 391: scsiReq.lun = (unsigned char)addr; ! 392: ! 393: /* ! 394: * Careful. this assumes that the old and new cdb structs are ! 395: * equivalent... ! 396: */ ! 397: scsiReq.cdb = srp->sr_cdb; ! 398: scsiReq.read = (srp->sr_dma_dir == SR_DMA_RD) ! 399: ? YES : NO; ! 400: scsiReq.maxTransfer = alignedLen; ! 401: scsiReq.timeoutLength = srp->sr_ioto; ! 402: scsiReq.disconnect = srp->sr_discon_disable ? 0 : 1; ! 403: scsiReq.cmdQueueDisable = srp->sr_cmd_queue_disable; ! 404: scsiReq.syncDisable = srp->sr_sync_disable; ! 405: scsiReq.cdbLength = srp->sr_cdb_length; ! 406: ! 407: ! 408: /* ! 409: * Go for it. ! 410: */ ! 411: srtn = [devId executeRequest : &scsiReq ! 412: buffer : alignedPtr ! 413: client : client ! 414: senseBuf : &srp->sr_esense]; ! 415: ! 416: /* ! 417: * Copy status back to user. Note that if we got this far, we ! 418: * return good status from the function; errors are in ! 419: * srp->sr_io_status. ! 420: */ ! 421: srp->sr_io_status = srtn; ! 422: srp->sr_scsi_status = scsiReq.scsiStatus; ! 423: bytesTransferred = srp->sr_dma_xfr = scsiReq.bytesTransferred; ! 424: if(srp->sr_dma_xfr > srp->sr_dma_max) { ! 425: srp->sr_dma_xfr = srp->sr_dma_max; ! 426: } ! 427: ns_time_to_timeval(scsiReq.totalTime, &srp->sr_exec_time); ! 428: } ! 429: else { ! 430: IOSCSI3Request scsi3Req; ! 431: ! 432: bzero(&scsi3Req, sizeof(scsi3Req)); ! 433: scsi3Req.target = [devId SCSI3_target]; ! 434: scsi3Req.lun = [devId SCSI3_lun]; ! 435: ! 436: /* ! 437: * Careful. this assumes that the old and new cdb structs are ! 438: * equivalent... ! 439: */ ! 440: scsi3Req.cdb = s3rp->s3r_cdb; ! 441: scsi3Req.read = (s3rp->s3r_dma_dir == SR_DMA_RD) ! 442: ? YES : NO; ! 443: scsi3Req.maxTransfer = alignedLen; ! 444: scsi3Req.timeoutLength = s3rp->s3r_ioto; ! 445: scsi3Req.disconnect = s3rp->s3r_discon_disable ? 0 : 1; ! 446: scsi3Req.cmdQueueDisable = s3rp->s3r_cmd_queue_disable; ! 447: scsi3Req.syncDisable = s3rp->s3r_sync_disable; ! 448: scsi3Req.cdbLength = s3rp->s3r_cdb_length; ! 449: ! 450: ! 451: /* ! 452: * Go for it. ! 453: */ ! 454: srtn = [devId executeSCSI3Request : &scsi3Req ! 455: buffer : alignedPtr ! 456: client : client ! 457: senseBuf : &srp->sr_esense]; ! 458: ! 459: /* ! 460: * Copy status back to user. Note that if we got this far, we ! 461: * return good status from the function; errors are in ! 462: * s3rp->sr_io_status. ! 463: */ ! 464: s3rp->s3r_io_status = srtn; ! 465: s3rp->s3r_scsi_status = scsi3Req.scsiStatus; ! 466: bytesTransferred = s3rp->s3r_dma_xfr = scsi3Req.bytesTransferred; ! 467: if(s3rp->s3r_dma_xfr > s3rp->s3r_dma_max) { ! 468: s3rp->s3r_dma_xfr = s3rp->s3r_dma_max; ! 469: } ! 470: ns_time_to_timeval(scsi3Req.totalTime, &s3rp->s3r_exec_time); ! 471: } ! 472: ! 473: /* ! 474: * Copy read data back to user if appropriate. ! 475: */ ! 476: if((dma_dir == SR_DMA_RD) && ! 477: (bytesTransferred != 0) && ! 478: didAlign) { ! 479: rtn = copyout(alignedPtr, dma_addr, bytesTransferred); ! 480: } ! 481: err_exit: ! 482: if(didAlign) { ! 483: IOFree(freePtr, freeLen); ! 484: } ! 485: return rtn; ! 486: } ! 487: ! 488: ! 489:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.