home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer) / NeXT_Developer-3.3.iso / NextDeveloper / Examples / DriverKit / SCSITape / SCSITape_reloc.tproj / SCSITapeKern.m < prev    next >
Encoding:
Text File  |  1994-11-11  |  17.4 KB  |  750 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. 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. }
  750.