Annotation of qemu/roms/seabios/src/virtio-scsi.c, revision 1.1

1.1     ! root        1: // Virtio SCSI boot support.
        !             2: //
        !             3: // Copyright (C) 2012 Red Hat Inc.
        !             4: //
        !             5: // Authors:
        !             6: //  Paolo Bonzini <[email protected]>
        !             7: //
        !             8: // This file may be distributed under the terms of the GNU LGPLv3 license.
        !             9: 
        !            10: #include "util.h" // dprintf
        !            11: #include "pci.h" // foreachpci
        !            12: #include "config.h" // CONFIG_*
        !            13: #include "biosvar.h" // GET_GLOBAL
        !            14: #include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
        !            15: #include "pci_regs.h" // PCI_VENDOR_ID
        !            16: #include "boot.h" // bootprio_find_scsi_device
        !            17: #include "blockcmd.h" // scsi_init_drive
        !            18: #include "virtio-pci.h"
        !            19: #include "virtio-ring.h"
        !            20: #include "virtio-scsi.h"
        !            21: #include "disk.h"
        !            22: 
        !            23: struct virtio_lun_s {
        !            24:     struct drive_s drive;
        !            25:     struct pci_device *pci;
        !            26:     struct vring_virtqueue *vq;
        !            27:     u16 ioaddr;
        !            28:     u16 target;
        !            29:     u16 lun;
        !            30: };
        !            31: 
        !            32: static int
        !            33: virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
        !            34:                 void *cdbcmd, u16 target, u16 lun, u16 blocksize)
        !            35: {
        !            36:     struct virtio_scsi_req_cmd req;
        !            37:     struct virtio_scsi_resp_cmd resp;
        !            38:     struct vring_list sg[3];
        !            39: 
        !            40:     memset(&req, 0, sizeof(req));
        !            41:     req.lun[0] = 1;
        !            42:     req.lun[1] = target;
        !            43:     req.lun[2] = (lun >> 8) | 0x40;
        !            44:     req.lun[3] = (lun & 0xff);
        !            45:     memcpy(req.cdb, cdbcmd, 16);
        !            46: 
        !            47:     u32 len = op->count * blocksize;
        !            48:     int datain = cdb_is_read(cdbcmd, blocksize);
        !            49:     int in_num = (datain ? 2 : 1);
        !            50:     int out_num = (len ? 3 : 2) - in_num;
        !            51: 
        !            52:     sg[0].addr   = MAKE_FLATPTR(GET_SEG(SS), &req);
        !            53:     sg[0].length = sizeof(req);
        !            54: 
        !            55:     sg[out_num].addr   = MAKE_FLATPTR(GET_SEG(SS), &resp);
        !            56:     sg[out_num].length = sizeof(resp);
        !            57: 
        !            58:     if (len) {
        !            59:         int data_idx = (datain ? 2 : 1);
        !            60:         sg[data_idx].addr   = op->buf_fl;
        !            61:         sg[data_idx].length = len;
        !            62:     }
        !            63: 
        !            64:     /* Add to virtqueue and kick host */
        !            65:     vring_add_buf(vq, sg, out_num, in_num, 0, 0);
        !            66:     vring_kick(ioaddr, vq, 1);
        !            67: 
        !            68:     /* Wait for reply */
        !            69:     while (!vring_more_used(vq))
        !            70:         usleep(5);
        !            71: 
        !            72:     /* Reclaim virtqueue element */
        !            73:     vring_get_buf(vq, NULL);
        !            74: 
        !            75:     /* Clear interrupt status register.  Avoid leaving interrupts stuck if
        !            76:      * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
        !            77:      */
        !            78:     vp_get_isr(ioaddr);
        !            79: 
        !            80:     if (resp.response == VIRTIO_SCSI_S_OK && resp.status == 0) {
        !            81:         return DISK_RET_SUCCESS;
        !            82:     }
        !            83:     return DISK_RET_EBADTRACK;
        !            84: }
        !            85: 
        !            86: int
        !            87: virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
        !            88: {
        !            89:     struct virtio_lun_s *vlun =
        !            90:         container_of(op->drive_g, struct virtio_lun_s, drive);
        !            91: 
        !            92:     return virtio_scsi_cmd(GET_GLOBAL(vlun->ioaddr),
        !            93:                            GET_GLOBAL(vlun->vq), op, cdbcmd,
        !            94:                            GET_GLOBAL(vlun->target), GET_GLOBAL(vlun->lun),
        !            95:                            blocksize);
        !            96: }
        !            97: 
        !            98: static int
        !            99: virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr,
        !           100:                     struct vring_virtqueue *vq, u16 target, u16 lun)
        !           101: {
        !           102:     struct virtio_lun_s *vlun = malloc_fseg(sizeof(*vlun));
        !           103:     if (!vlun) {
        !           104:         warn_noalloc();
        !           105:         return -1;
        !           106:     }
        !           107:     memset(vlun, 0, sizeof(*vlun));
        !           108:     vlun->drive.type = DTYPE_VIRTIO_SCSI;
        !           109:     vlun->drive.cntl_id = pci->bdf;
        !           110:     vlun->pci = pci;
        !           111:     vlun->ioaddr = ioaddr;
        !           112:     vlun->vq = vq;
        !           113:     vlun->target = target;
        !           114:     vlun->lun = lun;
        !           115: 
        !           116:     int prio = bootprio_find_scsi_device(pci, target, lun);
        !           117:     int ret = scsi_init_drive(&vlun->drive, "virtio-scsi", prio);
        !           118:     if (ret)
        !           119:         goto fail;
        !           120:     return 0;
        !           121: 
        !           122: fail:
        !           123:     free(vlun);
        !           124:     return -1;
        !           125: }
        !           126: 
        !           127: static int
        !           128: virtio_scsi_scan_target(struct pci_device *pci, u16 ioaddr,
        !           129:                         struct vring_virtqueue *vq, u16 target)
        !           130: {
        !           131:     /* TODO: send REPORT LUNS.  For now, only LUN 0 is recognized.  */
        !           132:     int ret = virtio_scsi_add_lun(pci, ioaddr, vq, target, 0);
        !           133:     return ret < 0 ? 0 : 1;
        !           134: }
        !           135: 
        !           136: static void
        !           137: init_virtio_scsi(struct pci_device *pci)
        !           138: {
        !           139:     u16 bdf = pci->bdf;
        !           140:     dprintf(1, "found virtio-scsi at %x:%x\n", pci_bdf_to_bus(bdf),
        !           141:             pci_bdf_to_dev(bdf));
        !           142:     struct vring_virtqueue *vq = NULL;
        !           143:     u16 ioaddr = vp_init_simple(bdf);
        !           144:     if (vp_find_vq(ioaddr, 2, &vq) < 0 ) {
        !           145:         dprintf(1, "fail to find vq for virtio-scsi %x:%x\n",
        !           146:                 pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
        !           147:         goto fail;
        !           148:     }
        !           149: 
        !           150:     int i, tot;
        !           151:     for (tot = 0, i = 0; i < 256; i++)
        !           152:         tot += virtio_scsi_scan_target(pci, ioaddr, vq, i);
        !           153: 
        !           154:     if (!tot)
        !           155:         goto fail;
        !           156: 
        !           157:     vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
        !           158:                   VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
        !           159:     return;
        !           160: 
        !           161: fail:
        !           162:     free(vq);
        !           163: }
        !           164: 
        !           165: void
        !           166: virtio_scsi_setup(void)
        !           167: {
        !           168:     ASSERT32FLAT();
        !           169:     if (! CONFIG_VIRTIO_SCSI || CONFIG_COREBOOT)
        !           170:         return;
        !           171: 
        !           172:     dprintf(3, "init virtio-scsi\n");
        !           173: 
        !           174:     struct pci_device *pci;
        !           175:     foreachpci(pci) {
        !           176:         if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET
        !           177:             || pci->device != PCI_DEVICE_ID_VIRTIO_SCSI)
        !           178:             continue;
        !           179:         init_virtio_scsi(pci);
        !           180:     }
        !           181: }

unix.superglobalmegacorp.com

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