Annotation of Examples/DriverKit/SCSITape/SCSITape_reloc.tproj/SCSITapeKern.m, revision 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.