1 /* $OpenBSD: vscsi.c,v 1.2 2009/02/16 21:19:06 miod 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 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 default: 283 err = ENOTTY; 284 break; 285 } 286 287 return (err); 288 } 289 290 int 291 vscsi_i2t(struct vscsi_softc *sc, struct vscsi_ioc_i2t *i2t) 292 { 293 struct vscsi_ccb *ccb; 294 struct scsi_xfer *xs; 295 struct scsi_link *link; 296 297 mtx_enter(&sc->sc_ccb_mtx); 298 ccb = TAILQ_FIRST(&sc->sc_ccb_i2t); 299 if (ccb != NULL) 300 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry); 301 mtx_leave(&sc->sc_ccb_mtx); 302 303 if (ccb == NULL) 304 return (EAGAIN); 305 306 xs = ccb->ccb_xs; 307 link = xs->sc_link; 308 309 i2t->tag = ccb->ccb_tag; 310 i2t->target = link->target; 311 i2t->lun = link->lun; 312 bcopy(xs->cmd, &i2t->cmd, xs->cmdlen); 313 i2t->cmdlen = xs->cmdlen; 314 i2t->datalen = xs->datalen; 315 316 switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 317 case SCSI_DATA_IN: 318 i2t->direction = VSCSI_DIR_READ; 319 break; 320 case SCSI_DATA_OUT: 321 i2t->direction = VSCSI_DIR_WRITE; 322 break; 323 default: 324 i2t->direction = VSCSI_DIR_NONE; 325 break; 326 } 327 328 TAILQ_INSERT_TAIL(&sc->sc_ccb_t2i, ccb, ccb_entry); 329 330 return (0); 331 } 332 333 int 334 vscsi_data(struct vscsi_softc *sc, struct vscsi_ioc_data *data, int read) 335 { 336 struct vscsi_ccb *ccb; 337 struct scsi_xfer *xs; 338 int xsread; 339 u_int8_t *buf; 340 int rv = EINVAL; 341 342 TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) { 343 if (ccb->ccb_tag == data->tag) 344 break; 345 } 346 if (ccb == NULL) 347 return (EFAULT); 348 349 xs = ccb->ccb_xs; 350 351 if (data->datalen + ccb->ccb_datalen > xs->datalen) 352 return (ENOMEM); 353 354 switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 355 case SCSI_DATA_IN: 356 xsread = 1; 357 break; 358 case SCSI_DATA_OUT: 359 xsread = 0; 360 break; 361 default: 362 return (EINVAL); 363 } 364 365 if (read != xsread) 366 return (EINVAL); 367 368 buf = xs->data; 369 buf += ccb->ccb_datalen; 370 371 if (read) 372 rv = copyin(data->data, buf, data->datalen); 373 else 374 rv = copyout(buf, data->data, data->datalen); 375 376 if (rv == 0) 377 ccb->ccb_datalen += data->datalen; 378 379 return (rv); 380 } 381 382 int 383 vscsi_t2i(struct vscsi_softc *sc, struct vscsi_ioc_t2i *t2i) 384 { 385 struct vscsi_ccb *ccb; 386 struct scsi_xfer *xs; 387 struct scsi_link *link; 388 int rv = 0; 389 int polled; 390 int s; 391 392 TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) { 393 if (ccb->ccb_tag == t2i->tag) 394 break; 395 } 396 if (ccb == NULL) 397 return (EFAULT); 398 399 TAILQ_REMOVE(&sc->sc_ccb_t2i, ccb, ccb_entry); 400 401 xs = ccb->ccb_xs; 402 link = xs->sc_link; 403 404 xs->resid = xs->datalen - ccb->ccb_datalen; 405 xs->status = SCSI_OK; 406 407 switch (t2i->status) { 408 case VSCSI_STAT_DONE: 409 xs->error = XS_NOERROR; 410 break; 411 case VSCSI_STAT_SENSE: 412 xs->error = XS_SENSE; 413 bcopy(&t2i->sense, &xs->sense, t2i->senselen); 414 xs->req_sense_length = t2i->senselen; 415 break; 416 case VSCSI_STAT_ERR: 417 default: 418 xs->error = XS_DRIVER_STUFFUP; 419 break; 420 } 421 422 polled = ISSET(xs->flags, SCSI_POLL); 423 424 xs->flags |= ITSDONE; 425 s = splbio(); 426 scsi_done(xs); 427 splx(s); 428 429 if (polled) { 430 ccb->ccb_xs = NULL; 431 wakeup(ccb); 432 } else 433 vscsi_ccb_put(sc, ccb); 434 435 return (rv); 436 } 437 438 int 439 vscsipoll(dev_t dev, int events, struct proc *p) 440 { 441 struct vscsi_softc *sc = DEV2SC(dev); 442 int revents = 0; 443 444 if (events & (POLLIN | POLLRDNORM)) { 445 mtx_enter(&sc->sc_ccb_mtx); 446 if (!TAILQ_EMPTY(&sc->sc_ccb_i2t)) 447 revents |= events & (POLLIN | POLLRDNORM); 448 mtx_leave(&sc->sc_ccb_mtx); 449 } 450 451 if (revents == 0) { 452 if (events & (POLLIN | POLLRDNORM)) 453 selrecord(p, &sc->sc_sel); 454 } 455 456 return (revents); 457 } 458 459 int 460 vscsikqfilter(dev_t dev, struct knote *kn) 461 { 462 struct vscsi_softc *sc = DEV2SC(dev); 463 struct klist *klist = &sc->sc_sel.si_note; 464 465 switch (kn->kn_filter) { 466 case EVFILT_READ: 467 kn->kn_fop = &vscsi_filtops; 468 break; 469 default: 470 return (1); 471 } 472 473 kn->kn_hook = (caddr_t)sc; 474 475 mtx_enter(&sc->sc_sel_mtx); 476 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 477 mtx_leave(&sc->sc_sel_mtx); 478 479 return (0); 480 } 481 482 void 483 filt_vscsidetach(struct knote *kn) 484 { 485 struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook; 486 struct klist *klist = &sc->sc_sel.si_note; 487 488 mtx_enter(&sc->sc_sel_mtx); 489 SLIST_REMOVE(klist, kn, knote, kn_selnext); 490 mtx_leave(&sc->sc_sel_mtx); 491 } 492 493 int 494 filt_vscsiread(struct knote *kn, long hint) 495 { 496 struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook; 497 int event = 0; 498 499 mtx_enter(&sc->sc_ccb_mtx); 500 if (!TAILQ_EMPTY(&sc->sc_ccb_i2t)) 501 event = 1; 502 mtx_leave(&sc->sc_ccb_mtx); 503 504 return (event); 505 } 506 507 int 508 vscsiclose(dev_t dev, int flags, int mode, struct proc *p) 509 { 510 struct vscsi_softc *sc = DEV2SC(dev); 511 struct vscsi_ccb *ccb; 512 int polled; 513 int i; 514 515 sc->sc_opened = 0; 516 517 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_t2i)) != NULL) { 518 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry); 519 polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL); 520 521 vscsi_xs_stuffup(ccb->ccb_xs); 522 523 if (polled) { 524 ccb->ccb_xs = NULL; 525 wakeup(ccb); 526 } else 527 vscsi_ccb_put(sc, ccb); 528 } 529 530 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_i2t)) != NULL) { 531 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry); 532 polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL); 533 534 vscsi_xs_stuffup(ccb->ccb_xs); 535 536 if (polled) { 537 ccb->ccb_xs = NULL; 538 wakeup(ccb); 539 } else 540 vscsi_ccb_put(sc, ccb); 541 } 542 543 rw_enter_write(&sc->sc_ccb_polling); 544 pool_destroy(&sc->sc_ccb_pool); 545 rw_exit_write(&sc->sc_ccb_polling); 546 547 for (i = 0; i < sc->sc_link.adapter_buswidth; i++) 548 scsi_detach_target(sc->sc_scsibus, i, DETACH_FORCE); 549 550 rw_exit(&sc->sc_open); 551 552 return (0); 553 } 554 555 struct vscsi_ccb * 556 vscsi_ccb_get(struct vscsi_softc *sc, int waitok) 557 { 558 struct vscsi_ccb *ccb; 559 560 ccb = pool_get(&sc->sc_ccb_pool, waitok ? PR_WAITOK : PR_NOWAIT); 561 if (ccb == NULL) 562 return (NULL); 563 564 ccb->ccb_tag = sc->sc_ccb_tag++; 565 ccb->ccb_datalen = 0; 566 567 return (ccb); 568 } 569