Annotation of qemu/roms/seabios/src/blockcmd.c, revision 1.1.1.3

1.1       root        1: // Support for several common scsi like command data block requests
                      2: //
                      3: // Copyright (C) 2010  Kevin O'Connor <[email protected]>
                      4: // Copyright (C) 2002  MandrakeSoft S.A.
                      5: //
                      6: // This file may be distributed under the terms of the GNU LGPLv3 license.
                      7: 
                      8: #include "biosvar.h" // GET_GLOBAL
                      9: #include "util.h" // htonl
                     10: #include "disk.h" // struct disk_op_s
                     11: #include "blockcmd.h" // struct cdb_request_sense
                     12: #include "ata.h" // atapi_cmd_data
1.1.1.2   root       13: #include "ahci.h" // atapi_cmd_data
1.1       root       14: #include "usb-msc.h" // usb_cmd_data
1.1.1.3 ! root       15: #include "virtio-scsi.h" // virtio_scsi_cmd_data
        !            16: #include "boot.h" // boot_add_hd
1.1       root       17: 
                     18: // Route command to low-level handler.
                     19: static int
                     20: cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
                     21: {
                     22:     u8 type = GET_GLOBAL(op->drive_g->type);
                     23:     switch (type) {
                     24:     case DTYPE_ATAPI:
                     25:         return atapi_cmd_data(op, cdbcmd, blocksize);
                     26:     case DTYPE_USB:
                     27:         return usb_cmd_data(op, cdbcmd, blocksize);
1.1.1.2   root       28:     case DTYPE_AHCI:
                     29:         return ahci_cmd_data(op, cdbcmd, blocksize);
1.1.1.3 ! root       30:     case DTYPE_VIRTIO_SCSI:
        !            31:         return virtio_scsi_cmd_data(op, cdbcmd, blocksize);
1.1       root       32:     default:
                     33:         op->count = 0;
                     34:         return DISK_RET_EPARAM;
                     35:     }
                     36: }
                     37: 
1.1.1.3 ! root       38: // Determine if the command is a request to pull data from the device
        !            39: int
        !            40: cdb_is_read(u8 *cdbcmd, u16 blocksize)
        !            41: {
        !            42:     return blocksize && cdbcmd[0] != CDB_CMD_WRITE_10;
        !            43: }
        !            44: 
        !            45: int
        !            46: scsi_is_ready(struct disk_op_s *op)
        !            47: {
        !            48:     dprintf(6, "scsi_is_ready (drive=%p)\n", op->drive_g);
        !            49: 
        !            50:     /* Retry TEST UNIT READY for 5 seconds unless MEDIUM NOT PRESENT is
        !            51:      * reported by the device.  If the device reports "IN PROGRESS",
        !            52:      * 30 seconds is added. */
        !            53:     int in_progress = 0;
        !            54:     u64 end = calc_future_tsc(5000);
        !            55:     for (;;) {
        !            56:         if (check_tsc(end)) {
        !            57:             dprintf(1, "test unit ready failed\n");
        !            58:             return -1;
        !            59:         }
        !            60: 
        !            61:         int ret = cdb_test_unit_ready(op);
        !            62:         if (!ret)
        !            63:             // Success
        !            64:             break;
        !            65: 
        !            66:         struct cdbres_request_sense sense;
        !            67:         ret = cdb_get_sense(op, &sense);
        !            68:         if (ret)
        !            69:             // Error - retry.
        !            70:             continue;
        !            71: 
        !            72:         // Sense succeeded.
        !            73:         if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */
        !            74:             dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
        !            75:             return -1;
        !            76:         }
        !            77: 
        !            78:         if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
        !            79:             /* IN PROGRESS OF BECOMING READY */
        !            80:             printf("Waiting for device to detect medium... ");
        !            81:             /* Allow 30 seconds more */
        !            82:             end = calc_future_tsc(30000);
        !            83:             in_progress = 1;
        !            84:         }
        !            85:     }
        !            86:     return 0;
        !            87: }
        !            88: 
        !            89: // Validate drive, find block size / sector count, and register drive.
        !            90: int
        !            91: scsi_init_drive(struct drive_s *drive, const char *s, int prio)
        !            92: {
        !            93:     if (!CONFIG_USB_MSC && !CONFIG_VIRTIO_SCSI)
        !            94:         return 0;
        !            95: 
        !            96:     struct disk_op_s dop;
        !            97:     memset(&dop, 0, sizeof(dop));
        !            98:     dop.drive_g = drive;
        !            99:     struct cdbres_inquiry data;
        !           100:     int ret = cdb_get_inquiry(&dop, &data);
        !           101:     if (ret)
        !           102:         return ret;
        !           103:     char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1];
        !           104:     char rev[sizeof(data.rev)+1];
        !           105:     strtcpy(vendor, data.vendor, sizeof(vendor));
        !           106:     nullTrailingSpace(vendor);
        !           107:     strtcpy(product, data.product, sizeof(product));
        !           108:     nullTrailingSpace(product);
        !           109:     strtcpy(rev, data.rev, sizeof(rev));
        !           110:     nullTrailingSpace(rev);
        !           111:     int pdt = data.pdt & 0x1f;
        !           112:     int removable = !!(data.removable & 0x80);
        !           113:     dprintf(1, "%s vendor='%s' product='%s' rev='%s' type=%d removable=%d\n"
        !           114:             , s, vendor, product, rev, pdt, removable);
        !           115:     drive->removable = removable;
        !           116: 
        !           117:     if (pdt == SCSI_TYPE_CDROM) {
        !           118:         drive->blksize = CDROM_SECTOR_SIZE;
        !           119:         drive->sectors = (u64)-1;
        !           120: 
        !           121:         char *desc = znprintf(MAXDESCSIZE, "DVD/CD [%s Drive %s %s %s]"
        !           122:                               , s, vendor, product, rev);
        !           123:         boot_add_cd(drive, desc, prio);
        !           124:         return 0;
        !           125:     }
        !           126: 
        !           127:     ret = scsi_is_ready(&dop);
        !           128:     if (ret) {
        !           129:         dprintf(1, "scsi_is_ready returned %d\n", ret);
        !           130:         return ret;
        !           131:     }
        !           132: 
        !           133:     struct cdbres_read_capacity capdata;
        !           134:     ret = cdb_read_capacity(&dop, &capdata);
        !           135:     if (ret)
        !           136:         return ret;
        !           137: 
        !           138:     // READ CAPACITY returns the address of the last block.
        !           139:     // We do not bother with READ CAPACITY(16) because BIOS does not support
        !           140:     // 64-bit LBA anyway.
        !           141:     drive->blksize = ntohl(capdata.blksize);
        !           142:     if (drive->blksize != DISK_SECTOR_SIZE) {
        !           143:         dprintf(1, "%s: unsupported block size %d\n", s, drive->blksize);
        !           144:         return -1;
        !           145:     }
        !           146:     drive->sectors = (u64)ntohl(capdata.sectors) + 1;
        !           147:     dprintf(1, "%s blksize=%d sectors=%d\n"
        !           148:             , s, drive->blksize, (unsigned)drive->sectors);
        !           149: 
        !           150:     // We do not recover from USB stalls, so try to be safe and avoid
        !           151:     // sending the command if the (obsolete, but still provided by QEMU)
        !           152:     // fixed disk geometry page may not be supported.
        !           153:     //
        !           154:     // We could also send the command only to small disks (e.g. <504MiB)
        !           155:     // but some old USB keys only support a very small subset of SCSI which
        !           156:     // does not even include the MODE SENSE command!
        !           157:     //
        !           158:     if (! CONFIG_COREBOOT && memcmp(vendor, "QEMU    ", 8) == 0) {
        !           159:         struct cdbres_mode_sense_geom geomdata;
        !           160:         ret = cdb_mode_sense_geom(&dop, &geomdata);
        !           161:         if (ret == 0) {
        !           162:             u32 cylinders;
        !           163:             cylinders = geomdata.cyl[0] << 16;
        !           164:             cylinders |= geomdata.cyl[1] << 8;
        !           165:             cylinders |= geomdata.cyl[2];
        !           166:             if (cylinders && geomdata.heads &&
        !           167:                 drive->sectors <= 0xFFFFFFFFULL &&
        !           168:                 ((u32)drive->sectors % (geomdata.heads * cylinders) == 0)) {
        !           169:                 drive->pchs.cylinders = cylinders;
        !           170:                 drive->pchs.heads = geomdata.heads;
        !           171:                 drive->pchs.spt = (u32)drive->sectors / (geomdata.heads * cylinders);
        !           172:             }
        !           173:         }
        !           174:     }
        !           175: 
        !           176:     char *desc = znprintf(MAXDESCSIZE, "%s Drive %s %s %s"
        !           177:                           , s, vendor, product, rev);
        !           178:     boot_add_hd(drive, desc, prio);
        !           179:     return 0;
        !           180: }
        !           181: 
1.1       root      182: int
                    183: cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
                    184: {
                    185:     struct cdb_request_sense cmd;
                    186:     memset(&cmd, 0, sizeof(cmd));
                    187:     cmd.command = CDB_CMD_INQUIRY;
                    188:     cmd.length = sizeof(*data);
                    189:     op->count = 1;
                    190:     op->buf_fl = data;
                    191:     return cdb_cmd_data(op, &cmd, sizeof(*data));
                    192: }
                    193: 
                    194: // Request SENSE
                    195: int
                    196: cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data)
                    197: {
                    198:     struct cdb_request_sense cmd;
                    199:     memset(&cmd, 0, sizeof(cmd));
                    200:     cmd.command = CDB_CMD_REQUEST_SENSE;
                    201:     cmd.length = sizeof(*data);
                    202:     op->count = 1;
                    203:     op->buf_fl = data;
                    204:     return cdb_cmd_data(op, &cmd, sizeof(*data));
                    205: }
                    206: 
1.1.1.3 ! root      207: // Test unit ready
        !           208: int
        !           209: cdb_test_unit_ready(struct disk_op_s *op)
        !           210: {
        !           211:     struct cdb_request_sense cmd;
        !           212:     memset(&cmd, 0, sizeof(cmd));
        !           213:     cmd.command = CDB_CMD_TEST_UNIT_READY;
        !           214:     op->count = 0;
        !           215:     op->buf_fl = NULL;
        !           216:     return cdb_cmd_data(op, &cmd, 0);
        !           217: }
        !           218: 
1.1       root      219: // Request capacity
                    220: int
                    221: cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data)
                    222: {
                    223:     struct cdb_read_capacity cmd;
                    224:     memset(&cmd, 0, sizeof(cmd));
                    225:     cmd.command = CDB_CMD_READ_CAPACITY;
                    226:     op->count = 1;
                    227:     op->buf_fl = data;
                    228:     return cdb_cmd_data(op, &cmd, sizeof(*data));
                    229: }
                    230: 
1.1.1.3 ! root      231: // Mode sense, geometry page.
        !           232: int
        !           233: cdb_mode_sense_geom(struct disk_op_s *op, struct cdbres_mode_sense_geom *data)
        !           234: {
        !           235:     struct cdb_mode_sense cmd;
        !           236:     memset(&cmd, 0, sizeof(cmd));
        !           237:     cmd.command = CDB_CMD_MODE_SENSE;
        !           238:     cmd.flags = 8; /* DBD */
        !           239:     cmd.page = MODE_PAGE_HD_GEOMETRY;
        !           240:     cmd.count = htons(sizeof(*data));
        !           241:     op->count = 1;
        !           242:     op->buf_fl = data;
        !           243:     return cdb_cmd_data(op, &cmd, sizeof(*data));
        !           244: }
        !           245: 
1.1       root      246: // Read sectors.
                    247: int
                    248: cdb_read(struct disk_op_s *op)
                    249: {
                    250:     struct cdb_rwdata_10 cmd;
                    251:     memset(&cmd, 0, sizeof(cmd));
                    252:     cmd.command = CDB_CMD_READ_10;
                    253:     cmd.lba = htonl(op->lba);
                    254:     cmd.count = htons(op->count);
                    255:     return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize));
                    256: }
1.1.1.3 ! root      257: 
        !           258: // Write sectors.
        !           259: int
        !           260: cdb_write(struct disk_op_s *op)
        !           261: {
        !           262:     struct cdb_rwdata_10 cmd;
        !           263:     memset(&cmd, 0, sizeof(cmd));
        !           264:     cmd.command = CDB_CMD_WRITE_10;
        !           265:     cmd.lba = htonl(op->lba);
        !           266:     cmd.count = htons(op->count);
        !           267:     return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize));
        !           268: }

unix.superglobalmegacorp.com

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