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
gdrom_read_toc(struct gdrom_softc * sc,struct gd_toc * toc)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
gdrom_read_sectors(struct gdrom_softc * sc,struct buf * bp)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
gdrom_mount_disk(struct gdrom_softc * sc)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
gdrommatch(device_t parent,cfdata_t cf,void * aux)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
gdromattach(device_t parent,device_t self,void * aux)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
gdromopen(dev_t dev,int flags,int devtype,struct lwp * l)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
gdromclose(dev_t dev,int flags,int devtype,struct lwp * l)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
gdromstrategy(struct buf * bp)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
gdrom_start(struct scsipi_periph * periph)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
gdrom_done(struct scsipi_xfer * xs,int error)509 gdrom_done(struct scsipi_xfer *xs, int error)
510 {
511
512 GDROM_DPRINTF(("%s: called\n", __func__));
513 }
514
515 int
gdromioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)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
gdromread(dev_t dev,struct uio * uio,int flags)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
gdromwrite(dev_t dev,struct uio * uio,int flags)601 gdromwrite(dev_t dev, struct uio *uio, int flags)
602 {
603
604 return EROFS;
605 }
606