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