1 /* $OpenBSD: vscsi.c,v 1.4 2009/11/09 17:53:39 nicm 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 198 if (polled) { 199 rw_enter_read(&sc->sc_ccb_polling); 200 while (ccb->ccb_xs != NULL) 201 tsleep(ccb, PRIBIO, "vscsipoll", 0); 202 vscsi_ccb_put(sc, ccb); 203 rw_exit_read(&sc->sc_ccb_polling); 204 return (COMPLETE); 205 } 206 207 return (SUCCESSFULLY_QUEUED); 208 } 209 210 void 211 vscsi_xs_stuffup(struct scsi_xfer *xs) 212 { 213 int s; 214 215 xs->error = XS_DRIVER_STUFFUP; 216 xs->flags |= ITSDONE; 217 s = splbio(); 218 scsi_done(xs); 219 splx(s); 220 } 221 222 int 223 vscsi_probe(struct scsi_link *link) 224 { 225 struct vscsi_softc *sc = link->adapter_softc; 226 227 if (sc->sc_opened == 0) 228 return (ENXIO); 229 230 return (0); 231 } 232 233 int 234 vscsiopen(dev_t dev, int flags, int mode, struct proc *p) 235 { 236 struct vscsi_softc *sc = DEV2SC(dev); 237 int rv; 238 239 if (sc == NULL) 240 return (ENXIO); 241 242 rv = rw_enter(&sc->sc_open, RW_WRITE | RW_NOSLEEP); 243 if (rv != 0) 244 return (rv); 245 246 pool_init(&sc->sc_ccb_pool, sizeof(struct vscsi_ccb), 0, 0, 0, 247 "vscsiccb", NULL); 248 pool_setipl(&sc->sc_ccb_pool, IPL_BIO); 249 TAILQ_INIT(&sc->sc_ccb_i2t); 250 TAILQ_INIT(&sc->sc_ccb_t2i); 251 mtx_init(&sc->sc_ccb_mtx, IPL_BIO); 252 mtx_init(&sc->sc_sel_mtx, IPL_BIO); 253 254 sc->sc_opened = 1; 255 256 return (0); 257 } 258 259 int 260 vscsiioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 261 { 262 struct vscsi_softc *sc = DEV2SC(dev); 263 struct vscsi_ioc_devevent *de = (struct vscsi_ioc_devevent *)addr; 264 int read = 0; 265 int err = 0; 266 267 switch (cmd) { 268 case VSCSI_I2T: 269 err = vscsi_i2t(sc, (struct vscsi_ioc_i2t *)addr); 270 break; 271 272 case VSCSI_DATA_READ: 273 read = 1; 274 case VSCSI_DATA_WRITE: 275 err = vscsi_data(sc, (struct vscsi_ioc_data *)addr, read); 276 break; 277 278 case VSCSI_T2I: 279 err = vscsi_t2i(sc, (struct vscsi_ioc_t2i *)addr); 280 break; 281 282 case VSCSI_REQPROBE: 283 err = scsi_req_probe(sc->sc_scsibus, de->target, de->lun); 284 break; 285 286 case VSCSI_REQDETACH: 287 err = scsi_req_detach(sc->sc_scsibus, de->target, de->lun, 288 DETACH_FORCE); 289 break; 290 291 default: 292 err = ENOTTY; 293 break; 294 } 295 296 return (err); 297 } 298 299 int 300 vscsi_i2t(struct vscsi_softc *sc, struct vscsi_ioc_i2t *i2t) 301 { 302 struct vscsi_ccb *ccb; 303 struct scsi_xfer *xs; 304 struct scsi_link *link; 305 306 mtx_enter(&sc->sc_ccb_mtx); 307 ccb = TAILQ_FIRST(&sc->sc_ccb_i2t); 308 if (ccb != NULL) 309 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry); 310 mtx_leave(&sc->sc_ccb_mtx); 311 312 if (ccb == NULL) 313 return (EAGAIN); 314 315 xs = ccb->ccb_xs; 316 link = xs->sc_link; 317 318 i2t->tag = ccb->ccb_tag; 319 i2t->target = link->target; 320 i2t->lun = link->lun; 321 bcopy(xs->cmd, &i2t->cmd, xs->cmdlen); 322 i2t->cmdlen = xs->cmdlen; 323 i2t->datalen = xs->datalen; 324 325 switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 326 case SCSI_DATA_IN: 327 i2t->direction = VSCSI_DIR_READ; 328 break; 329 case SCSI_DATA_OUT: 330 i2t->direction = VSCSI_DIR_WRITE; 331 break; 332 default: 333 i2t->direction = VSCSI_DIR_NONE; 334 break; 335 } 336 337 TAILQ_INSERT_TAIL(&sc->sc_ccb_t2i, ccb, ccb_entry); 338 339 return (0); 340 } 341 342 int 343 vscsi_data(struct vscsi_softc *sc, struct vscsi_ioc_data *data, int read) 344 { 345 struct vscsi_ccb *ccb; 346 struct scsi_xfer *xs; 347 int xsread; 348 u_int8_t *buf; 349 int rv = EINVAL; 350 351 TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) { 352 if (ccb->ccb_tag == data->tag) 353 break; 354 } 355 if (ccb == NULL) 356 return (EFAULT); 357 358 xs = ccb->ccb_xs; 359 360 if (data->datalen + ccb->ccb_datalen > xs->datalen) 361 return (ENOMEM); 362 363 switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 364 case SCSI_DATA_IN: 365 xsread = 1; 366 break; 367 case SCSI_DATA_OUT: 368 xsread = 0; 369 break; 370 default: 371 return (EINVAL); 372 } 373 374 if (read != xsread) 375 return (EINVAL); 376 377 buf = xs->data; 378 buf += ccb->ccb_datalen; 379 380 if (read) 381 rv = copyin(data->data, buf, data->datalen); 382 else 383 rv = copyout(buf, data->data, data->datalen); 384 385 if (rv == 0) 386 ccb->ccb_datalen += data->datalen; 387 388 return (rv); 389 } 390 391 int 392 vscsi_t2i(struct vscsi_softc *sc, struct vscsi_ioc_t2i *t2i) 393 { 394 struct vscsi_ccb *ccb; 395 struct scsi_xfer *xs; 396 struct scsi_link *link; 397 int rv = 0; 398 int polled; 399 int s; 400 401 TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) { 402 if (ccb->ccb_tag == t2i->tag) 403 break; 404 } 405 if (ccb == NULL) 406 return (EFAULT); 407 408 TAILQ_REMOVE(&sc->sc_ccb_t2i, ccb, ccb_entry); 409 410 xs = ccb->ccb_xs; 411 link = xs->sc_link; 412 413 xs->resid = xs->datalen - ccb->ccb_datalen; 414 xs->status = SCSI_OK; 415 416 switch (t2i->status) { 417 case VSCSI_STAT_DONE: 418 xs->error = XS_NOERROR; 419 break; 420 case VSCSI_STAT_SENSE: 421 xs->error = XS_SENSE; 422 bcopy(&t2i->sense, &xs->sense, t2i->senselen); 423 xs->req_sense_length = t2i->senselen; 424 break; 425 case VSCSI_STAT_ERR: 426 default: 427 xs->error = XS_DRIVER_STUFFUP; 428 break; 429 } 430 431 polled = ISSET(xs->flags, SCSI_POLL); 432 433 xs->flags |= ITSDONE; 434 s = splbio(); 435 scsi_done(xs); 436 splx(s); 437 438 if (polled) { 439 ccb->ccb_xs = NULL; 440 wakeup(ccb); 441 } else 442 vscsi_ccb_put(sc, ccb); 443 444 return (rv); 445 } 446 447 int 448 vscsipoll(dev_t dev, int events, struct proc *p) 449 { 450 struct vscsi_softc *sc = DEV2SC(dev); 451 int revents = 0; 452 453 if (events & (POLLIN | POLLRDNORM)) { 454 mtx_enter(&sc->sc_ccb_mtx); 455 if (!TAILQ_EMPTY(&sc->sc_ccb_i2t)) 456 revents |= events & (POLLIN | POLLRDNORM); 457 mtx_leave(&sc->sc_ccb_mtx); 458 } 459 460 if (revents == 0) { 461 if (events & (POLLIN | POLLRDNORM)) 462 selrecord(p, &sc->sc_sel); 463 } 464 465 return (revents); 466 } 467 468 int 469 vscsikqfilter(dev_t dev, struct knote *kn) 470 { 471 struct vscsi_softc *sc = DEV2SC(dev); 472 struct klist *klist = &sc->sc_sel.si_note; 473 474 switch (kn->kn_filter) { 475 case EVFILT_READ: 476 kn->kn_fop = &vscsi_filtops; 477 break; 478 default: 479 return (1); 480 } 481 482 kn->kn_hook = (caddr_t)sc; 483 484 mtx_enter(&sc->sc_sel_mtx); 485 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 486 mtx_leave(&sc->sc_sel_mtx); 487 488 return (0); 489 } 490 491 void 492 filt_vscsidetach(struct knote *kn) 493 { 494 struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook; 495 struct klist *klist = &sc->sc_sel.si_note; 496 497 mtx_enter(&sc->sc_sel_mtx); 498 SLIST_REMOVE(klist, kn, knote, kn_selnext); 499 mtx_leave(&sc->sc_sel_mtx); 500 } 501 502 int 503 filt_vscsiread(struct knote *kn, long hint) 504 { 505 struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook; 506 int event = 0; 507 508 mtx_enter(&sc->sc_ccb_mtx); 509 if (!TAILQ_EMPTY(&sc->sc_ccb_i2t)) 510 event = 1; 511 mtx_leave(&sc->sc_ccb_mtx); 512 513 return (event); 514 } 515 516 int 517 vscsiclose(dev_t dev, int flags, int mode, struct proc *p) 518 { 519 struct vscsi_softc *sc = DEV2SC(dev); 520 struct vscsi_ccb *ccb; 521 int polled; 522 int i; 523 524 sc->sc_opened = 0; 525 526 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_t2i)) != NULL) { 527 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry); 528 polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL); 529 530 vscsi_xs_stuffup(ccb->ccb_xs); 531 532 if (polled) { 533 ccb->ccb_xs = NULL; 534 wakeup(ccb); 535 } else 536 vscsi_ccb_put(sc, ccb); 537 } 538 539 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_i2t)) != NULL) { 540 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry); 541 polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL); 542 543 vscsi_xs_stuffup(ccb->ccb_xs); 544 545 if (polled) { 546 ccb->ccb_xs = NULL; 547 wakeup(ccb); 548 } else 549 vscsi_ccb_put(sc, ccb); 550 } 551 552 rw_enter_write(&sc->sc_ccb_polling); 553 pool_destroy(&sc->sc_ccb_pool); 554 rw_exit_write(&sc->sc_ccb_polling); 555 556 for (i = 0; i < sc->sc_link.adapter_buswidth; i++) 557 scsi_detach_target(sc->sc_scsibus, i, DETACH_FORCE); 558 559 rw_exit(&sc->sc_open); 560 561 return (0); 562 } 563 564 struct vscsi_ccb * 565 vscsi_ccb_get(struct vscsi_softc *sc, int waitok) 566 { 567 struct vscsi_ccb *ccb; 568 569 ccb = pool_get(&sc->sc_ccb_pool, waitok ? PR_WAITOK : PR_NOWAIT); 570 if (ccb == NULL) 571 return (NULL); 572 573 ccb->ccb_tag = sc->sc_ccb_tag++; 574 ccb->ccb_datalen = 0; 575 576 return (ccb); 577 } 578