home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.2 (Developer) / NS_dev_3.2.iso / NextDeveloper / Examples / DriverKit / SCSITape / SCSITape_reloc.tproj / SCSITapeKern.m < prev    next >
Encoding:
Text File  |  1993-08-21  |  16.8 KB  |  722 lines

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