|
|
1.1 ! root 1: /* Copyright (c) 1993 NeXT Computer, Inc. All rights reserved. ! 2: * ! 3: * SCSITapeKern.m -- implementation of scsi tape driver entry point routines ! 4: * ! 5: * HISTORY ! 6: * 31-Mar-93 Phillip Dibner at NeXT ! 7: * Created. Adapted from st.c, created by Doug Mitchell at NeXT. ! 8: * ! 9: */ ! 10: ! 11: /* ! 12: * Four different devices are implemented here: ! 13: * ! 14: * rst - generic SCSI tape, rewind on close ! 15: * nrst - generic SCSI tape, no rewind on close ! 16: * rxt - Exabyte SCSI tape, rewind on close ! 17: * nrxt - Exabyte SCSI tape, no rewind on close ! 18: * ! 19: * All 4 devices have the same major number. Bit 0 of the minor number ! 20: * selects "rewind on close" (0) or "no rewind" (1). Bit 1 of the ! 21: * minor number select generic (0) or Exabyte (1). ! 22: * ! 23: * The Exabyte drive currently requires these actions on open: ! 24: * ! 25: * -- enable Buffered Write mode ! 26: * -- Inhibit Illegal Length errors ! 27: * -- Disable Disconnect During Data Transfer ! 28: */ ! 29: ! 30: #import <sys/errno.h> ! 31: #import <sys/types.h> ! 32: #import <sys/buf.h> ! 33: #import <sys/conf.h> ! 34: #import <sys/uio.h> ! 35: #import <sys/mtio.h> ! 36: #import <bsd/dev/scsireg.h> ! 37: ! 38: #import <driverkit/scsiTypes.h> ! 39: #import <driverkit/align.h> ! 40: #import <driverkit/kernelDriver.h> ! 41: #import <driverkit/scsiTypes.h> ! 42: #import <driverkit/return.h> ! 43: #import <driverkit/devsw.h> ! 44: #import <kernserv/prototypes.h> ! 45: #import "SCSITape.h" ! 46: ! 47: ! 48: #define USE_EBD 1 /* use "even byte diconnect" rather than ! 49: * "no disconnect during data xfer" for exabyte ! 50: */ ! 51: ! 52: /* ! 53: * Unix-style entry points ! 54: */ ! 55: int stopen (dev_t dev); ! 56: int stclose (dev_t dev); ! 57: int stread (dev_t dev, struct uio *uiop); ! 58: int stwrite (dev_t dev, struct uio *uiop); ! 59: int stioctl (dev_t dev, int cmd, caddr_t data, int flag); ! 60: ! 61: /* ! 62: * Subsidiary functions used by the kernel "glue" layer ! 63: */ ! 64: static int st_rw (dev_t dev, struct uio *uiop, int rw_flag); ! 65: static int st_doiocsrq (id scsiTape, scsi_req_t *srp); ! 66: ! 67: /* ! 68: * Functions to take care of byte-ordering issues ! 69: */ ! 70: extern void assign_cdb_c6s_len(); ! 71: extern void assign_msbd_numblocks(); ! 72: extern void assign_msbd_blocklength(); ! 73: unsigned int read_er_info_low_24(); ! 74: ! 75: extern id stIdMap[]; ! 76: ! 77: ! 78: /* ! 79: * Add ourself to cdevsw. Called from SCSIGeneric layer at probe time. ! 80: */ ! 81: extern int nulldev(); ! 82: extern int nodev(); ! 83: ! 84: static int stMajor = -1; ! 85: ! 86: int ! 87: st_devsw_init() ! 88: { ! 89: int rtn; ! 90: ! 91: /* ! 92: * We get called once for each IOSCSIController in the system; we ! 93: * only have to call IOAddToCdevsw() once. ! 94: */ ! 95: if(stMajor >= 0) { ! 96: return stMajor; ! 97: } ! 98: rtn = IOAddToCdevsw ((IOSwitchFunc) stopen, ! 99: (IOSwitchFunc) stclose, ! 100: (IOSwitchFunc) stread, ! 101: (IOSwitchFunc) stwrite, ! 102: (IOSwitchFunc) stioctl, ! 103: (IOSwitchFunc) nodev, ! 104: (IOSwitchFunc) nulldev, // reset ! 105: (IOSwitchFunc) nulldev, ! 106: (IOSwitchFunc) nodev, // mmap ! 107: (IOSwitchFunc) nodev, // getc ! 108: (IOSwitchFunc) nodev); // putc ! 109: if(rtn < 0) { ! 110: IOLog("st: Can't find space in devsw\n"); ! 111: } ! 112: else { ! 113: IOLog("st: major number %d\n", rtn); ! 114: stMajor = rtn; ! 115: } ! 116: return rtn; ! 117: } ! 118: ! 119: ! 120: int ! 121: stopen(dev_t dev) ! 122: { ! 123: int unit = ST_UNIT(dev); ! 124: id scsiTape = stIdMap[unit]; ! 125: ! 126: if([scsiTape acquireDevice] == IO_R_BUSY) ! 127: return(EBUSY); /* already open */ ! 128: if ((unit >= NST) || /* illegal device */ ! 129: ([scsiTape isInitialized] == NO)) { /* hasn't been init'd */ ! 130: [scsiTape releaseDevice]; ! 131: return(ENXIO); /* FIXME - try to init here */ ! 132: } ! 133: ! 134: /* ! 135: * We send this once, and ignore result, to clear check condition ! 136: * due to media change, etc. ! 137: */ ! 138: [scsiTape setIgnoreCheckCondition: YES]; ! 139: [scsiTape stTestReady]; ! 140: [scsiTape setIgnoreCheckCondition: NO]; ! 141: ! 142: if(ST_EXABYTE(dev)) { ! 143: struct modesel_parms *mspp; ! 144: struct exabyte_vudata *evudp; ! 145: struct mode_sel_hdr *mshp; ! 146: ! 147: mspp = IOMalloc (sizeof (struct modesel_parms)); ! 148: evudp = (struct exabyte_vudata *) &mspp->msp_data.msd_vudata; ! 149: ! 150: /* ! 151: * Exabyte "custom" setup ! 152: */ ! 153: ! 154: /* Set variable block size */ ! 155: if([scsiTape setBlockSize: 0] != IO_R_SUCCESS) { ! 156: IOFree (mspp, sizeof (struct modesel_parms)); ! 157: [scsiTape releaseDevice]; ! 158: ! 159: #ifdef DEBUG ! 160: IOLog ("stopen: cannot set block size variable\n"); ! 161: #endif DEBUG ! 162: ! 163: return(EIO); ! 164: } ! 165: ! 166: /* Suppress illegal length errors */ ! 167: [scsiTape setSuppressIllegalLength: YES]; ! 168: ! 169: /* Do a mode sense */ ! 170: mspp->msp_bcount = sizeof(struct mode_sel_hdr) + ! 171: sizeof(struct mode_sel_bd) + MSP_VU_EXABYTE; ! 172: ! 173: if([scsiTape stModeSense: mspp] != SR_IOST_GOOD) { ! 174: IOFree (mspp, sizeof (struct modesel_parms)); ! 175: [scsiTape releaseDevice]; ! 176: ! 177: #ifdef DEBUG ! 178: IOLog ("stopen: Mode Sense failed\n"); ! 179: #endif DEBUG ! 180: ! 181: return(EIO); ! 182: } ! 183: ! 184: /* some fields we have to zero as a matter of course */ ! 185: mshp = &mspp->msp_data.msd_header; ! 186: mshp->msh_sd_length_0 = 0; ! 187: mshp->msh_med_type = 0; ! 188: mshp->msh_wp = 0; ! 189: mshp->msh_bd_length = sizeof(struct mode_sel_bd); ! 190: assign_msbd_blocklength (&mspp->msp_data.msd_blockdescript, 0); ! 191: assign_msbd_numblocks (&mspp->msp_data.msd_blockdescript, 0); ! 192: ! 193: /* ! 194: * set up buffered mode, #blocks = 0, even byte disconnect, ! 195: * enable parity; do mode selsect ! 196: */ ! 197: mspp->msp_data.msd_header.msh_bufmode = 1; ! 198: ! 199: #ifdef USE_EBD ! 200: /* clear NDD and set EBD; enable parity */ ! 201: evudp->nd = 0; /* disconnects OK */ ! 202: evudp->ebd = 1; /* but only on word boundaries */ ! 203: evudp->pe = 1; /* parity enabled */ ! 204: evudp->nbe = 1; /* Busy status disabled */ ! 205: #else USE_EBD ! 206: evudp->nd = 1; ! 207: #endif USE_EBD ! 208: if([scsiTape stModeSelect: mspp] != SR_IOST_GOOD) { ! 209: IOFree (mspp, sizeof (struct modesel_parms)); ! 210: [scsiTape releaseDevice]; ! 211: ! 212: #ifdef DEBUG ! 213: IOLog ("stopen: Mode Select failed\n"); ! 214: #endif DEBUG ! 215: ! 216: return(EIO); ! 217: } ! 218: IOFree (mspp, sizeof (struct modesel_parms)); ! 219: } ! 220: return(0); ! 221: } ! 222: ! 223: ! 224: ! 225: ! 226: int ! 227: stclose(dev_t dev) ! 228: { ! 229: int unit = ST_UNIT(dev); ! 230: id scsiTape = stIdMap[unit]; ! 231: int rtn = 0; ! 232: ! 233: if ([scsiTape didWrite] == YES) { ! 234: /* we must write a file mark to close the file */ ! 235: if ([scsiTape stCloseFile] != SR_IOST_GOOD) { ! 236: rtn = EIO; ! 237: } ! 238: } ! 239: ! 240: if(ST_RETURN(dev) == 0) { /* returning device? */ ! 241: if ([scsiTape stRewind] != SR_IOST_GOOD) { ! 242: rtn = EIO; ! 243: } ! 244: } ! 245: ! 246: [scsiTape releaseDevice]; ! 247: return(rtn); ! 248: } ! 249: ! 250: ! 251: int ! 252: stread(dev_t dev, struct uio *uiop) ! 253: { ! 254: return(st_rw(dev,uiop,SR_DMA_RD)); ! 255: } ! 256: ! 257: int ! 258: stwrite(dev_t dev, struct uio *uiop) ! 259: { ! 260: return(st_rw(dev,uiop,SR_DMA_WR)); ! 261: } ! 262: ! 263: ! 264: static int ! 265: st_rw(dev_t dev, struct uio *uiop, int rw_flag) { ! 266: ! 267: int unit = ST_UNIT(dev); ! 268: id scsiTape = stIdMap[unit]; ! 269: IOSCSIRequest scsiReq; ! 270: struct cdb_6s *cdbp = &scsiReq.cdb.cdb_c6s; ! 271: void *freePtr; ! 272: int freeCnt; ! 273: unsigned char *alignedBuf; ! 274: IODMAAlignment dmaAlign; ! 275: int length; ! 276: int rtn = 0; ! 277: ! 278: sc_status_t scRet = -1; ! 279: ! 280: if (unit >= NST) ! 281: return(ENXIO); ! 282: if(uiop->uio_iovcnt != 1) /* single requests only */ ! 283: return(EINVAL); ! 284: if(uiop->uio_iov->iov_len == 0) ! 285: return(0); /* nothing to do */ ! 286: ! 287: #ifdef DEBUG ! 288: // if(rw_flag == SR_DMA_RD) { ! 289: // XCDBG(("st: READ; count = %xH\n", uiop->uio_iov->iov_len)); ! 290: // } ! 291: // else { ! 292: // XCDBG(("st: WRITE; count = %xH\n", uiop->uio_iov->iov_len)); ! 293: // } ! 294: #endif DEBUG ! 295: ! 296: /* ! 297: * FIXME: should wire user's memory and DMA from there, avoiding ! 298: * a copyin() or copyout(). ! 299: */ ! 300: ! 301: alignedBuf = [[scsiTape controller] ! 302: allocateBufferOfLength: uiop->uio_iov->iov_len ! 303: actualStart: &freePtr ! 304: actualLength: &freeCnt]; ! 305: ! 306: ! 307: bzero(&scsiReq, sizeof(IOSCSIRequest)); ! 308: ! 309: scsiReq.target = [scsiTape target]; ! 310: scsiReq.lun = [scsiTape lun]; ! 311: ! 312: [[scsiTape controller] getDMAAlignment:&dmaAlign]; ! 313: if(dmaAlign.readLength > 1) { ! 314: scsiReq.maxTransfer = IOAlign(int, uiop->uio_iov->iov_len, ! 315: dmaAlign.readLength); ! 316: ! 317: } else { ! 318: scsiReq.maxTransfer = uiop->uio_iov->iov_len; ! 319: } ! 320: ! 321: scsiReq.timeoutLength = ST_IOTO_NORM; ! 322: scsiReq.disconnect = 1; ! 323: cdbp->c6s_lun = [scsiTape lun]; ! 324: ! 325: if ([scsiTape isFixedBlock]) { ! 326: /* c6s_len is BLOCK COUNT */ ! 327: length = howmany(uiop->uio_iov->iov_len, [scsiTape blockSize]); ! 328: cdbp->c6s_opt = C6OPT_FIXED; ! 329: ! 330: #ifdef DEBUG ! 331: IOLog ("SCSI Tape read/write: set up for fixed block transfer\n"); ! 332: #endif DEBUG ! 333: ! 334: ! 335: } else { ! 336: length = uiop->uio_iov->iov_len; ! 337: if(rw_flag == SR_DMA_RD) ! 338: if ([scsiTape suppressIllegalLength]) { ! 339: cdbp->c6s_opt |= C6OPT_SIL; ! 340: ! 341: #ifdef DEBUG ! 342: IOLog ("SCSI Tape read: variable block read, suppress illegal len errs\n"); ! 343: #endif DEBUG ! 344: ! 345: } ! 346: else { ! 347: ! 348: #ifdef DEBUG ! 349: IOLog ("SCSI Tape read: variable block read, allow illegal len errs\n"); ! 350: #endif DEBUG ! 351: ! 352: } ! 353: } ! 354: assign_cdb_c6s_len (cdbp, length); ! 355: ! 356: #ifdef DEBUG ! 357: IOLog ("Transfer Length is %d\n", length); ! 358: #endif DEBUG ! 359: ! 360: if(length > C6S_MAXLEN) { ! 361: rtn = EINVAL; ! 362: goto out; ! 363: } ! 364: ! 365: if(rw_flag == SR_DMA_RD) { ! 366: cdbp->c6s_opcode = C6OP_READ; ! 367: scsiReq.read = YES; ! 368: } ! 369: else { ! 370: cdbp->c6s_opcode = C6OP_WRITE; ! 371: scsiReq.read = NO; ! 372: ! 373: } ! 374: ! 375: scsiReq.bytesTransferred = 0; ! 376: ! 377: /* Copy user data to kernel space if write. */ ! 378: if(rw_flag == SR_DMA_WR) ! 379: if((rtn = copyin(uiop->uio_iov->iov_base, alignedBuf, ! 380: uiop->uio_iov->iov_len))) ! 381: goto out; ! 382: ! 383: if ((scRet = [scsiTape executeRequest: &scsiReq ! 384: buffer: alignedBuf ! 385: client: IOVmTaskSelf() ! 386: senseBuf: [scsiTape senseDataPtr]]) != SR_IOST_GOOD) { ! 387: ! 388: rtn = EIO; ! 389: ! 390: #ifdef DEBUG ! 391: IOLog ("st_rw: returned on failure from executeRequest\n"); ! 392: IOLog ("st_rw: ---- returned %d\n", scRet); ! 393: #endif DEBUG ! 394: ! 395: ! 396: goto out; ! 397: } ! 398: ! 399: /* It worked. Copy data to user space if read. */ ! 400: if(scsiReq.bytesTransferred && (rw_flag == SR_DMA_RD)) { ! 401: rtn = copyout(alignedBuf, uiop->uio_iov->iov_base, ! 402: scsiReq.bytesTransferred); ! 403: ! 404: #ifdef DEBUG ! 405: IOLog ("return value from copyout is %d\n", rtn); ! 406: #endif DEBUG ! 407: ! 408: } ! 409: ! 410: if(scsiReq.driverStatus != SR_IOST_GOOD) { // XXX Can this happen? ! 411: rtn = EIO; ! 412: } ! 413: ! 414: out: ! 415: ! 416: #ifdef DEBUG ! 417: IOLog ("SCSI st_rw transferred %d bytes out of %d\n", ! 418: scsiReq.bytesTransferred, uiop->uio_iov->iov_len); ! 419: #endif DEBUG ! 420: ! 421: uiop->uio_resid = uiop->uio_iov->iov_len - scsiReq.bytesTransferred; ! 422: IOFree (freePtr, freeCnt); ! 423: IOSetUNIXError (rtn); ! 424: return rtn; ! 425: ! 426: } /* st_rw() */ ! 427: ! 428: ! 429: /* ! 430: * ioctl for SCSI Tape. ! 431: * XXX sc_return_t to errno conversions could use more review. ! 432: */ ! 433: int ! 434: stioctl(dev_t dev, ! 435: int cmd, /* MTIOCTOP, etc */ ! 436: caddr_t data, /* actually a ptr to mt_op or mtget, if used */ ! 437: int flag) /* for historical reasons. Not used. */ ! 438: { ! 439: int error = 0; ! 440: int unit = ST_UNIT(dev); ! 441: id scsiTape = stIdMap[unit]; ! 442: struct mtget *mgp = (struct mtget *)data; ! 443: struct esense_reply *erp; ! 444: sc_status_t scsi_err; ! 445: ! 446: ! 447: if (unit >= NST) ! 448: return(ENXIO); ! 449: switch (cmd) { ! 450: case MTIOCTOP: /* do tape op */ ! 451: ! 452: if ((scsi_err = ! 453: [scsiTape executeMTOperation: (struct mtop *) data]) != ! 454: SR_IOST_GOOD) { ! 455: ! 456: if (scsi_err == SR_IOST_CMDREJ) { ! 457: error = EINVAL; ! 458: } else { ! 459: error = EIO; ! 460: } ! 461: } ! 462: break; ! 463: ! 464: case MTIOCGET: /* get status */ ! 465: ! 466: erp = [scsiTape senseDataPtr]; ! 467: ! 468: /* ! 469: * If we just did a request sense command as part of ! 470: * error recovery, avoid doing another one and ! 471: * thus blowing away possible volatile status info. ! 472: */ ! 473: if([scsiTape senseDataValid] == NO) { ! 474: if((scsi_err = [scsiTape requestSense: erp]) != SR_IOST_GOOD) { ! 475: error = EIO; ! 476: break; ! 477: } ! 478: } ! 479: ! 480: /* ! 481: * [scsiTape senseDataPtr] now definitely contains valid ! 482: * sense data. ! 483: */ ! 484: if(ST_EXABYTE(dev)) ! 485: mgp->mt_type = MT_ISEXB; ! 486: else ! 487: mgp->mt_type = MT_ISGS; ! 488: mgp->mt_dsreg = ((u_char *)erp)[2]; ! 489: mgp->mt_erreg = erp->er_addsensecode; ! 490: mgp->mt_ext_err0 = (((u_short)erp->er_stat_13) << 8) | ! 491: ((u_short)erp->er_stat_14); ! 492: mgp->mt_ext_err1 = (((u_short)erp->er_stat_15) << 8) | ! 493: ((u_short)erp->er_rsvd_16); ! 494: ! 495: #if __BIG_ENDIAN__ ! 496: mgp->mt_resid = (u_int) erp->er_info; ! 497: #elif __LITTLE_ENDIAN__ ! 498: mgp->mt_resid = read_er_info_low_24(); ! 499: mgp->mt_resid |= (u_int) erp->er_info3; ! 500: #endif ! 501: ! 502: /* force actual request sense next time */ ! 503: [scsiTape forceSenseDataInvalid]; ! 504: break; ! 505: ! 506: case MTIOCFIXBLK: /* set fixed block mode */ ! 507: error = [scsiTape ! 508: errnoFromReturn: [scsiTape setBlockSize: *(int *)data]]; ! 509: break; ! 510: ! 511: case MTIOCVARBLK: /* set variable block mode */ ! 512: error = [scsiTape ! 513: errnoFromReturn: [scsiTape setBlockSize: 0]]; ! 514: break; ! 515: ! 516: case MTIOCINILL: /* inhibit illegal length ! 517: * errors on Read */ ! 518: [scsiTape setSuppressIllegalLength: YES]; ! 519: break; ! 520: ! 521: case MTIOCALILL: /* allow illegal length ! 522: * errors on Read */ ! 523: [scsiTape setSuppressIllegalLength: NO]; ! 524: break; ! 525: ! 526: case MTIOCMODSEL: /* mode select */ ! 527: error = 0; ! 528: if ([scsiTape stModeSelect: (struct modesel_parms *)data] != ! 529: SR_IOST_GOOD) { ! 530: ! 531: error = EIO; ! 532: break; ! 533: } ! 534: ! 535: case MTIOCMODSEN: /* mode sense */ ! 536: error = 0; ! 537: if ([scsiTape stModeSense: (struct modesel_parms *)data] != ! 538: SR_IOST_GOOD) { ! 539: ! 540: error = EIO; ! 541: break; ! 542: } ! 543: ! 544: case MTIOCSRQ: /* I/O via scsi_req */ ! 545: error = st_doiocsrq(scsiTape, (struct scsi_req *) data); ! 546: break; ! 547: ! 548: default: ! 549: error = EINVAL; /* invalid argument */ ! 550: break; ! 551: } ! 552: IOSetUNIXError (error); /* XXX Probably not necessary */ ! 553: return error; ! 554: } /* stioctl() */ ! 555: ! 556: ! 557: ! 558: /* ! 559: * Lifted directly from sg driver. ! 560: * ! 561: * Execute one scsi_req. Called from client's task context. Returns an errno. ! 562: */ ! 563: ! 564: /* ! 565: * FIXME - DMA to non-page-aligned user memory doesn't work. There ! 566: * is data corruption on read operations; the corruption occurs on page ! 567: * boundaries. ! 568: */ ! 569: #define FORCE_PAGE_ALIGN 1 ! 570: #if FORCE_PAGE_ALIGN ! 571: int stForcePageAlign = 1; ! 572: #endif FORCE_PAGE_ALIGN ! 573: ! 574: static int st_doiocsrq(id scsiTape, scsi_req_t *srp) ! 575: { ! 576: void *alignedPtr = NULL; ! 577: unsigned alignedLen = 0; ! 578: void *freePtr; ! 579: unsigned freeLen; ! 580: BOOL didAlign = NO; ! 581: vm_task_t client = NULL; ! 582: int rtn = 0; ! 583: IOSCSIRequest scsiReq; ! 584: sc_status_t srtn; ! 585: ! 586: if(srp->sr_dma_max > [[scsiTape controller] maxTransfer]) { ! 587: return EINVAL; ! 588: } ! 589: ! 590: /* Get some well-aligned memory if necessary. By using ! 591: * allocateBufferOfLength we guarantee that there is enough space ! 592: * in the buffer we pass to the controller to handle ! 593: * end-of-buffer alignment, although we won't copy more ! 594: * than sr_dma_max to or from the caller. ! 595: */ ! 596: if(srp->sr_dma_max != 0) { ! 597: ! 598: IODMAAlignment dmaAlign; ! 599: id controller = [scsiTape controller]; ! 600: unsigned alignLength; ! 601: unsigned alignStart; ! 602: ! 603: /* ! 604: * Get appropriate alignment from controller. ! 605: */ ! 606: [[scsiTape controller] getDMAAlignment:&dmaAlign]; ! 607: if(srp->sr_dma_dir == SR_DMA_WR) { ! 608: alignLength = dmaAlign.writeLength; ! 609: alignStart = dmaAlign.writeStart; ! 610: } ! 611: else { ! 612: alignLength = dmaAlign.readLength; ! 613: alignStart = dmaAlign.readStart; ! 614: } ! 615: #if FORCE_PAGE_ALIGN ! 616: if(stForcePageAlign) { ! 617: alignStart = PAGE_SIZE; ! 618: } ! 619: #endif FORCE_PAGE_ALIGN ! 620: if( ( (alignStart > 1) && ! 621: !IOIsAligned(srp->sr_addr, alignStart) ! 622: ) || ! 623: ( (alignLength > 1) && ! 624: !IOIsAligned(srp->sr_dma_max, alignLength) ! 625: ) || ! 626: /* ! 627: ` * XXX Prevent DMA from user space for now, even if the ! 628: * buffer is well-aligned. We need to wire down the user ! 629: * memory if we are going to DMA from it. ! 630: */ ! 631: YES ! 632: ) { ! 633: ! 634: /* ! 635: * DMA from kernel memory, we allocate and copy. ! 636: */ ! 637: ! 638: didAlign = YES; ! 639: client = IOVmTaskSelf(); ! 640: ! 641: if(alignLength > 1) { ! 642: alignedLen = IOAlign(unsigned, ! 643: srp->sr_dma_max, ! 644: alignLength); ! 645: } ! 646: else { ! 647: alignedLen = srp->sr_dma_max; ! 648: } ! 649: alignedPtr = [controller allocateBufferOfLength: ! 650: srp->sr_dma_max ! 651: actualStart:&freePtr ! 652: actualLength:&freeLen]; ! 653: if(srp->sr_dma_dir == SR_DMA_WR) { ! 654: rtn = copyin(srp->sr_addr, alignedPtr, ! 655: srp->sr_dma_max); ! 656: if(rtn) { ! 657: rtn = EFAULT; ! 658: goto err_exit; ! 659: } ! 660: } ! 661: } ! 662: else { ! 663: /* ! 664: * Well-aligned buffer, DMA directly to/from user ! 665: * space. ! 666: */ ! 667: alignedLen = srp->sr_dma_max; ! 668: alignedPtr = srp->sr_addr; ! 669: client = IOVmTaskCurrent(); ! 670: didAlign = NO; ! 671: } ! 672: } ! 673: ! 674: /* ! 675: * Generate a contemporary version of scsi_req. ! 676: */ ! 677: bzero(&scsiReq, sizeof(scsiReq)); ! 678: scsiReq.target = [scsiTape target]; ! 679: scsiReq.lun = [scsiTape lun]; ! 680: ! 681: /* ! 682: * Careful. this assumes that the old and new cdb structs are ! 683: * equivalent... ! 684: */ ! 685: scsiReq.cdb = srp->sr_cdb; ! 686: scsiReq.read = (srp->sr_dma_dir == SR_DMA_RD) ? YES : NO; ! 687: scsiReq.maxTransfer = alignedLen; ! 688: scsiReq.timeoutLength = srp->sr_ioto; ! 689: scsiReq.disconnect = 1; ! 690: ! 691: /* ! 692: * Go for it. ! 693: * ! 694: * XXX Should use the SCSITape object's sense buffer, because ! 695: * that's where MTIOCGET looks for valid sense data, and then ! 696: * copy back the sense data to the old-style scsi_req's sense ! 697: * buffer. ! 698: */ ! 699: srtn = [scsiTape executeRequest:&scsiReq ! 700: buffer : alignedPtr ! 701: client : client ! 702: senseBuf : &srp->sr_esense]; ! 703: ! 704: /* ! 705: * Copy status back to user. Note that if we got this far, we ! 706: * return good status from the function; errors are in ! 707: * srp->sr_io_status. ! 708: */ ! 709: srp->sr_io_status = srtn; ! 710: srp->sr_scsi_status = scsiReq.scsiStatus; ! 711: srp->sr_dma_xfr = scsiReq.bytesTransferred; ! 712: if(srp->sr_dma_xfr > srp->sr_dma_max) { ! 713: srp->sr_dma_xfr = srp->sr_dma_max; ! 714: } ! 715: ns_time_to_timeval(scsiReq.totalTime, &srp->sr_exec_time); ! 716: ! 717: /* ! 718: * Copy read data back to user if appropriate. ! 719: */ ! 720: if((srp->sr_dma_dir == SR_DMA_RD) && ! 721: (scsiReq.bytesTransferred != 0) && didAlign) { ! 722: ! 723: rtn = copyout(alignedPtr, ! 724: srp->sr_addr, ! 725: srp->sr_dma_xfr); ! 726: } ! 727: err_exit: ! 728: if(didAlign) { ! 729: IOFree(freePtr, freeLen); ! 730: } ! 731: return rtn; ! 732: } ! 733: ! 734: ! 735: /* ! 736: * Supporting function for managing byte-order swapping. ! 737: */ ! 738: unsigned int ! 739: read_er_info_low_24(struct esense_reply *erp) ! 740: { ! 741: #if __BIG_ENDIAN__ ! 742: return ((unsigned int) erp->er_info); ! 743: #elif __LITTLE_ENDIAN__ ! 744: return (unsigned int) ! 745: (erp->er_info2 << 16) + (erp->er_info1 << 8) + erp->er_info0; ! 746: ! 747: #endif ! 748: ! 749: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.