1 /* $OpenBSD: vioscsi.c,v 1.31 2023/04/27 13:52:58 krw Exp $ */ 2 /* 3 * Copyright (c) 2013 Google Inc. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/mutex.h> 22 23 #include <machine/bus.h> 24 #include <machine/intr.h> 25 26 #include <dev/pv/vioscsireg.h> 27 #include <dev/pv/virtiovar.h> 28 29 #include <scsi/scsi_all.h> 30 #include <scsi/scsiconf.h> 31 32 enum { vioscsi_debug = 0 }; 33 #define DPRINTF(f...) do { if (vioscsi_debug) printf(f); } while (0) 34 35 /* Number of DMA segments for buffers that the device must support */ 36 #define SEG_MAX (MAXPHYS/PAGE_SIZE + 1) 37 /* In the virtqueue, we need space for header and footer, too */ 38 #define ALLOC_SEGS (SEG_MAX + 2) 39 40 struct vioscsi_req { 41 struct virtio_scsi_req_hdr vr_req; 42 struct virtio_scsi_res_hdr vr_res; 43 struct scsi_xfer *vr_xs; 44 bus_dmamap_t vr_control; 45 bus_dmamap_t vr_data; 46 SLIST_ENTRY(vioscsi_req) vr_list; 47 int vr_qe_index; 48 }; 49 50 struct vioscsi_softc { 51 struct device sc_dev; 52 struct scsi_iopool sc_iopool; 53 struct mutex sc_vr_mtx; 54 55 struct virtqueue sc_vqs[3]; 56 struct vioscsi_req *sc_reqs; 57 bus_dma_segment_t sc_reqs_segs[1]; 58 SLIST_HEAD(, vioscsi_req) sc_freelist; 59 }; 60 61 int vioscsi_match(struct device *, void *, void *); 62 void vioscsi_attach(struct device *, struct device *, void *); 63 64 int vioscsi_alloc_reqs(struct vioscsi_softc *, 65 struct virtio_softc *, int); 66 void vioscsi_scsi_cmd(struct scsi_xfer *); 67 int vioscsi_vq_done(struct virtqueue *); 68 void vioscsi_req_done(struct vioscsi_softc *, struct virtio_softc *, 69 struct vioscsi_req *); 70 void *vioscsi_req_get(void *); 71 void vioscsi_req_put(void *, void *); 72 73 const struct cfattach vioscsi_ca = { 74 sizeof(struct vioscsi_softc), 75 vioscsi_match, 76 vioscsi_attach, 77 }; 78 79 struct cfdriver vioscsi_cd = { 80 NULL, "vioscsi", DV_DULL, 81 }; 82 83 const struct scsi_adapter vioscsi_switch = { 84 vioscsi_scsi_cmd, NULL, NULL, NULL, NULL 85 }; 86 87 const char *const vioscsi_vq_names[] = { 88 "control", 89 "event", 90 "request", 91 }; 92 93 int 94 vioscsi_match(struct device *parent, void *self, void *aux) 95 { 96 struct virtio_softc *va = (struct virtio_softc *)aux; 97 98 if (va->sc_childdevid == PCI_PRODUCT_VIRTIO_SCSI) 99 return (1); 100 return (0); 101 } 102 103 void 104 vioscsi_attach(struct device *parent, struct device *self, void *aux) 105 { 106 struct virtio_softc *vsc = (struct virtio_softc *)parent; 107 struct vioscsi_softc *sc = (struct vioscsi_softc *)self; 108 struct scsibus_attach_args saa; 109 int i, rv; 110 111 if (vsc->sc_child != NULL) { 112 printf(": parent already has a child\n"); 113 return; 114 } 115 vsc->sc_child = &sc->sc_dev; 116 vsc->sc_ipl = IPL_BIO; 117 118 // TODO(matthew): Negotiate hotplug. 119 120 vsc->sc_vqs = sc->sc_vqs; 121 vsc->sc_nvqs = nitems(sc->sc_vqs); 122 123 virtio_negotiate_features(vsc, NULL); 124 uint32_t cmd_per_lun = virtio_read_device_config_4(vsc, 125 VIRTIO_SCSI_CONFIG_CMD_PER_LUN); 126 uint32_t seg_max = virtio_read_device_config_4(vsc, 127 VIRTIO_SCSI_CONFIG_SEG_MAX); 128 uint16_t max_target = virtio_read_device_config_2(vsc, 129 VIRTIO_SCSI_CONFIG_MAX_TARGET); 130 131 if (seg_max < SEG_MAX) { 132 printf("\nMax number of segments %d too small\n", seg_max); 133 goto err; 134 } 135 136 for (i = 0; i < nitems(sc->sc_vqs); i++) { 137 rv = virtio_alloc_vq(vsc, &sc->sc_vqs[i], i, MAXPHYS, 138 ALLOC_SEGS, vioscsi_vq_names[i]); 139 if (rv) { 140 printf(": failed to allocate virtqueue %d\n", i); 141 goto err; 142 } 143 sc->sc_vqs[i].vq_done = vioscsi_vq_done; 144 } 145 146 int qsize = sc->sc_vqs[2].vq_num; 147 printf(": qsize %d\n", qsize); 148 149 SLIST_INIT(&sc->sc_freelist); 150 mtx_init(&sc->sc_vr_mtx, IPL_BIO); 151 scsi_iopool_init(&sc->sc_iopool, sc, vioscsi_req_get, vioscsi_req_put); 152 153 int nreqs = vioscsi_alloc_reqs(sc, vsc, qsize); 154 if (nreqs == 0) { 155 printf("\nCan't alloc reqs\n"); 156 goto err; 157 } 158 159 saa.saa_adapter = &vioscsi_switch; 160 saa.saa_adapter_softc = sc; 161 saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET; 162 saa.saa_adapter_buswidth = max_target; 163 saa.saa_luns = 8; 164 saa.saa_openings = (nreqs > cmd_per_lun) ? cmd_per_lun : nreqs; 165 saa.saa_pool = &sc->sc_iopool; 166 saa.saa_quirks = saa.saa_flags = 0; 167 saa.saa_wwpn = saa.saa_wwnn = 0; 168 169 config_found(self, &saa, scsiprint); 170 return; 171 172 err: 173 vsc->sc_child = VIRTIO_CHILD_ERROR; 174 return; 175 } 176 177 void 178 vioscsi_scsi_cmd(struct scsi_xfer *xs) 179 { 180 struct vioscsi_softc *sc = xs->sc_link->bus->sb_adapter_softc; 181 struct virtio_softc *vsc = (struct virtio_softc *)sc->sc_dev.dv_parent; 182 struct vioscsi_req *vr = xs->io; 183 struct virtio_scsi_req_hdr *req = &vr->vr_req; 184 struct virtqueue *vq = &sc->sc_vqs[2]; 185 int slot = vr->vr_qe_index; 186 187 DPRINTF("vioscsi_scsi_cmd: enter\n"); 188 189 // TODO(matthew): Support bidirectional SCSI commands? 190 if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) 191 == (SCSI_DATA_IN | SCSI_DATA_OUT)) { 192 goto stuffup; 193 } 194 195 vr->vr_xs = xs; 196 197 /* 198 * "The only supported format for the LUN field is: first byte set to 199 * 1, second byte set to target, third and fourth byte representing a 200 * single level LUN structure, followed by four zero bytes." 201 */ 202 if (xs->sc_link->target >= 256 || xs->sc_link->lun >= 16384) 203 goto stuffup; 204 req->lun[0] = 1; 205 req->lun[1] = xs->sc_link->target; 206 req->lun[2] = 0x40 | (xs->sc_link->lun >> 8); 207 req->lun[3] = xs->sc_link->lun; 208 memset(req->lun + 4, 0, 4); 209 210 if ((size_t)xs->cmdlen > sizeof(req->cdb)) 211 goto stuffup; 212 memset(req->cdb, 0, sizeof(req->cdb)); 213 memcpy(req->cdb, &xs->cmd, xs->cmdlen); 214 215 int isread = !!(xs->flags & SCSI_DATA_IN); 216 217 int nsegs = 2; 218 if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 219 if (bus_dmamap_load(vsc->sc_dmat, vr->vr_data, 220 xs->data, xs->datalen, NULL, 221 ((isread ? BUS_DMA_READ : BUS_DMA_WRITE) | 222 BUS_DMA_NOWAIT))) 223 goto stuffup; 224 nsegs += vr->vr_data->dm_nsegs; 225 } 226 227 /* 228 * Adjust reservation to the number needed, or virtio gets upset. Note 229 * that it may trim UP if 'xs' is being recycled w/o getting a new 230 * reservation! 231 */ 232 int s = splbio(); 233 virtio_enqueue_trim(vq, slot, nsegs); 234 splx(s); 235 236 bus_dmamap_sync(vsc->sc_dmat, vr->vr_control, 237 offsetof(struct vioscsi_req, vr_req), 238 sizeof(struct virtio_scsi_req_hdr), 239 BUS_DMASYNC_PREWRITE); 240 bus_dmamap_sync(vsc->sc_dmat, vr->vr_control, 241 offsetof(struct vioscsi_req, vr_res), 242 sizeof(struct virtio_scsi_res_hdr), 243 BUS_DMASYNC_PREREAD); 244 if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) 245 bus_dmamap_sync(vsc->sc_dmat, vr->vr_data, 0, xs->datalen, 246 isread ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 247 248 s = splbio(); 249 virtio_enqueue_p(vq, slot, vr->vr_control, 250 offsetof(struct vioscsi_req, vr_req), 251 sizeof(struct virtio_scsi_req_hdr), 252 1); 253 if (xs->flags & SCSI_DATA_OUT) 254 virtio_enqueue(vq, slot, vr->vr_data, 1); 255 virtio_enqueue_p(vq, slot, vr->vr_control, 256 offsetof(struct vioscsi_req, vr_res), 257 sizeof(struct virtio_scsi_res_hdr), 258 0); 259 if (xs->flags & SCSI_DATA_IN) 260 virtio_enqueue(vq, slot, vr->vr_data, 0); 261 262 virtio_enqueue_commit(vsc, vq, slot, 1); 263 264 if (ISSET(xs->flags, SCSI_POLL)) { 265 DPRINTF("vioscsi_scsi_cmd: polling...\n"); 266 int timeout = 1000; 267 do { 268 virtio_poll_intr(vsc); 269 if (vr->vr_xs != xs) 270 break; 271 delay(1000); 272 } while (--timeout > 0); 273 if (vr->vr_xs == xs) { 274 // TODO(matthew): Abort the request. 275 xs->error = XS_TIMEOUT; 276 xs->resid = xs->datalen; 277 DPRINTF("vioscsi_scsi_cmd: polling timeout\n"); 278 scsi_done(xs); 279 } 280 DPRINTF("vioscsi_scsi_cmd: done (timeout=%d)\n", timeout); 281 } 282 splx(s); 283 return; 284 285 stuffup: 286 xs->error = XS_DRIVER_STUFFUP; 287 xs->resid = xs->datalen; 288 DPRINTF("vioscsi_scsi_cmd: stuffup\n"); 289 scsi_done(xs); 290 } 291 292 void 293 vioscsi_req_done(struct vioscsi_softc *sc, struct virtio_softc *vsc, 294 struct vioscsi_req *vr) 295 { 296 struct scsi_xfer *xs = vr->vr_xs; 297 DPRINTF("vioscsi_req_done: enter vr: %p xs: %p\n", vr, xs); 298 299 bus_dmamap_sync(vsc->sc_dmat, vr->vr_control, 300 offsetof(struct vioscsi_req, vr_req), 301 sizeof(struct virtio_scsi_req_hdr), 302 BUS_DMASYNC_POSTWRITE); 303 bus_dmamap_sync(vsc->sc_dmat, vr->vr_control, 304 offsetof(struct vioscsi_req, vr_res), 305 sizeof(struct virtio_scsi_res_hdr), 306 BUS_DMASYNC_POSTREAD); 307 308 /* 309 * XXX Should be impossible but somehow happens on Oracle Cloud and 310 * particular QEMU configurations. 311 * 312 * Stop the crashing while investigation into 313 * the apparent queuing/dequeuing issue proceeds. 314 */ 315 if (xs == NULL) 316 return; 317 318 int isread = !!(xs->flags & SCSI_DATA_IN); 319 if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 320 bus_dmamap_sync(vsc->sc_dmat, vr->vr_data, 0, xs->datalen, 321 isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 322 bus_dmamap_unload(vsc->sc_dmat, vr->vr_data); 323 } 324 325 if (vr->vr_res.response != VIRTIO_SCSI_S_OK) { 326 xs->error = XS_DRIVER_STUFFUP; 327 xs->resid = xs->datalen; 328 DPRINTF("vioscsi_req_done: stuffup: %d\n", vr->vr_res.response); 329 goto done; 330 } 331 332 size_t sense_len = MIN(sizeof(xs->sense), vr->vr_res.sense_len); 333 memcpy(&xs->sense, vr->vr_res.sense, sense_len); 334 xs->error = (sense_len == 0) ? XS_NOERROR : XS_SENSE; 335 336 xs->status = vr->vr_res.status; 337 xs->resid = vr->vr_res.residual; 338 339 DPRINTF("vioscsi_req_done: done %d, %d, %zd\n", 340 xs->error, xs->status, xs->resid); 341 342 done: 343 vr->vr_xs = NULL; 344 scsi_done(xs); 345 } 346 347 int 348 vioscsi_vq_done(struct virtqueue *vq) 349 { 350 struct virtio_softc *vsc = vq->vq_owner; 351 struct vioscsi_softc *sc = (struct vioscsi_softc *)vsc->sc_child; 352 struct vq_entry *qe; 353 struct vioscsi_req *vr; 354 int ret = 0; 355 356 DPRINTF("vioscsi_vq_done: enter\n"); 357 358 for (;;) { 359 int r, s, slot; 360 s = splbio(); 361 r = virtio_dequeue(vsc, vq, &slot, NULL); 362 splx(s); 363 if (r != 0) 364 break; 365 366 DPRINTF("vioscsi_vq_done: slot=%d\n", slot); 367 qe = &vq->vq_entries[slot]; 368 vr = &sc->sc_reqs[qe->qe_vr_index]; 369 vioscsi_req_done(sc, vsc, vr); 370 ret = 1; 371 } 372 373 DPRINTF("vioscsi_vq_done: exit %d\n", ret); 374 375 return (ret); 376 } 377 378 /* 379 * vioscso_req_get() provides the SCSI layer with all the 380 * resources necessary to start an I/O on the device. 381 * 382 * Since the size of the I/O is unknown at this time the 383 * resources allocated (a.k.a. reserved) must be sufficient 384 * to allow the maximum possible I/O size. 385 * 386 * When the I/O is actually attempted via vioscsi_scsi_cmd() 387 * excess resources will be returned via virtio_enqueue_trim(). 388 */ 389 void * 390 vioscsi_req_get(void *cookie) 391 { 392 struct vioscsi_softc *sc = cookie; 393 struct vioscsi_req *vr = NULL; 394 395 mtx_enter(&sc->sc_vr_mtx); 396 vr = SLIST_FIRST(&sc->sc_freelist); 397 if (vr != NULL) 398 SLIST_REMOVE_HEAD(&sc->sc_freelist, vr_list); 399 mtx_leave(&sc->sc_vr_mtx); 400 401 DPRINTF("vioscsi_req_get: %p\n", vr); 402 403 return (vr); 404 } 405 406 void 407 vioscsi_req_put(void *cookie, void *io) 408 { 409 struct vioscsi_softc *sc = cookie; 410 struct vioscsi_req *vr = io; 411 412 DPRINTF("vioscsi_req_put: %p\n", vr); 413 414 mtx_enter(&sc->sc_vr_mtx); 415 /* 416 * Do *NOT* call virtio_dequeue_commit()! 417 * 418 * Descriptors are permanently associated with the vioscsi_req and 419 * should not be placed on the free list! 420 */ 421 SLIST_INSERT_HEAD(&sc->sc_freelist, vr, vr_list); 422 mtx_leave(&sc->sc_vr_mtx); 423 } 424 425 int 426 vioscsi_alloc_reqs(struct vioscsi_softc *sc, struct virtio_softc *vsc, 427 int qsize) 428 { 429 struct virtqueue *vq = &sc->sc_vqs[2]; 430 struct vioscsi_req *vr; 431 struct vring_desc *vd; 432 size_t allocsize; 433 int i, r, nreqs, rsegs, slot; 434 void *vaddr; 435 436 if (vq->vq_indirect != NULL) 437 nreqs = qsize; 438 else 439 nreqs = qsize / ALLOC_SEGS; 440 441 allocsize = nreqs * sizeof(struct vioscsi_req); 442 r = bus_dmamem_alloc(vsc->sc_dmat, allocsize, 0, 0, 443 &sc->sc_reqs_segs[0], 1, &rsegs, BUS_DMA_NOWAIT); 444 if (r != 0) { 445 printf("bus_dmamem_alloc, size %zd, error %d\n", 446 allocsize, r); 447 return 0; 448 } 449 r = bus_dmamem_map(vsc->sc_dmat, &sc->sc_reqs_segs[0], 1, 450 allocsize, (caddr_t *)&vaddr, BUS_DMA_NOWAIT); 451 if (r != 0) { 452 printf("bus_dmamem_map failed, error %d\n", r); 453 bus_dmamem_free(vsc->sc_dmat, &sc->sc_reqs_segs[0], 1); 454 return 0; 455 } 456 sc->sc_reqs = vaddr; 457 memset(vaddr, 0, allocsize); 458 459 for (i = 0; i < nreqs; i++) { 460 /* 461 * Assign descriptors and create the DMA maps for each 462 * allocated request. 463 */ 464 vr = &sc->sc_reqs[i]; 465 r = virtio_enqueue_prep(vq, &slot); 466 if (r == 0) 467 r = virtio_enqueue_reserve(vq, slot, ALLOC_SEGS); 468 if (r != 0) 469 return i; 470 471 if (vq->vq_indirect == NULL) { 472 /* 473 * The reserved slots must be a contiguous block 474 * starting at vq_desc[slot]. 475 */ 476 vd = &vq->vq_desc[slot]; 477 for (r = 0; r < ALLOC_SEGS - 1; r++) { 478 DPRINTF("vd[%d].next = %d should be %d\n", 479 r, vd[r].next, (slot + r + 1)); 480 if (vd[r].next != (slot + r + 1)) 481 return i; 482 } 483 if (r == (ALLOC_SEGS -1) && vd[r].next != 0) 484 return i; 485 DPRINTF("Reserved slots are contiguous as required!\n"); 486 } 487 488 vr->vr_qe_index = slot; 489 vr->vr_req.id = slot; 490 vr->vr_req.task_attr = VIRTIO_SCSI_S_SIMPLE; 491 vq->vq_entries[slot].qe_vr_index = i; 492 493 r = bus_dmamap_create(vsc->sc_dmat, 494 offsetof(struct vioscsi_req, vr_xs), 1, 495 offsetof(struct vioscsi_req, vr_xs), 0, 496 BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &vr->vr_control); 497 if (r != 0) { 498 printf("bus_dmamap_create vr_control failed, error %d\n", r); 499 return i; 500 } 501 r = bus_dmamap_create(vsc->sc_dmat, MAXPHYS, SEG_MAX, 502 MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &vr->vr_data); 503 if (r != 0) { 504 printf("bus_dmamap_create vr_data failed, error %d\n", r ); 505 return i; 506 } 507 r = bus_dmamap_load(vsc->sc_dmat, vr->vr_control, 508 vr, offsetof(struct vioscsi_req, vr_xs), NULL, 509 BUS_DMA_NOWAIT); 510 if (r != 0) { 511 printf("bus_dmamap_load vr_control failed, error %d\n", r ); 512 return i; 513 } 514 515 SLIST_INSERT_HEAD(&sc->sc_freelist, vr, vr_list); 516 } 517 518 return nreqs; 519 } 520