1 // (qemu-emulated) lsi53c895a boot support.
3 // Copyright (C) 2012 Red Hat Inc.
6 // Gerd Hoffmann <kraxel@redhat.com>
8 // based on virtio-scsi.c which is written by:
9 // Paolo Bonzini <pbonzini@redhat.com>
11 // This file may be distributed under the terms of the GNU LGPLv3 license.
13 #include "biosvar.h" // GET_GLOBALFLAT
14 #include "block.h" // struct drive_s
15 #include "blockcmd.h" // scsi_drive_setup
16 #include "config.h" // CONFIG_*
17 #include "fw/paravirt.h" // runningOnQEMU
18 #include "malloc.h" // free
19 #include "output.h" // dprintf
20 #include "pci.h" // foreachpci
21 #include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
22 #include "pci_regs.h" // PCI_VENDOR_ID
23 #include "std/disk.h" // DISK_RET_SUCCESS
24 #include "string.h" // memset
25 #include "util.h" // usleep
27 #define LSI_REG_DSTAT 0x0c
28 #define LSI_REG_ISTAT0 0x14
29 #define LSI_REG_DSP0 0x2c
30 #define LSI_REG_DSP1 0x2d
31 #define LSI_REG_DSP2 0x2e
32 #define LSI_REG_DSP3 0x2f
33 #define LSI_REG_SIST0 0x42
34 #define LSI_REG_SIST1 0x43
36 #define LSI_ISTAT0_DIP 0x01
37 #define LSI_ISTAT0_SIP 0x02
38 #define LSI_ISTAT0_INTF 0x04
39 #define LSI_ISTAT0_CON 0x08
40 #define LSI_ISTAT0_SEM 0x10
41 #define LSI_ISTAT0_SIGP 0x20
42 #define LSI_ISTAT0_SRST 0x40
43 #define LSI_ISTAT0_ABRT 0x80
47 struct pci_device *pci;
54 lsi_scsi_process_op(struct disk_op_s *op)
57 return DISK_RET_EBADTRACK;
58 struct lsi_lun_s *llun_gf =
59 container_of(op->drive_gf, struct lsi_lun_s, drive);
60 u16 target = GET_GLOBALFLAT(llun_gf->target);
61 u16 lun = GET_GLOBALFLAT(llun_gf->lun);
63 int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd));
65 return default_process_op(op);
66 u32 iobase = GET_GLOBALFLAT(llun_gf->iobase);
67 u32 dma = ((scsi_is_read(op) ? 0x01000000 : 0x00000000) |
68 (op->count * blocksize));
70 0x80 | lun, // select lun
78 /* select target, send scsi command */
79 0x40000000 | target << 16, // select target
82 (u32)MAKE_FLATPTR(GET_SEG(SS), &msgout),
83 0x02000010, // scsi command
84 (u32)MAKE_FLATPTR(GET_SEG(SS), cdbcmd),
86 /* handle disconnect */
87 0x87820000, // phase == msgin ?
90 (u32)MAKE_FLATPTR(GET_SEG(SS), &msgin_tmp),
91 0x50000000, // re-select
94 (u32)MAKE_FLATPTR(GET_SEG(SS), &msgin_tmp),
96 /* dma data, get status, raise irq */
100 (u32)MAKE_FLATPTR(GET_SEG(SS), &status),
102 (u32)MAKE_FLATPTR(GET_SEG(SS), &msgin),
103 0x98080000, // dma irq
106 u32 dsp = (u32)MAKE_FLATPTR(GET_SEG(SS), &script);
108 outb(dsp & 0xff, iobase + LSI_REG_DSP0);
109 outb((dsp >> 8) & 0xff, iobase + LSI_REG_DSP1);
110 outb((dsp >> 16) & 0xff, iobase + LSI_REG_DSP2);
111 outb((dsp >> 24) & 0xff, iobase + LSI_REG_DSP3);
114 u8 dstat = inb(iobase + LSI_REG_DSTAT);
115 u8 sist0 = inb(iobase + LSI_REG_SIST0);
116 u8 sist1 = inb(iobase + LSI_REG_SIST1);
117 if (sist0 || sist1) {
126 if (msgin == 0 && status == 0) {
127 return DISK_RET_SUCCESS;
131 return DISK_RET_EBADTRACK;
135 lsi_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
137 struct lsi_lun_s *llun = malloc_fseg(sizeof(*llun));
142 memset(llun, 0, sizeof(*llun));
143 llun->drive.type = DTYPE_LSI_SCSI;
144 llun->drive.cntl_id = pci->bdf;
146 llun->target = target;
148 llun->iobase = iobase;
150 char *name = znprintf(16, "lsi %02x:%02x.%x %d:%d",
151 pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
152 pci_bdf_to_fn(pci->bdf), target, lun);
153 int prio = bootprio_find_scsi_device(pci, target, lun);
154 int ret = scsi_drive_setup(&llun->drive, name, prio);
166 lsi_scsi_scan_target(struct pci_device *pci, u32 iobase, u8 target)
168 /* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */
169 lsi_scsi_add_lun(pci, iobase, target, 0);
173 init_lsi_scsi(struct pci_device *pci)
176 u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
177 & PCI_BASE_ADDRESS_IO_MASK;
179 pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
181 dprintf(1, "found lsi53c895a at %02x:%02x.%x, io @ %x\n",
182 pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
183 pci_bdf_to_fn(bdf), iobase);
186 outb(LSI_ISTAT0_SRST, iobase + LSI_REG_ISTAT0);
189 for (i = 0; i < 7; i++)
190 lsi_scsi_scan_target(pci, iobase, i);
199 if (!CONFIG_LSI_SCSI || !runningOnQEMU())
202 dprintf(3, "init lsi53c895a\n");
204 struct pci_device *pci;
206 if (pci->vendor != PCI_VENDOR_ID_LSI_LOGIC
207 || pci->device != PCI_DEVICE_ID_LSI_53C895A)