Annotation of Examples/DriverKit/SCSITape/SCSITape_reloc.tproj/SCSITapeKern.m, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.