Annotation of qemu/roms/seabios/src/virtio-scsi.c, revision 1.1.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.