Annotation of qemu/roms/ipxe/src/drivers/block/scsi.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2006 Michael Brown <[email protected]>.
        !             3:  *
        !             4:  * This program is free software; you can redistribute it and/or
        !             5:  * modify it under the terms of the GNU General Public License as
        !             6:  * published by the Free Software Foundation; either version 2 of the
        !             7:  * License, or any later version.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful, but
        !            10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            12:  * General Public License for more details.
        !            13:  *
        !            14:  * You should have received a copy of the GNU General Public License
        !            15:  * along with this program; if not, write to the Free Software
        !            16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            17:  */
        !            18: 
        !            19: FILE_LICENCE ( GPL2_OR_LATER );
        !            20: 
        !            21: #include <stddef.h>
        !            22: #include <stdlib.h>
        !            23: #include <string.h>
        !            24: #include <byteswap.h>
        !            25: #include <errno.h>
        !            26: #include <ipxe/list.h>
        !            27: #include <ipxe/process.h>
        !            28: #include <ipxe/xfer.h>
        !            29: #include <ipxe/blockdev.h>
        !            30: #include <ipxe/scsi.h>
        !            31: 
        !            32: /** @file
        !            33:  *
        !            34:  * SCSI block device
        !            35:  *
        !            36:  */
        !            37: 
        !            38: /** Maximum number of command retries */
        !            39: #define SCSICMD_MAX_RETRIES 10
        !            40: 
        !            41: /* Error numbers generated by SCSI sense data */
        !            42: #define EIO_NO_SENSE __einfo_error ( EINFO_EIO_NO_SENSE )
        !            43: #define EINFO_EIO_NO_SENSE \
        !            44:        __einfo_uniqify ( EINFO_EIO, 0x00, "No sense" )
        !            45: #define EIO_RECOVERED_ERROR __einfo_error ( EINFO_EIO_RECOVERED_ERROR )
        !            46: #define EINFO_EIO_RECOVERED_ERROR \
        !            47:        __einfo_uniqify ( EINFO_EIO, 0x01, "Recovered error" )
        !            48: #define EIO_NOT_READY __einfo_error ( EINFO_EIO_NOT_READY )
        !            49: #define EINFO_EIO_NOT_READY \
        !            50:        __einfo_uniqify ( EINFO_EIO, 0x02, "Not ready" )
        !            51: #define EIO_MEDIUM_ERROR __einfo_error ( EINFO_EIO_MEDIUM_ERROR )
        !            52: #define EINFO_EIO_MEDIUM_ERROR \
        !            53:        __einfo_uniqify ( EINFO_EIO, 0x03, "Medium error" )
        !            54: #define EIO_HARDWARE_ERROR __einfo_error ( EINFO_EIO_HARDWARE_ERROR )
        !            55: #define EINFO_EIO_HARDWARE_ERROR \
        !            56:        __einfo_uniqify ( EINFO_EIO, 0x04, "Hardware error" )
        !            57: #define EIO_ILLEGAL_REQUEST __einfo_error ( EINFO_EIO_ILLEGAL_REQUEST )
        !            58: #define EINFO_EIO_ILLEGAL_REQUEST \
        !            59:        __einfo_uniqify ( EINFO_EIO, 0x05, "Illegal request" )
        !            60: #define EIO_UNIT_ATTENTION __einfo_error ( EINFO_EIO_UNIT_ATTENTION )
        !            61: #define EINFO_EIO_UNIT_ATTENTION \
        !            62:        __einfo_uniqify ( EINFO_EIO, 0x06, "Unit attention" )
        !            63: #define EIO_DATA_PROTECT __einfo_error ( EINFO_EIO_DATA_PROTECT )
        !            64: #define EINFO_EIO_DATA_PROTECT \
        !            65:        __einfo_uniqify ( EINFO_EIO, 0x07, "Data protect" )
        !            66: #define EIO_BLANK_CHECK __einfo_error ( EINFO_EIO_BLANK_CHECK )
        !            67: #define EINFO_EIO_BLANK_CHECK \
        !            68:        __einfo_uniqify ( EINFO_EIO, 0x08, "Blank check" )
        !            69: #define EIO_VENDOR_SPECIFIC __einfo_error ( EINFO_EIO_VENDOR_SPECIFIC )
        !            70: #define EINFO_EIO_VENDOR_SPECIFIC \
        !            71:        __einfo_uniqify ( EINFO_EIO, 0x09, "Vendor specific" )
        !            72: #define EIO_COPY_ABORTED __einfo_error ( EINFO_EIO_COPY_ABORTED )
        !            73: #define EINFO_EIO_COPY_ABORTED \
        !            74:        __einfo_uniqify ( EINFO_EIO, 0x0a, "Copy aborted" )
        !            75: #define EIO_ABORTED_COMMAND __einfo_error ( EINFO_EIO_ABORTED_COMMAND )
        !            76: #define EINFO_EIO_ABORTED_COMMAND \
        !            77:        __einfo_uniqify ( EINFO_EIO, 0x0b, "Aborted command" )
        !            78: #define EIO_RESERVED __einfo_error ( EINFO_EIO_RESERVED )
        !            79: #define EINFO_EIO_RESERVED \
        !            80:        __einfo_uniqify ( EINFO_EIO, 0x0c, "Reserved" )
        !            81: #define EIO_VOLUME_OVERFLOW __einfo_error ( EINFO_EIO_VOLUME_OVERFLOW )
        !            82: #define EINFO_EIO_VOLUME_OVERFLOW \
        !            83:        __einfo_uniqify ( EINFO_EIO, 0x0d, "Volume overflow" )
        !            84: #define EIO_MISCOMPARE __einfo_error ( EINFO_EIO_MISCOMPARE )
        !            85: #define EINFO_EIO_MISCOMPARE \
        !            86:        __einfo_uniqify ( EINFO_EIO, 0x0e, "Miscompare" )
        !            87: #define EIO_COMPLETED __einfo_error ( EINFO_EIO_COMPLETED )
        !            88: #define EINFO_EIO_COMPLETED \
        !            89:        __einfo_uniqify ( EINFO_EIO, 0x0f, "Completed" )
        !            90: #define EIO_SENSE( key )                                               \
        !            91:        EUNIQ ( EIO, (key), EIO_NO_SENSE, EIO_RECOVERED_ERROR,          \
        !            92:                EIO_NOT_READY, EIO_MEDIUM_ERROR, EIO_HARDWARE_ERROR,    \
        !            93:                EIO_ILLEGAL_REQUEST, EIO_UNIT_ATTENTION,                \
        !            94:                EIO_DATA_PROTECT, EIO_BLANK_CHECK, EIO_VENDOR_SPECIFIC, \
        !            95:                EIO_COPY_ABORTED, EIO_ABORTED_COMMAND, EIO_RESERVED,    \
        !            96:                EIO_VOLUME_OVERFLOW, EIO_MISCOMPARE, EIO_COMPLETED )
        !            97: 
        !            98: /******************************************************************************
        !            99:  *
        !           100:  * Utility functions
        !           101:  *
        !           102:  ******************************************************************************
        !           103:  */
        !           104: 
        !           105: /**
        !           106:  * Parse SCSI LUN
        !           107:  *
        !           108:  * @v lun_string       LUN string representation
        !           109:  * @v lun              LUN to fill in
        !           110:  * @ret rc             Return status code
        !           111:  */
        !           112: int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun ) {
        !           113:        char *p;
        !           114:        int i;
        !           115: 
        !           116:        memset ( lun, 0, sizeof ( *lun ) );
        !           117:        if ( lun_string ) {
        !           118:                p = ( char * ) lun_string;
        !           119:                for ( i = 0 ; i < 4 ; i++ ) {
        !           120:                        lun->u16[i] = htons ( strtoul ( p, &p, 16 ) );
        !           121:                        if ( *p == '\0' )
        !           122:                                break;
        !           123:                        if ( *p != '-' )
        !           124:                                return -EINVAL;
        !           125:                        p++;
        !           126:                }
        !           127:                if ( *p )
        !           128:                        return -EINVAL;
        !           129:        }
        !           130: 
        !           131:        return 0;
        !           132: }
        !           133: 
        !           134: /******************************************************************************
        !           135:  *
        !           136:  * Interface methods
        !           137:  *
        !           138:  ******************************************************************************
        !           139:  */
        !           140: 
        !           141: /**
        !           142:  * Issue SCSI command
        !           143:  *
        !           144:  * @v control          SCSI control interface
        !           145:  * @v data             SCSI data interface
        !           146:  * @v command          SCSI command
        !           147:  * @ret tag            Command tag, or negative error
        !           148:  */
        !           149: int scsi_command ( struct interface *control, struct interface *data,
        !           150:                   struct scsi_cmd *command ) {
        !           151:        struct interface *dest;
        !           152:        scsi_command_TYPE ( void * ) *op =
        !           153:                intf_get_dest_op ( control, scsi_command, &dest );
        !           154:        void *object = intf_object ( dest );
        !           155:        int tap;
        !           156: 
        !           157:        if ( op ) {
        !           158:                tap = op ( object, data, command );
        !           159:        } else {
        !           160:                /* Default is to fail to issue the command */
        !           161:                tap = -EOPNOTSUPP;
        !           162:        }
        !           163: 
        !           164:        intf_put ( dest );
        !           165:        return tap;
        !           166: }
        !           167: 
        !           168: /**
        !           169:  * Report SCSI response
        !           170:  *
        !           171:  * @v interface                SCSI command interface
        !           172:  * @v response         SCSI response
        !           173:  */
        !           174: void scsi_response ( struct interface *intf, struct scsi_rsp *response ) {
        !           175:        struct interface *dest;
        !           176:        scsi_response_TYPE ( void * ) *op =
        !           177:                intf_get_dest_op ( intf, scsi_response, &dest );
        !           178:        void *object = intf_object ( dest );
        !           179: 
        !           180:        if ( op ) {
        !           181:                op ( object, response );
        !           182:        } else {
        !           183:                /* Default is to ignore the response */
        !           184:        }
        !           185: 
        !           186:        intf_put ( dest );
        !           187: }
        !           188: 
        !           189: /******************************************************************************
        !           190:  *
        !           191:  * SCSI devices and commands
        !           192:  *
        !           193:  ******************************************************************************
        !           194:  */
        !           195: 
        !           196: /** A SCSI device */
        !           197: struct scsi_device {
        !           198:        /** Reference count */
        !           199:        struct refcnt refcnt;
        !           200:        /** Block control interface */
        !           201:        struct interface block;
        !           202:        /** SCSI control interface */
        !           203:        struct interface scsi;
        !           204: 
        !           205:        /** SCSI LUN */
        !           206:        struct scsi_lun lun;
        !           207:        /** Flags */
        !           208:        unsigned int flags;
        !           209: 
        !           210:        /** TEST UNIT READY interface */
        !           211:        struct interface ready;
        !           212:        /** TEST UNIT READY process */
        !           213:        struct process process;
        !           214: 
        !           215:        /** List of commands */
        !           216:        struct list_head cmds;
        !           217: };
        !           218: 
        !           219: /** SCSI device flags */
        !           220: enum scsi_device_flags {
        !           221:        /** Unit is ready */
        !           222:        SCSIDEV_UNIT_READY = 0x0001,
        !           223: };
        !           224: 
        !           225: /** A SCSI command */
        !           226: struct scsi_command {
        !           227:        /** Reference count */
        !           228:        struct refcnt refcnt;
        !           229:        /** SCSI device */
        !           230:        struct scsi_device *scsidev;
        !           231:        /** List of SCSI commands */
        !           232:        struct list_head list;
        !           233: 
        !           234:        /** Block data interface */
        !           235:        struct interface block;
        !           236:        /** SCSI data interface */
        !           237:        struct interface scsi;
        !           238: 
        !           239:        /** Command type */
        !           240:        struct scsi_command_type *type;
        !           241:        /** Starting logical block address */
        !           242:        uint64_t lba;
        !           243:        /** Number of blocks */
        !           244:        unsigned int count;
        !           245:        /** Data buffer */
        !           246:        userptr_t buffer;
        !           247:        /** Length of data buffer */
        !           248:        size_t len;
        !           249:        /** Command tag */
        !           250:        uint32_t tag;
        !           251: 
        !           252:        /** Retry count */
        !           253:        unsigned int retries;
        !           254: 
        !           255:        /** Private data */
        !           256:        uint8_t priv[0];
        !           257: };
        !           258: 
        !           259: /** A SCSI command type */
        !           260: struct scsi_command_type {
        !           261:        /** Name */
        !           262:        const char *name;
        !           263:        /** Additional working space */
        !           264:        size_t priv_len;
        !           265:        /**
        !           266:         * Construct SCSI command IU
        !           267:         *
        !           268:         * @v scsicmd           SCSI command
        !           269:         * @v command           SCSI command IU
        !           270:         */
        !           271:        void ( * cmd ) ( struct scsi_command *scsicmd,
        !           272:                         struct scsi_cmd *command );
        !           273:        /**
        !           274:         * Handle SCSI command completion
        !           275:         *
        !           276:         * @v scsicmd           SCSI command
        !           277:         * @v rc                Reason for completion
        !           278:         */
        !           279:        void ( * done ) ( struct scsi_command *scsicmd, int rc );
        !           280: };
        !           281: 
        !           282: /**
        !           283:  * Get reference to SCSI device
        !           284:  *
        !           285:  * @v scsidev          SCSI device
        !           286:  * @ret scsidev                SCSI device
        !           287:  */
        !           288: static inline __attribute__ (( always_inline )) struct scsi_device *
        !           289: scsidev_get ( struct scsi_device *scsidev ) {
        !           290:        ref_get ( &scsidev->refcnt );
        !           291:        return scsidev;
        !           292: }
        !           293: 
        !           294: /**
        !           295:  * Drop reference to SCSI device
        !           296:  *
        !           297:  * @v scsidev          SCSI device
        !           298:  */
        !           299: static inline __attribute__ (( always_inline )) void
        !           300: scsidev_put ( struct scsi_device *scsidev ) {
        !           301:        ref_put ( &scsidev->refcnt );
        !           302: }
        !           303: 
        !           304: /**
        !           305:  * Get reference to SCSI command
        !           306:  *
        !           307:  * @v scsicmd          SCSI command
        !           308:  * @ret scsicmd                SCSI command
        !           309:  */
        !           310: static inline __attribute__ (( always_inline )) struct scsi_command *
        !           311: scsicmd_get ( struct scsi_command *scsicmd ) {
        !           312:        ref_get ( &scsicmd->refcnt );
        !           313:        return scsicmd;
        !           314: }
        !           315: 
        !           316: /**
        !           317:  * Drop reference to SCSI command
        !           318:  *
        !           319:  * @v scsicmd          SCSI command
        !           320:  */
        !           321: static inline __attribute__ (( always_inline )) void
        !           322: scsicmd_put ( struct scsi_command *scsicmd ) {
        !           323:        ref_put ( &scsicmd->refcnt );
        !           324: }
        !           325: 
        !           326: /**
        !           327:  * Get SCSI command private data
        !           328:  *
        !           329:  * @v scsicmd          SCSI command
        !           330:  * @ret priv           Private data
        !           331:  */
        !           332: static inline __attribute__ (( always_inline )) void *
        !           333: scsicmd_priv ( struct scsi_command *scsicmd ) {
        !           334:        return scsicmd->priv;
        !           335: }
        !           336: 
        !           337: /**
        !           338:  * Free SCSI command
        !           339:  *
        !           340:  * @v refcnt           Reference count
        !           341:  */
        !           342: static void scsicmd_free ( struct refcnt *refcnt ) {
        !           343:        struct scsi_command *scsicmd =
        !           344:                container_of ( refcnt, struct scsi_command, refcnt );
        !           345: 
        !           346:        /* Remove from list of commands */
        !           347:        list_del ( &scsicmd->list );
        !           348:        scsidev_put ( scsicmd->scsidev );
        !           349: 
        !           350:        /* Free command */
        !           351:        free ( scsicmd );
        !           352: }
        !           353: 
        !           354: /**
        !           355:  * Close SCSI command
        !           356:  *
        !           357:  * @v scsicmd          SCSI command
        !           358:  * @v rc               Reason for close
        !           359:  */
        !           360: static void scsicmd_close ( struct scsi_command *scsicmd, int rc ) {
        !           361:        struct scsi_device *scsidev = scsicmd->scsidev;
        !           362: 
        !           363:        if ( rc != 0 ) {
        !           364:                DBGC ( scsidev, "SCSI %p tag %08x closed: %s\n",
        !           365:                       scsidev, scsicmd->tag, strerror ( rc ) );
        !           366:        }
        !           367: 
        !           368:        /* Shut down interfaces */
        !           369:        intf_shutdown ( &scsicmd->scsi, rc );
        !           370:        intf_shutdown ( &scsicmd->block, rc );
        !           371: }
        !           372: 
        !           373: /**
        !           374:  * Construct and issue SCSI command
        !           375:  *
        !           376:  * @ret rc             Return status code
        !           377:  */
        !           378: static int scsicmd_command ( struct scsi_command *scsicmd ) {
        !           379:        struct scsi_device *scsidev = scsicmd->scsidev;
        !           380:        struct scsi_cmd command;
        !           381:        int tag;
        !           382:        int rc;
        !           383: 
        !           384:        /* Construct command */
        !           385:        memset ( &command, 0, sizeof ( command ) );
        !           386:        memcpy ( &command.lun, &scsidev->lun, sizeof ( command.lun ) );
        !           387:        scsicmd->type->cmd ( scsicmd, &command );
        !           388: 
        !           389:        /* Issue command */
        !           390:        if ( ( tag = scsi_command ( &scsidev->scsi, &scsicmd->scsi,
        !           391:                                    &command ) ) < 0 ) {
        !           392:                rc = tag;
        !           393:                DBGC ( scsidev, "SCSI %p could not issue command: %s\n",
        !           394:                       scsidev, strerror ( rc ) );
        !           395:                return rc;
        !           396:        }
        !           397: 
        !           398:        /* Record tag */
        !           399:        if ( scsicmd->tag ) {
        !           400:                DBGC ( scsidev, "SCSI %p tag %08x is now tag %08x\n",
        !           401:                       scsidev, scsicmd->tag, tag );
        !           402:        }
        !           403:        scsicmd->tag = tag;
        !           404:        DBGC2 ( scsidev, "SCSI %p tag %08x %s " SCSI_CDB_FORMAT "\n",
        !           405:                scsidev, scsicmd->tag, scsicmd->type->name,
        !           406:                SCSI_CDB_DATA ( command.cdb ) );
        !           407: 
        !           408:        return 0;
        !           409: }
        !           410: 
        !           411: /**
        !           412:  * Handle SCSI command completion
        !           413:  *
        !           414:  * @v scsicmd          SCSI command
        !           415:  * @v rc               Reason for close
        !           416:  */
        !           417: static void scsicmd_done ( struct scsi_command *scsicmd, int rc ) {
        !           418:        struct scsi_device *scsidev = scsicmd->scsidev;
        !           419: 
        !           420:        /* Restart SCSI interface */
        !           421:        intf_restart ( &scsicmd->scsi, rc );
        !           422: 
        !           423:        /* SCSI targets have an annoying habit of returning occasional
        !           424:         * pointless "error" messages such as "power-on occurred", so
        !           425:         * we have to be prepared to retry commands.
        !           426:         */
        !           427:        if ( ( rc != 0 ) && ( scsicmd->retries++ < SCSICMD_MAX_RETRIES ) ) {
        !           428:                /* Retry command */
        !           429:                DBGC ( scsidev, "SCSI %p tag %08x failed: %s\n",
        !           430:                       scsidev, scsicmd->tag, strerror ( rc ) );
        !           431:                DBGC ( scsidev, "SCSI %p tag %08x retrying (retry %d)\n",
        !           432:                       scsidev, scsicmd->tag, scsicmd->retries );
        !           433:                if ( ( rc = scsicmd_command ( scsicmd ) ) == 0 )
        !           434:                        return;
        !           435:        }
        !           436: 
        !           437:        /* If we didn't (successfully) reissue the command, hand over
        !           438:         * to the command completion handler.
        !           439:         */
        !           440:        scsicmd->type->done ( scsicmd, rc );
        !           441: }
        !           442: 
        !           443: /**
        !           444:  * Handle SCSI response
        !           445:  *
        !           446:  * @v scsicmd          SCSI command
        !           447:  * @v response         SCSI response
        !           448:  */
        !           449: static void scsicmd_response ( struct scsi_command *scsicmd,
        !           450:                               struct scsi_rsp *response ) {
        !           451:        struct scsi_device *scsidev = scsicmd->scsidev;
        !           452:        size_t overrun;
        !           453:        size_t underrun;
        !           454:        int rc;
        !           455: 
        !           456:        if ( response->status == 0 ) {
        !           457:                scsicmd_done ( scsicmd, 0 );
        !           458:        } else {
        !           459:                DBGC ( scsidev, "SCSI %p tag %08x status %02x",
        !           460:                       scsidev, scsicmd->tag, response->status );
        !           461:                if ( response->overrun > 0 ) {
        !           462:                        overrun = response->overrun;
        !           463:                        DBGC ( scsidev, " overrun +%zd", overrun );
        !           464:                } else if ( response->overrun < 0 ) {
        !           465:                        underrun = -(response->overrun);
        !           466:                        DBGC ( scsidev, " underrun -%zd", underrun );
        !           467:                }
        !           468:                DBGC ( scsidev, " sense %02x:%02x:%08x\n",
        !           469:                       response->sense.code, response->sense.key,
        !           470:                       ntohl ( response->sense.info ) );
        !           471: 
        !           472:                /* Construct error number from sense data */
        !           473:                rc = -EIO_SENSE ( response->sense.key & SCSI_SENSE_KEY_MASK );
        !           474:                scsicmd_done ( scsicmd, rc );
        !           475:        }
        !           476: }
        !           477: 
        !           478: /**
        !           479:  * Construct SCSI READ command
        !           480:  *
        !           481:  * @v scsicmd          SCSI command
        !           482:  * @v command          SCSI command IU
        !           483:  */
        !           484: static void scsicmd_read_cmd ( struct scsi_command *scsicmd,
        !           485:                               struct scsi_cmd *command ) {
        !           486: 
        !           487:        if ( ( scsicmd->lba + scsicmd->count ) > SCSI_MAX_BLOCK_10 ) {
        !           488:                /* Use READ (16) */
        !           489:                command->cdb.read16.opcode = SCSI_OPCODE_READ_16;
        !           490:                command->cdb.read16.lba = cpu_to_be64 ( scsicmd->lba );
        !           491:                command->cdb.read16.len = cpu_to_be32 ( scsicmd->count );
        !           492:        } else {
        !           493:                /* Use READ (10) */
        !           494:                command->cdb.read10.opcode = SCSI_OPCODE_READ_10;
        !           495:                command->cdb.read10.lba = cpu_to_be32 ( scsicmd->lba );
        !           496:                command->cdb.read10.len = cpu_to_be16 ( scsicmd->count );
        !           497:        }
        !           498:        command->data_in = scsicmd->buffer;
        !           499:        command->data_in_len = scsicmd->len;
        !           500: }
        !           501: 
        !           502: /** SCSI READ command type */
        !           503: static struct scsi_command_type scsicmd_read = {
        !           504:        .name = "READ",
        !           505:        .cmd = scsicmd_read_cmd,
        !           506:        .done = scsicmd_close,
        !           507: };
        !           508: 
        !           509: /**
        !           510:  * Construct SCSI WRITE command
        !           511:  *
        !           512:  * @v scsicmd          SCSI command
        !           513:  * @v command          SCSI command IU
        !           514:  */
        !           515: static void scsicmd_write_cmd ( struct scsi_command *scsicmd,
        !           516:                                struct scsi_cmd *command ) {
        !           517: 
        !           518:        if ( ( scsicmd->lba + scsicmd->count ) > SCSI_MAX_BLOCK_10 ) {
        !           519:                /* Use WRITE (16) */
        !           520:                command->cdb.write16.opcode = SCSI_OPCODE_WRITE_16;
        !           521:                command->cdb.write16.lba = cpu_to_be64 ( scsicmd->lba );
        !           522:                command->cdb.write16.len = cpu_to_be32 ( scsicmd->count );
        !           523:        } else {
        !           524:                /* Use WRITE (10) */
        !           525:                command->cdb.write10.opcode = SCSI_OPCODE_WRITE_10;
        !           526:                command->cdb.write10.lba = cpu_to_be32 ( scsicmd->lba );
        !           527:                command->cdb.write10.len = cpu_to_be16 ( scsicmd->count );
        !           528:        }
        !           529:        command->data_out = scsicmd->buffer;
        !           530:        command->data_out_len = scsicmd->len;
        !           531: }
        !           532: 
        !           533: /** SCSI WRITE command type */
        !           534: static struct scsi_command_type scsicmd_write = {
        !           535:        .name = "WRITE",
        !           536:        .cmd = scsicmd_write_cmd,
        !           537:        .done = scsicmd_close,
        !           538: };
        !           539: 
        !           540: /** SCSI READ CAPACITY private data */
        !           541: struct scsi_read_capacity_private {
        !           542:        /** Use READ CAPACITY (16) */
        !           543:        int use16;
        !           544:        /** Data buffer for READ CAPACITY commands */
        !           545:        union {
        !           546:                /** Data buffer for READ CAPACITY (10) */
        !           547:                struct scsi_capacity_10 capacity10;
        !           548:                /** Data buffer for READ CAPACITY (16) */
        !           549:                struct scsi_capacity_16 capacity16;
        !           550:        } capacity;
        !           551: };
        !           552: 
        !           553: /**
        !           554:  * Construct SCSI READ CAPACITY command
        !           555:  *
        !           556:  * @v scsicmd          SCSI command
        !           557:  * @v command          SCSI command IU
        !           558:  */
        !           559: static void scsicmd_read_capacity_cmd ( struct scsi_command *scsicmd,
        !           560:                                        struct scsi_cmd *command ) {
        !           561:        struct scsi_read_capacity_private *priv = scsicmd_priv ( scsicmd );
        !           562:        struct scsi_cdb_read_capacity_16 *readcap16 = &command->cdb.readcap16;
        !           563:        struct scsi_cdb_read_capacity_10 *readcap10 = &command->cdb.readcap10;
        !           564:        struct scsi_capacity_16 *capacity16 = &priv->capacity.capacity16;
        !           565:        struct scsi_capacity_10 *capacity10 = &priv->capacity.capacity10;
        !           566: 
        !           567:        if ( priv->use16 ) {
        !           568:                /* Use READ CAPACITY (16) */
        !           569:                readcap16->opcode = SCSI_OPCODE_SERVICE_ACTION_IN;
        !           570:                readcap16->service_action =
        !           571:                        SCSI_SERVICE_ACTION_READ_CAPACITY_16;
        !           572:                readcap16->len = cpu_to_be32 ( sizeof ( *capacity16 ) );
        !           573:                command->data_in = virt_to_user ( capacity16 );
        !           574:                command->data_in_len = sizeof ( *capacity16 );
        !           575:        } else {
        !           576:                /* Use READ CAPACITY (10) */
        !           577:                readcap10->opcode = SCSI_OPCODE_READ_CAPACITY_10;
        !           578:                command->data_in = virt_to_user ( capacity10 );
        !           579:                command->data_in_len = sizeof ( *capacity10 );
        !           580:        }
        !           581: }
        !           582: 
        !           583: /**
        !           584:  * Handle SCSI READ CAPACITY command completion
        !           585:  *
        !           586:  * @v scsicmd          SCSI command
        !           587:  * @v rc               Reason for completion
        !           588:  */
        !           589: static void scsicmd_read_capacity_done ( struct scsi_command *scsicmd,
        !           590:                                         int rc ) {
        !           591:        struct scsi_read_capacity_private *priv = scsicmd_priv ( scsicmd );
        !           592:        struct scsi_capacity_16 *capacity16 = &priv->capacity.capacity16;
        !           593:        struct scsi_capacity_10 *capacity10 = &priv->capacity.capacity10;
        !           594:        struct block_device_capacity capacity;
        !           595: 
        !           596:        /* Close if command failed */
        !           597:        if ( rc != 0 ) {
        !           598:                scsicmd_close ( scsicmd, rc );
        !           599:                return;
        !           600:        }
        !           601: 
        !           602:        /* Extract capacity */
        !           603:        if ( priv->use16 ) {
        !           604:                capacity.blocks = ( be64_to_cpu ( capacity16->lba ) + 1 );
        !           605:                capacity.blksize = be32_to_cpu ( capacity16->blksize );
        !           606:        } else {
        !           607:                capacity.blocks = ( be32_to_cpu ( capacity10->lba ) + 1 );
        !           608:                capacity.blksize = be32_to_cpu ( capacity10->blksize );
        !           609: 
        !           610:                /* If capacity range was exceeded (i.e. capacity.lba
        !           611:                 * was 0xffffffff, meaning that blockdev->blocks is
        !           612:                 * now zero), use READ CAPACITY (16) instead.  READ
        !           613:                 * CAPACITY (16) is not mandatory, so we can't just
        !           614:                 * use it straight off.
        !           615:                 */
        !           616:                if ( capacity.blocks == 0 ) {
        !           617:                        priv->use16 = 1;
        !           618:                        if ( ( rc = scsicmd_command ( scsicmd ) ) != 0 ) {
        !           619:                                scsicmd_close ( scsicmd, rc );
        !           620:                                return;
        !           621:                        }
        !           622:                        return;
        !           623:                }
        !           624:        }
        !           625:        capacity.max_count = -1U;
        !           626: 
        !           627:        /* Return capacity to caller */
        !           628:        block_capacity ( &scsicmd->block, &capacity );
        !           629: 
        !           630:        /* Close command */
        !           631:        scsicmd_close ( scsicmd, 0 );
        !           632: }
        !           633: 
        !           634: /** SCSI READ CAPACITY command type */
        !           635: static struct scsi_command_type scsicmd_read_capacity = {
        !           636:        .name = "READ CAPACITY",
        !           637:        .priv_len = sizeof ( struct scsi_read_capacity_private ),
        !           638:        .cmd = scsicmd_read_capacity_cmd,
        !           639:        .done = scsicmd_read_capacity_done,
        !           640: };
        !           641: 
        !           642: /**
        !           643:  * Construct SCSI TEST UNIT READY command
        !           644:  *
        !           645:  * @v scsicmd          SCSI command
        !           646:  * @v command          SCSI command IU
        !           647:  */
        !           648: static void scsicmd_test_unit_ready_cmd ( struct scsi_command *scsicmd __unused,
        !           649:                                          struct scsi_cmd *command ) {
        !           650:        struct scsi_cdb_test_unit_ready *testready = &command->cdb.testready;
        !           651: 
        !           652:        testready->opcode = SCSI_OPCODE_TEST_UNIT_READY;
        !           653: }
        !           654: 
        !           655: /** SCSI TEST UNIT READY command type */
        !           656: static struct scsi_command_type scsicmd_test_unit_ready = {
        !           657:        .name = "TEST UNIT READY",
        !           658:        .cmd = scsicmd_test_unit_ready_cmd,
        !           659:        .done = scsicmd_close,
        !           660: };
        !           661: 
        !           662: /** SCSI command block interface operations */
        !           663: static struct interface_operation scsicmd_block_op[] = {
        !           664:        INTF_OP ( intf_close, struct scsi_command *, scsicmd_close ),
        !           665: };
        !           666: 
        !           667: /** SCSI command block interface descriptor */
        !           668: static struct interface_descriptor scsicmd_block_desc =
        !           669:        INTF_DESC_PASSTHRU ( struct scsi_command, block,
        !           670:                             scsicmd_block_op, scsi );
        !           671: 
        !           672: /** SCSI command SCSI interface operations */
        !           673: static struct interface_operation scsicmd_scsi_op[] = {
        !           674:        INTF_OP ( intf_close, struct scsi_command *, scsicmd_done ),
        !           675:        INTF_OP ( scsi_response, struct scsi_command *, scsicmd_response ),
        !           676: };
        !           677: 
        !           678: /** SCSI command SCSI interface descriptor */
        !           679: static struct interface_descriptor scsicmd_scsi_desc =
        !           680:        INTF_DESC_PASSTHRU ( struct scsi_command, scsi,
        !           681:                             scsicmd_scsi_op, block );
        !           682: 
        !           683: /**
        !           684:  * Create SCSI command
        !           685:  *
        !           686:  * @v scsidev          SCSI device
        !           687:  * @v block            Block data interface
        !           688:  * @v type             SCSI command type
        !           689:  * @v lba              Starting logical block address
        !           690:  * @v count            Number of blocks to transfer
        !           691:  * @v buffer           Data buffer
        !           692:  * @v len              Length of data buffer
        !           693:  * @ret rc             Return status code
        !           694:  */
        !           695: static int scsidev_command ( struct scsi_device *scsidev,
        !           696:                             struct interface *block,
        !           697:                             struct scsi_command_type *type,
        !           698:                             uint64_t lba, unsigned int count,
        !           699:                             userptr_t buffer, size_t len ) {
        !           700:        struct scsi_command *scsicmd;
        !           701:        int rc;
        !           702: 
        !           703:        /* Allocate and initialise structure */
        !           704:        scsicmd = zalloc ( sizeof ( *scsicmd ) + type->priv_len );
        !           705:        if ( ! scsicmd ) {
        !           706:                rc = -ENOMEM;
        !           707:                goto err_zalloc;
        !           708:        }
        !           709:        ref_init ( &scsicmd->refcnt, scsicmd_free );
        !           710:        intf_init ( &scsicmd->block, &scsicmd_block_desc, &scsicmd->refcnt );
        !           711:        intf_init ( &scsicmd->scsi, &scsicmd_scsi_desc,
        !           712:                    &scsicmd->refcnt );
        !           713:        scsicmd->scsidev = scsidev_get ( scsidev );
        !           714:        list_add ( &scsicmd->list, &scsidev->cmds );
        !           715:        scsicmd->type = type;
        !           716:        scsicmd->lba = lba;
        !           717:        scsicmd->count = count;
        !           718:        scsicmd->buffer = buffer;
        !           719:        scsicmd->len = len;
        !           720: 
        !           721:        /* Issue SCSI command */
        !           722:        if ( ( rc = scsicmd_command ( scsicmd ) ) != 0 )
        !           723:                goto err_command;
        !           724: 
        !           725:        /* Attach to parent interface, mortalise self, and return */
        !           726:        intf_plug_plug ( &scsicmd->block, block );
        !           727:        ref_put ( &scsicmd->refcnt );
        !           728:        return 0;
        !           729: 
        !           730:  err_command:
        !           731:        scsicmd_close ( scsicmd, rc );
        !           732:        ref_put ( &scsicmd->refcnt );
        !           733:  err_zalloc:
        !           734:        return rc;
        !           735: }
        !           736: 
        !           737: /**
        !           738:  * Issue SCSI block read
        !           739:  *
        !           740:  * @v scsidev          SCSI device
        !           741:  * @v block            Block data interface
        !           742:  * @v lba              Starting logical block address
        !           743:  * @v count            Number of blocks to transfer
        !           744:  * @v buffer           Data buffer
        !           745:  * @v len              Length of data buffer
        !           746:  * @ret rc             Return status code
        !           747: 
        !           748:  */
        !           749: static int scsidev_read ( struct scsi_device *scsidev,
        !           750:                          struct interface *block,
        !           751:                          uint64_t lba, unsigned int count,
        !           752:                          userptr_t buffer, size_t len ) {
        !           753:        return scsidev_command ( scsidev, block, &scsicmd_read,
        !           754:                                 lba, count, buffer, len );
        !           755: }
        !           756: 
        !           757: /**
        !           758:  * Issue SCSI block write
        !           759:  *
        !           760:  * @v scsidev          SCSI device
        !           761:  * @v block            Block data interface
        !           762:  * @v lba              Starting logical block address
        !           763:  * @v count            Number of blocks to transfer
        !           764:  * @v buffer           Data buffer
        !           765:  * @v len              Length of data buffer
        !           766:  * @ret rc             Return status code
        !           767:  */
        !           768: static int scsidev_write ( struct scsi_device *scsidev,
        !           769:                           struct interface *block,
        !           770:                           uint64_t lba, unsigned int count,
        !           771:                           userptr_t buffer, size_t len ) {
        !           772:        return scsidev_command ( scsidev, block, &scsicmd_write,
        !           773:                                 lba, count, buffer, len );
        !           774: }
        !           775: 
        !           776: /**
        !           777:  * Read SCSI device capacity
        !           778:  *
        !           779:  * @v scsidev          SCSI device
        !           780:  * @v block            Block data interface
        !           781:  * @ret rc             Return status code
        !           782:  */
        !           783: static int scsidev_read_capacity ( struct scsi_device *scsidev,
        !           784:                                   struct interface *block ) {
        !           785:        return scsidev_command ( scsidev, block, &scsicmd_read_capacity,
        !           786:                                 0, 0, UNULL, 0 );
        !           787: }
        !           788: 
        !           789: /**
        !           790:  * Test to see if SCSI device is ready
        !           791:  *
        !           792:  * @v scsidev          SCSI device
        !           793:  * @v block            Block data interface
        !           794:  * @ret rc             Return status code
        !           795:  */
        !           796: static int scsidev_test_unit_ready ( struct scsi_device *scsidev,
        !           797:                                     struct interface *block ) {
        !           798:        return scsidev_command ( scsidev, block, &scsicmd_test_unit_ready,
        !           799:                                 0, 0, UNULL, 0 );
        !           800: }
        !           801: 
        !           802: /**
        !           803:  * Check SCSI device flow-control window
        !           804:  *
        !           805:  * @v scsidev          SCSI device
        !           806:  * @ret len            Length of window
        !           807:  */
        !           808: static size_t scsidev_window ( struct scsi_device *scsidev ) {
        !           809: 
        !           810:        /* Refuse commands until unit is confirmed ready */
        !           811:        if ( ! ( scsidev->flags & SCSIDEV_UNIT_READY ) )
        !           812:                return 0;
        !           813: 
        !           814:        return xfer_window ( &scsidev->scsi );
        !           815: }
        !           816: 
        !           817: /**
        !           818:  * Close SCSI device
        !           819:  *
        !           820:  * @v scsidev          SCSI device
        !           821:  * @v rc               Reason for close
        !           822:  */
        !           823: static void scsidev_close ( struct scsi_device *scsidev, int rc ) {
        !           824:        struct scsi_command *scsicmd;
        !           825:        struct scsi_command *tmp;
        !           826: 
        !           827:        /* Stop process */
        !           828:        process_del ( &scsidev->process );
        !           829: 
        !           830:        /* Shut down interfaces */
        !           831:        intf_shutdown ( &scsidev->block, rc );
        !           832:        intf_shutdown ( &scsidev->scsi, rc );
        !           833:        intf_shutdown ( &scsidev->ready, rc );
        !           834: 
        !           835:        /* Shut down any remaining commands */
        !           836:        list_for_each_entry_safe ( scsicmd, tmp, &scsidev->cmds, list ) {
        !           837:                scsicmd_get ( scsicmd );
        !           838:                scsicmd_close ( scsicmd, rc );
        !           839:                scsicmd_put ( scsicmd );
        !           840:        }
        !           841: }
        !           842: 
        !           843: /** SCSI device block interface operations */
        !           844: static struct interface_operation scsidev_block_op[] = {
        !           845:        INTF_OP ( xfer_window, struct scsi_device *, scsidev_window ),
        !           846:        INTF_OP ( block_read, struct scsi_device *, scsidev_read ),
        !           847:        INTF_OP ( block_write, struct scsi_device *, scsidev_write ),
        !           848:        INTF_OP ( block_read_capacity, struct scsi_device *,
        !           849:                  scsidev_read_capacity ),
        !           850:        INTF_OP ( intf_close, struct scsi_device *, scsidev_close ),
        !           851: };
        !           852: 
        !           853: /** SCSI device block interface descriptor */
        !           854: static struct interface_descriptor scsidev_block_desc =
        !           855:        INTF_DESC_PASSTHRU ( struct scsi_device, block,
        !           856:                             scsidev_block_op, scsi );
        !           857: 
        !           858: /**
        !           859:  * Handle SCSI TEST UNIT READY response
        !           860:  *
        !           861:  * @v scsidev          SCSI device
        !           862:  * @v rc               Reason for close
        !           863:  */
        !           864: static void scsidev_ready ( struct scsi_device *scsidev, int rc ) {
        !           865: 
        !           866:        /* Shut down interface */
        !           867:        intf_shutdown ( &scsidev->ready, rc );
        !           868: 
        !           869:        /* Close device on failure */
        !           870:        if ( rc != 0 ) {
        !           871:                DBGC ( scsidev, "SCSI %p not ready: %s\n",
        !           872:                       scsidev, strerror ( rc ) );
        !           873:                scsidev_close ( scsidev, rc );
        !           874:                return;
        !           875:        }
        !           876: 
        !           877:        /* Mark device as ready */
        !           878:        scsidev->flags |= SCSIDEV_UNIT_READY;
        !           879:        xfer_window_changed ( &scsidev->block );
        !           880:        DBGC ( scsidev, "SCSI %p unit is ready\n", scsidev );
        !           881: }
        !           882: 
        !           883: /** SCSI device TEST UNIT READY interface operations */
        !           884: static struct interface_operation scsidev_ready_op[] = {
        !           885:        INTF_OP ( intf_close, struct scsi_device *, scsidev_ready ),
        !           886: };
        !           887: 
        !           888: /** SCSI device TEST UNIT READY interface descriptor */
        !           889: static struct interface_descriptor scsidev_ready_desc =
        !           890:        INTF_DESC ( struct scsi_device, ready, scsidev_ready_op );
        !           891: 
        !           892: /**
        !           893:  * SCSI TEST UNIT READY process
        !           894:  *
        !           895:  * @v process          Process
        !           896:  */
        !           897: static void scsidev_step ( struct process *process ) {
        !           898:        struct scsi_device *scsidev =
        !           899:                container_of ( process, struct scsi_device, process );
        !           900:        int rc;
        !           901: 
        !           902:        /* Wait until underlying SCSI device is ready */
        !           903:        if ( xfer_window ( &scsidev->scsi ) == 0 )
        !           904:                return;
        !           905: 
        !           906:        /* Stop process */
        !           907:        process_del ( &scsidev->process );
        !           908: 
        !           909:        DBGC ( scsidev, "SCSI %p waiting for unit to become ready\n",
        !           910:               scsidev );
        !           911: 
        !           912:        /* Issue TEST UNIT READY command */
        !           913:        if ( ( rc = scsidev_test_unit_ready ( scsidev, &scsidev->ready )) !=0){
        !           914:                scsidev_close ( scsidev, rc );
        !           915:                return;
        !           916:        }
        !           917: }
        !           918: 
        !           919: /** SCSI device SCSI interface operations */
        !           920: static struct interface_operation scsidev_scsi_op[] = {
        !           921:        INTF_OP ( intf_close, struct scsi_device *, scsidev_close ),
        !           922: };
        !           923: 
        !           924: /** SCSI device SCSI interface descriptor */
        !           925: static struct interface_descriptor scsidev_scsi_desc =
        !           926:        INTF_DESC_PASSTHRU ( struct scsi_device, scsi,
        !           927:                             scsidev_scsi_op, block );
        !           928: 
        !           929: /**
        !           930:  * Open SCSI device
        !           931:  *
        !           932:  * @v block            Block control interface
        !           933:  * @v scsi             SCSI control interface
        !           934:  * @v lun              SCSI LUN
        !           935:  * @ret rc             Return status code
        !           936:  */
        !           937: int scsi_open ( struct interface *block, struct interface *scsi,
        !           938:                struct scsi_lun *lun ) {
        !           939:        struct scsi_device *scsidev;
        !           940: 
        !           941:        /* Allocate and initialise structure */
        !           942:        scsidev = zalloc ( sizeof ( *scsidev ) );
        !           943:        if ( ! scsidev )
        !           944:                return -ENOMEM;
        !           945:        ref_init ( &scsidev->refcnt, NULL );
        !           946:        intf_init ( &scsidev->block, &scsidev_block_desc, &scsidev->refcnt );
        !           947:        intf_init ( &scsidev->scsi, &scsidev_scsi_desc, &scsidev->refcnt );
        !           948:        intf_init ( &scsidev->ready, &scsidev_ready_desc, &scsidev->refcnt );
        !           949:        process_init ( &scsidev->process, scsidev_step, &scsidev->refcnt );
        !           950:        INIT_LIST_HEAD ( &scsidev->cmds );
        !           951:        memcpy ( &scsidev->lun, lun, sizeof ( scsidev->lun ) );
        !           952:        DBGC ( scsidev, "SCSI %p created for LUN " SCSI_LUN_FORMAT "\n",
        !           953:               scsidev, SCSI_LUN_DATA ( scsidev->lun ) );
        !           954: 
        !           955:        /* Attach to SCSI and parent interfaces, mortalise self, and return */
        !           956:        intf_plug_plug ( &scsidev->scsi, scsi );
        !           957:        intf_plug_plug ( &scsidev->block, block );
        !           958:        ref_put ( &scsidev->refcnt );
        !           959:        return 0;
        !           960: }

unix.superglobalmegacorp.com

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