Home | History | Annotate | Line # | Download | only in g1
      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