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