1 /* $OpenBSD: vscsi.c,v 1.3 2009/08/13 19:51:49 dlg Exp $ */ 2 3 /* 4 * Copyright (c) 2008 David Gwynne <dlg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/buf.h> 22 #include <sys/kernel.h> 23 #include <sys/malloc.h> 24 #include <sys/device.h> 25 #include <sys/proc.h> 26 #include <sys/conf.h> 27 #include <sys/queue.h> 28 #include <sys/rwlock.h> 29 #include <sys/pool.h> 30 #include <sys/ioctl.h> 31 #include <sys/poll.h> 32 #include <sys/selinfo.h> 33 34 #include <scsi/scsi_all.h> 35 #include <scsi/scsiconf.h> 36 37 #include <dev/vscsivar.h> 38 39 #ifdef VSCSI_DEBUG 40 #define VSCSI_D_INIT (1<<0) 41 42 int vscsidebug = 0; 43 44 #define DPRINTF(_m, _p...) do { \ 45 if (ISSET(vscsidebug, (_m))) \ 46 printf(p); \ 47 } while (0) 48 #else 49 #define DPRINTF(_m, _p...) /* _m, _p */ 50 #endif 51 52 int vscsi_match(struct device *, void *, void *); 53 void vscsi_attach(struct device *, struct device *, void *); 54 void vscsi_shutdown(void *); 55 56 struct vscsi_ccb { 57 TAILQ_ENTRY(vscsi_ccb) ccb_entry; 58 int ccb_tag; 59 struct scsi_xfer *ccb_xs; 60 size_t ccb_datalen; 61 }; 62 63 TAILQ_HEAD(vscsi_ccb_list, vscsi_ccb); 64 65 struct vscsi_softc { 66 struct device sc_dev; 67 struct scsi_link sc_link; 68 struct scsibus_softc *sc_scsibus; 69 70 struct pool sc_ccb_pool; 71 struct vscsi_ccb_list sc_ccb_i2t; 72 struct vscsi_ccb_list sc_ccb_t2i; 73 int sc_ccb_tag; 74 struct mutex sc_ccb_mtx; 75 struct rwlock sc_ccb_polling; 76 77 struct selinfo sc_sel; 78 struct mutex sc_sel_mtx; 79 80 struct rwlock sc_open; 81 volatile int sc_opened; 82 }; 83 84 #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) 85 #define DEV2SC(_d) ((struct vscsi_softc *)device_lookup(&vscsi_cd, minor(_d))) 86 87 struct cfattach vscsi_ca = { 88 sizeof(struct vscsi_softc), 89 vscsi_match, 90 vscsi_attach 91 }; 92 93 struct cfdriver vscsi_cd = { 94 NULL, 95 "vscsi", 96 DV_DULL 97 }; 98 99 int vscsi_cmd(struct scsi_xfer *); 100 int vscsi_probe(struct scsi_link *); 101 102 struct scsi_adapter vscsi_switch = { 103 vscsi_cmd, 104 scsi_minphys, 105 vscsi_probe, 106 NULL 107 }; 108 109 struct scsi_device vscsi_dev = { 110 NULL, NULL, NULL, NULL 111 }; 112 113 void vscsi_xs_stuffup(struct scsi_xfer *); 114 115 116 int vscsi_i2t(struct vscsi_softc *, struct vscsi_ioc_i2t *); 117 int vscsi_data(struct vscsi_softc *, struct vscsi_ioc_data *, int); 118 int vscsi_t2i(struct vscsi_softc *, struct vscsi_ioc_t2i *); 119 120 struct vscsi_ccb * vscsi_ccb_get(struct vscsi_softc *, int); 121 #define vscsi_ccb_put(_s, _c) pool_put(&(_s)->sc_ccb_pool, (_c)) 122 123 void filt_vscsidetach(struct knote *); 124 int filt_vscsiread(struct knote *, long); 125 126 struct filterops vscsi_filtops = { 127 1, 128 NULL, 129 filt_vscsidetach, 130 filt_vscsiread 131 }; 132 133 134 int 135 vscsi_match(struct device *parent, void *match, void *aux) 136 { 137 return (1); 138 } 139 140 void 141 vscsi_attach(struct device *parent, struct device *self, void *aux) 142 { 143 struct vscsi_softc *sc = (struct vscsi_softc *)self; 144 struct scsibus_attach_args saa; 145 146 printf("\n"); 147 148 rw_init(&sc->sc_open, DEVNAME(sc)); 149 rw_init(&sc->sc_ccb_polling, DEVNAME(sc)); 150 151 sc->sc_link.device = &vscsi_dev; 152 sc->sc_link.adapter = &vscsi_switch; 153 sc->sc_link.adapter_softc = sc; 154 sc->sc_link.adapter_target = 256; 155 sc->sc_link.adapter_buswidth = 256; 156 sc->sc_link.openings = 1; 157 158 bzero(&saa, sizeof(saa)); 159 saa.saa_sc_link = &sc->sc_link; 160 161 sc->sc_scsibus = (struct scsibus_softc *)config_found(&sc->sc_dev, 162 &saa, scsiprint); 163 } 164 165 int 166 vscsi_cmd(struct scsi_xfer *xs) 167 { 168 struct scsi_link *link = xs->sc_link; 169 struct vscsi_softc *sc = link->adapter_softc; 170 struct vscsi_ccb *ccb; 171 int polled = ISSET(xs->flags, SCSI_POLL); 172 173 if (sc->sc_opened == 0) { 174 vscsi_xs_stuffup(xs); 175 return (COMPLETE); 176 } 177 178 if (ISSET(xs->flags, SCSI_POLL) && ISSET(xs->flags, SCSI_NOSLEEP)) { 179 printf("%s: POLL && NOSLEEP for 0x%02x\n", DEVNAME(sc), 180 xs->cmd->opcode); 181 vscsi_xs_stuffup(xs); 182 return (COMPLETE); 183 } 184 185 ccb = vscsi_ccb_get(sc, ISSET(xs->flags, SCSI_NOSLEEP) ? 0 : 1); 186 if (ccb == NULL) { 187 vscsi_xs_stuffup(xs); 188 return (COMPLETE); 189 } 190 191 ccb->ccb_xs = xs; 192 mtx_enter(&sc->sc_ccb_mtx); 193 TAILQ_INSERT_TAIL(&sc->sc_ccb_i2t, ccb, ccb_entry); 194 mtx_leave(&sc->sc_ccb_mtx); 195 196 selwakeup(&sc->sc_sel); 197 KNOTE(&sc->sc_sel.si_note, 0); 198 199 if (polled) { 200 rw_enter_read(&sc->sc_ccb_polling); 201 while (ccb->ccb_xs != NULL) 202 tsleep(ccb, PRIBIO, "vscsipoll", 0); 203 vscsi_ccb_put(sc, ccb); 204 rw_exit_read(&sc->sc_ccb_polling); 205 return (COMPLETE); 206 } 207 208 return (SUCCESSFULLY_QUEUED); 209 } 210 211 void 212 vscsi_xs_stuffup(struct scsi_xfer *xs) 213 { 214 int s; 215 216 xs->error = XS_DRIVER_STUFFUP; 217 xs->flags |= ITSDONE; 218 s = splbio(); 219 scsi_done(xs); 220 splx(s); 221 } 222 223 int 224 vscsi_probe(struct scsi_link *link) 225 { 226 struct vscsi_softc *sc = link->adapter_softc; 227 228 if (sc->sc_opened == 0) 229 return (ENXIO); 230 231 return (0); 232 } 233 234 int 235 vscsiopen(dev_t dev, int flags, int mode, struct proc *p) 236 { 237 struct vscsi_softc *sc = DEV2SC(dev); 238 int rv; 239 240 if (sc == NULL) 241 return (ENXIO); 242 243 rv = rw_enter(&sc->sc_open, RW_WRITE | RW_NOSLEEP); 244 if (rv != 0) 245 return (rv); 246 247 pool_init(&sc->sc_ccb_pool, sizeof(struct vscsi_ccb), 0, 0, 0, 248 "vscsiccb", NULL); 249 pool_setipl(&sc->sc_ccb_pool, IPL_BIO); 250 TAILQ_INIT(&sc->sc_ccb_i2t); 251 TAILQ_INIT(&sc->sc_ccb_t2i); 252 mtx_init(&sc->sc_ccb_mtx, IPL_BIO); 253 mtx_init(&sc->sc_sel_mtx, IPL_BIO); 254 255 sc->sc_opened = 1; 256 257 return (0); 258 } 259 260 int 261 vscsiioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 262 { 263 struct vscsi_softc *sc = DEV2SC(dev); 264 struct vscsi_ioc_devevent *de = (struct vscsi_ioc_devevent *)addr; 265 int read = 0; 266 int err = 0; 267 268 switch (cmd) { 269 case VSCSI_I2T: 270 err = vscsi_i2t(sc, (struct vscsi_ioc_i2t *)addr); 271 break; 272 273 case VSCSI_DATA_READ: 274 read = 1; 275 case VSCSI_DATA_WRITE: 276 err = vscsi_data(sc, (struct vscsi_ioc_data *)addr, read); 277 break; 278 279 case VSCSI_T2I: 280 err = vscsi_t2i(sc, (struct vscsi_ioc_t2i *)addr); 281 break; 282 283 case VSCSI_REQPROBE: 284 err = scsi_req_probe(sc->sc_scsibus, de->target, de->lun); 285 break; 286 287 case VSCSI_REQDETACH: 288 err = scsi_req_detach(sc->sc_scsibus, de->target, de->lun, 289 DETACH_FORCE); 290 break; 291 292 default: 293 err = ENOTTY; 294 break; 295 } 296 297 return (err); 298 } 299 300 int 301 vscsi_i2t(struct vscsi_softc *sc, struct vscsi_ioc_i2t *i2t) 302 { 303 struct vscsi_ccb *ccb; 304 struct scsi_xfer *xs; 305 struct scsi_link *link; 306 307 mtx_enter(&sc->sc_ccb_mtx); 308 ccb = TAILQ_FIRST(&sc->sc_ccb_i2t); 309 if (ccb != NULL) 310 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry); 311 mtx_leave(&sc->sc_ccb_mtx); 312 313 if (ccb == NULL) 314 return (EAGAIN); 315 316 xs = ccb->ccb_xs; 317 link = xs->sc_link; 318 319 i2t->tag = ccb->ccb_tag; 320 i2t->target = link->target; 321 i2t->lun = link->lun; 322 bcopy(xs->cmd, &i2t->cmd, xs->cmdlen); 323 i2t->cmdlen = xs->cmdlen; 324 i2t->datalen = xs->datalen; 325 326 switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 327 case SCSI_DATA_IN: 328 i2t->direction = VSCSI_DIR_READ; 329 break; 330 case SCSI_DATA_OUT: 331 i2t->direction = VSCSI_DIR_WRITE; 332 break; 333 default: 334 i2t->direction = VSCSI_DIR_NONE; 335 break; 336 } 337 338 TAILQ_INSERT_TAIL(&sc->sc_ccb_t2i, ccb, ccb_entry); 339 340 return (0); 341 } 342 343 int 344 vscsi_data(struct vscsi_softc *sc, struct vscsi_ioc_data *data, int read) 345 { 346 struct vscsi_ccb *ccb; 347 struct scsi_xfer *xs; 348 int xsread; 349 u_int8_t *buf; 350 int rv = EINVAL; 351 352 TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) { 353 if (ccb->ccb_tag == data->tag) 354 break; 355 } 356 if (ccb == NULL) 357 return (EFAULT); 358 359 xs = ccb->ccb_xs; 360 361 if (data->datalen + ccb->ccb_datalen > xs->datalen) 362 return (ENOMEM); 363 364 switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 365 case SCSI_DATA_IN: 366 xsread = 1; 367 break; 368 case SCSI_DATA_OUT: 369 xsread = 0; 370 break; 371 default: 372 return (EINVAL); 373 } 374 375 if (read != xsread) 376 return (EINVAL); 377 378 buf = xs->data; 379 buf += ccb->ccb_datalen; 380 381 if (read) 382 rv = copyin(data->data, buf, data->datalen); 383 else 384 rv = copyout(buf, data->data, data->datalen); 385 386 if (rv == 0) 387 ccb->ccb_datalen += data->datalen; 388 389 return (rv); 390 } 391 392 int 393 vscsi_t2i(struct vscsi_softc *sc, struct vscsi_ioc_t2i *t2i) 394 { 395 struct vscsi_ccb *ccb; 396 struct scsi_xfer *xs; 397 struct scsi_link *link; 398 int rv = 0; 399 int polled; 400 int s; 401 402 TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) { 403 if (ccb->ccb_tag == t2i->tag) 404 break; 405 } 406 if (ccb == NULL) 407 return (EFAULT); 408 409 TAILQ_REMOVE(&sc->sc_ccb_t2i, ccb, ccb_entry); 410 411 xs = ccb->ccb_xs; 412 link = xs->sc_link; 413 414 xs->resid = xs->datalen - ccb->ccb_datalen; 415 xs->status = SCSI_OK; 416 417 switch (t2i->status) { 418 case VSCSI_STAT_DONE: 419 xs->error = XS_NOERROR; 420 break; 421 case VSCSI_STAT_SENSE: 422 xs->error = XS_SENSE; 423 bcopy(&t2i->sense, &xs->sense, t2i->senselen); 424 xs->req_sense_length = t2i->senselen; 425 break; 426 case VSCSI_STAT_ERR: 427 default: 428 xs->error = XS_DRIVER_STUFFUP; 429 break; 430 } 431 432 polled = ISSET(xs->flags, SCSI_POLL); 433 434 xs->flags |= ITSDONE; 435 s = splbio(); 436 scsi_done(xs); 437 splx(s); 438 439 if (polled) { 440 ccb->ccb_xs = NULL; 441 wakeup(ccb); 442 } else 443 vscsi_ccb_put(sc, ccb); 444 445 return (rv); 446 } 447 448 int 449 vscsipoll(dev_t dev, int events, struct proc *p) 450 { 451 struct vscsi_softc *sc = DEV2SC(dev); 452 int revents = 0; 453 454 if (events & (POLLIN | POLLRDNORM)) { 455 mtx_enter(&sc->sc_ccb_mtx); 456 if (!TAILQ_EMPTY(&sc->sc_ccb_i2t)) 457 revents |= events & (POLLIN | POLLRDNORM); 458 mtx_leave(&sc->sc_ccb_mtx); 459 } 460 461 if (revents == 0) { 462 if (events & (POLLIN | POLLRDNORM)) 463 selrecord(p, &sc->sc_sel); 464 } 465 466 return (revents); 467 } 468 469 int 470 vscsikqfilter(dev_t dev, struct knote *kn) 471 { 472 struct vscsi_softc *sc = DEV2SC(dev); 473 struct klist *klist = &sc->sc_sel.si_note; 474 475 switch (kn->kn_filter) { 476 case EVFILT_READ: 477 kn->kn_fop = &vscsi_filtops; 478 break; 479 default: 480 return (1); 481 } 482 483 kn->kn_hook = (caddr_t)sc; 484 485 mtx_enter(&sc->sc_sel_mtx); 486 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 487 mtx_leave(&sc->sc_sel_mtx); 488 489 return (0); 490 } 491 492 void 493 filt_vscsidetach(struct knote *kn) 494 { 495 struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook; 496 struct klist *klist = &sc->sc_sel.si_note; 497 498 mtx_enter(&sc->sc_sel_mtx); 499 SLIST_REMOVE(klist, kn, knote, kn_selnext); 500 mtx_leave(&sc->sc_sel_mtx); 501 } 502 503 int 504 filt_vscsiread(struct knote *kn, long hint) 505 { 506 struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook; 507 int event = 0; 508 509 mtx_enter(&sc->sc_ccb_mtx); 510 if (!TAILQ_EMPTY(&sc->sc_ccb_i2t)) 511 event = 1; 512 mtx_leave(&sc->sc_ccb_mtx); 513 514 return (event); 515 } 516 517 int 518 vscsiclose(dev_t dev, int flags, int mode, struct proc *p) 519 { 520 struct vscsi_softc *sc = DEV2SC(dev); 521 struct vscsi_ccb *ccb; 522 int polled; 523 int i; 524 525 sc->sc_opened = 0; 526 527 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_t2i)) != NULL) { 528 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry); 529 polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL); 530 531 vscsi_xs_stuffup(ccb->ccb_xs); 532 533 if (polled) { 534 ccb->ccb_xs = NULL; 535 wakeup(ccb); 536 } else 537 vscsi_ccb_put(sc, ccb); 538 } 539 540 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_i2t)) != NULL) { 541 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry); 542 polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL); 543 544 vscsi_xs_stuffup(ccb->ccb_xs); 545 546 if (polled) { 547 ccb->ccb_xs = NULL; 548 wakeup(ccb); 549 } else 550 vscsi_ccb_put(sc, ccb); 551 } 552 553 rw_enter_write(&sc->sc_ccb_polling); 554 pool_destroy(&sc->sc_ccb_pool); 555 rw_exit_write(&sc->sc_ccb_polling); 556 557 for (i = 0; i < sc->sc_link.adapter_buswidth; i++) 558 scsi_detach_target(sc->sc_scsibus, i, DETACH_FORCE); 559 560 rw_exit(&sc->sc_open); 561 562 return (0); 563 } 564 565 struct vscsi_ccb * 566 vscsi_ccb_get(struct vscsi_softc *sc, int waitok) 567 { 568 struct vscsi_ccb *ccb; 569 570 ccb = pool_get(&sc->sc_ccb_pool, waitok ? PR_WAITOK : PR_NOWAIT); 571 if (ccb == NULL) 572 return (NULL); 573 574 ccb->ccb_tag = sc->sc_ccb_tag++; 575 ccb->ccb_datalen = 0; 576 577 return (ccb); 578 } 579