Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Virtio driver bits |
| 3 | * |
| 4 | * Copyright (c) 2013 Alexander Graf <agraf@suse.de> |
| 5 | * |
| 6 | * This work is licensed under the terms of the GNU GPL, version 2 or (at |
| 7 | * your option) any later version. See the COPYING file in the top-level |
| 8 | * directory. |
| 9 | */ |
| 10 | |
Thomas Huth | 90806fe | 2017-07-12 14:49:43 +0200 | [diff] [blame^] | 11 | #include "libc.h" |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 12 | #include "s390-ccw.h" |
| 13 | #include "virtio.h" |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 14 | #include "virtio-scsi.h" |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 15 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 16 | #define VRING_WAIT_REPLY_TIMEOUT 3 |
| 17 | |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 18 | static VRing block[VIRTIO_MAX_VQS]; |
| 19 | static char ring_area[VIRTIO_RING_SIZE * VIRTIO_MAX_VQS] |
| 20 | __attribute__((__aligned__(PAGE_SIZE))); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 21 | |
Dominik Dingel | c8cda87 | 2013-06-17 14:29:42 +0200 | [diff] [blame] | 22 | static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); |
| 23 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 24 | static VDev vdev = { |
| 25 | .nr_vqs = 1, |
| 26 | .vrings = block, |
| 27 | .cmd_vr_idx = 0, |
| 28 | .ring_area = ring_area, |
| 29 | .wait_reply_timeout = VRING_WAIT_REPLY_TIMEOUT, |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 30 | .schid = { .one = 1 }, |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 31 | .scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE, |
| 32 | .blk_factor = 1, |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 33 | }; |
| 34 | |
| 35 | VDev *virtio_get_device(void) |
| 36 | { |
| 37 | return &vdev; |
| 38 | } |
| 39 | |
| 40 | VirtioDevType virtio_get_device_type(void) |
| 41 | { |
| 42 | return vdev.senseid.cu_model; |
| 43 | } |
| 44 | |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 45 | /* virtio spec v1.0 para 4.3.3.2 */ |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 46 | static long kvm_hypercall(unsigned long nr, unsigned long param1, |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 47 | unsigned long param2, unsigned long param3) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 48 | { |
Eugene (jno) Dvurechenski | abd696e | 2014-05-19 20:05:40 +0200 | [diff] [blame] | 49 | register ulong r_nr asm("1") = nr; |
| 50 | register ulong r_param1 asm("2") = param1; |
| 51 | register ulong r_param2 asm("3") = param2; |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 52 | register ulong r_param3 asm("4") = param3; |
Eugene (jno) Dvurechenski | abd696e | 2014-05-19 20:05:40 +0200 | [diff] [blame] | 53 | register long retval asm("2"); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 54 | |
Eugene (jno) Dvurechenski | abd696e | 2014-05-19 20:05:40 +0200 | [diff] [blame] | 55 | asm volatile ("diag 2,4,0x500" |
| 56 | : "=d" (retval) |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 57 | : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3) |
Eugene (jno) Dvurechenski | abd696e | 2014-05-19 20:05:40 +0200 | [diff] [blame] | 58 | : "memory", "cc"); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 59 | |
Eugene (jno) Dvurechenski | abd696e | 2014-05-19 20:05:40 +0200 | [diff] [blame] | 60 | return retval; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 61 | } |
| 62 | |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 63 | static long virtio_notify(SubChannelId schid, int vq_idx, long cookie) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 64 | { |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 65 | return kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid, |
| 66 | vq_idx, cookie); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 67 | } |
| 68 | |
| 69 | /*********************************************** |
| 70 | * Virtio functions * |
| 71 | ***********************************************/ |
| 72 | |
Eugene (jno) Dvurechenski | b88d7fa | 2015-11-10 14:10:20 +0100 | [diff] [blame] | 73 | static int drain_irqs(SubChannelId schid) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 74 | { |
Eugene (jno) Dvurechenski | b88d7fa | 2015-11-10 14:10:20 +0100 | [diff] [blame] | 75 | Irb irb = {}; |
Cornelia Huck | 776e7f0 | 2013-04-26 02:12:53 +0000 | [diff] [blame] | 76 | int r = 0; |
| 77 | |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 78 | while (1) { |
Cornelia Huck | 776e7f0 | 2013-04-26 02:12:53 +0000 | [diff] [blame] | 79 | /* FIXME: make use of TPI, for that enable subchannel and isc */ |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 80 | if (tsch(schid, &irb)) { |
Cornelia Huck | 776e7f0 | 2013-04-26 02:12:53 +0000 | [diff] [blame] | 81 | /* Might want to differentiate error codes later on. */ |
| 82 | if (irb.scsw.cstat) { |
| 83 | r = -EIO; |
| 84 | } else if (irb.scsw.dstat != 0xc) { |
| 85 | r = -EIO; |
| 86 | } |
| 87 | return r; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 88 | } |
| 89 | } |
| 90 | } |
| 91 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 92 | static int run_ccw(VDev *vdev, int cmd, void *ptr, int len) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 93 | { |
Eugene (jno) Dvurechenski | b88d7fa | 2015-11-10 14:10:20 +0100 | [diff] [blame] | 94 | Ccw1 ccw = {}; |
| 95 | CmdOrb orb = {}; |
| 96 | Schib schib; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 97 | int r; |
| 98 | |
| 99 | /* start command processing */ |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 100 | stsch_err(vdev->schid, &schib); |
Dong Jia Shi | 9c9f5f3 | 2016-09-22 10:36:39 +0200 | [diff] [blame] | 101 | /* enable the subchannel for IPL device */ |
| 102 | schib.pmcw.ena = 1; |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 103 | msch(vdev->schid, &schib); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 104 | |
| 105 | /* start subchannel command */ |
| 106 | orb.fmt = 1; |
| 107 | orb.cpa = (u32)(long)&ccw; |
| 108 | orb.lpm = 0x80; |
| 109 | |
| 110 | ccw.cmd_code = cmd; |
| 111 | ccw.cda = (long)ptr; |
| 112 | ccw.count = len; |
| 113 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 114 | r = ssch(vdev->schid, &orb); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 115 | /* |
| 116 | * XXX Wait until device is done processing the CCW. For now we can |
| 117 | * assume that a simple tsch will have finished the CCW processing, |
| 118 | * but the architecture allows for asynchronous operation |
| 119 | */ |
Cornelia Huck | 0f3f1f3 | 2013-04-26 02:12:54 +0000 | [diff] [blame] | 120 | if (!r) { |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 121 | r = drain_irqs(vdev->schid); |
Cornelia Huck | 0f3f1f3 | 2013-04-26 02:12:54 +0000 | [diff] [blame] | 122 | } |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 123 | return r; |
| 124 | } |
| 125 | |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 126 | static void vring_init(VRing *vr, VqInfo *info) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 127 | { |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 128 | void *p = (void *) info->queue; |
| 129 | |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 130 | debug_print_addr("init p", p); |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 131 | vr->id = info->index; |
| 132 | vr->num = info->num; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 133 | vr->desc = p; |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 134 | vr->avail = p + info->num * sizeof(VRingDesc); |
| 135 | vr->used = (void *)(((unsigned long)&vr->avail->ring[info->num] |
| 136 | + info->align - 1) & ~(info->align - 1)); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 137 | |
Christian Borntraeger | 39c93c6 | 2013-05-23 13:51:41 +0200 | [diff] [blame] | 138 | /* Zero out all relevant field */ |
| 139 | vr->avail->flags = 0; |
| 140 | vr->avail->idx = 0; |
| 141 | |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 142 | /* We're running with interrupts off anyways, so don't bother */ |
| 143 | vr->used->flags = VRING_USED_F_NO_NOTIFY; |
Christian Borntraeger | 39c93c6 | 2013-05-23 13:51:41 +0200 | [diff] [blame] | 144 | vr->used->idx = 0; |
Cornelia Huck | 441ea69 | 2013-08-29 17:52:43 +0200 | [diff] [blame] | 145 | vr->used_idx = 0; |
Christian Borntraeger | d1028f1 | 2014-02-12 16:17:35 +0100 | [diff] [blame] | 146 | vr->next_idx = 0; |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 147 | vr->cookie = 0; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 148 | |
| 149 | debug_print_addr("init vr", vr); |
| 150 | } |
| 151 | |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 152 | static bool vring_notify(VRing *vr) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 153 | { |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 154 | vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie); |
| 155 | return vr->cookie >= 0; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 156 | } |
| 157 | |
Eugene (jno) Dvurechenski | b88d7fa | 2015-11-10 14:10:20 +0100 | [diff] [blame] | 158 | static void vring_send_buf(VRing *vr, void *p, int len, int flags) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 159 | { |
| 160 | /* For follow-up chains we need to keep the first entry point */ |
| 161 | if (!(flags & VRING_HIDDEN_IS_CHAIN)) { |
| 162 | vr->avail->ring[vr->avail->idx % vr->num] = vr->next_idx; |
| 163 | } |
| 164 | |
| 165 | vr->desc[vr->next_idx].addr = (ulong)p; |
| 166 | vr->desc[vr->next_idx].len = len; |
| 167 | vr->desc[vr->next_idx].flags = flags & ~VRING_HIDDEN_IS_CHAIN; |
Christian Borntraeger | dc03640 | 2013-04-23 01:23:04 +0000 | [diff] [blame] | 168 | vr->desc[vr->next_idx].next = vr->next_idx; |
| 169 | vr->desc[vr->next_idx].next++; |
| 170 | vr->next_idx++; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 171 | |
| 172 | /* Chains only have a single ID */ |
| 173 | if (!(flags & VRING_DESC_F_NEXT)) { |
| 174 | vr->avail->idx++; |
| 175 | } |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | static u64 get_clock(void) |
| 179 | { |
| 180 | u64 r; |
| 181 | |
| 182 | asm volatile("stck %0" : "=Q" (r) : : "cc"); |
| 183 | return r; |
| 184 | } |
| 185 | |
Eugene (jno) Dvurechenski | dc25e84 | 2015-10-27 09:49:27 +0100 | [diff] [blame] | 186 | ulong get_second(void) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 187 | { |
| 188 | return (get_clock() >> 12) / 1000000; |
| 189 | } |
| 190 | |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 191 | static int vr_poll(VRing *vr) |
| 192 | { |
| 193 | if (vr->used->idx == vr->used_idx) { |
| 194 | vring_notify(vr); |
| 195 | yield(); |
| 196 | return 0; |
| 197 | } |
| 198 | |
| 199 | vr->used_idx = vr->used->idx; |
| 200 | vr->next_idx = 0; |
| 201 | vr->desc[0].len = 0; |
| 202 | vr->desc[0].flags = 0; |
| 203 | return 1; /* vr has been updated */ |
| 204 | } |
| 205 | |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 206 | /* |
| 207 | * Wait for the host to reply. |
| 208 | * |
| 209 | * timeout is in seconds if > 0. |
| 210 | * |
| 211 | * Returns 0 on success, 1 on timeout. |
| 212 | */ |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 213 | static int vring_wait_reply(void) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 214 | { |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 215 | ulong target_second = get_second() + vdev.wait_reply_timeout; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 216 | |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 217 | /* Wait for any queue to be updated by the host */ |
| 218 | do { |
| 219 | int i, r = 0; |
| 220 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 221 | for (i = 0; i < vdev.nr_vqs; i++) { |
| 222 | r += vr_poll(&vdev.vrings[i]); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 223 | } |
| 224 | yield(); |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 225 | if (r) { |
| 226 | return 0; |
| 227 | } |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 228 | } while (!vdev.wait_reply_timeout || (get_second() < target_second)); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 229 | |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 230 | return 1; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 231 | } |
| 232 | |
Eugene (jno) Dvurechenski | 8944edc | 2015-10-28 11:12:13 +0100 | [diff] [blame] | 233 | int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd) |
| 234 | { |
| 235 | VRing *vr = &vdev->vrings[vqid]; |
| 236 | int i = 0; |
| 237 | |
| 238 | do { |
| 239 | vring_send_buf(vr, cmd[i].data, cmd[i].size, |
| 240 | cmd[i].flags | (i ? VRING_HIDDEN_IS_CHAIN : 0)); |
| 241 | } while (cmd[i++].flags & VRING_DESC_F_NEXT); |
| 242 | |
| 243 | vring_wait_reply(); |
| 244 | if (drain_irqs(vr->schid)) { |
| 245 | return -1; |
| 246 | } |
| 247 | return 0; |
| 248 | } |
| 249 | |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 250 | /*********************************************** |
| 251 | * Virtio block * |
| 252 | ***********************************************/ |
| 253 | |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 254 | static int virtio_blk_read_many(VDev *vdev, |
| 255 | ulong sector, void *load_addr, int sec_num) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 256 | { |
Eugene (jno) Dvurechenski | b88d7fa | 2015-11-10 14:10:20 +0100 | [diff] [blame] | 257 | VirtioBlkOuthdr out_hdr; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 258 | u8 status; |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 259 | VRing *vr = &vdev->vrings[vdev->cmd_vr_idx]; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 260 | |
| 261 | /* Tell the host we want to read */ |
| 262 | out_hdr.type = VIRTIO_BLK_T_IN; |
| 263 | out_hdr.ioprio = 99; |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 264 | out_hdr.sector = virtio_sector_adjust(sector); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 265 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 266 | vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 267 | |
| 268 | /* This is where we want to receive data */ |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 269 | vring_send_buf(vr, load_addr, virtio_get_block_size() * sec_num, |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 270 | VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN | |
| 271 | VRING_DESC_F_NEXT); |
| 272 | |
| 273 | /* status field */ |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 274 | vring_send_buf(vr, &status, sizeof(u8), |
| 275 | VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 276 | |
| 277 | /* Now we can tell the host to read */ |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 278 | vring_wait_reply(); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 279 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 280 | if (drain_irqs(vr->schid)) { |
Cornelia Huck | 0f3f1f3 | 2013-04-26 02:12:54 +0000 | [diff] [blame] | 281 | /* Well, whatever status is supposed to contain... */ |
| 282 | status = 1; |
| 283 | } |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 284 | return status; |
| 285 | } |
| 286 | |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 287 | int virtio_read_many(ulong sector, void *load_addr, int sec_num) |
| 288 | { |
| 289 | switch (vdev.senseid.cu_model) { |
| 290 | case VIRTIO_ID_BLOCK: |
| 291 | return virtio_blk_read_many(&vdev, sector, load_addr, sec_num); |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 292 | case VIRTIO_ID_SCSI: |
| 293 | return virtio_scsi_read_many(&vdev, sector, load_addr, sec_num); |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 294 | } |
| 295 | panic("\n! No readable IPL device !\n"); |
| 296 | return -1; |
| 297 | } |
| 298 | |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 299 | unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2, |
Eugene (jno) Dvurechenski | abd696e | 2014-05-19 20:05:40 +0200 | [diff] [blame] | 300 | ulong subchan_id, void *load_addr) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 301 | { |
| 302 | u8 status; |
| 303 | int sec = rec_list1; |
David Hildenbrand | 554f808 | 2014-06-18 14:16:44 +0200 | [diff] [blame] | 304 | int sec_num = ((rec_list2 >> 32) & 0xffff) + 1; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 305 | int sec_len = rec_list2 >> 48; |
| 306 | ulong addr = (ulong)load_addr; |
| 307 | |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 308 | if (sec_len != virtio_get_block_size()) { |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 309 | return -1; |
| 310 | } |
| 311 | |
| 312 | sclp_print("."); |
Eugene (jno) Dvurechenski | abd696e | 2014-05-19 20:05:40 +0200 | [diff] [blame] | 313 | status = virtio_read_many(sec, (void *)addr, sec_num); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 314 | if (status) { |
Eugene (jno) Dvurechenski | c9262e8 | 2015-09-17 12:47:27 +0200 | [diff] [blame] | 315 | panic("I/O Error"); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 316 | } |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 317 | addr += sec_num * virtio_get_block_size(); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 318 | |
| 319 | return addr; |
| 320 | } |
| 321 | |
| 322 | int virtio_read(ulong sector, void *load_addr) |
| 323 | { |
| 324 | return virtio_read_many(sector, load_addr, 1); |
| 325 | } |
| 326 | |
Eugene (jno) Dvurechenski | 00a47e7 | 2014-08-29 11:01:37 +0200 | [diff] [blame] | 327 | /* |
| 328 | * Other supported value pairs, if any, would need to be added here. |
| 329 | * Note: head count is always 15. |
| 330 | */ |
| 331 | static inline u8 virtio_eckd_sectors_for_block_size(int size) |
| 332 | { |
| 333 | switch (size) { |
| 334 | case 512: |
| 335 | return 49; |
| 336 | case 1024: |
| 337 | return 33; |
| 338 | case 2048: |
| 339 | return 21; |
| 340 | case 4096: |
| 341 | return 12; |
| 342 | } |
| 343 | return 0; |
| 344 | } |
| 345 | |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 346 | VirtioGDN virtio_guessed_disk_nature(void) |
| 347 | { |
| 348 | return vdev.guessed_disk_nature; |
| 349 | } |
| 350 | |
| 351 | void virtio_assume_scsi(void) |
| 352 | { |
| 353 | switch (vdev.senseid.cu_model) { |
| 354 | case VIRTIO_ID_BLOCK: |
| 355 | vdev.guessed_disk_nature = VIRTIO_GDN_SCSI; |
| 356 | vdev.config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE; |
| 357 | vdev.config.blk.physical_block_exp = 0; |
| 358 | vdev.blk_factor = 1; |
| 359 | break; |
| 360 | case VIRTIO_ID_SCSI: |
| 361 | vdev.scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE; |
| 362 | break; |
| 363 | } |
| 364 | } |
| 365 | |
| 366 | void virtio_assume_iso9660(void) |
| 367 | { |
| 368 | switch (vdev.senseid.cu_model) { |
| 369 | case VIRTIO_ID_BLOCK: |
| 370 | vdev.guessed_disk_nature = VIRTIO_GDN_SCSI; |
| 371 | vdev.config.blk.blk_size = VIRTIO_ISO_BLOCK_SIZE; |
| 372 | vdev.config.blk.physical_block_exp = 0; |
| 373 | vdev.blk_factor = VIRTIO_ISO_BLOCK_SIZE / VIRTIO_SECTOR_SIZE; |
| 374 | break; |
| 375 | case VIRTIO_ID_SCSI: |
| 376 | vdev.scsi_block_size = VIRTIO_ISO_BLOCK_SIZE; |
| 377 | break; |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | void virtio_assume_eckd(void) |
| 382 | { |
| 383 | vdev.guessed_disk_nature = VIRTIO_GDN_DASD; |
| 384 | vdev.blk_factor = 1; |
| 385 | vdev.config.blk.physical_block_exp = 0; |
| 386 | switch (vdev.senseid.cu_model) { |
| 387 | case VIRTIO_ID_BLOCK: |
| 388 | vdev.config.blk.blk_size = 4096; |
| 389 | break; |
| 390 | case VIRTIO_ID_SCSI: |
| 391 | vdev.config.blk.blk_size = vdev.scsi_block_size; |
| 392 | break; |
| 393 | } |
| 394 | vdev.config.blk.geometry.heads = 15; |
| 395 | vdev.config.blk.geometry.sectors = |
| 396 | virtio_eckd_sectors_for_block_size(vdev.config.blk.blk_size); |
| 397 | } |
| 398 | |
| 399 | bool virtio_disk_is_scsi(void) |
| 400 | { |
| 401 | if (vdev.guessed_disk_nature == VIRTIO_GDN_SCSI) { |
| 402 | return true; |
| 403 | } |
| 404 | switch (vdev.senseid.cu_model) { |
| 405 | case VIRTIO_ID_BLOCK: |
| 406 | return (vdev.config.blk.geometry.heads == 255) |
| 407 | && (vdev.config.blk.geometry.sectors == 63) |
| 408 | && (virtio_get_block_size() == VIRTIO_SCSI_BLOCK_SIZE); |
| 409 | case VIRTIO_ID_SCSI: |
| 410 | return true; |
| 411 | } |
| 412 | return false; |
| 413 | } |
| 414 | |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 415 | bool virtio_disk_is_eckd(void) |
| 416 | { |
Eugene (jno) Dvurechenski | 00a47e7 | 2014-08-29 11:01:37 +0200 | [diff] [blame] | 417 | const int block_size = virtio_get_block_size(); |
| 418 | |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 419 | if (vdev.guessed_disk_nature == VIRTIO_GDN_DASD) { |
| 420 | return true; |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 421 | } |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 422 | switch (vdev.senseid.cu_model) { |
| 423 | case VIRTIO_ID_BLOCK: |
| 424 | return (vdev.config.blk.geometry.heads == 15) |
| 425 | && (vdev.config.blk.geometry.sectors == |
| 426 | virtio_eckd_sectors_for_block_size(block_size)); |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 427 | case VIRTIO_ID_SCSI: |
| 428 | return false; |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 429 | } |
| 430 | return false; |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 431 | } |
| 432 | |
| 433 | bool virtio_ipl_disk_is_valid(void) |
| 434 | { |
Eugene (jno) Dvurechenski | 92cb055 | 2014-08-29 11:01:36 +0200 | [diff] [blame] | 435 | return virtio_disk_is_scsi() || virtio_disk_is_eckd(); |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 436 | } |
| 437 | |
| 438 | int virtio_get_block_size(void) |
| 439 | { |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 440 | switch (vdev.senseid.cu_model) { |
| 441 | case VIRTIO_ID_BLOCK: |
| 442 | return vdev.config.blk.blk_size << vdev.config.blk.physical_block_exp; |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 443 | case VIRTIO_ID_SCSI: |
| 444 | return vdev.scsi_block_size; |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 445 | } |
| 446 | return 0; |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 447 | } |
| 448 | |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 449 | uint8_t virtio_get_heads(void) |
| 450 | { |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 451 | switch (vdev.senseid.cu_model) { |
| 452 | case VIRTIO_ID_BLOCK: |
| 453 | return vdev.config.blk.geometry.heads; |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 454 | case VIRTIO_ID_SCSI: |
| 455 | return vdev.guessed_disk_nature == VIRTIO_GDN_DASD |
| 456 | ? vdev.config.blk.geometry.heads : 255; |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 457 | } |
| 458 | return 0; |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 459 | } |
| 460 | |
| 461 | uint8_t virtio_get_sectors(void) |
| 462 | { |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 463 | switch (vdev.senseid.cu_model) { |
| 464 | case VIRTIO_ID_BLOCK: |
| 465 | return vdev.config.blk.geometry.sectors; |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 466 | case VIRTIO_ID_SCSI: |
| 467 | return vdev.guessed_disk_nature == VIRTIO_GDN_DASD |
| 468 | ? vdev.config.blk.geometry.sectors : 63; |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 469 | } |
| 470 | return 0; |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 471 | } |
| 472 | |
Eugene (jno) Dvurechenski | f04db28 | 2014-08-29 11:01:39 +0200 | [diff] [blame] | 473 | uint64_t virtio_get_blocks(void) |
| 474 | { |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 475 | const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE; |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 476 | switch (vdev.senseid.cu_model) { |
| 477 | case VIRTIO_ID_BLOCK: |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 478 | return vdev.config.blk.capacity / factor; |
| 479 | case VIRTIO_ID_SCSI: |
| 480 | return vdev.scsi_last_block / factor; |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 481 | } |
| 482 | return 0; |
Eugene (jno) Dvurechenski | f04db28 | 2014-08-29 11:01:39 +0200 | [diff] [blame] | 483 | } |
| 484 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 485 | static void virtio_setup_ccw(VDev *vdev) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 486 | { |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 487 | int i, cfg_size = 0; |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 488 | unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 489 | |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 490 | IPL_assert(virtio_is_supported(vdev->schid), "PE"); |
| 491 | /* device ID has been established now */ |
| 492 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 493 | vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */ |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 494 | vdev->guessed_disk_nature = VIRTIO_GDN_NONE; |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 495 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 496 | run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0); |
| 497 | |
| 498 | switch (vdev->senseid.cu_model) { |
| 499 | case VIRTIO_ID_BLOCK: |
| 500 | vdev->nr_vqs = 1; |
| 501 | vdev->cmd_vr_idx = 0; |
| 502 | cfg_size = sizeof(vdev->config.blk); |
| 503 | break; |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 504 | case VIRTIO_ID_SCSI: |
| 505 | vdev->nr_vqs = 3; |
| 506 | vdev->cmd_vr_idx = VR_REQUEST; |
| 507 | cfg_size = sizeof(vdev->config.scsi); |
| 508 | break; |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 509 | default: |
| 510 | panic("Unsupported virtio device\n"); |
| 511 | } |
| 512 | IPL_assert(run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size) == 0, |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 513 | "Could not get block device configuration"); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 514 | |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 515 | /* |
| 516 | * Skipping CCW_CMD_READ_FEAT. We're not doing anything fancy, and |
| 517 | * we'll just stop dead anyway if anything does not work like we |
| 518 | * expect it. |
| 519 | */ |
| 520 | |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 521 | for (i = 0; i < vdev->nr_vqs; i++) { |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 522 | VqInfo info = { |
| 523 | .queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE), |
| 524 | .align = KVM_S390_VIRTIO_RING_ALIGN, |
| 525 | .index = i, |
| 526 | .num = 0, |
| 527 | }; |
| 528 | VqConfig config = { |
| 529 | .index = i, |
| 530 | .num = 0, |
| 531 | }; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 532 | |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 533 | IPL_assert( |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 534 | run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config)) == 0, |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 535 | "Could not get block device VQ configuration"); |
| 536 | info.num = config.num; |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 537 | vring_init(&vdev->vrings[i], &info); |
| 538 | vdev->vrings[i].schid = vdev->schid; |
| 539 | IPL_assert(run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info)) == 0, |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 540 | "Cannot set VQ info"); |
Cornelia Huck | 0f3f1f3 | 2013-04-26 02:12:54 +0000 | [diff] [blame] | 541 | } |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 542 | IPL_assert( |
| 543 | run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status)) == 0, |
| 544 | "Could not write status to host"); |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 545 | } |
| 546 | |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 547 | void virtio_setup_device(SubChannelId schid) |
Eugene (jno) Dvurechenski | 8512989 | 2015-11-10 15:13:36 +0100 | [diff] [blame] | 548 | { |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 549 | vdev.schid = schid; |
| 550 | virtio_setup_ccw(&vdev); |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 551 | |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 552 | switch (vdev.senseid.cu_model) { |
| 553 | case VIRTIO_ID_BLOCK: |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 554 | sclp_print("Using virtio-blk.\n"); |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 555 | if (!virtio_ipl_disk_is_valid()) { |
| 556 | /* make sure all getters but blocksize return 0 for |
| 557 | * invalid IPL disk |
| 558 | */ |
| 559 | memset(&vdev.config.blk, 0, sizeof(vdev.config.blk)); |
| 560 | virtio_assume_scsi(); |
| 561 | } |
| 562 | break; |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 563 | case VIRTIO_ID_SCSI: |
| 564 | IPL_assert(vdev.config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE, |
| 565 | "Config: sense size mismatch"); |
| 566 | IPL_assert(vdev.config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE, |
| 567 | "Config: CDB size mismatch"); |
| 568 | |
| 569 | sclp_print("Using virtio-scsi.\n"); |
| 570 | virtio_scsi_setup(&vdev); |
| 571 | break; |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 572 | default: |
| 573 | panic("\n! No IPL device available !\n"); |
Eugene (jno) Dvurechenski | 91a03f9 | 2014-05-19 20:10:27 +0200 | [diff] [blame] | 574 | } |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 575 | } |
| 576 | |
Eugene (jno) Dvurechenski | a1102ce | 2015-10-26 16:55:16 +0100 | [diff] [blame] | 577 | bool virtio_is_supported(SubChannelId schid) |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 578 | { |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 579 | vdev.schid = schid; |
| 580 | memset(&vdev.senseid, 0, sizeof(vdev.senseid)); |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 581 | /* run sense id command */ |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 582 | if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid))) { |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 583 | return false; |
| 584 | } |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 585 | if (vdev.senseid.cu_type == 0x3832) { |
| 586 | switch (vdev.senseid.cu_model) { |
| 587 | case VIRTIO_ID_BLOCK: |
Eugene (jno) Dvurechenski | 80ba3e2 | 2015-11-10 15:37:22 +0100 | [diff] [blame] | 588 | case VIRTIO_ID_SCSI: |
Farhan Ali | 99b72e0 | 2016-11-01 17:34:00 -0400 | [diff] [blame] | 589 | case VIRTIO_ID_NET: |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 590 | return true; |
| 591 | } |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 592 | } |
Eugene (jno) Dvurechenski | 6942968 | 2015-10-26 15:47:24 +0100 | [diff] [blame] | 593 | return false; |
Alexander Graf | 1e17c2c | 2013-04-22 21:01:00 +0200 | [diff] [blame] | 594 | } |
| 595 | |
Dominik Dingel | c8cda87 | 2013-06-17 14:29:42 +0200 | [diff] [blame] | 596 | int enable_mss_facility(void) |
| 597 | { |
| 598 | int ret; |
Eugene (jno) Dvurechenski | b88d7fa | 2015-11-10 14:10:20 +0100 | [diff] [blame] | 599 | ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page; |
Dominik Dingel | c8cda87 | 2013-06-17 14:29:42 +0200 | [diff] [blame] | 600 | |
| 601 | memset(sda_area, 0, PAGE_SIZE); |
| 602 | sda_area->request.length = 0x0400; |
| 603 | sda_area->request.code = 0x0031; |
| 604 | sda_area->operation_code = 0x2; |
| 605 | |
| 606 | ret = chsc(sda_area); |
| 607 | if ((ret == 0) && (sda_area->response.code == 0x0001)) { |
| 608 | return 0; |
| 609 | } |
| 610 | return -EIO; |
| 611 | } |