Annotation of uae/src/scg-linux-sg/scsi.c, revision 1.1

1.1     ! root        1: /* @(#)scsi-linux-sg.c 1.30 98/11/06 Copyright 1997 J. Schilling */
        !             2: #ifndef lint
        !             3: static char __sccsid[] =
        !             4:        "@(#)scsi-linux-sg.c    1.30 98/11/06 Copyright 1997 J. Schilling";
        !             5: #endif
        !             6: /*
        !             7:  *     Interface for Linux generic SCSI implementation (sg).
        !             8:  *
        !             9:  *     This is the interface for the broken Linux SCSI generic driver.
        !            10:  *     This is a hack, that tries to emulate the functionality
        !            11:  *     of the scg driver.
        !            12:  *
        !            13:  *     Design flaws of the sg driver:
        !            14:  *     -       cannot see if SCSI command could not be send
        !            15:  *     -       cannot get SCSI status byte
        !            16:  *     -       cannot get real dma count of tranfer
        !            17:  *     -       cannot get number of bytes valid in auto sense data
        !            18:  *     -       to few data in auto sense (CCS/SCSI-2/SCSI-3 needs >= 18)
        !            19:  *
        !            20:  *     This code contains support for the sg driver version 2
        !            21:  *
        !            22:  *     Copyright (c) 1997 J. Schilling
        !            23:  */
        !            24: /*
        !            25:  * This program is free software; you can redistribute it and/or modify
        !            26:  * it under the terms of the GNU General Public License as published by
        !            27:  * the Free Software Foundation; either version 2, or (at your option)
        !            28:  * any later version.
        !            29:  *
        !            30:  * This program is distributed in the hope that it will be useful,
        !            31:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            32:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            33:  * GNU General Public License for more details.
        !            34:  *
        !            35:  * You should have received a copy of the GNU General Public License
        !            36:  * along with this program; see the file COPYING.  If not, write to
        !            37:  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
        !            38:  */
        !            39: 
        !            40: #include <linux/version.h>
        !            41: 
        !            42: #define DEBUG
        !            43: 
        !            44: #ifndef LINUX_VERSION_CODE     /* Very old kernel? */
        !            45: #      define LINUX_VERSION_CODE 0
        !            46: #endif
        !            47: 
        !            48: #if LINUX_VERSION_CODE >= 0x01031a /* <linux/scsi.h> introduced in 1.3.26 */
        !            49: #if LINUX_VERSION_CODE >= 0x020000 /* <scsi/scsi.h> introduced somewhere. */
        !            50: /* Need to fine tune the ifdef so we get the transition point right. */
        !            51: #include <scsi/scsi.h>
        !            52: #else
        !            53: #include <linux/scsi.h>
        !            54: #endif
        !            55: #else
        !            56: #define __KERNEL__
        !            57: #include <linux/fs.h>
        !            58: #undef __KERNEL__
        !            59: #include "block/blk.h"
        !            60: #include "scsi/scsi.h"
        !            61: #endif
        !            62: 
        !            63: #include <stdlib.h>
        !            64: #include <stdio.h>
        !            65: #include <errno.h>
        !            66: #include <unistd.h>
        !            67: #include <sys/types.h>
        !            68: #include <sys/stat.h>
        !            69: #include <sys/ioctl.h>
        !            70: #include <sys/time.h>
        !            71: #include <fcntl.h>
        !            72: #include <scsi/sg.h>
        !            73: #include <asm/param.h>
        !            74: 
        !            75: #include "scg/defs.h"
        !            76: #include "scg/scsitransp.h"
        !            77: #include "scg/scgcmd.h"
        !            78: 
        !            79: #ifndef        SCSI_IOCTL_GET_BUS_NUMBER
        !            80: #define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
        !            81: #endif
        !            82: 
        !            83: /*
        !            84:  * XXX There must be a better way than duplicating things from system include
        !            85:  * XXX files. This is stolen from /usr/src/linux/drivers/scsi/scsi.h
        !            86:  */
        !            87: #ifndef        DID_OK
        !            88: #define DID_OK          0x00 /* NO error                                */
        !            89: #define DID_NO_CONNECT  0x01 /* Couldn't connect before timeout period  */
        !            90: #define DID_BUS_BUSY    0x02 /* BUS stayed busy through time out period */
        !            91: #define DID_TIME_OUT    0x03 /* TIMED OUT for other reason              */
        !            92: #define DID_BAD_TARGET  0x04 /* BAD target.                             */
        !            93: #define DID_ABORT       0x05 /* Told to abort for some other reason     */
        !            94: #define DID_PARITY      0x06 /* Parity error                            */
        !            95: #define DID_ERROR       0x07 /* Internal error                          */
        !            96: #define DID_RESET       0x08 /* Reset by somebody.                      */
        !            97: #define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */ 
        !            98: #endif
        !            99: 
        !           100: #define        MAX_SCG         4       /* Max # of SCSI controllers */
        !           101: #define        MAX_TGT        16
        !           102: #define        MAX_LUN         8
        !           103: 
        !           104: typedef struct SCSIPrivate {
        !           105:     int        scgfile;        /* Used for SG_GET_BUFSIZE ioctl()      */
        !           106:     short      scgfiles[MAX_SCG][MAX_TGT][MAX_LUN];
        !           107:     short      buscookies[MAX_SCG];
        !           108:     int        pack_id;                /* Should be a random number    */
        !           109:     char       *SCSIbuf;
        !           110:     long scg_maxdma;
        !           111: } SCSIPrivate;
        !           112: 
        !           113: #ifdef SG_BIG_BUFF
        !           114: #define        MAX_DMA_LINUX   SG_BIG_BUFF     /* Defined in include/scsi/sg.h */
        !           115: #else
        !           116: #define        MAX_DMA_LINUX   (4*1024)        /* Old Linux versions           */
        !           117: #endif
        !           118: 
        !           119: #ifndef        SG_MAX_SENSE
        !           120: #      define  SG_MAX_SENSE    16      /* Too small for CCS / SCSI-2   */
        !           121: #endif                                 /* But cannot be changed        */
        !           122: 
        !           123: 
        !           124: #if    !defined(__i386) && !defined(i386) && !defined(mc68000)
        !           125: #define        MISALIGN
        !           126: #endif
        !           127: /*#define      MISALIGN*/
        !           128: /*#undef       SG_GET_BUFSIZE*/
        !           129: 
        !           130: #if    defined(USE_PG) && !defined(USE_PG_ONLY)
        !           131: #include "scsi-linux-pg.c"
        !           132: #endif
        !           133: 
        !           134: #ifdef MISALIGN
        !           135: LOCAL  int     scsi_getint     __PR((int *ip));
        !           136: #endif
        !           137: LOCAL  int     scsi_send       __PR((SCSI *scgp, int f, struct scg_cmd *sp));
        !           138: LOCAL  BOOL    sg_setup        __PR((SCSI *scgp, int f, int busno, int tgt, int tlun));
        !           139: LOCAL  void    sg_initdev      __PR((SCSI *scgp, int f));
        !           140: LOCAL  int     sg_mapbus       __PR((SCSI *scgp, int ino));
        !           141: LOCAL  BOOL    sg_mapdev       __PR((SCSI *scgp, int f, int *busp, int *tgtp, int *lunp,
        !           142:                                                        int *chanp, int *inop));
        !           143: LOCAL  void    sg_settimeout   __PR((int f, int timeout));
        !           144: LOCAL   long    scsi_maxdma     __PR((SCSI *scgp));
        !           145: LOCAL   void    scsitimes       __PR((SCSI *scgp));
        !           146: 
        !           147: EXPORT
        !           148: int scsi_open(scgp, device, busno, tgt, tlun)
        !           149:        SCSI    *scgp;
        !           150:        char    *device;
        !           151:        int     busno;
        !           152:        int     tgt;
        !           153:        int     tlun;
        !           154: {
        !           155:        register int    f;
        !           156:        register int    i;
        !           157:        register int    b;
        !           158:        register int    t;
        !           159:        register int    l;
        !           160:        register int    nopen = 0;
        !           161:        char            devname[64];
        !           162: 
        !           163:         if (!(scgp->private = calloc(1, sizeof(*scgp->private)))) {
        !           164:             return -1;
        !           165:         }
        !           166:         scgp->private->pack_id = rand(); /* now is a random number */
        !           167:         scgp->private->scgfile = -1;
        !           168:         scgp->private->SCSIbuf = (void *)-1;
        !           169:         
        !           170:        for (b=0; b < MAX_SCG; b++) {
        !           171:                scgp->private->buscookies[b] = (short)-1;
        !           172:                for (t=0; t < MAX_TGT; t++) {
        !           173:                        for (l=0; l < MAX_LUN ; l++)
        !           174:                                scgp->private->scgfiles[b][t][l] = (short)-1;
        !           175:                }
        !           176:        }
        !           177:        if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2))
        !           178:                goto openbydev;
        !           179: 
        !           180:        if (busno >= 0 && tgt >= 0 && tlun >= 0) {
        !           181:                if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN)
        !           182:                        return (-1);
        !           183:        }
        !           184: 
        !           185:        for (i=0; i < 32; i++) {
        !           186:                sprintf(devname, "/dev/sg%d", i);
        !           187:                f = open(devname, 2);
        !           188:                if (f < 0) {
        !           189:                        if (errno != ENOENT && errno != ENXIO && errno != ENODEV)
        !           190:                                fprintf(stderr, "Cannot open '%s'.\n", devname);
        !           191:                } else {
        !           192:                        if (sg_setup(scgp, f, busno, tgt, tlun))
        !           193:                                return (++nopen);
        !           194:                        if (busno < 0 && tgt < 0 && tlun < 0)
        !           195:                                nopen++;
        !           196:                }
        !           197:        }
        !           198:        if (nopen == 0) for (i=0; i <= 25; i++) {
        !           199:                sprintf(devname, "/dev/sg%c", i+'a');
        !           200:                f = open(devname, 2);
        !           201:                if (f < 0) {
        !           202:                        if (errno != ENOENT && errno != ENXIO && errno != ENODEV)
        !           203:                                fprintf(stderr, "Cannot open '%s'.\n", devname);
        !           204:                } else {
        !           205:                        if (sg_setup(scgp, f, busno, tgt, tlun))
        !           206:                                return (++nopen);
        !           207:                        if (busno < 0 && tgt < 0 && tlun < 0)
        !           208:                                nopen++;
        !           209:                }
        !           210:        }
        !           211: openbydev:
        !           212:        if (device != NULL && *device != '\0') {
        !           213:                f = open(device, 2);
        !           214:                if (f < 0 && errno == ENOENT)
        !           215:                        goto openpg;
        !           216: 
        !           217:                if (!sg_mapdev(scgp, f, &busno, &tgt, &tlun, 0, 0)) {
        !           218:                        close(f);
        !           219:                        goto openpg;
        !           220:                }
        !           221: 
        !           222:                if (scgp->scsibus < 0)
        !           223:                        scgp->scsibus = busno;
        !           224:                if (scgp->target < 0)
        !           225:                        scgp->target = tgt;
        !           226:                if (scgp->lun < 0)
        !           227:                        scgp->lun = tlun;
        !           228: 
        !           229:                if (sg_setup(scgp, f, busno, tgt, tlun))
        !           230:                        return (++nopen);
        !           231:        }
        !           232: openpg:
        !           233: #ifdef USE_PG
        !           234:        nopen += pg_open(scgp, device, busno, tgt, tlun);
        !           235: #endif
        !           236:        return (nopen);
        !           237: }
        !           238: 
        !           239: LOCAL BOOL
        !           240: sg_setup(scgp, f, busno, tgt, tlun)
        !           241:        SCSI    *scgp;
        !           242:        int     f;
        !           243:        int     busno;
        !           244:        int     tgt;
        !           245:        int     tlun;
        !           246: {
        !           247:        int     n;
        !           248:        int     Chan;
        !           249:        int     Ino;
        !           250:        int     Bus;
        !           251:        int     Target;
        !           252:        int     Lun;
        !           253:        BOOL    onetarget = FALSE;
        !           254: 
        !           255: 
        !           256:        if (scgp->scsibus >= 0 && scgp->target >= 0 && scgp->lun >= 0)
        !           257:                onetarget = TRUE;
        !           258: 
        !           259:        sg_mapdev(scgp, f, &Bus, &Target, &Lun, &Chan, &Ino);
        !           260: 
        !           261:        /*
        !           262:         * For old kernels try to make the best guess.
        !           263:         */
        !           264:        Ino |= Chan << 8;
        !           265:        n = sg_mapbus(scgp, Ino);
        !           266:        if (Bus == -1) {
        !           267:                Bus = n;
        !           268:                if (scgp->debug)
        !           269:                        printf("SCSI Bus: %d (mapped from %d)\n", Bus, Ino);
        !           270:        }
        !           271: 
        !           272:        /* if (scgp->private->scgfiles[Bus][Target][Lun] == (short)-1) */
        !           273:                scgp->private->scgfiles[Bus][Target][Lun] = (short)f;
        !           274: 
        !           275:        if (onetarget) {
        !           276:                if (Bus == busno && Target == tgt && Lun == tlun) {
        !           277:                        sg_initdev(scgp, f);
        !           278:                        scgp->private->scgfile = f;     /* remember file for ioctl's */
        !           279:                        return (TRUE);
        !           280:                } else {
        !           281:                        scgp->private->scgfiles[Bus][Target][Lun] = (short)-1;
        !           282:                        close(f);
        !           283:                }
        !           284:        } else {
        !           285:                sg_initdev(scgp, f);
        !           286:                if (scgp->private->scgfile < 0)
        !           287:                        scgp->private->scgfile = f;     /* remember file for ioctl's */
        !           288:        }
        !           289:        return (FALSE);
        !           290: }
        !           291: 
        !           292: LOCAL void
        !           293: sg_initdev(scgp, f)
        !           294:        SCSI    *scgp;
        !           295:        int     f;
        !           296: {
        !           297:        struct sg_rep {
        !           298:                struct sg_header        hd;
        !           299:                unsigned char           rbuf[100];
        !           300:        } sg_rep;
        !           301:        int     n;
        !           302: 
        !           303:        /* Eat any unwanted garbage from prior use of this device */
        !           304: 
        !           305:        n = fcntl(f, F_GETFL);  /* Be very proper about this */
        !           306:        fcntl(f, F_SETFL, n|O_NONBLOCK);
        !           307: 
        !           308:        fillbytes((caddr_t)&sg_rep, sizeof(struct sg_header), '\0');
        !           309:        sg_rep.hd.reply_len = sizeof(struct sg_header);
        !           310: 
        !           311:        while (read(f, &sg_rep, sizeof(sg_rep)) >= 0 || errno != EAGAIN)
        !           312:                ;
        !           313: 
        !           314:        fcntl(f, F_SETFL, n);
        !           315: 
        !           316:        sg_settimeout(f, scgp->deftimeout);
        !           317: }
        !           318: 
        !           319: LOCAL int
        !           320: sg_mapbus(scgp, ino)
        !           321:         SCSI *scgp;
        !           322:        int     ino;
        !           323: {
        !           324:        register int    i;
        !           325: 
        !           326:        for (i=0; i < MAX_SCG; i++) {
        !           327:                if (scgp->private->buscookies[i] == (short)-1) {
        !           328:                        scgp->private->buscookies[i] = ino;
        !           329:                        return (i);
        !           330:                }
        !           331: 
        !           332:                if (scgp->private->buscookies[i] == ino)
        !           333:                        return (i);
        !           334:        }
        !           335:        return (0);
        !           336: }
        !           337: 
        !           338: LOCAL BOOL
        !           339: sg_mapdev(scgp, f, busp, tgtp, lunp, chanp, inop)
        !           340:        SCSI    *scgp;
        !           341:        int     f;
        !           342:        int     *busp;
        !           343:        int     *tgtp;
        !           344:        int     *lunp;
        !           345:        int     *chanp;
        !           346:        int     *inop;
        !           347: {
        !           348:        struct  sg_id {
        !           349:                long    l1; /* target | lun << 8 | channel << 16 | low_ino << 24 */
        !           350:                long    l2; /* Unique id */
        !           351:        } sg_id;
        !           352:        int     Chan;
        !           353:        int     Ino;
        !           354:        int     Bus;
        !           355:        int     Target;
        !           356:        int     Lun;
        !           357: 
        !           358:        if (ioctl(f, SCSI_IOCTL_GET_IDLUN, &sg_id))
        !           359:                return (FALSE);
        !           360:        if (scgp->debug)
        !           361:                printf("l1: 0x%lX l2: 0x%lX\n", sg_id.l1, sg_id.l2);
        !           362:        if (ioctl(f, SCSI_IOCTL_GET_BUS_NUMBER, &Bus) < 0) {
        !           363:                Bus = -1;
        !           364:        }
        !           365: 
        !           366:        Target  = sg_id.l1 & 0xFF;
        !           367:        Lun     = (sg_id.l1 >> 8) & 0xFF;
        !           368:        Chan    = (sg_id.l1 >> 16) & 0xFF;
        !           369:        Ino     = (sg_id.l1 >> 24) & 0xFF;
        !           370:        if (scgp->debug) {
        !           371:                printf("Bus: %d Target: %d Lun: %d Chan: %d Ino: %d\n",
        !           372:                                Bus, Target, Lun, Chan, Ino);
        !           373:        }
        !           374:        *busp = Bus;
        !           375:        *tgtp = Target;
        !           376:        *lunp = Lun;
        !           377:        if (chanp)
        !           378:                *chanp = Chan;
        !           379:        if (inop)
        !           380:                *inop = Ino;
        !           381:        return (TRUE);
        !           382: }
        !           383: 
        !           384: LOCAL long
        !           385: scsi_maxdma(scgp)
        !           386:        SCSI    *scgp;
        !           387: {
        !           388:        long maxdma = MAX_DMA_LINUX;
        !           389: 
        !           390: #ifdef SG_GET_BUFSIZE
        !           391:        /*
        !           392:         * We assume that all /dev/sg instances use the same
        !           393:         * maximum buffer size.
        !           394:         */
        !           395:        if ((maxdma = ioctl(scgp->private->scgfile, SG_GET_BUFSIZE, 0)) < 0) {
        !           396:                if (scgp->private->scgfile >= 0) {
        !           397:                        maxdma = MAX_DMA_LINUX;
        !           398:                }
        !           399:        }
        !           400: #endif
        !           401: #ifdef USE_PG
        !           402:        if (scgp->scsibus == pgbus)
        !           403:                return (pg_maxdma(scgp));
        !           404:        if ((scgp->scsibus < 0) && (pg_maxdma(scgp) < maxdma))
        !           405:                return (pg_maxdma(scgp));
        !           406: #endif
        !           407:        return (maxdma);
        !           408: }
        !           409: 
        !           410: EXPORT void *
        !           411: scsi_getbuf(scgp, amt)
        !           412:        SCSI    *scgp;
        !           413:        long    amt;
        !           414: {
        !           415:        char    *ret;
        !           416: 
        !           417:        if (scgp->private->scg_maxdma == 0)
        !           418:                scgp->private->scg_maxdma = scsi_maxdma(scgp);
        !           419: 
        !           420:        if (amt <= 0 || amt > scgp->private->scg_maxdma)
        !           421:                return ((void *)0);
        !           422:        if (scgp->debug)
        !           423:                printf("scsi_getbuf: %ld bytes\n", amt);
        !           424:        /*
        !           425:         * For performance reason, we allocate pagesize()
        !           426:         * bytes before the SCSI buffer to avoid
        !           427:         * copying the whole buffer contents when
        !           428:         * setting up the /dev/sg data structures.
        !           429:         */
        !           430:        ret = valloc((size_t)(amt+getpagesize()));
        !           431:        if (ret == NULL)
        !           432:                return (ret);
        !           433:        ret += getpagesize();
        !           434:        scgp->private->SCSIbuf = ret;
        !           435:        return ((void *)ret);
        !           436: }
        !           437: 
        !           438: EXPORT
        !           439: BOOL scsi_havebus(scgp, busno)
        !           440:        SCSI    *scgp;
        !           441:        int     busno;
        !           442: {
        !           443:        register int    t;
        !           444:        register int    l;
        !           445: 
        !           446:        if (busno < 0 || busno >= MAX_SCG)
        !           447:                return (FALSE);
        !           448: 
        !           449:        for (t=0; t < MAX_TGT; t++) {
        !           450:                for (l=0; l < MAX_LUN ; l++)
        !           451:                        if (scgp->private->scgfiles[busno][t][l] >= 0)
        !           452:                                return (TRUE);
        !           453:        }
        !           454:        return (FALSE);
        !           455: }
        !           456: 
        !           457: EXPORT
        !           458: int scsi_fileno(scgp, busno, tgt, tlun)
        !           459:        SCSI    *scgp;
        !           460:        int     busno;
        !           461:        int     tgt;
        !           462:        int     tlun;
        !           463: {
        !           464:        if (busno < 0 || busno >= MAX_SCG ||
        !           465:            tgt < 0 || tgt >= MAX_TGT ||
        !           466:            tlun < 0 || tlun >= MAX_LUN)
        !           467:                return (-1);
        !           468: 
        !           469:        return ((int)scgp->private->scgfiles[busno][tgt][tlun]);
        !           470: }
        !           471: 
        !           472: EXPORT
        !           473: int scsi_isatapi(scgp)
        !           474:        SCSI    *scgp;
        !           475: {
        !           476: #ifdef USE_PG
        !           477:        if (scgp->scsibus == pgbus)
        !           478:                return (pg_isatapi(scgp));
        !           479: #endif
        !           480: 
        !           481: #ifdef SG_EMULATED_HOST
        !           482:        {
        !           483:        int     emulated = FALSE;
        !           484:        int     f = scsi_fileno(scgp, scgp->scsibus, scgp->target, scgp->lun);
        !           485: 
        !           486:        if (ioctl(f, SG_EMULATED_HOST, &emulated) >= 0)
        !           487:                return (emulated != 0);
        !           488:        }
        !           489: #endif
        !           490:        return (-1);
        !           491: }
        !           492: 
        !           493: EXPORT
        !           494: int scsireset(scgp)
        !           495:        SCSI    *scgp;
        !           496: {
        !           497: #ifdef USE_PG
        !           498:        if (scgp->scsibus == pgbus)
        !           499:                return (pg_reset(scgp));
        !           500: #endif
        !           501:        /*
        !           502:         * Do we have a SCSI reset in the Linux sg driver?
        !           503:         */
        !           504:        return (-1);
        !           505: }
        !           506: 
        !           507: LOCAL void
        !           508: sg_settimeout(f, tmo)
        !           509:        int     f;
        !           510:        int     tmo;
        !           511: {
        !           512:        tmo *= HZ;
        !           513:        if (tmo)
        !           514:                tmo += HZ/2;
        !           515: 
        !           516:        if (ioctl(f, SG_SET_TIMEOUT, &tmo) < 0)
        !           517:                fprintf(stderr, "Cannot set SG_SET_TIMEOUT.\n");
        !           518: }
        !           519: 
        !           520: /*
        !           521:  * Get misaligned int.
        !           522:  * Needed for all recent processors (sparc/ppc/alpha)
        !           523:  * because the /dev/sg design forces us to do misaligned
        !           524:  * reads of integers.
        !           525:  */
        !           526: #ifdef MISALIGN
        !           527: LOCAL int
        !           528: scsi_getint(ip)
        !           529:        int     *ip;
        !           530: {
        !           531:                 int    ret;
        !           532:        register char   *cp = (char *)ip;
        !           533:        register char   *tp = (char *)&ret;
        !           534:        register int    i;
        !           535: 
        !           536:        for (i = sizeof(int); --i >= 0; )
        !           537:                *tp++ = *cp++;
        !           538:        
        !           539:        return (ret);
        !           540: }
        !           541: #define        GETINT(a)       scsi_getint(&(a))
        !           542: #else
        !           543: #define        GETINT(a)       (a)
        !           544: #endif
        !           545: 
        !           546: LOCAL int
        !           547: scsi_send(scgp, f, sp)
        !           548:        SCSI            *scgp;
        !           549:        int             f;
        !           550:        struct scg_cmd  *sp;
        !           551: {
        !           552:        struct sg_rq    *sgp;
        !           553:        struct sg_rq    *sgp2;
        !           554:        int     i;
        !           555:        int     pack_len;
        !           556:        int     reply_len;
        !           557:        int     amt = sp->cdb_len;
        !           558:        struct sg_rq {
        !           559:                struct sg_header        hd;
        !           560:                unsigned char           buf[MAX_DMA_LINUX+SCG_MAX_CMD];
        !           561:        } sg_rq;
        !           562: #ifdef SG_GET_BUFSIZE          /* We may use a 'sg' version 2 driver   */
        !           563:        char    driver_byte;
        !           564:        char    host_byte;
        !           565:        char    msg_byte;
        !           566:        char    status_byte;
        !           567: #endif
        !           568: 
        !           569:        if (f < 0) {
        !           570:                sp->error = SCG_FATAL;
        !           571:                return (0);
        !           572:        }
        !           573: #ifdef USE_PG
        !           574:        if (scgp->scsibus == pgbus)
        !           575:                return (pg_send(scgp, f, sp));
        !           576: #endif
        !           577:        if (sp->timeout != scgp->deftimeout)
        !           578:                sg_settimeout(f, sp->timeout);
        !           579: 
        !           580: 
        !           581:        sgp2 = sgp = &sg_rq;
        !           582:        if (sp->addr == scgp->private->SCSIbuf) {
        !           583:                sgp = (struct sg_rq *)
        !           584:                        (scgp->private->SCSIbuf - (sizeof(struct sg_header) + amt));
        !           585:                sgp2 = (struct sg_rq *)
        !           586:                        (scgp->private->SCSIbuf - (sizeof(struct sg_header)));
        !           587:        } else {
        !           588:                if (scgp->debug) {
        !           589:                        printf("DMA addr: 0x%8.8lX size: %d - using copy buffer\n",
        !           590:                                (long)sp->addr, sp->size);
        !           591:                }
        !           592:                if (sp->size > (int)(sizeof(sg_rq.buf) - SCG_MAX_CMD)) {
        !           593:                        errno = ENOMEM;
        !           594:                        return (-1);
        !           595:                }
        !           596:        }
        !           597: 
        !           598:        /*
        !           599:         * This is done to avoid misaligned access of sgp->some_int
        !           600:         */
        !           601:        pack_len = sizeof(struct sg_header) + amt;
        !           602:        reply_len = sizeof(struct sg_header);
        !           603:        if (sp->flags & SCG_RECV_DATA) {
        !           604:                reply_len += sp->size;
        !           605:        } else {
        !           606:                pack_len += sp->size;
        !           607:        }
        !           608: 
        !           609: #ifdef MISALIGN
        !           610:        /*
        !           611:         * sgp->some_int may be misaligned if (sp->addr == SCSIbuf)
        !           612:         * This is no problem on Intel porocessors, however
        !           613:         * all other processors don't like it.
        !           614:         * sizeof(struct sg_header) + amt is usually not a multiple of
        !           615:         * sizeof(int). For this reason, we fill in the values into sg_rq
        !           616:         * which is always corectly aligned and then copy it to the real
        !           617:         * location if this location differs from sg_rq.
        !           618:         * Never read/write directly to sgp->some_int !!!!!
        !           619:         */
        !           620:        fillbytes((caddr_t)&sg_rq, sizeof(struct sg_header), '\0');
        !           621: 
        !           622:        sg_rq.hd.pack_len = pack_len;
        !           623:        sg_rq.hd.reply_len = reply_len;
        !           624:        sg_rq.hd.pack_id = scgp->private->pack_id++;
        !           625: /*     sg_rq.hd.result = 0;    not needed because of fillbytes() */
        !           626: 
        !           627:        if ((caddr_t)&sg_rq != (caddr_t)sgp)
        !           628:                movebytes((caddr_t)&sg_rq, (caddr_t)sgp, sizeof(struct sg_header));
        !           629: #else
        !           630:        fillbytes((caddr_t)sgp, sizeof(struct sg_header), '\0');
        !           631: 
        !           632:        sgp->hd.pack_len = pack_len;
        !           633:        sgp->hd.reply_len = reply_len;
        !           634:        sgp->hd.pack_id = scgp->private->pack_id++;
        !           635: /*     sgp->hd.result = 0;     not needed because of fillbytes() */
        !           636: #endif
        !           637:        if (amt == 12)
        !           638:                sgp->hd.twelve_byte = 1;
        !           639: 
        !           640: 
        !           641:        for (i = 0; i < amt; i++ ) {
        !           642:                sgp->buf[i] = sp->cdb.cmd_cdb[i];;
        !           643:        }
        !           644:        if (!(sp->flags & SCG_RECV_DATA)) {
        !           645:                if ((void *)sp->addr != (void *)&sgp->buf[amt])
        !           646:                        movebytes(sp->addr, &sgp->buf[amt], sp->size);
        !           647:                amt += sp->size;
        !           648:        }
        !           649: #ifdef SG_GET_BUFSIZE
        !           650:        sgp->hd.want_new  = 1;                  /* Order new behaviour  */
        !           651:        sgp->hd.cdb_len   = sp->cdb_len;        /* Set CDB length       */
        !           652:        if (sp->sense_len > SG_MAX_SENSE)
        !           653:                sgp->hd.sense_len = SG_MAX_SENSE;
        !           654:        else
        !           655:                sgp->hd.sense_len = sp->sense_len;
        !           656: #endif
        !           657:        i = sizeof(struct sg_header) + amt;
        !           658:        if ((amt = write(f, sgp, i)) < 0) {                     /* write */
        !           659:                sg_settimeout(f, scgp->deftimeout);
        !           660:                return (-1);
        !           661:        } else if (amt != i) {
        !           662: /*             errmsg("scsi_send(%s) wrote %d bytes (expected %d).\n",
        !           663:                 scsi_command, amt, i);*/
        !           664:        }
        !           665: 
        !           666:        if (sp->addr == scgp->private->SCSIbuf) {
        !           667:                movebytes(sgp, sgp2, sizeof(struct sg_header));
        !           668:                sgp = sgp2;
        !           669:        }
        !           670:        sgp->hd.sense_buffer[0] = 0;
        !           671:        if ((amt = read(f, sgp, reply_len)) < 0) {              /* read */
        !           672:                sg_settimeout(f, scgp->deftimeout);
        !           673:                return (-1);
        !           674:        }
        !           675: 
        !           676:        if (sp->flags & SCG_RECV_DATA && ((void *)sgp->buf != (void *)sp->addr)) {
        !           677:                movebytes(sgp->buf, sp->addr, sp->size);
        !           678:        }
        !           679:        sp->ux_errno = GETINT(sgp->hd.result);          /* Unaligned read */
        !           680:        sp->error = SCG_NO_ERROR;
        !           681: 
        !           682: #ifdef SG_GET_BUFSIZE
        !           683:        if (sgp->hd.grant_new) {
        !           684:                sp->sense_count = sgp->hd.sense_len;
        !           685:                pack_len    = GETINT(sgp->hd.sg_cmd_status);    /* Unaligned read */
        !           686:                driver_byte = (pack_len  >> 24) & 0xFF;
        !           687:                host_byte   = (pack_len  >> 16) & 0xFF;
        !           688:                msg_byte    = (pack_len  >> 8) & 0xFF;
        !           689:                status_byte =  pack_len  & 0xFF;
        !           690: 
        !           691:                switch (host_byte) {
        !           692: 
        !           693:                case DID_OK:
        !           694:                                if (sgp->hd.sense_buffer[0] != 0) {
        !           695:                                        /*
        !           696:                                         * The Linux SCSI system up to 2.1.xx
        !           697:                                         * trashes the status byte in the
        !           698:                                         * kernel. Until this gets fixed, we
        !           699:                                         * need this hack.
        !           700:                                         */
        !           701:                                        sp->error = SCG_RETRYABLE;
        !           702:                                        status_byte = 2;
        !           703:                                        sgp->hd.sense_len = SG_MAX_SENSE;
        !           704:                                }
        !           705:                                break;
        !           706: 
        !           707:                case DID_NO_CONNECT:    /* Arbitration won, retry NO_CONNECT? */
        !           708:                case DID_BAD_TARGET:
        !           709:                                sp->error = SCG_FATAL;
        !           710:                                break;
        !           711:        
        !           712:                case DID_TIME_OUT:
        !           713:                                sp->error = SCG_TIMEOUT;
        !           714:                                break;
        !           715: 
        !           716:                default:
        !           717:                                sp->error = SCG_RETRYABLE;
        !           718:                                break;
        !           719: 
        !           720:                }
        !           721:                if ((host_byte != DID_OK || status_byte != 0) && sp->ux_errno == 0)
        !           722:                        sp->ux_errno = EIO;
        !           723:                sp->u_scb.cmd_scb[0] = status_byte;
        !           724:                if (status_byte & 2) {
        !           725:                        sp->sense_count = sgp->hd.sense_len;
        !           726:                        movebytes(sgp->hd.sense_buffer, sp->u_sense.cmd_sense, sp->sense_count);
        !           727:                }
        !           728:        } else
        !           729: #endif
        !           730:        {
        !           731:                if (GETINT(sgp->hd.result) == EBUSY) {  /* Unaligned read */
        !           732:                        struct timeval to;
        !           733: 
        !           734:                        to.tv_sec = sp->timeout;
        !           735:                        to.tv_usec = 500000;
        !           736:                        scsitimes(scgp);
        !           737: 
        !           738:                        if (scgp->cmdstop->tv_sec < to.tv_sec ||
        !           739:                            (scgp->cmdstop->tv_sec == to.tv_sec &&
        !           740:                                scgp->cmdstop->tv_usec < to.tv_usec)) {
        !           741: 
        !           742:                                sp->ux_errno = 0;
        !           743:                                sp->error = SCG_TIMEOUT;        /* a timeout */
        !           744:                        } else {
        !           745:                                sp->error = SCG_RETRYABLE;      /* may be BUS_BUSY */
        !           746:                        }
        !           747:                }
        !           748: 
        !           749:                if (sp->flags & SCG_RECV_DATA)
        !           750:                        sp->resid = (sp->size + sizeof(struct sg_header)) - amt;
        !           751:                else
        !           752:                        sp->resid = 0;  /* sg version1 cannot return DMA resid count */
        !           753: 
        !           754:                if (sgp->hd.sense_buffer[0] != 0) {
        !           755:                        sp->error = SCG_RETRYABLE;
        !           756:                        sp->scb.chk = 1;
        !           757:                        sp->sense_count = SG_MAX_SENSE;
        !           758:                        movebytes(sgp->hd.sense_buffer, sp->u_sense.cmd_sense, sp->sense_count);
        !           759:                        if (sp->ux_errno == 0)
        !           760:                                sp->ux_errno = EIO;
        !           761:                }
        !           762:        }
        !           763: 
        !           764:        if (scgp->verbose > 0 && scgp->debug) {
        !           765: #ifdef SG_GET_BUFSIZE
        !           766:                printf("status: %X pack_len: %d, reply_len: %d pack_id: %d result: %d wn: %d gn: %d cdb_len: %d sense_len: %d sense[0]: %02X\n",
        !           767:                                GETINT(sgp->hd.sg_cmd_status),
        !           768:                                GETINT(sgp->hd.pack_len),
        !           769:                                GETINT(sgp->hd.reply_len),
        !           770:                                GETINT(sgp->hd.pack_id),
        !           771:                                GETINT(sgp->hd.result),
        !           772:                                sgp->hd.want_new,
        !           773:                                sgp->hd.grant_new,
        !           774:                                sgp->hd.cdb_len,
        !           775:                                sgp->hd.sense_len,      
        !           776:                                sgp->hd.sense_buffer[0]);
        !           777: #else
        !           778:                printf("pack_len: %d, reply_len: %d pack_id: %d result: %d sense[0]: %02X\n",
        !           779:                                GETINT(sgp->hd.pack_len),
        !           780:                                GETINT(sgp->hd.reply_len),
        !           781:                                GETINT(sgp->hd.pack_id),
        !           782:                                GETINT(sgp->hd.result),
        !           783:                                sgp->hd.sense_buffer[0]);
        !           784: #endif
        !           785: #ifdef DEBUG
        !           786:                printf("sense: ");
        !           787:                for (i=0; i < 16; i++)
        !           788:                        printf("%02X ", sgp->hd.sense_buffer[i]);
        !           789:                printf("\n");
        !           790: #endif
        !           791:        }
        !           792: 
        !           793:        if (sp->timeout != scgp->deftimeout)
        !           794:                sg_settimeout(f, scgp->deftimeout);
        !           795:        return 0;
        !           796: }
        !           797: 
        !           798: LOCAL
        !           799: void scsitimes(scgp)
        !           800:         SCSI    *scgp;
        !           801: {
        !           802:     struct timeval  *stp = scgp->cmdstop;
        !           803: 
        !           804:     gettimeofday(stp, (struct timezone *)0);
        !           805:     stp->tv_sec -= scgp->cmdstart->tv_sec;
        !           806:     stp->tv_usec -= scgp->cmdstart->tv_usec;
        !           807:     while (stp->tv_usec < 0) {
        !           808:         stp->tv_sec -= 1;
        !           809:         stp->tv_usec += 1000000;
        !           810:     }
        !           811: }

unix.superglobalmegacorp.com

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