1 /* $NetBSD: gdrom.c,v 1.1 2016/12/29 11:49:05 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 Marcus Comstedt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Marcus Comstedt. 18 * 4. Neither the name of The NetBSD Foundation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * WIP gdrom driver using MI ATA/ATAPI drivers. 37 * 38 * XXX: Still not functional because GD-ROM driver does not generate 39 * XXX: interrupts after ATAPI command packet xfers and such quirks 40 * XXX: need to be handled in MI scsipi layer. 41 */ 42 43 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 44 __KERNEL_RCSID(0, "$NetBSD: gdrom.c,v 1.1 2016/12/29 11:49:05 tsutsui Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/device.h> 49 50 #include <sys/buf.h> 51 #include <sys/bufq.h> 52 #include <sys/ioctl.h> 53 #include <sys/fcntl.h> 54 #include <sys/disklabel.h> 55 #include <sys/disk.h> 56 #include <sys/cdio.h> 57 #include <sys/proc.h> 58 #include <sys/conf.h> 59 #include <sys/scsiio.h> 60 61 #include <dev/scsipi/scsi_spc.h> 62 #include <dev/scsipi/scsipi_all.h> 63 #include <dev/scsipi/scsipi_cd.h> 64 #include <dev/scsipi/scsipi_disk.h> 65 #include <dev/scsipi/scsi_all.h> 66 #include <dev/scsipi/scsi_disk.h> 67 #include <dev/scsipi/scsipiconf.h> 68 #include <dev/scsipi/scsipi_base.h> 69 70 #include "ioconf.h" 71 72 struct gdrom_softc { 73 device_t sc_dev; /* generic device info */ 74 struct disk sc_dk; /* generic disk info */ 75 struct bufq_state *sc_bufq; /* device buffer queue */ 76 struct buf curbuf; /* state of current I/O operation */ 77 78 kmutex_t sc_lock; 79 struct scsipi_periph *sc_periph; 80 81 bool is_open; 82 bool is_busy; 83 bool is_active; 84 int openpart_start; /* start sector of currently open partition */ 85 86 int cmd_active; 87 void *cmd_result_buf; /* where to store result data (16 bit aligned) */ 88 int cmd_result_size; /* number of bytes allocated for buf */ 89 int cmd_actual; /* number of bytes actually read */ 90 int cmd_cond; /* resulting condition of command */ 91 }; 92 93 struct gd_toc { 94 unsigned int entry[99]; 95 unsigned int first, last; 96 unsigned int leadout; 97 }; 98 99 static int gdrommatch(device_t, cfdata_t, void *); 100 static void gdromattach(device_t, device_t, void *); 101 102 #if 0 103 static int gdrom_command_sense(struct gdrom_softc *, void *, void *, 104 unsigned int, int *); 105 #endif 106 static int gdrom_read_toc(struct gdrom_softc *, struct gd_toc *); 107 static int gdrom_read_sectors(struct gdrom_softc *, struct buf *); 108 static int gdrom_mount_disk(struct gdrom_softc *); 109 static void gdrom_start(struct scsipi_periph *); 110 static void gdrom_done(struct scsipi_xfer *, int); 111 112 static const struct scsipi_inquiry_pattern gdrom_patterns[] = { 113 {T_DIRECT, T_FIXED, 114 "", "DCR-MOD", ""}, 115 }; 116 117 static dev_type_open(gdromopen); 118 static dev_type_close(gdromclose); 119 static dev_type_read(gdromread); 120 static dev_type_write(gdromwrite); 121 static dev_type_ioctl(gdromioctl); 122 static dev_type_strategy(gdromstrategy); 123 124 const struct bdevsw gdrom_bdevsw = { 125 .d_open = gdromopen, 126 .d_close = gdromclose, 127 .d_strategy = gdromstrategy, 128 .d_ioctl = gdromioctl, 129 .d_dump = nodump, 130 .d_psize = nosize, 131 .d_discard = nodiscard, 132 .d_flag = D_DISK 133 }; 134 135 const struct cdevsw gdrom_cdevsw = { 136 .d_open = gdromopen, 137 .d_close = gdromclose, 138 .d_read = gdromread, 139 .d_write = gdromwrite, 140 .d_ioctl = gdromioctl, 141 .d_stop = nostop, 142 .d_tty = notty, 143 .d_poll = nopoll, 144 .d_mmap = nommap, 145 .d_kqfilter = nokqfilter, 146 .d_discard = nodiscard, 147 .d_flag = D_DISK 148 }; 149 150 CFATTACH_DECL_NEW(gdrom, sizeof(struct gdrom_softc), 151 gdrommatch, gdromattach, NULL, NULL); 152 153 struct dkdriver gdromdkdriver = { 154 .d_strategy = gdromstrategy 155 }; 156 157 static const struct scsipi_periphsw gdrom_switch = { 158 NULL/*gdrom_interpret_sense*/, /* use our error handler first */ 159 gdrom_start, /* we have a queue, which is started by this */ 160 NULL, /* we do not have an async handler */ 161 gdrom_done, /* deal with stats at interrupt time */ 162 }; 163 164 #define GDROMDEBUG 165 #ifdef GDROMDEBUG 166 int gdrom_debug = 0; /* patchable */ 167 #define GDROM_DPRINTF(x) if (gdrom_debug) printf x 168 #else 169 #define GDROM_DPRINTF(x) /**/ 170 #endif 171 172 #define TOC_LBA(n) ((n) & 0xffffff00) 173 #define TOC_ADR(n) ((n) & 0x0f) 174 #define TOC_CTRL(n) (((n) & 0xf0) >> 4) 175 #define TOC_TRACK(n) (((n) & 0x0000ff00) >> 8) 176 177 #if 0 178 int gdrom_command_sense(struct gdrom_softc *sc, void *req, void *buf, 179 unsigned int nbyt, int *resid) 180 { 181 /* 182 * 76543210 76543210 183 * 0 0x13 - 184 * 2 - bufsz(hi) 185 * 4 bufsz(lo) - 186 * 6 - - 187 * 8 - - 188 * 10 - - 189 */ 190 uint16_t sense_data[5]; 191 uint8_t cmd[12]; 192 int cond, sense_key, sense_specific; 193 194 cond = scsipi_command(sc->sc_periph, req, 12, buf, nbyt, 195 4, 3000, NULL, XS_CTL_DATA_IN); 196 if (resid != NULL) 197 *resid = nbyt; 198 199 if (cond < 0) { 200 GDROM_DPRINTF(("GDROM: not ready (2:58)\n")); 201 return EIO; 202 } 203 204 if ((cond & 1) == 0) { 205 GDROM_DPRINTF(("GDROM: no sense. 0:0\n")); 206 return 0; 207 } 208 209 memset(cmd, 0, sizeof(cmd)); 210 211 cmd[0] = 0x13; 212 cmd[4] = sizeof(sense_data); 213 214 scsipi_command(sc->sc_periph, (void *)cmd, sizeof(cmd), 215 (void *)sense_data, sizeof(sense_data), 216 4, 3000, NULL, XS_CTL_DATA_IN); 217 218 sense_key = sense_data[1] & 0xf; 219 sense_specific = sense_data[4]; 220 if (sense_key == 11 && sense_specific == 0) { 221 GDROM_DPRINTF(("GDROM: aborted (ignored). 0:0\n")); 222 return 0; 223 } 224 225 GDROM_DPRINTF(("GDROM: SENSE %d:", sense_key)); 226 GDROM_DPRINTF(("GDROM: %d\n", sense_specific)); 227 228 return sense_key == 0 ? 0 : EIO; 229 } 230 #endif 231 232 int gdrom_read_toc(struct gdrom_softc *sc, struct gd_toc *toc) 233 { 234 /* 235 * 76543210 76543210 236 * 0 0x14 - 237 * 2 - bufsz(hi) 238 * 4 bufsz(lo) - 239 * 6 - - 240 * 8 - - 241 * 10 - - 242 */ 243 uint8_t cmd[12]; 244 245 GDROM_DPRINTF(("%s: called\n", __func__)); 246 memset(cmd, 0, sizeof(cmd)); 247 248 cmd[0] = 0x14; 249 cmd[3] = sizeof(struct gd_toc) >> 8; 250 cmd[4] = sizeof(struct gd_toc) & 0xff; 251 252 return scsipi_command(sc->sc_periph, (void *)cmd, 12, 253 (void *)toc, sizeof(struct gd_toc), 254 4, 3000, NULL, XS_CTL_DATA_IN); 255 } 256 257 int gdrom_read_sectors(struct gdrom_softc *sc, struct buf *bp) 258 { 259 /* 260 * 76543210 76543210 261 * 0 0x30 datafmt 262 * 2 sec(hi) sec(mid) 263 * 4 sec(lo) - 264 * 6 - - 265 * 8 cnt(hi) cnt(mid) 266 * 10 cnt(lo) - 267 */ 268 uint8_t cmd[12]; 269 void *buf; 270 int sector, cnt; 271 int cond; 272 273 GDROM_DPRINTF(("%s: called\n", __func__)); 274 275 buf = bp->b_data; 276 sector = bp->b_rawblkno; 277 cnt = bp->b_bcount >> 11; 278 279 memset(cmd, 0, sizeof(cmd)); 280 281 cmd[0] = 0x30; 282 cmd[1] = 0x20; 283 cmd[2] = sector >> 16; 284 cmd[3] = sector >> 8; 285 cmd[4] = sector; 286 cmd[8] = cnt >> 16; 287 cmd[9] = cnt >> 8; 288 cmd[10] = cnt; 289 290 cond = scsipi_command(sc->sc_periph, (void *)cmd, 12, 291 (void *)buf, bp->b_bcount, 292 4, 3000, bp, XS_CTL_DATA_IN); 293 294 GDROM_DPRINTF(("%s: cond = %d\n", __func__, cond)); 295 296 return cond; 297 } 298 299 int gdrom_mount_disk(struct gdrom_softc *sc) 300 { 301 /* 302 * 76543210 76543210 303 * 0 0x70 - 304 * 2 0x1f - 305 * 4 - - 306 * 6 - - 307 * 8 - - 308 * 10 - - 309 */ 310 uint8_t cmd[12]; 311 int cond; 312 313 GDROM_DPRINTF(("%s: called\n", __func__)); 314 memset(cmd, 0, sizeof(cmd)); 315 316 cmd[0] = 0x70; 317 cmd[2] = 0x1f; 318 319 cond = scsipi_command(sc->sc_periph, (void *)cmd, 12, NULL, 0, 320 4, 3000, NULL, 0); 321 322 GDROM_DPRINTF(("%s: cond = %d\n", __func__, cond)); 323 return cond; 324 } 325 326 int 327 gdrommatch(device_t parent, cfdata_t cf, void *aux) 328 { 329 struct scsipibus_attach_args *sa = aux; 330 int priority; 331 332 (void)scsipi_inqmatch(&sa->sa_inqbuf, 333 gdrom_patterns, __arraycount(gdrom_patterns), 334 sizeof(gdrom_patterns[0]), &priority); 335 336 if (priority > 0) { 337 /* beat generic direct fixed device */ 338 priority = 255; 339 } 340 341 return priority; 342 } 343 344 void 345 gdromattach(device_t parent, device_t self, void *aux) 346 { 347 struct gdrom_softc *sc; 348 struct scsipibus_attach_args *sa; 349 struct scsipi_periph *periph; 350 351 sc = device_private(self); 352 sa = aux; 353 periph = sa->sa_periph; 354 sc->sc_dev = self; 355 sc->sc_periph = periph; 356 periph->periph_dev = sc->sc_dev; 357 periph->periph_switch = &gdrom_switch; 358 359 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 360 361 bufq_alloc(&sc->sc_bufq, "disksort", BUFQ_SORT_RAWBLOCK); 362 363 /* 364 * Initialize and attach the disk structure. 365 */ 366 disk_init(&sc->sc_dk, device_xname(self), &gdromdkdriver); 367 disk_attach(&sc->sc_dk); 368 369 aprint_normal("\n"); 370 aprint_naive("\n"); 371 } 372 373 int 374 gdromopen(dev_t dev, int flags, int devtype, struct lwp *l) 375 { 376 struct gdrom_softc *sc; 377 int s, error, unit, cnt; 378 struct gd_toc toc; 379 380 GDROM_DPRINTF(("%s: called\n", __func__)); 381 382 unit = DISKUNIT(dev); 383 384 sc = device_lookup_private(&gdrom_cd, unit); 385 if (sc == NULL) 386 return ENXIO; 387 388 if (sc->is_open) 389 return EBUSY; 390 391 s = splbio(); 392 while (sc->is_busy) 393 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 394 sc->is_busy = true; 395 splx(s); 396 397 for (cnt = 0; cnt < 1; cnt++) 398 if ((error = gdrom_mount_disk(sc)) == 0) 399 break; 400 401 if (error == 0) 402 error = gdrom_read_toc(sc, &toc); 403 404 sc->is_busy = false; 405 wakeup(&sc->is_busy); 406 407 if (error != 0) 408 return error; 409 410 sc->is_open = true; 411 sc->openpart_start = 150; 412 413 GDROM_DPRINTF(("%s: open OK\n", __func__)); 414 return 0; 415 } 416 417 int 418 gdromclose(dev_t dev, int flags, int devtype, struct lwp *l) 419 { 420 struct gdrom_softc *sc; 421 int unit; 422 423 GDROM_DPRINTF(("%s: called\n", __func__)); 424 425 unit = DISKUNIT(dev); 426 sc = device_lookup_private(&gdrom_cd, unit); 427 428 sc->is_open = false; 429 430 return 0; 431 } 432 433 void 434 gdromstrategy(struct buf *bp) 435 { 436 struct gdrom_softc *sc; 437 struct scsipi_periph *periph; 438 int s, unit; 439 440 GDROM_DPRINTF(("%s: called\n", __func__)); 441 442 unit = DISKUNIT(bp->b_dev); 443 sc = device_lookup_private(&gdrom_cd, unit); 444 periph = sc->sc_periph; 445 446 if (bp->b_bcount == 0) 447 goto done; 448 449 bp->b_rawblkno = bp->b_blkno / (2048 / DEV_BSIZE) + sc->openpart_start; 450 451 GDROM_DPRINTF(("%s: read_sectors(%p, %lld, %d) [%d bytes]\n", __func__, 452 bp->b_data, bp->b_rawblkno, 453 bp->b_bcount >> 11, bp->b_bcount)); 454 455 s = splbio(); 456 bufq_put(sc->sc_bufq, bp); 457 splx(s); 458 if (!sc->is_active) 459 gdrom_start(periph); 460 return; 461 462 done: 463 bp->b_resid = bp->b_bcount; 464 biodone(bp); 465 } 466 467 void 468 gdrom_start(struct scsipi_periph *periph) 469 { 470 struct gdrom_softc *sc = device_private(periph->periph_dev); 471 struct buf *bp; 472 int error, s; 473 474 sc->is_active = true; 475 476 for (;;) { 477 s = splbio(); 478 bp = bufq_get(sc->sc_bufq); 479 if (bp == NULL) { 480 splx(s); 481 break; 482 } 483 484 while (sc->is_busy) 485 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 486 sc->is_busy = true; 487 disk_busy(&sc->sc_dk); 488 splx(s); 489 490 error = gdrom_read_sectors(sc, bp); 491 bp->b_error = error; 492 if (error != 0) 493 bp->b_resid = bp->b_bcount; 494 495 sc->is_busy = false; 496 wakeup(&sc->is_busy); 497 498 s = splbio(); 499 disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid, 500 (bp->b_flags & B_READ) != 0); 501 splx(s); 502 biodone(bp); 503 } 504 505 sc->is_active = false; 506 } 507 508 void 509 gdrom_done(struct scsipi_xfer *xs, int error) 510 { 511 512 GDROM_DPRINTF(("%s: called\n", __func__)); 513 } 514 515 int 516 gdromioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 517 { 518 struct gdrom_softc *sc; 519 int unit, error; 520 521 GDROM_DPRINTF(("%s: cmd %lx\n", __func__, cmd)); 522 523 unit = DISKUNIT(dev); 524 sc = device_lookup_private(&gdrom_cd, unit); 525 526 switch (cmd) { 527 case CDIOREADMSADDR: { 528 int s, track, sessno = *(int *)addr; 529 struct gd_toc toc; 530 531 if (sessno != 0) 532 return EINVAL; 533 534 s = splbio(); 535 while (sc->is_busy) 536 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 537 sc->is_busy = true; 538 splx(s); 539 540 error = gdrom_read_toc(sc, &toc); 541 542 sc->is_busy = false; 543 wakeup(&sc->is_busy); 544 545 if (error != 0) 546 return error; 547 #ifdef GDROMDEBUGTOC 548 { /* Dump the GDROM TOC */ 549 unsigned char *ptr = (unsigned char *)&toc; 550 int i; 551 552 printf("gdrom: TOC\n"); 553 for(i = 0; i < sizeof(toc); ++i) { 554 printf("%02x", *ptr++); 555 if( i%32 == 31) 556 printf("\n"); 557 else if( i%4 == 3) 558 printf(","); 559 } 560 printf("\n"); 561 } 562 #endif 563 for (track = TOC_TRACK(toc.last); 564 track >= TOC_TRACK(toc.first); 565 --track) { 566 if (track < 1 || track > 100) 567 return ENXIO; 568 if (TOC_CTRL(toc.entry[track - 1])) 569 break; 570 } 571 572 #ifdef GDROMDEBUGTOC 573 printf("gdrom: Using track %d, LBA %u\n", track, 574 TOC_LBA(toc.entry[track - 1])); 575 #endif 576 577 *(int *)addr = htonl(TOC_LBA(toc.entry[track - 1])) - 578 sc->openpart_start; 579 580 return 0; 581 } 582 default: 583 return ENOTTY; 584 } 585 586 #ifdef DIAGNOSTIC 587 panic("gdromioctl: impossible"); 588 #endif 589 } 590 591 592 int 593 gdromread(dev_t dev, struct uio *uio, int flags) 594 { 595 596 GDROM_DPRINTF(("%s: called\n", __func__)); 597 return physio(gdromstrategy, NULL, dev, B_READ, minphys, uio); 598 } 599 600 int 601 gdromwrite(dev_t dev, struct uio *uio, int flags) 602 { 603 604 return EROFS; 605 } 606