Deleted Added
sdiff udiff text old ( 76322 ) new ( 76362 )
full compact
1/*
2 * Copyright (c) 1997 Justin T. Gibbs.
3 * Copyright (c) 1997, 1998, 1999, 2000, 2001 Kenneth D. Merry.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer,
11 * without modification, immediately at the beginning of the file.
12 * 2. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sys/cam/scsi/scsi_cd.c 76322 2001-05-06 20:00:03Z phk $
28 */
29/*
30 * Portions of this driver taken from the original FreeBSD cd driver.
31 * Written by Julian Elischer (julian@tfs.com)
32 * for TRW Financial Systems for use under the MACH(2.5) operating system.
33 *
34 * TRW Financial Systems, in accordance with their agreement with Carnegie
35 * Mellon University, makes this software available to CMU to distribute
36 * or use in any manner that they see fit as long as this message is kept with
37 * the software. For this reason TFS also grants any other persons or
38 * organisations permission to use or modify this software.
39 *
40 * TFS supplies this software to be publicly redistributed
41 * on the understanding that TFS is not responsible for the correct
42 * functioning of this software in any circumstances.
43 *
44 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
45 *
46 * from: cd.c,v 1.83 1997/05/04 15:24:22 joerg Exp $
47 */
48
49#include "opt_cd.h"
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/kernel.h>
54#include <sys/bio.h>
55#include <sys/conf.h>
56#include <sys/disk.h>
57#include <sys/malloc.h>
58#include <sys/cdio.h>
59#include <sys/dvdio.h>
60#include <sys/devicestat.h>
61#include <sys/sysctl.h>
62
63#include <cam/cam.h>
64#include <cam/cam_ccb.h>
65#include <cam/cam_extend.h>
66#include <cam/cam_periph.h>
67#include <cam/cam_xpt_periph.h>
68#include <cam/cam_queue.h>
69
70#include <cam/scsi/scsi_message.h>
71#include <cam/scsi/scsi_da.h>
72#include <cam/scsi/scsi_cd.h>
73
74#define LEADOUT 0xaa /* leadout toc entry */
75
76struct cd_params {
77 u_int32_t blksize;
78 u_long disksize;
79};
80
81typedef enum {
82 CD_Q_NONE = 0x00,
83 CD_Q_NO_TOUCH = 0x01,
84 CD_Q_BCD_TRACKS = 0x02,
85 CD_Q_NO_CHANGER = 0x04,
86 CD_Q_CHANGER = 0x08
87} cd_quirks;
88
89typedef enum {
90 CD_FLAG_INVALID = 0x001,
91 CD_FLAG_NEW_DISC = 0x002,
92 CD_FLAG_DISC_LOCKED = 0x004,
93 CD_FLAG_DISC_REMOVABLE = 0x008,
94 CD_FLAG_TAGGED_QUEUING = 0x010,
95 CD_FLAG_CHANGER = 0x040,
96 CD_FLAG_ACTIVE = 0x080,
97 CD_FLAG_SCHED_ON_COMP = 0x100,
98 CD_FLAG_RETRY_UA = 0x200
99} cd_flags;
100
101typedef enum {
102 CD_CCB_PROBE = 0x01,
103 CD_CCB_BUFFER_IO = 0x02,
104 CD_CCB_WAITING = 0x03,
105 CD_CCB_TYPE_MASK = 0x0F,
106 CD_CCB_RETRY_UA = 0x10
107} cd_ccb_state;
108
109typedef enum {
110 CHANGER_TIMEOUT_SCHED = 0x01,
111 CHANGER_SHORT_TMOUT_SCHED = 0x02,
112 CHANGER_MANUAL_CALL = 0x04,
113 CHANGER_NEED_TIMEOUT = 0x08
114} cd_changer_flags;
115
116#define ccb_state ppriv_field0
117#define ccb_bp ppriv_ptr1
118
119typedef enum {
120 CD_STATE_PROBE,
121 CD_STATE_NORMAL
122} cd_state;
123
124struct cd_softc {
125 cam_pinfo pinfo;
126 cd_state state;
127 volatile cd_flags flags;
128 struct bio_queue_head bio_queue;
129 LIST_HEAD(, ccb_hdr) pending_ccbs;
130 struct cd_params params;
131 struct disk disk;
132 union ccb saved_ccb;
133 cd_quirks quirks;
134 struct devstat device_stats;
135 STAILQ_ENTRY(cd_softc) changer_links;
136 struct cdchanger *changer;
137 int bufs_left;
138 struct cam_periph *periph;
139};
140
141struct cd_quirk_entry {
142 struct scsi_inquiry_pattern inq_pat;
143 cd_quirks quirks;
144};
145
146/*
147 * These quirk entries aren't strictly necessary. Basically, what they do
148 * is tell cdregister() up front that a device is a changer. Otherwise, it
149 * will figure that fact out once it sees a LUN on the device that is
150 * greater than 0. If it is known up front that a device is a changer, all
151 * I/O to the device will go through the changer scheduling routines, as
152 * opposed to the "normal" CD code.
153 */
154static struct cd_quirk_entry cd_quirk_table[] =
155{
156 {
157 { T_CDROM, SIP_MEDIA_REMOVABLE, "NRC", "MBR-7", "*"},
158 /*quirks*/ CD_Q_CHANGER
159 },
160 {
161 { T_CDROM, SIP_MEDIA_REMOVABLE, "PIONEER", "CD-ROM DRM*",
162 "*"}, /* quirks */ CD_Q_CHANGER
163 },
164 {
165 { T_CDROM, SIP_MEDIA_REMOVABLE, "NAKAMICH", "MJ-*", "*"},
166 /* quirks */ CD_Q_CHANGER
167 },
168 {
169 { T_CDROM, SIP_MEDIA_REMOVABLE, "CHINON", "CD-ROM CDS-535","*"},
170 /* quirks */ CD_Q_BCD_TRACKS
171 }
172};
173
174#ifndef MIN
175#define MIN(x,y) ((x<y) ? x : y)
176#endif
177
178#define CD_CDEV_MAJOR 15
179
180static d_open_t cdopen;
181static d_close_t cdclose;
182static d_ioctl_t cdioctl;
183static d_strategy_t cdstrategy;
184
185static periph_init_t cdinit;
186static periph_ctor_t cdregister;
187static periph_dtor_t cdcleanup;
188static periph_start_t cdstart;
189static periph_oninv_t cdoninvalidate;
190static void cdasync(void *callback_arg, u_int32_t code,
191 struct cam_path *path, void *arg);
192static void cdshorttimeout(void *arg);
193static void cdschedule(struct cam_periph *periph, int priority);
194static void cdrunchangerqueue(void *arg);
195static void cdchangerschedule(struct cd_softc *softc);
196static int cdrunccb(union ccb *ccb,
197 int (*error_routine)(union ccb *ccb,
198 u_int32_t cam_flags,
199 u_int32_t sense_flags),
200 u_int32_t cam_flags, u_int32_t sense_flags);
201static union ccb *cdgetccb(struct cam_periph *periph,
202 u_int32_t priority);
203static void cddone(struct cam_periph *periph,
204 union ccb *start_ccb);
205static int cderror(union ccb *ccb, u_int32_t cam_flags,
206 u_int32_t sense_flags);
207static void cdprevent(struct cam_periph *periph, int action);
208static int cdsize(dev_t dev, u_int32_t *size);
209static int cdfirsttrackisdata(struct cam_periph *periph);
210static int cdreadtoc(struct cam_periph *periph, u_int32_t mode,
211 u_int32_t start, struct cd_toc_entry *data,
212 u_int32_t len);
213static int cdgetmode(struct cam_periph *periph,
214 struct cd_mode_data *data, u_int32_t page);
215static int cdsetmode(struct cam_periph *periph,
216 struct cd_mode_data *data);
217static int cdplay(struct cam_periph *periph, u_int32_t blk,
218 u_int32_t len);
219static int cdreadsubchannel(struct cam_periph *periph,
220 u_int32_t mode, u_int32_t format,
221 int track,
222 struct cd_sub_channel_info *data,
223 u_int32_t len);
224static int cdplaymsf(struct cam_periph *periph, u_int32_t startm,
225 u_int32_t starts, u_int32_t startf,
226 u_int32_t endm, u_int32_t ends,
227 u_int32_t endf);
228static int cdplaytracks(struct cam_periph *periph,
229 u_int32_t strack, u_int32_t sindex,
230 u_int32_t etrack, u_int32_t eindex);
231static int cdpause(struct cam_periph *periph, u_int32_t go);
232static int cdstopunit(struct cam_periph *periph, u_int32_t eject);
233static int cdstartunit(struct cam_periph *periph);
234static int cdreportkey(struct cam_periph *periph,
235 struct dvd_authinfo *authinfo);
236static int cdsendkey(struct cam_periph *periph,
237 struct dvd_authinfo *authinfo);
238static int cdreaddvdstructure(struct cam_periph *periph,
239 struct dvd_struct *dvdstruct);
240
241static struct periph_driver cddriver =
242{
243 cdinit, "cd",
244 TAILQ_HEAD_INITIALIZER(cddriver.units), /* generation */ 0
245};
246
247PERIPHDRIVER_DECLARE(cd, cddriver);
248
249/* For 2.2-stable support */
250#ifndef D_DISK
251#define D_DISK 0
252#endif
253static struct cdevsw cd_cdevsw = {
254 /* open */ cdopen,
255 /* close */ cdclose,
256 /* read */ physread,
257 /* write */ physwrite,
258 /* ioctl */ cdioctl,
259 /* poll */ nopoll,
260 /* mmap */ nommap,
261 /* strategy */ cdstrategy,
262 /* name */ "cd",
263 /* maj */ CD_CDEV_MAJOR,
264 /* dump */ nodump,
265 /* psize */ nopsize,
266 /* flags */ D_DISK,
267};
268static struct cdevsw cddisk_cdevsw;
269
270static struct extend_array *cdperiphs;
271static int num_changers;
272
273#ifndef CHANGER_MIN_BUSY_SECONDS
274#define CHANGER_MIN_BUSY_SECONDS 5
275#endif
276#ifndef CHANGER_MAX_BUSY_SECONDS
277#define CHANGER_MAX_BUSY_SECONDS 15
278#endif
279
280static int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS;
281static int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS;
282
283/*
284 * XXX KDM this CAM node should be moved if we ever get more CAM sysctl
285 * variables.
286 */
287SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem");
288SYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver");
289SYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0, "CD Changer");
290SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW,
291 &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum");
292SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, max_busy_seconds, CTLFLAG_RW,
293 &changer_max_busy_seconds, 0, "Maximum changer scheduling quantum");
294
295struct cdchanger {
296 path_id_t path_id;
297 target_id_t target_id;
298 int num_devices;
299 struct camq devq;
300 struct timeval start_time;
301 struct cd_softc *cur_device;
302 struct callout_handle short_handle;
303 struct callout_handle long_handle;
304 volatile cd_changer_flags flags;
305 STAILQ_ENTRY(cdchanger) changer_links;
306 STAILQ_HEAD(chdevlist, cd_softc) chluns;
307};
308
309static STAILQ_HEAD(changerlist, cdchanger) changerq;
310
311void
312cdinit(void)
313{
314 cam_status status;
315 struct cam_path *path;
316
317 /*
318 * Create our extend array for storing the devices we attach to.
319 */
320 cdperiphs = cam_extend_new();
321 if (cdperiphs == NULL) {
322 printf("cd: Failed to alloc extend array!\n");
323 return;
324 }
325
326 /*
327 * Install a global async callback. This callback will
328 * receive async callbacks like "new device found".
329 */
330 status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
331 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
332
333 if (status == CAM_REQ_CMP) {
334 struct ccb_setasync csa;
335
336 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
337 csa.ccb_h.func_code = XPT_SASYNC_CB;
338 csa.event_enable = AC_FOUND_DEVICE;
339 csa.callback = cdasync;
340 csa.callback_arg = NULL;
341 xpt_action((union ccb *)&csa);
342 status = csa.ccb_h.status;
343 xpt_free_path(path);
344 }
345
346 if (status != CAM_REQ_CMP) {
347 printf("cd: Failed to attach master async callback "
348 "due to status 0x%x!\n", status);
349 }
350}
351
352static void
353cdoninvalidate(struct cam_periph *periph)
354{
355 int s;
356 struct cd_softc *softc;
357 struct bio *q_bp;
358 struct ccb_setasync csa;
359
360 softc = (struct cd_softc *)periph->softc;
361
362 /*
363 * De-register any async callbacks.
364 */
365 xpt_setup_ccb(&csa.ccb_h, periph->path,
366 /* priority */ 5);
367 csa.ccb_h.func_code = XPT_SASYNC_CB;
368 csa.event_enable = 0;
369 csa.callback = cdasync;
370 csa.callback_arg = periph;
371 xpt_action((union ccb *)&csa);
372
373 softc->flags |= CD_FLAG_INVALID;
374
375 /*
376 * Although the oninvalidate() routines are always called at
377 * splsoftcam, we need to be at splbio() here to keep the buffer
378 * queue from being modified while we traverse it.
379 */
380 s = splbio();
381
382 /*
383 * Return all queued I/O with ENXIO.
384 * XXX Handle any transactions queued to the card
385 * with XPT_ABORT_CCB.
386 */
387 while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){
388 bioq_remove(&softc->bio_queue, q_bp);
389 q_bp->bio_resid = q_bp->bio_bcount;
390 biofinish(q_bp, NULL, ENXIO);
391 }
392 splx(s);
393
394 /*
395 * If this device is part of a changer, and it was scheduled
396 * to run, remove it from the run queue since we just nuked
397 * all of its scheduled I/O.
398 */
399 if ((softc->flags & CD_FLAG_CHANGER)
400 && (softc->pinfo.index != CAM_UNQUEUED_INDEX))
401 camq_remove(&softc->changer->devq, softc->pinfo.index);
402
403 xpt_print_path(periph->path);
404 printf("lost device\n");
405}
406
407static void
408cdcleanup(struct cam_periph *periph)
409{
410 struct cd_softc *softc;
411 int s;
412
413 softc = (struct cd_softc *)periph->softc;
414
415 xpt_print_path(periph->path);
416 printf("removing device entry\n");
417
418 s = splsoftcam();
419 /*
420 * In the queued, non-active case, the device in question
421 * has already been removed from the changer run queue. Since this
422 * device is active, we need to de-activate it, and schedule
423 * another device to run. (if there is another one to run)
424 */
425 if ((softc->flags & CD_FLAG_CHANGER)
426 && (softc->flags & CD_FLAG_ACTIVE)) {
427
428 /*
429 * The purpose of the short timeout is soley to determine
430 * whether the current device has finished or not. Well,
431 * since we're removing the active device, we know that it
432 * is finished. So, get rid of the short timeout.
433 * Otherwise, if we're in the time period before the short
434 * timeout fires, and there are no other devices in the
435 * queue to run, there won't be any other device put in the
436 * active slot. i.e., when we call cdrunchangerqueue()
437 * below, it won't do anything. Then, when the short
438 * timeout fires, it'll look at the "current device", which
439 * we are free below, and possibly panic the kernel on a
440 * bogus pointer reference.
441 *
442 * The long timeout doesn't really matter, since we
443 * decrement the qfrozen_cnt to indicate that there is
444 * nothing in the active slot now. Therefore, there won't
445 * be any bogus pointer references there.
446 */
447 if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
448 untimeout(cdshorttimeout, softc->changer,
449 softc->changer->short_handle);
450 softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
451 }
452 softc->changer->devq.qfrozen_cnt--;
453 softc->changer->flags |= CHANGER_MANUAL_CALL;
454 cdrunchangerqueue(softc->changer);
455 }
456
457 /*
458 * If we're removing the last device on the changer, go ahead and
459 * remove the changer device structure.
460 */
461 if ((softc->flags & CD_FLAG_CHANGER)
462 && (--softc->changer->num_devices == 0)) {
463
464 /*
465 * Theoretically, there shouldn't be any timeouts left, but
466 * I'm not completely sure that that will be the case. So,
467 * it won't hurt to check and see if there are any left.
468 */
469 if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) {
470 untimeout(cdrunchangerqueue, softc->changer,
471 softc->changer->long_handle);
472 softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED;
473 }
474
475 if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
476 untimeout(cdshorttimeout, softc->changer,
477 softc->changer->short_handle);
478 softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
479 }
480
481 STAILQ_REMOVE(&changerq, softc->changer, cdchanger,
482 changer_links);
483 xpt_print_path(periph->path);
484 printf("removing changer entry\n");
485 free(softc->changer, M_DEVBUF);
486 num_changers--;
487 }
488 devstat_remove_entry(&softc->device_stats);
489 cam_extend_release(cdperiphs, periph->unit_number);
490 free(softc, M_DEVBUF);
491 splx(s);
492}
493
494static void
495cdasync(void *callback_arg, u_int32_t code,
496 struct cam_path *path, void *arg)
497{
498 struct cam_periph *periph;
499
500 periph = (struct cam_periph *)callback_arg;
501 switch (code) {
502 case AC_FOUND_DEVICE:
503 {
504 struct ccb_getdev *cgd;
505 cam_status status;
506
507 cgd = (struct ccb_getdev *)arg;
508
509 if (SID_TYPE(&cgd->inq_data) != T_CDROM
510 && SID_TYPE(&cgd->inq_data) != T_WORM)
511 break;
512
513 /*
514 * Allocate a peripheral instance for
515 * this device and start the probe
516 * process.
517 */
518 status = cam_periph_alloc(cdregister, cdoninvalidate,
519 cdcleanup, cdstart,
520 "cd", CAM_PERIPH_BIO,
521 cgd->ccb_h.path, cdasync,
522 AC_FOUND_DEVICE, cgd);
523
524 if (status != CAM_REQ_CMP
525 && status != CAM_REQ_INPROG)
526 printf("cdasync: Unable to attach new device "
527 "due to status 0x%x\n", status);
528
529 break;
530 }
531 case AC_SENT_BDR:
532 case AC_BUS_RESET:
533 {
534 struct cd_softc *softc;
535 struct ccb_hdr *ccbh;
536 int s;
537
538 softc = (struct cd_softc *)periph->softc;
539 s = splsoftcam();
540 /*
541 * Don't fail on the expected unit attention
542 * that will occur.
543 */
544 softc->flags |= CD_FLAG_RETRY_UA;
545 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
546 ccbh->ccb_state |= CD_CCB_RETRY_UA;
547 splx(s);
548 /* FALLTHROUGH */
549 }
550 default:
551 cam_periph_async(periph, code, path, arg);
552 break;
553 }
554}
555
556static cam_status
557cdregister(struct cam_periph *periph, void *arg)
558{
559 struct cd_softc *softc;
560 struct ccb_setasync csa;
561 struct ccb_getdev *cgd;
562 caddr_t match;
563
564 cgd = (struct ccb_getdev *)arg;
565 if (periph == NULL) {
566 printf("cdregister: periph was NULL!!\n");
567 return(CAM_REQ_CMP_ERR);
568 }
569 if (cgd == NULL) {
570 printf("cdregister: no getdev CCB, can't register device\n");
571 return(CAM_REQ_CMP_ERR);
572 }
573
574 softc = (struct cd_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
575
576 if (softc == NULL) {
577 printf("cdregister: Unable to probe new device. "
578 "Unable to allocate softc\n");
579 return(CAM_REQ_CMP_ERR);
580 }
581
582 bzero(softc, sizeof(*softc));
583 LIST_INIT(&softc->pending_ccbs);
584 softc->state = CD_STATE_PROBE;
585 bioq_init(&softc->bio_queue);
586 if (SID_IS_REMOVABLE(&cgd->inq_data))
587 softc->flags |= CD_FLAG_DISC_REMOVABLE;
588 if ((cgd->inq_data.flags & SID_CmdQue) != 0)
589 softc->flags |= CD_FLAG_TAGGED_QUEUING;
590
591 periph->softc = softc;
592 softc->periph = periph;
593
594 cam_extend_set(cdperiphs, periph->unit_number, periph);
595
596 /*
597 * See if this device has any quirks.
598 */
599 match = cam_quirkmatch((caddr_t)&cgd->inq_data,
600 (caddr_t)cd_quirk_table,
601 sizeof(cd_quirk_table)/sizeof(*cd_quirk_table),
602 sizeof(*cd_quirk_table), scsi_inquiry_match);
603
604 if (match != NULL)
605 softc->quirks = ((struct cd_quirk_entry *)match)->quirks;
606 else
607 softc->quirks = CD_Q_NONE;
608
609 /*
610 * We need to register the statistics structure for this device,
611 * but we don't have the blocksize yet for it. So, we register
612 * the structure and indicate that we don't have the blocksize
613 * yet. Unlike other SCSI peripheral drivers, we explicitly set
614 * the device type here to be CDROM, rather than just ORing in
615 * the device type. This is because this driver can attach to either
616 * CDROM or WORM devices, and we want this peripheral driver to
617 * show up in the devstat list as a CD peripheral driver, not a
618 * WORM peripheral driver. WORM drives will also have the WORM
619 * driver attached to them.
620 */
621 devstat_add_entry(&softc->device_stats, "cd",
622 periph->unit_number, 0,
623 DEVSTAT_BS_UNAVAILABLE,
624 DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_SCSI,
625 DEVSTAT_PRIORITY_CD);
626 disk_create(periph->unit_number, &softc->disk,
627 DSO_ONESLICE | DSO_COMPATLABEL,
628 &cd_cdevsw, &cddisk_cdevsw);
629
630 /*
631 * Add an async callback so that we get
632 * notified if this device goes away.
633 */
634 xpt_setup_ccb(&csa.ccb_h, periph->path,
635 /* priority */ 5);
636 csa.ccb_h.func_code = XPT_SASYNC_CB;
637 csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
638 csa.callback = cdasync;
639 csa.callback_arg = periph;
640 xpt_action((union ccb *)&csa);
641
642 /*
643 * If the target lun is greater than 0, we most likely have a CD
644 * changer device. Check the quirk entries as well, though, just
645 * in case someone has a CD tower with one lun per drive or
646 * something like that. Also, if we know up front that a
647 * particular device is a changer, we can mark it as such starting
648 * with lun 0, instead of lun 1. It shouldn't be necessary to have
649 * a quirk entry to define something as a changer, however.
650 */
651 if (((cgd->ccb_h.target_lun > 0)
652 && ((softc->quirks & CD_Q_NO_CHANGER) == 0))
653 || ((softc->quirks & CD_Q_CHANGER) != 0)) {
654 struct cdchanger *nchanger;
655 struct cam_periph *nperiph;
656 struct cam_path *path;
657 cam_status status;
658 int found;
659
660 /* Set the changer flag in the current device's softc */
661 softc->flags |= CD_FLAG_CHANGER;
662
663 if (num_changers == 0)
664 STAILQ_INIT(&changerq);
665
666 /*
667 * Now, look around for an existing changer device with the
668 * same path and target ID as the current device.
669 */
670 for (found = 0,
671 nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq);
672 nchanger != NULL;
673 nchanger = STAILQ_NEXT(nchanger, changer_links)){
674 if ((nchanger->path_id == cgd->ccb_h.path_id)
675 && (nchanger->target_id == cgd->ccb_h.target_id)) {
676 found = 1;
677 break;
678 }
679 }
680
681 /*
682 * If we found a matching entry, just add this device to
683 * the list of devices on this changer.
684 */
685 if (found == 1) {
686 struct chdevlist *chlunhead;
687
688 chlunhead = &nchanger->chluns;
689
690 /*
691 * XXX KDM look at consolidating this code with the
692 * code below in a separate function.
693 */
694
695 /*
696 * Create a path with lun id 0, and see if we can
697 * find a matching device
698 */
699 status = xpt_create_path(&path, /*periph*/ periph,
700 cgd->ccb_h.path_id,
701 cgd->ccb_h.target_id, 0);
702
703 if ((status == CAM_REQ_CMP)
704 && ((nperiph = cam_periph_find(path, "cd")) != NULL)){
705 struct cd_softc *nsoftc;
706
707 nsoftc = (struct cd_softc *)nperiph->softc;
708
709 if ((nsoftc->flags & CD_FLAG_CHANGER) == 0){
710 nsoftc->flags |= CD_FLAG_CHANGER;
711 nchanger->num_devices++;
712 if (camq_resize(&nchanger->devq,
713 nchanger->num_devices)!=CAM_REQ_CMP){
714 printf("cdregister: "
715 "camq_resize "
716 "failed, changer "
717 "support may "
718 "be messed up\n");
719 }
720 nsoftc->changer = nchanger;
721 nsoftc->pinfo.index =CAM_UNQUEUED_INDEX;
722
723 STAILQ_INSERT_TAIL(&nchanger->chluns,
724 nsoftc,changer_links);
725 }
726 xpt_free_path(path);
727 } else if (status == CAM_REQ_CMP)
728 xpt_free_path(path);
729 else {
730 printf("cdregister: unable to allocate path\n"
731 "cdregister: changer support may be "
732 "broken\n");
733 }
734
735 nchanger->num_devices++;
736
737 softc->changer = nchanger;
738 softc->pinfo.index = CAM_UNQUEUED_INDEX;
739
740 if (camq_resize(&nchanger->devq,
741 nchanger->num_devices) != CAM_REQ_CMP) {
742 printf("cdregister: camq_resize "
743 "failed, changer support may "
744 "be messed up\n");
745 }
746
747 STAILQ_INSERT_TAIL(chlunhead, softc, changer_links);
748 }
749 /*
750 * In this case, we don't already have an entry for this
751 * particular changer, so we need to create one, add it to
752 * the queue, and queue this device on the list for this
753 * changer. Before we queue this device, however, we need
754 * to search for lun id 0 on this target, and add it to the
755 * queue first, if it exists. (and if it hasn't already
756 * been marked as part of the changer.)
757 */
758 else {
759 nchanger = malloc(sizeof(struct cdchanger),
760 M_DEVBUF, M_NOWAIT);
761
762 if (nchanger == NULL) {
763 softc->flags &= ~CD_FLAG_CHANGER;
764 printf("cdregister: unable to malloc "
765 "changer structure\ncdregister: "
766 "changer support disabled\n");
767
768 /*
769 * Yes, gotos can be gross but in this case
770 * I think it's justified..
771 */
772 goto cdregisterexit;
773 }
774
775 /* zero the structure */
776 bzero(nchanger, sizeof(struct cdchanger));
777
778 if (camq_init(&nchanger->devq, 1) != 0) {
779 softc->flags &= ~CD_FLAG_CHANGER;
780 printf("cdregister: changer support "
781 "disabled\n");
782 goto cdregisterexit;
783 }
784
785 num_changers++;
786
787 nchanger->path_id = cgd->ccb_h.path_id;
788 nchanger->target_id = cgd->ccb_h.target_id;
789
790 /* this is superfluous, but it makes things clearer */
791 nchanger->num_devices = 0;
792
793 STAILQ_INIT(&nchanger->chluns);
794
795 STAILQ_INSERT_TAIL(&changerq, nchanger,
796 changer_links);
797
798 /*
799 * Create a path with lun id 0, and see if we can
800 * find a matching device
801 */
802 status = xpt_create_path(&path, /*periph*/ periph,
803 cgd->ccb_h.path_id,
804 cgd->ccb_h.target_id, 0);
805
806 /*
807 * If we were able to allocate the path, and if we
808 * find a matching device and it isn't already
809 * marked as part of a changer, then we add it to
810 * the current changer.
811 */
812 if ((status == CAM_REQ_CMP)
813 && ((nperiph = cam_periph_find(path, "cd")) != NULL)
814 && ((((struct cd_softc *)periph->softc)->flags &
815 CD_FLAG_CHANGER) == 0)) {
816 struct cd_softc *nsoftc;
817
818 nsoftc = (struct cd_softc *)nperiph->softc;
819
820 nsoftc->flags |= CD_FLAG_CHANGER;
821 nchanger->num_devices++;
822 if (camq_resize(&nchanger->devq,
823 nchanger->num_devices) != CAM_REQ_CMP) {
824 printf("cdregister: camq_resize "
825 "failed, changer support may "
826 "be messed up\n");
827 }
828 nsoftc->changer = nchanger;
829 nsoftc->pinfo.index = CAM_UNQUEUED_INDEX;
830
831 STAILQ_INSERT_TAIL(&nchanger->chluns,
832 nsoftc, changer_links);
833 xpt_free_path(path);
834 } else if (status == CAM_REQ_CMP)
835 xpt_free_path(path);
836 else {
837 printf("cdregister: unable to allocate path\n"
838 "cdregister: changer support may be "
839 "broken\n");
840 }
841
842 softc->changer = nchanger;
843 softc->pinfo.index = CAM_UNQUEUED_INDEX;
844 nchanger->num_devices++;
845 if (camq_resize(&nchanger->devq,
846 nchanger->num_devices) != CAM_REQ_CMP) {
847 printf("cdregister: camq_resize "
848 "failed, changer support may "
849 "be messed up\n");
850 }
851 STAILQ_INSERT_TAIL(&nchanger->chluns, softc,
852 changer_links);
853 }
854 }
855
856cdregisterexit:
857
858 /* Lock this peripheral until we are setup */
859 /* Can't block */
860 cam_periph_lock(periph, PRIBIO);
861
862 if ((softc->flags & CD_FLAG_CHANGER) == 0)
863 xpt_schedule(periph, /*priority*/5);
864 else
865 cdschedule(periph, /*priority*/ 5);
866
867 return(CAM_REQ_CMP);
868}
869
870static int
871cdopen(dev_t dev, int flags, int fmt, struct proc *p)
872{
873 struct disklabel *label;
874 struct cam_periph *periph;
875 struct cd_softc *softc;
876 struct ccb_getdev cgd;
877 u_int32_t size;
878 int unit, error;
879 int s;
880
881 unit = dkunit(dev);
882 periph = cam_extend_get(cdperiphs, unit);
883
884 if (periph == NULL)
885 return (ENXIO);
886
887 softc = (struct cd_softc *)periph->softc;
888
889 /*
890 * Grab splsoftcam and hold it until we lock the peripheral.
891 */
892 s = splsoftcam();
893 if (softc->flags & CD_FLAG_INVALID) {
894 splx(s);
895 return(ENXIO);
896 }
897
898 if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) {
899 splx(s);
900 return (error);
901 }
902
903 splx(s);
904
905 if (cam_periph_acquire(periph) != CAM_REQ_CMP)
906 return(ENXIO);
907
908 cdprevent(periph, PR_PREVENT);
909
910 /* find out the size */
911 if ((error = cdsize(dev, &size)) != 0) {
912 cdprevent(periph, PR_ALLOW);
913 cam_periph_unlock(periph);
914 cam_periph_release(periph);
915 return(error);
916 }
917
918 /*
919 * If we get a non-zero return, revert back to not reading the
920 * label off the disk. The first track is likely audio, which
921 * won't have a disklabel.
922 */
923 if ((error = cdfirsttrackisdata(periph)) != 0) {
924 softc->disk.d_dsflags &= ~DSO_COMPATLABEL;
925 softc->disk.d_dsflags |= DSO_NOLABELS;
926 error = 0;
927 }
928
929 /*
930 * Build prototype label for whole disk.
931 * Should take information about different data tracks from the
932 * TOC and put it in the partition table.
933 */
934 label = &softc->disk.d_label;
935 bzero(label, sizeof(*label));
936 label->d_type = DTYPE_SCSI;
937
938 /*
939 * Grab the inquiry data to get the vendor and product names.
940 * Put them in the typename and packname for the label.
941 */
942 xpt_setup_ccb(&cgd.ccb_h, periph->path, /*priority*/ 1);
943 cgd.ccb_h.func_code = XPT_GDEV_TYPE;
944 xpt_action((union ccb *)&cgd);
945
946 strncpy(label->d_typename, cgd.inq_data.vendor,
947 min(SID_VENDOR_SIZE, sizeof(label->d_typename)));
948 strncpy(label->d_packname, cgd.inq_data.product,
949 min(SID_PRODUCT_SIZE, sizeof(label->d_packname)));
950
951 label->d_secsize = softc->params.blksize;
952 label->d_secperunit = softc->params.disksize;
953 label->d_flags = D_REMOVABLE;
954 /*
955 * Make partition 'a' cover the whole disk. This is a temporary
956 * compatibility hack. The 'a' partition should not exist, so
957 * the slice code won't create it. The slice code will make
958 * partition (RAW_PART + 'a') cover the whole disk and fill in
959 * some more defaults.
960 */
961 label->d_partitions[0].p_size = label->d_secperunit;
962 label->d_partitions[0].p_fstype = FS_OTHER;
963
964 /*
965 * We unconditionally (re)set the blocksize each time the
966 * CD device is opened. This is because the CD can change,
967 * and therefore the blocksize might change.
968 * XXX problems here if some slice or partition is still
969 * open with the old size?
970 */
971 if ((softc->device_stats.flags & DEVSTAT_BS_UNAVAILABLE) != 0)
972 softc->device_stats.flags &= ~DEVSTAT_BS_UNAVAILABLE;
973 softc->device_stats.block_size = softc->params.blksize;
974
975 cam_periph_unlock(periph);
976
977 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n"));
978
979 return (error);
980}
981
982static int
983cdclose(dev_t dev, int flag, int fmt, struct proc *p)
984{
985 struct cam_periph *periph;
986 struct cd_softc *softc;
987 int unit, error;
988
989 unit = dkunit(dev);
990 periph = cam_extend_get(cdperiphs, unit);
991 if (periph == NULL)
992 return (ENXIO);
993
994 softc = (struct cd_softc *)periph->softc;
995
996 if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
997 return (error);
998
999 if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0)
1000 cdprevent(periph, PR_ALLOW);
1001
1002 /*
1003 * Unconditionally set the dsopen() flags back to their default
1004 * state.
1005 */
1006 softc->disk.d_dsflags &= ~DSO_NOLABELS;
1007 softc->disk.d_dsflags |= DSO_COMPATLABEL;
1008
1009 /*
1010 * Since we're closing this CD, mark the blocksize as unavailable.
1011 * It will be marked as available whence the CD is opened again.
1012 */
1013 softc->device_stats.flags |= DEVSTAT_BS_UNAVAILABLE;
1014
1015 cam_periph_unlock(periph);
1016 cam_periph_release(periph);
1017
1018 return (0);
1019}
1020
1021static void
1022cdshorttimeout(void *arg)
1023{
1024 struct cdchanger *changer;
1025 int s;
1026
1027 s = splsoftcam();
1028
1029 changer = (struct cdchanger *)arg;
1030
1031 /* Always clear the short timeout flag, since that's what we're in */
1032 changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
1033
1034 /*
1035 * Check to see if there is any more pending or outstanding I/O for
1036 * this device. If not, move it out of the active slot.
1037 */
1038 if ((bioq_first(&changer->cur_device->bio_queue) == NULL)
1039 && (changer->cur_device->device_stats.busy_count == 0)) {
1040 changer->flags |= CHANGER_MANUAL_CALL;
1041 cdrunchangerqueue(changer);
1042 }
1043
1044 splx(s);
1045}
1046
1047/*
1048 * This is a wrapper for xpt_schedule. It only applies to changers.
1049 */
1050static void
1051cdschedule(struct cam_periph *periph, int priority)
1052{
1053 struct cd_softc *softc;
1054 int s;
1055
1056 s = splsoftcam();
1057
1058 softc = (struct cd_softc *)periph->softc;
1059
1060 /*
1061 * If this device isn't currently queued, and if it isn't
1062 * the active device, then we queue this device and run the
1063 * changer queue if there is no timeout scheduled to do it.
1064 * If this device is the active device, just schedule it
1065 * to run again. If this device is queued, there should be
1066 * a timeout in place already that will make sure it runs.
1067 */
1068 if ((softc->pinfo.index == CAM_UNQUEUED_INDEX)
1069 && ((softc->flags & CD_FLAG_ACTIVE) == 0)) {
1070 /*
1071 * We don't do anything with the priority here.
1072 * This is strictly a fifo queue.
1073 */
1074 softc->pinfo.priority = 1;
1075 softc->pinfo.generation = ++softc->changer->devq.generation;
1076 camq_insert(&softc->changer->devq, (cam_pinfo *)softc);
1077
1078 /*
1079 * Since we just put a device in the changer queue,
1080 * check and see if there is a timeout scheduled for
1081 * this changer. If so, let the timeout handle
1082 * switching this device into the active slot. If
1083 * not, manually call the timeout routine to
1084 * bootstrap things.
1085 */
1086 if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0)
1087 && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0)
1088 && ((softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED)==0)){
1089 softc->changer->flags |= CHANGER_MANUAL_CALL;
1090 cdrunchangerqueue(softc->changer);
1091 }
1092 } else if ((softc->flags & CD_FLAG_ACTIVE)
1093 && ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0))
1094 xpt_schedule(periph, priority);
1095
1096 splx(s);
1097
1098}
1099
1100static void
1101cdrunchangerqueue(void *arg)
1102{
1103 struct cd_softc *softc;
1104 struct cdchanger *changer;
1105 int called_from_timeout;
1106 int s;
1107
1108 s = splsoftcam();
1109
1110 changer = (struct cdchanger *)arg;
1111
1112 /*
1113 * If we have NOT been called from cdstrategy() or cddone(), and
1114 * instead from a timeout routine, go ahead and clear the
1115 * timeout flag.
1116 */
1117 if ((changer->flags & CHANGER_MANUAL_CALL) == 0) {
1118 changer->flags &= ~CHANGER_TIMEOUT_SCHED;
1119 called_from_timeout = 1;
1120 } else
1121 called_from_timeout = 0;
1122
1123 /* Always clear the manual call flag */
1124 changer->flags &= ~CHANGER_MANUAL_CALL;
1125
1126 /* nothing to do if the queue is empty */
1127 if (changer->devq.entries <= 0) {
1128 splx(s);
1129 return;
1130 }
1131
1132 /*
1133 * If the changer queue is frozen, that means we have an active
1134 * device.
1135 */
1136 if (changer->devq.qfrozen_cnt > 0) {
1137
1138 if (changer->cur_device->device_stats.busy_count > 0) {
1139 changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP;
1140 changer->cur_device->bufs_left =
1141 changer->cur_device->device_stats.busy_count;
1142 if (called_from_timeout) {
1143 changer->long_handle =
1144 timeout(cdrunchangerqueue, changer,
1145 changer_max_busy_seconds * hz);
1146 changer->flags |= CHANGER_TIMEOUT_SCHED;
1147 }
1148 splx(s);
1149 return;
1150 }
1151
1152 /*
1153 * We always need to reset the frozen count and clear the
1154 * active flag.
1155 */
1156 changer->devq.qfrozen_cnt--;
1157 changer->cur_device->flags &= ~CD_FLAG_ACTIVE;
1158 changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP;
1159
1160 /*
1161 * Check to see whether the current device has any I/O left
1162 * to do. If so, requeue it at the end of the queue. If
1163 * not, there is no need to requeue it.
1164 */
1165 if (bioq_first(&changer->cur_device->bio_queue) != NULL) {
1166
1167 changer->cur_device->pinfo.generation =
1168 ++changer->devq.generation;
1169 camq_insert(&changer->devq,
1170 (cam_pinfo *)changer->cur_device);
1171 }
1172 }
1173
1174 softc = (struct cd_softc *)camq_remove(&changer->devq, CAMQ_HEAD);
1175
1176 changer->cur_device = softc;
1177
1178 changer->devq.qfrozen_cnt++;
1179 softc->flags |= CD_FLAG_ACTIVE;
1180
1181 /* Just in case this device is waiting */
1182 wakeup(&softc->changer);
1183 xpt_schedule(softc->periph, /*priority*/ 1);
1184
1185 /*
1186 * Get rid of any pending timeouts, and set a flag to schedule new
1187 * ones so this device gets its full time quantum.
1188 */
1189 if (changer->flags & CHANGER_TIMEOUT_SCHED) {
1190 untimeout(cdrunchangerqueue, changer, changer->long_handle);
1191 changer->flags &= ~CHANGER_TIMEOUT_SCHED;
1192 }
1193
1194 if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
1195 untimeout(cdshorttimeout, changer, changer->short_handle);
1196 changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
1197 }
1198
1199 /*
1200 * We need to schedule timeouts, but we only do this after the
1201 * first transaction has completed. This eliminates the changer
1202 * switch time.
1203 */
1204 changer->flags |= CHANGER_NEED_TIMEOUT;
1205
1206 splx(s);
1207}
1208
1209static void
1210cdchangerschedule(struct cd_softc *softc)
1211{
1212 struct cdchanger *changer;
1213 int s;
1214
1215 s = splsoftcam();
1216
1217 changer = softc->changer;
1218
1219 /*
1220 * If this is a changer, and this is the current device,
1221 * and this device has at least the minimum time quantum to
1222 * run, see if we can switch it out.
1223 */
1224 if ((softc->flags & CD_FLAG_ACTIVE)
1225 && ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0)
1226 && ((changer->flags & CHANGER_NEED_TIMEOUT) == 0)) {
1227 /*
1228 * We try three things here. The first is that we
1229 * check to see whether the schedule on completion
1230 * flag is set. If it is, we decrement the number
1231 * of buffers left, and if it's zero, we reschedule.
1232 * Next, we check to see whether the pending buffer
1233 * queue is empty and whether there are no
1234 * outstanding transactions. If so, we reschedule.
1235 * Next, we see if the pending buffer queue is empty.
1236 * If it is, we set the number of buffers left to
1237 * the current active buffer count and set the
1238 * schedule on complete flag.
1239 */
1240 if (softc->flags & CD_FLAG_SCHED_ON_COMP) {
1241 if (--softc->bufs_left == 0) {
1242 softc->changer->flags |=
1243 CHANGER_MANUAL_CALL;
1244 softc->flags &= ~CD_FLAG_SCHED_ON_COMP;
1245 cdrunchangerqueue(softc->changer);
1246 }
1247 } else if ((bioq_first(&softc->bio_queue) == NULL)
1248 && (softc->device_stats.busy_count == 0)) {
1249 softc->changer->flags |= CHANGER_MANUAL_CALL;
1250 cdrunchangerqueue(softc->changer);
1251 }
1252 } else if ((softc->changer->flags & CHANGER_NEED_TIMEOUT)
1253 && (softc->flags & CD_FLAG_ACTIVE)) {
1254
1255 /*
1256 * Now that the first transaction to this
1257 * particular device has completed, we can go ahead
1258 * and schedule our timeouts.
1259 */
1260 if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) {
1261 changer->long_handle =
1262 timeout(cdrunchangerqueue, changer,
1263 changer_max_busy_seconds * hz);
1264 changer->flags |= CHANGER_TIMEOUT_SCHED;
1265 } else
1266 printf("cdchangerschedule: already have a long"
1267 " timeout!\n");
1268
1269 if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) {
1270 changer->short_handle =
1271 timeout(cdshorttimeout, changer,
1272 changer_min_busy_seconds * hz);
1273 changer->flags |= CHANGER_SHORT_TMOUT_SCHED;
1274 } else
1275 printf("cdchangerschedule: already have a short "
1276 "timeout!\n");
1277
1278 /*
1279 * We just scheduled timeouts, no need to schedule
1280 * more.
1281 */
1282 changer->flags &= ~CHANGER_NEED_TIMEOUT;
1283
1284 }
1285 splx(s);
1286}
1287
1288static int
1289cdrunccb(union ccb *ccb, int (*error_routine)(union ccb *ccb,
1290 u_int32_t cam_flags,
1291 u_int32_t sense_flags),
1292 u_int32_t cam_flags, u_int32_t sense_flags)
1293{
1294 struct cd_softc *softc;
1295 struct cam_periph *periph;
1296 int error;
1297
1298 periph = xpt_path_periph(ccb->ccb_h.path);
1299 softc = (struct cd_softc *)periph->softc;
1300
1301 error = cam_periph_runccb(ccb, error_routine, cam_flags, sense_flags,
1302 &softc->device_stats);
1303
1304 if (softc->flags & CD_FLAG_CHANGER)
1305 cdchangerschedule(softc);
1306
1307 return(error);
1308}
1309
1310static union ccb *
1311cdgetccb(struct cam_periph *periph, u_int32_t priority)
1312{
1313 struct cd_softc *softc;
1314 int s;
1315
1316 softc = (struct cd_softc *)periph->softc;
1317
1318 if (softc->flags & CD_FLAG_CHANGER) {
1319
1320 s = splsoftcam();
1321
1322 /*
1323 * This should work the first time this device is woken up,
1324 * but just in case it doesn't, we use a while loop.
1325 */
1326 while ((softc->flags & CD_FLAG_ACTIVE) == 0) {
1327 /*
1328 * If this changer isn't already queued, queue it up.
1329 */
1330 if (softc->pinfo.index == CAM_UNQUEUED_INDEX) {
1331 softc->pinfo.priority = 1;
1332 softc->pinfo.generation =
1333 ++softc->changer->devq.generation;
1334 camq_insert(&softc->changer->devq,
1335 (cam_pinfo *)softc);
1336 }
1337 if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0)
1338 && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0)
1339 && ((softc->changer->flags
1340 & CHANGER_SHORT_TMOUT_SCHED)==0)) {
1341 softc->changer->flags |= CHANGER_MANUAL_CALL;
1342 cdrunchangerqueue(softc->changer);
1343 } else
1344 tsleep(&softc->changer, PRIBIO, "cgticb", 0);
1345 }
1346 splx(s);
1347 }
1348 return(cam_periph_getccb(periph, priority));
1349}
1350
1351
1352/*
1353 * Actually translate the requested transfer into one the physical driver
1354 * can understand. The transfer is described by a buf and will include
1355 * only one physical transfer.
1356 */
1357static void
1358cdstrategy(struct bio *bp)
1359{
1360 struct cam_periph *periph;
1361 struct cd_softc *softc;
1362 u_int unit, part;
1363 int s;
1364
1365 unit = dkunit(bp->bio_dev);
1366 part = dkpart(bp->bio_dev);
1367 periph = cam_extend_get(cdperiphs, unit);
1368 if (periph == NULL) {
1369 bp->bio_error = ENXIO;
1370 goto bad;
1371 }
1372
1373 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n"));
1374
1375 softc = (struct cd_softc *)periph->softc;
1376
1377 /*
1378 * Mask interrupts so that the pack cannot be invalidated until
1379 * after we are in the queue. Otherwise, we might not properly
1380 * clean up one of the buffers.
1381 */
1382 s = splbio();
1383
1384 /*
1385 * If the device has been made invalid, error out
1386 */
1387 if ((softc->flags & CD_FLAG_INVALID)) {
1388 splx(s);
1389 bp->bio_error = ENXIO;
1390 goto bad;
1391 }
1392
1393 /*
1394 * Place it in the queue of disk activities for this disk
1395 */
1396 bioqdisksort(&softc->bio_queue, bp);
1397
1398 splx(s);
1399
1400 /*
1401 * Schedule ourselves for performing the work. We do things
1402 * differently for changers.
1403 */
1404 if ((softc->flags & CD_FLAG_CHANGER) == 0)
1405 xpt_schedule(periph, /* XXX priority */1);
1406 else
1407 cdschedule(periph, /* priority */ 1);
1408
1409 return;
1410bad:
1411 bp->bio_flags |= BIO_ERROR;
1412 /*
1413 * Correctly set the buf to indicate a completed xfer
1414 */
1415 bp->bio_resid = bp->bio_bcount;
1416 biodone(bp);
1417 return;
1418}
1419
1420static void
1421cdstart(struct cam_periph *periph, union ccb *start_ccb)
1422{
1423 struct cd_softc *softc;
1424 struct bio *bp;
1425 struct ccb_scsiio *csio;
1426 struct scsi_read_capacity_data *rcap;
1427 int s;
1428
1429 softc = (struct cd_softc *)periph->softc;
1430
1431 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n"));
1432
1433 switch (softc->state) {
1434 case CD_STATE_NORMAL:
1435 {
1436 int oldspl;
1437
1438 s = splbio();
1439 bp = bioq_first(&softc->bio_queue);
1440 if (periph->immediate_priority <= periph->pinfo.priority) {
1441 start_ccb->ccb_h.ccb_state = CD_CCB_WAITING;
1442
1443 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
1444 periph_links.sle);
1445 periph->immediate_priority = CAM_PRIORITY_NONE;
1446 splx(s);
1447 wakeup(&periph->ccb_list);
1448 } else if (bp == NULL) {
1449 splx(s);
1450 xpt_release_ccb(start_ccb);
1451 } else {
1452 bioq_remove(&softc->bio_queue, bp);
1453
1454 devstat_start_transaction(&softc->device_stats);
1455
1456 scsi_read_write(&start_ccb->csio,
1457 /*retries*/4,
1458 /* cbfcnp */ cddone,
1459 (bp->bio_flags & BIO_ORDERED) != 0 ?
1460 MSG_ORDERED_Q_TAG :
1461 MSG_SIMPLE_Q_TAG,
1462 /* read */bp->bio_cmd == BIO_READ,
1463 /* byte2 */ 0,
1464 /* minimum_cmd_size */ 10,
1465 /* lba */ bp->bio_pblkno,
1466 bp->bio_bcount / softc->params.blksize,
1467 /* data_ptr */ bp->bio_data,
1468 /* dxfer_len */ bp->bio_bcount,
1469 /* sense_len */ SSD_FULL_SIZE,
1470 /* timeout */ 30000);
1471 start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO;
1472
1473
1474 /*
1475 * Block out any asyncronous callbacks
1476 * while we touch the pending ccb list.
1477 */
1478 oldspl = splcam();
1479 LIST_INSERT_HEAD(&softc->pending_ccbs,
1480 &start_ccb->ccb_h, periph_links.le);
1481 splx(oldspl);
1482
1483 /* We expect a unit attention from this device */
1484 if ((softc->flags & CD_FLAG_RETRY_UA) != 0) {
1485 start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA;
1486 softc->flags &= ~CD_FLAG_RETRY_UA;
1487 }
1488
1489 start_ccb->ccb_h.ccb_bp = bp;
1490 bp = bioq_first(&softc->bio_queue);
1491 splx(s);
1492
1493 xpt_action(start_ccb);
1494 }
1495 if (bp != NULL) {
1496 /* Have more work to do, so ensure we stay scheduled */
1497 xpt_schedule(periph, /* XXX priority */1);
1498 }
1499 break;
1500 }
1501 case CD_STATE_PROBE:
1502 {
1503
1504 rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap),
1505 M_TEMP,
1506 M_NOWAIT);
1507 if (rcap == NULL) {
1508 xpt_print_path(periph->path);
1509 printf("cdstart: Couldn't malloc read_capacity data\n");
1510 /* cd_free_periph??? */
1511 break;
1512 }
1513 csio = &start_ccb->csio;
1514 scsi_read_capacity(csio,
1515 /*retries*/1,
1516 cddone,
1517 MSG_SIMPLE_Q_TAG,
1518 rcap,
1519 SSD_FULL_SIZE,
1520 /*timeout*/20000);
1521 start_ccb->ccb_h.ccb_bp = NULL;
1522 start_ccb->ccb_h.ccb_state = CD_CCB_PROBE;
1523 xpt_action(start_ccb);
1524 break;
1525 }
1526 }
1527}
1528
1529static void
1530cddone(struct cam_periph *periph, union ccb *done_ccb)
1531{
1532 struct cd_softc *softc;
1533 struct ccb_scsiio *csio;
1534
1535 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n"));
1536
1537 softc = (struct cd_softc *)periph->softc;
1538 csio = &done_ccb->csio;
1539
1540 switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) {
1541 case CD_CCB_BUFFER_IO:
1542 {
1543 struct bio *bp;
1544 int error;
1545 int oldspl;
1546
1547 bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
1548 error = 0;
1549
1550 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1551 int sf;
1552
1553 if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0)
1554 sf = SF_RETRY_UA;
1555 else
1556 sf = 0;
1557
1558 error = cderror(done_ccb, CAM_RETRY_SELTO, sf);
1559 if (error == ERESTART) {
1560 /*
1561 * A retry was scheuled, so
1562 * just return.
1563 */
1564 return;
1565 }
1566 }
1567
1568 if (error != 0) {
1569 int s;
1570 struct bio *q_bp;
1571
1572 xpt_print_path(periph->path);
1573 printf("cddone: got error %#x back\n", error);
1574 s = splbio();
1575 while ((q_bp = bioq_first(&softc->bio_queue)) != NULL) {
1576 bioq_remove(&softc->bio_queue, q_bp);
1577 q_bp->bio_resid = q_bp->bio_bcount;
1578 biofinish(q_bp, NULL, EIO);
1579 }
1580 splx(s);
1581 bp->bio_resid = bp->bio_bcount;
1582 bp->bio_error = error;
1583 bp->bio_flags |= BIO_ERROR;
1584 cam_release_devq(done_ccb->ccb_h.path,
1585 /*relsim_flags*/0,
1586 /*reduction*/0,
1587 /*timeout*/0,
1588 /*getcount_only*/0);
1589
1590 } else {
1591 bp->bio_resid = csio->resid;
1592 bp->bio_error = 0;
1593 if (bp->bio_resid != 0) {
1594 /* Short transfer ??? */
1595 bp->bio_flags |= BIO_ERROR;
1596 }
1597 }
1598
1599 /*
1600 * Block out any asyncronous callbacks
1601 * while we touch the pending ccb list.
1602 */
1603 oldspl = splcam();
1604 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
1605 splx(oldspl);
1606
1607 if (softc->flags & CD_FLAG_CHANGER)
1608 cdchangerschedule(softc);
1609
1610 biofinish(bp, &softc->device_stats, 0);
1611 break;
1612 }
1613 case CD_CCB_PROBE:
1614 {
1615 struct scsi_read_capacity_data *rdcap;
1616 char announce_buf[120]; /*
1617 * Currently (9/30/97) the
1618 * longest possible announce
1619 * buffer is 108 bytes, for the
1620 * first error case below.
1621 * That is 39 bytes for the
1622 * basic string, 16 bytes for the
1623 * biggest sense key (hardware
1624 * error), 52 bytes for the
1625 * text of the largest sense
1626 * qualifier valid for a CDROM,
1627 * (0x72, 0x03 or 0x04,
1628 * 0x03), and one byte for the
1629 * null terminating character.
1630 * To allow for longer strings,
1631 * the announce buffer is 120
1632 * bytes.
1633 */
1634 struct cd_params *cdp;
1635
1636 cdp = &softc->params;
1637
1638 rdcap = (struct scsi_read_capacity_data *)csio->data_ptr;
1639
1640 cdp->disksize = scsi_4btoul (rdcap->addr) + 1;
1641 cdp->blksize = scsi_4btoul (rdcap->length);
1642
1643 if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
1644
1645 snprintf(announce_buf, sizeof(announce_buf),
1646 "cd present [%lu x %lu byte records]",
1647 cdp->disksize, (u_long)cdp->blksize);
1648
1649 } else {
1650 int error;
1651 /*
1652 * Retry any UNIT ATTENTION type errors. They
1653 * are expected at boot.
1654 */
1655 error = cderror(done_ccb, CAM_RETRY_SELTO,
1656 SF_RETRY_UA | SF_NO_PRINT);
1657 if (error == ERESTART) {
1658 /*
1659 * A retry was scheuled, so
1660 * just return.
1661 */
1662 return;
1663 } else if (error != 0) {
1664
1665 struct scsi_sense_data *sense;
1666 int asc, ascq;
1667 int sense_key, error_code;
1668 int have_sense;
1669 cam_status status;
1670 struct ccb_getdev cgd;
1671
1672 /* Don't wedge this device's queue */
1673 cam_release_devq(done_ccb->ccb_h.path,
1674 /*relsim_flags*/0,
1675 /*reduction*/0,
1676 /*timeout*/0,
1677 /*getcount_only*/0);
1678
1679 status = done_ccb->ccb_h.status;
1680
1681 xpt_setup_ccb(&cgd.ccb_h,
1682 done_ccb->ccb_h.path,
1683 /* priority */ 1);
1684 cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1685 xpt_action((union ccb *)&cgd);
1686
1687 if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0)
1688 || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0)
1689 || ((status & CAM_AUTOSNS_VALID) == 0))
1690 have_sense = FALSE;
1691 else
1692 have_sense = TRUE;
1693
1694 if (have_sense) {
1695 sense = &csio->sense_data;
1696 scsi_extract_sense(sense, &error_code,
1697 &sense_key,
1698 &asc, &ascq);
1699 }
1700 /*
1701 * Attach to anything that claims to be a
1702 * CDROM or WORM device, as long as it
1703 * doesn't return a "Logical unit not
1704 * supported" (0x25) error.
1705 */
1706 if ((have_sense) && (asc != 0x25)
1707 && (error_code == SSD_CURRENT_ERROR)) {
1708 const char *sense_key_desc;
1709 const char *asc_desc;
1710
1711 scsi_sense_desc(sense_key, asc, ascq,
1712 &cgd.inq_data,
1713 &sense_key_desc,
1714 &asc_desc);
1715 snprintf(announce_buf,
1716 sizeof(announce_buf),
1717 "Attempt to query device "
1718 "size failed: %s, %s",
1719 sense_key_desc,
1720 asc_desc);
1721 } else if (SID_TYPE(&cgd.inq_data) == T_CDROM) {
1722 /*
1723 * We only print out an error for
1724 * CDROM type devices. For WORM
1725 * devices, we don't print out an
1726 * error since a few WORM devices
1727 * don't support CDROM commands.
1728 * If we have sense information, go
1729 * ahead and print it out.
1730 * Otherwise, just say that we
1731 * couldn't attach.
1732 */
1733
1734 /*
1735 * Just print out the error, not
1736 * the full probe message, when we
1737 * don't attach.
1738 */
1739 if (have_sense)
1740 scsi_sense_print(
1741 &done_ccb->csio);
1742 else {
1743 xpt_print_path(periph->path);
1744 printf("got CAM status %#x\n",
1745 done_ccb->ccb_h.status);
1746 }
1747 xpt_print_path(periph->path);
1748 printf("fatal error, failed"
1749 " to attach to device\n");
1750
1751 /*
1752 * Invalidate this peripheral.
1753 */
1754 cam_periph_invalidate(periph);
1755
1756 announce_buf[0] = '\0';
1757 } else {
1758
1759 /*
1760 * Invalidate this peripheral.
1761 */
1762 cam_periph_invalidate(periph);
1763 announce_buf[0] = '\0';
1764 }
1765 }
1766 }
1767 free(rdcap, M_TEMP);
1768 if (announce_buf[0] != '\0') {
1769 xpt_announce_periph(periph, announce_buf);
1770 if (softc->flags & CD_FLAG_CHANGER)
1771 cdchangerschedule(softc);
1772 }
1773 softc->state = CD_STATE_NORMAL;
1774 /*
1775 * Since our peripheral may be invalidated by an error
1776 * above or an external event, we must release our CCB
1777 * before releasing the probe lock on the peripheral.
1778 * The peripheral will only go away once the last lock
1779 * is removed, and we need it around for the CCB release
1780 * operation.
1781 */
1782 xpt_release_ccb(done_ccb);
1783 cam_periph_unlock(periph);
1784 return;
1785 }
1786 case CD_CCB_WAITING:
1787 {
1788 /* Caller will release the CCB */
1789 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
1790 ("trying to wakeup ccbwait\n"));
1791
1792 wakeup(&done_ccb->ccb_h.cbfcnp);
1793 return;
1794 }
1795 default:
1796 break;
1797 }
1798 xpt_release_ccb(done_ccb);
1799}
1800
1801static int
1802cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
1803{
1804
1805 struct cam_periph *periph;
1806 struct cd_softc *softc;
1807 int error, unit;
1808
1809 unit = dkunit(dev);
1810
1811 periph = cam_extend_get(cdperiphs, unit);
1812 if (periph == NULL)
1813 return(ENXIO);
1814
1815 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n"));
1816
1817 softc = (struct cd_softc *)periph->softc;
1818
1819 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
1820 ("trying to do ioctl %#lx\n", cmd));
1821
1822 error = cam_periph_lock(periph, PRIBIO | PCATCH);
1823
1824 if (error != 0)
1825 return(error);
1826
1827 switch (cmd) {
1828
1829 case CDIOCPLAYTRACKS:
1830 {
1831 struct ioc_play_track *args
1832 = (struct ioc_play_track *) addr;
1833 struct cd_mode_data *data;
1834
1835 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
1836 M_WAITOK);
1837
1838 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1839 ("trying to do CDIOCPLAYTRACKS\n"));
1840
1841 error = cdgetmode(periph, data, AUDIO_PAGE);
1842 if (error) {
1843 free(data, M_TEMP);
1844 break;
1845 }
1846 data->page.audio.flags &= ~CD_PA_SOTC;
1847 data->page.audio.flags |= CD_PA_IMMED;
1848 error = cdsetmode(periph, data);
1849 free(data, M_TEMP);
1850 if (error)
1851 break;
1852 if (softc->quirks & CD_Q_BCD_TRACKS) {
1853 args->start_track = bin2bcd(args->start_track);
1854 args->end_track = bin2bcd(args->end_track);
1855 }
1856 error = cdplaytracks(periph,
1857 args->start_track,
1858 args->start_index,
1859 args->end_track,
1860 args->end_index);
1861 }
1862 break;
1863 case CDIOCPLAYMSF:
1864 {
1865 struct ioc_play_msf *args
1866 = (struct ioc_play_msf *) addr;
1867 struct cd_mode_data *data;
1868
1869 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
1870 M_WAITOK);
1871
1872 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1873 ("trying to do CDIOCPLAYMSF\n"));
1874
1875 error = cdgetmode(periph, data, AUDIO_PAGE);
1876 if (error) {
1877 free(data, M_TEMP);
1878 break;
1879 }
1880 data->page.audio.flags &= ~CD_PA_SOTC;
1881 data->page.audio.flags |= CD_PA_IMMED;
1882 error = cdsetmode(periph, data);
1883 free(data, M_TEMP);
1884 if (error)
1885 break;
1886 error = cdplaymsf(periph,
1887 args->start_m,
1888 args->start_s,
1889 args->start_f,
1890 args->end_m,
1891 args->end_s,
1892 args->end_f);
1893 }
1894 break;
1895 case CDIOCPLAYBLOCKS:
1896 {
1897 struct ioc_play_blocks *args
1898 = (struct ioc_play_blocks *) addr;
1899 struct cd_mode_data *data;
1900
1901 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1902 ("trying to do CDIOCPLAYBLOCKS\n"));
1903
1904 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
1905 M_WAITOK);
1906
1907 error = cdgetmode(periph, data, AUDIO_PAGE);
1908 if (error) {
1909 free(data, M_TEMP);
1910 break;
1911 }
1912 data->page.audio.flags &= ~CD_PA_SOTC;
1913 data->page.audio.flags |= CD_PA_IMMED;
1914 error = cdsetmode(periph, data);
1915 free(data, M_TEMP);
1916 if (error)
1917 break;
1918 error = cdplay(periph, args->blk, args->len);
1919 }
1920 break;
1921 case CDIOCREADSUBCHANNEL:
1922 {
1923 struct ioc_read_subchannel *args
1924 = (struct ioc_read_subchannel *) addr;
1925 struct cd_sub_channel_info *data;
1926 u_int32_t len = args->data_len;
1927
1928 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1929 ("trying to do CDIOCREADSUBCHANNEL\n"));
1930
1931 data = malloc(sizeof(struct cd_sub_channel_info),
1932 M_TEMP, M_WAITOK);
1933
1934 if ((len > sizeof(struct cd_sub_channel_info)) ||
1935 (len < sizeof(struct cd_sub_channel_header))) {
1936 printf(
1937 "scsi_cd: cdioctl: "
1938 "cdioreadsubchannel: error, len=%d\n",
1939 len);
1940 error = EINVAL;
1941 free(data, M_TEMP);
1942 break;
1943 }
1944
1945 if (softc->quirks & CD_Q_BCD_TRACKS)
1946 args->track = bin2bcd(args->track);
1947
1948 error = cdreadsubchannel(periph, args->address_format,
1949 args->data_format, args->track, data, len);
1950
1951 if (error) {
1952 free(data, M_TEMP);
1953 break;
1954 }
1955 if (softc->quirks & CD_Q_BCD_TRACKS)
1956 data->what.track_info.track_number =
1957 bcd2bin(data->what.track_info.track_number);
1958 len = min(len, ((data->header.data_len[0] << 8) +
1959 data->header.data_len[1] +
1960 sizeof(struct cd_sub_channel_header)));
1961 if (copyout(data, args->data, len) != 0) {
1962 error = EFAULT;
1963 }
1964 free(data, M_TEMP);
1965 }
1966 break;
1967
1968 case CDIOREADTOCHEADER:
1969 {
1970 struct ioc_toc_header *th;
1971
1972 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1973 ("trying to do CDIOREADTOCHEADER\n"));
1974
1975 th = malloc(sizeof(struct ioc_toc_header), M_TEMP,
1976 M_WAITOK);
1977 error = cdreadtoc(periph, 0, 0,
1978 (struct cd_toc_entry *)th,
1979 sizeof (*th));
1980 if (error) {
1981 free(th, M_TEMP);
1982 break;
1983 }
1984 if (softc->quirks & CD_Q_BCD_TRACKS) {
1985 /* we are going to have to convert the BCD
1986 * encoding on the cd to what is expected
1987 */
1988 th->starting_track =
1989 bcd2bin(th->starting_track);
1990 th->ending_track = bcd2bin(th->ending_track);
1991 }
1992 NTOHS(th->len);
1993 bcopy(th, addr, sizeof(*th));
1994 free(th, M_TEMP);
1995 }
1996 break;
1997 case CDIOREADTOCENTRYS:
1998 {
1999 typedef struct {
2000 struct ioc_toc_header header;
2001 struct cd_toc_entry entries[100];
2002 } data_t;
2003 typedef struct {
2004 struct ioc_toc_header header;
2005 struct cd_toc_entry entry;
2006 } lead_t;
2007
2008 data_t *data;
2009 lead_t *lead;
2010 struct ioc_read_toc_entry *te =
2011 (struct ioc_read_toc_entry *) addr;
2012 struct ioc_toc_header *th;
2013 u_int32_t len, readlen, idx, num;
2014 u_int32_t starting_track = te->starting_track;
2015
2016 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2017 ("trying to do CDIOREADTOCENTRYS\n"));
2018
2019 data = malloc(sizeof(data_t), M_TEMP, M_WAITOK);
2020 lead = malloc(sizeof(lead_t), M_TEMP, M_WAITOK);
2021
2022 if (te->data_len < sizeof(struct cd_toc_entry)
2023 || (te->data_len % sizeof(struct cd_toc_entry)) != 0
2024 || (te->address_format != CD_MSF_FORMAT
2025 && te->address_format != CD_LBA_FORMAT)) {
2026 error = EINVAL;
2027 printf("scsi_cd: error in readtocentries, "
2028 "returning EINVAL\n");
2029 free(data, M_TEMP);
2030 free(lead, M_TEMP);
2031 break;
2032 }
2033
2034 th = &data->header;
2035 error = cdreadtoc(periph, 0, 0,
2036 (struct cd_toc_entry *)th,
2037 sizeof (*th));
2038 if (error) {
2039 free(data, M_TEMP);
2040 free(lead, M_TEMP);
2041 break;
2042 }
2043
2044 if (softc->quirks & CD_Q_BCD_TRACKS) {
2045 /* we are going to have to convert the BCD
2046 * encoding on the cd to what is expected
2047 */
2048 th->starting_track =
2049 bcd2bin(th->starting_track);
2050 th->ending_track = bcd2bin(th->ending_track);
2051 }
2052
2053 if (starting_track == 0)
2054 starting_track = th->starting_track;
2055 else if (starting_track == LEADOUT)
2056 starting_track = th->ending_track + 1;
2057 else if (starting_track < th->starting_track ||
2058 starting_track > th->ending_track + 1) {
2059 printf("scsi_cd: error in readtocentries, "
2060 "returning EINVAL\n");
2061 free(data, M_TEMP);
2062 free(lead, M_TEMP);
2063 error = EINVAL;
2064 break;
2065 }
2066
2067 /* calculate reading length without leadout entry */
2068 readlen = (th->ending_track - starting_track + 1) *
2069 sizeof(struct cd_toc_entry);
2070
2071 /* and with leadout entry */
2072 len = readlen + sizeof(struct cd_toc_entry);
2073 if (te->data_len < len) {
2074 len = te->data_len;
2075 if (readlen > len)
2076 readlen = len;
2077 }
2078 if (len > sizeof(data->entries)) {
2079 printf("scsi_cd: error in readtocentries, "
2080 "returning EINVAL\n");
2081 error = EINVAL;
2082 free(data, M_TEMP);
2083 free(lead, M_TEMP);
2084 break;
2085 }
2086 num = len / sizeof(struct cd_toc_entry);
2087
2088 if (readlen > 0) {
2089 error = cdreadtoc(periph, te->address_format,
2090 starting_track,
2091 (struct cd_toc_entry *)data,
2092 readlen + sizeof (*th));
2093 if (error) {
2094 free(data, M_TEMP);
2095 free(lead, M_TEMP);
2096 break;
2097 }
2098 }
2099
2100 /* make leadout entry if needed */
2101 idx = starting_track + num - 1;
2102 if (softc->quirks & CD_Q_BCD_TRACKS)
2103 th->ending_track = bcd2bin(th->ending_track);
2104 if (idx == th->ending_track + 1) {
2105 error = cdreadtoc(periph, te->address_format,
2106 LEADOUT,
2107 (struct cd_toc_entry *)lead,
2108 sizeof(*lead));
2109 if (error) {
2110 free(data, M_TEMP);
2111 free(lead, M_TEMP);
2112 break;
2113 }
2114 data->entries[idx - starting_track] =
2115 lead->entry;
2116 }
2117 if (softc->quirks & CD_Q_BCD_TRACKS) {
2118 for (idx = 0; idx < num - 1; idx++) {
2119 data->entries[idx].track =
2120 bcd2bin(data->entries[idx].track);
2121 }
2122 }
2123
2124 error = copyout(data->entries, te->data, len);
2125 free(data, M_TEMP);
2126 free(lead, M_TEMP);
2127 }
2128 break;
2129 case CDIOREADTOCENTRY:
2130 {
2131 /* yeah yeah, this is ugly */
2132 typedef struct {
2133 struct ioc_toc_header header;
2134 struct cd_toc_entry entry;
2135 } data_t;
2136
2137 data_t *data;
2138 struct ioc_read_toc_single_entry *te =
2139 (struct ioc_read_toc_single_entry *) addr;
2140 struct ioc_toc_header *th;
2141 u_int32_t track;
2142
2143 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2144 ("trying to do CDIOREADTOCENTRY\n"));
2145
2146 data = malloc(sizeof(data_t), M_TEMP, M_WAITOK);
2147
2148 if (te->address_format != CD_MSF_FORMAT
2149 && te->address_format != CD_LBA_FORMAT) {
2150 printf("error in readtocentry, "
2151 " returning EINVAL\n");
2152 free(data, M_TEMP);
2153 error = EINVAL;
2154 break;
2155 }
2156
2157 th = &data->header;
2158 error = cdreadtoc(periph, 0, 0,
2159 (struct cd_toc_entry *)th,
2160 sizeof (*th));
2161 if (error) {
2162 free(data, M_TEMP);
2163 break;
2164 }
2165
2166 if (softc->quirks & CD_Q_BCD_TRACKS) {
2167 /* we are going to have to convert the BCD
2168 * encoding on the cd to what is expected
2169 */
2170 th->starting_track =
2171 bcd2bin(th->starting_track);
2172 th->ending_track = bcd2bin(th->ending_track);
2173 }
2174 track = te->track;
2175 if (track == 0)
2176 track = th->starting_track;
2177 else if (track == LEADOUT)
2178 /* OK */;
2179 else if (track < th->starting_track ||
2180 track > th->ending_track + 1) {
2181 printf("error in readtocentry, "
2182 " returning EINVAL\n");
2183 free(data, M_TEMP);
2184 error = EINVAL;
2185 break;
2186 }
2187
2188 error = cdreadtoc(periph, te->address_format, track,
2189 (struct cd_toc_entry *)data,
2190 sizeof(data_t));
2191 if (error) {
2192 free(data, M_TEMP);
2193 break;
2194 }
2195
2196 if (softc->quirks & CD_Q_BCD_TRACKS)
2197 data->entry.track = bcd2bin(data->entry.track);
2198 bcopy(&data->entry, &te->entry,
2199 sizeof(struct cd_toc_entry));
2200 free(data, M_TEMP);
2201 }
2202 break;
2203 case CDIOCSETPATCH:
2204 {
2205 struct ioc_patch *arg = (struct ioc_patch *) addr;
2206 struct cd_mode_data *data;
2207
2208 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2209 ("trying to do CDIOCSETPATCH\n"));
2210
2211 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2212 M_WAITOK);
2213 error = cdgetmode(periph, data, AUDIO_PAGE);
2214 if (error) {
2215 free(data, M_TEMP);
2216 break;
2217 }
2218 data->page.audio.port[LEFT_PORT].channels =
2219 arg->patch[0];
2220 data->page.audio.port[RIGHT_PORT].channels =
2221 arg->patch[1];
2222 data->page.audio.port[2].channels = arg->patch[2];
2223 data->page.audio.port[3].channels = arg->patch[3];
2224 error = cdsetmode(periph, data);
2225 free(data, M_TEMP);
2226 }
2227 break;
2228 case CDIOCGETVOL:
2229 {
2230 struct ioc_vol *arg = (struct ioc_vol *) addr;
2231 struct cd_mode_data *data;
2232
2233 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2234 ("trying to do CDIOCGETVOL\n"));
2235
2236 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2237 M_WAITOK);
2238 error = cdgetmode(periph, data, AUDIO_PAGE);
2239 if (error) {
2240 free(data, M_TEMP);
2241 break;
2242 }
2243 arg->vol[LEFT_PORT] =
2244 data->page.audio.port[LEFT_PORT].volume;
2245 arg->vol[RIGHT_PORT] =
2246 data->page.audio.port[RIGHT_PORT].volume;
2247 arg->vol[2] = data->page.audio.port[2].volume;
2248 arg->vol[3] = data->page.audio.port[3].volume;
2249 free(data, M_TEMP);
2250 }
2251 break;
2252 case CDIOCSETVOL:
2253 {
2254 struct ioc_vol *arg = (struct ioc_vol *) addr;
2255 struct cd_mode_data *data;
2256
2257 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2258 ("trying to do CDIOCSETVOL\n"));
2259
2260 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2261 M_WAITOK);
2262 error = cdgetmode(periph, data, AUDIO_PAGE);
2263 if (error) {
2264 free(data, M_TEMP);
2265 break;
2266 }
2267 data->page.audio.port[LEFT_PORT].channels = CHANNEL_0;
2268 data->page.audio.port[LEFT_PORT].volume =
2269 arg->vol[LEFT_PORT];
2270 data->page.audio.port[RIGHT_PORT].channels = CHANNEL_1;
2271 data->page.audio.port[RIGHT_PORT].volume =
2272 arg->vol[RIGHT_PORT];
2273 data->page.audio.port[2].volume = arg->vol[2];
2274 data->page.audio.port[3].volume = arg->vol[3];
2275 error = cdsetmode(periph, data);
2276 free(data, M_TEMP);
2277 }
2278 break;
2279 case CDIOCSETMONO:
2280 {
2281 struct cd_mode_data *data;
2282
2283 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2284 ("trying to do CDIOCSETMONO\n"));
2285
2286 data = malloc(sizeof(struct cd_mode_data),
2287 M_TEMP, M_WAITOK);
2288 error = cdgetmode(periph, data, AUDIO_PAGE);
2289 if (error) {
2290 free(data, M_TEMP);
2291 break;
2292 }
2293 data->page.audio.port[LEFT_PORT].channels =
2294 LEFT_CHANNEL | RIGHT_CHANNEL;
2295 data->page.audio.port[RIGHT_PORT].channels =
2296 LEFT_CHANNEL | RIGHT_CHANNEL;
2297 data->page.audio.port[2].channels = 0;
2298 data->page.audio.port[3].channels = 0;
2299 error = cdsetmode(periph, data);
2300 free(data, M_TEMP);
2301 }
2302 break;
2303 case CDIOCSETSTEREO:
2304 {
2305 struct cd_mode_data *data;
2306
2307 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2308 ("trying to do CDIOCSETSTEREO\n"));
2309
2310 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2311 M_WAITOK);
2312 error = cdgetmode(periph, data, AUDIO_PAGE);
2313 if (error) {
2314 free(data, M_TEMP);
2315 break;
2316 }
2317 data->page.audio.port[LEFT_PORT].channels =
2318 LEFT_CHANNEL;
2319 data->page.audio.port[RIGHT_PORT].channels =
2320 RIGHT_CHANNEL;
2321 data->page.audio.port[2].channels = 0;
2322 data->page.audio.port[3].channels = 0;
2323 error = cdsetmode(periph, data);
2324 free(data, M_TEMP);
2325 }
2326 break;
2327 case CDIOCSETMUTE:
2328 {
2329 struct cd_mode_data *data;
2330
2331 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2332 ("trying to do CDIOCSETMUTE\n"));
2333
2334 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2335 M_WAITOK);
2336 error = cdgetmode(periph, data, AUDIO_PAGE);
2337 if (error) {
2338 free(data, M_TEMP);
2339 break;
2340 }
2341 data->page.audio.port[LEFT_PORT].channels = 0;
2342 data->page.audio.port[RIGHT_PORT].channels = 0;
2343 data->page.audio.port[2].channels = 0;
2344 data->page.audio.port[3].channels = 0;
2345 error = cdsetmode(periph, data);
2346 free(data, M_TEMP);
2347 }
2348 break;
2349 case CDIOCSETLEFT:
2350 {
2351 struct cd_mode_data *data;
2352
2353 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2354 ("trying to do CDIOCSETLEFT\n"));
2355
2356 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2357 M_WAITOK);
2358 error = cdgetmode(periph, data, AUDIO_PAGE);
2359 if (error) {
2360 free(data, M_TEMP);
2361 break;
2362 }
2363 data->page.audio.port[LEFT_PORT].channels =
2364 LEFT_CHANNEL;
2365 data->page.audio.port[RIGHT_PORT].channels =
2366 LEFT_CHANNEL;
2367 data->page.audio.port[2].channels = 0;
2368 data->page.audio.port[3].channels = 0;
2369 error = cdsetmode(periph, data);
2370 free(data, M_TEMP);
2371 }
2372 break;
2373 case CDIOCSETRIGHT:
2374 {
2375 struct cd_mode_data *data;
2376
2377 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2378 ("trying to do CDIOCSETRIGHT\n"));
2379
2380 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2381 M_WAITOK);
2382 error = cdgetmode(periph, data, AUDIO_PAGE);
2383 if (error) {
2384 free(data, M_TEMP);
2385 break;
2386 }
2387 data->page.audio.port[LEFT_PORT].channels =
2388 RIGHT_CHANNEL;
2389 data->page.audio.port[RIGHT_PORT].channels =
2390 RIGHT_CHANNEL;
2391 data->page.audio.port[2].channels = 0;
2392 data->page.audio.port[3].channels = 0;
2393 error = cdsetmode(periph, data);
2394 free(data, M_TEMP);
2395 }
2396 break;
2397 case CDIOCRESUME:
2398 error = cdpause(periph, 1);
2399 break;
2400 case CDIOCPAUSE:
2401 error = cdpause(periph, 0);
2402 break;
2403 case CDIOCSTART:
2404 error = cdstartunit(periph);
2405 break;
2406 case CDIOCSTOP:
2407 error = cdstopunit(periph, 0);
2408 break;
2409 case CDIOCEJECT:
2410 error = cdstopunit(periph, 1);
2411 break;
2412 case CDIOCALLOW:
2413 cdprevent(periph, PR_ALLOW);
2414 break;
2415 case CDIOCPREVENT:
2416 cdprevent(periph, PR_PREVENT);
2417 break;
2418 case CDIOCSETDEBUG:
2419 /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */
2420 error = ENOTTY;
2421 break;
2422 case CDIOCCLRDEBUG:
2423 /* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */
2424 error = ENOTTY;
2425 break;
2426 case CDIOCRESET:
2427 /* return (cd_reset(periph)); */
2428 error = ENOTTY;
2429 break;
2430 case DVDIOCSENDKEY:
2431 case DVDIOCREPORTKEY: {
2432 struct dvd_authinfo *authinfo;
2433
2434 authinfo = (struct dvd_authinfo *)addr;
2435
2436 if (cmd == DVDIOCREPORTKEY)
2437 error = cdreportkey(periph, authinfo);
2438 else
2439 error = cdsendkey(periph, authinfo);
2440 break;
2441 }
2442 case DVDIOCREADSTRUCTURE: {
2443 struct dvd_struct *dvdstruct;
2444
2445 dvdstruct = (struct dvd_struct *)addr;
2446
2447 error = cdreaddvdstructure(periph, dvdstruct);
2448
2449 break;
2450 }
2451 default:
2452 error = cam_periph_ioctl(periph, cmd, addr, cderror);
2453 break;
2454 }
2455
2456 cam_periph_unlock(periph);
2457
2458 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n"));
2459
2460 return (error);
2461}
2462
2463static void
2464cdprevent(struct cam_periph *periph, int action)
2465{
2466 union ccb *ccb;
2467 struct cd_softc *softc;
2468 int error;
2469
2470 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n"));
2471
2472 softc = (struct cd_softc *)periph->softc;
2473
2474 if (((action == PR_ALLOW)
2475 && (softc->flags & CD_FLAG_DISC_LOCKED) == 0)
2476 || ((action == PR_PREVENT)
2477 && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) {
2478 return;
2479 }
2480
2481 ccb = cdgetccb(periph, /* priority */ 1);
2482
2483 scsi_prevent(&ccb->csio,
2484 /*retries*/ 1,
2485 cddone,
2486 MSG_SIMPLE_Q_TAG,
2487 action,
2488 SSD_FULL_SIZE,
2489 /* timeout */60000);
2490
2491 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2492 /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT);
2493
2494 xpt_release_ccb(ccb);
2495
2496 if (error == 0) {
2497 if (action == PR_ALLOW)
2498 softc->flags &= ~CD_FLAG_DISC_LOCKED;
2499 else
2500 softc->flags |= CD_FLAG_DISC_LOCKED;
2501 }
2502}
2503
2504static int
2505cdsize(dev_t dev, u_int32_t *size)
2506{
2507 struct cam_periph *periph;
2508 struct cd_softc *softc;
2509 union ccb *ccb;
2510 struct scsi_read_capacity_data *rcap_buf;
2511 int error;
2512
2513 periph = cam_extend_get(cdperiphs, dkunit(dev));
2514
2515 if (periph == NULL)
2516 return (ENXIO);
2517
2518 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n"));
2519
2520 softc = (struct cd_softc *)periph->softc;
2521
2522 ccb = cdgetccb(periph, /* priority */ 1);
2523
2524 rcap_buf = malloc(sizeof(struct scsi_read_capacity_data),
2525 M_TEMP, M_WAITOK);
2526
2527 scsi_read_capacity(&ccb->csio,
2528 /*retries*/ 1,
2529 cddone,
2530 MSG_SIMPLE_Q_TAG,
2531 rcap_buf,
2532 SSD_FULL_SIZE,
2533 /* timeout */20000);
2534
2535 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2536 /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT);
2537
2538 xpt_release_ccb(ccb);
2539
2540 softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1;
2541 softc->params.blksize = scsi_4btoul(rcap_buf->length);
2542 /*
2543 * SCSI-3 mandates that the reported blocksize shall be 2048.
2544 * Older drives sometimes report funny values, trim it down to
2545 * 2048, or other parts of the kernel will get confused.
2546 *
2547 * XXX we leave drives alone that might report 512 bytes, as
2548 * well as drives reporting more weird sizes like perhaps 4K.
2549 */
2550 if (softc->params.blksize > 2048 && softc->params.blksize <= 2352)
2551 softc->params.blksize = 2048;
2552
2553 free(rcap_buf, M_TEMP);
2554 *size = softc->params.disksize;
2555
2556 return (error);
2557
2558}
2559
2560/*
2561 * The idea here is to try to figure out whether the first track is data or
2562 * audio. If it is data, we can at least attempt to read a disklabel off
2563 * the first sector of the disk. If it is audio, there won't be a
2564 * disklabel.
2565 *
2566 * This routine returns 0 if the first track is data, and non-zero if there
2567 * is an error or the first track is audio. (If either non-zero case, we
2568 * should not attempt to read the disklabel.)
2569 */
2570static int
2571cdfirsttrackisdata(struct cam_periph *periph)
2572{
2573 struct cdtocdata {
2574 struct ioc_toc_header header;
2575 struct cd_toc_entry entries[100];
2576 };
2577 struct cd_softc *softc;
2578 struct ioc_toc_header *th;
2579 struct cdtocdata *data;
2580 int num_entries, i;
2581 int error, first_track_audio;
2582
2583 error = 0;
2584 first_track_audio = -1;
2585
2586 softc = (struct cd_softc *)periph->softc;
2587
2588 data = malloc(sizeof(struct cdtocdata), M_TEMP, M_WAITOK);
2589
2590 th = &data->header;
2591 error = cdreadtoc(periph, 0, 0, (struct cd_toc_entry *)data,
2592 sizeof(*data));
2593
2594 if (error)
2595 goto bailout;
2596
2597 if (softc->quirks & CD_Q_BCD_TRACKS) {
2598 /* we are going to have to convert the BCD
2599 * encoding on the cd to what is expected
2600 */
2601 th->starting_track =
2602 bcd2bin(th->starting_track);
2603 th->ending_track = bcd2bin(th->ending_track);
2604 }
2605 th->len = scsi_2btoul((u_int8_t *)&th->len);
2606
2607 if ((th->len - 2) > 0)
2608 num_entries = (th->len - 2) / sizeof(struct cd_toc_entry);
2609 else
2610 num_entries = 0;
2611
2612 for (i = 0; i < num_entries; i++) {
2613 if (data->entries[i].track == th->starting_track) {
2614 if (data->entries[i].control & 0x4)
2615 first_track_audio = 0;
2616 else
2617 first_track_audio = 1;
2618 break;
2619 }
2620 }
2621
2622 if (first_track_audio == -1)
2623 error = ENOENT;
2624 else if (first_track_audio == 1)
2625 error = EINVAL;
2626 else
2627 error = 0;
2628bailout:
2629 free(data, M_TEMP);
2630
2631 return(error);
2632}
2633
2634static int
2635cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
2636{
2637 struct cd_softc *softc;
2638 struct cam_periph *periph;
2639
2640 periph = xpt_path_periph(ccb->ccb_h.path);
2641 softc = (struct cd_softc *)periph->softc;
2642
2643 /*
2644 * XXX
2645 * Until we have a better way of doing pack validation,
2646 * don't treat UAs as errors.
2647 */
2648 sense_flags |= SF_RETRY_UA;
2649 return (cam_periph_error(ccb, cam_flags, sense_flags,
2650 &softc->saved_ccb));
2651}
2652
2653/*
2654 * Read table of contents
2655 */
2656static int
2657cdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start,
2658 struct cd_toc_entry *data, u_int32_t len)
2659{
2660 struct scsi_read_toc *scsi_cmd;
2661 u_int32_t ntoc;
2662 struct ccb_scsiio *csio;
2663 union ccb *ccb;
2664 int error;
2665
2666 ntoc = len;
2667 error = 0;
2668
2669 ccb = cdgetccb(periph, /* priority */ 1);
2670
2671 csio = &ccb->csio;
2672
2673 cam_fill_csio(csio,
2674 /* retries */ 1,
2675 /* cbfcnp */ cddone,
2676 /* flags */ CAM_DIR_IN,
2677 /* tag_action */ MSG_SIMPLE_Q_TAG,
2678 /* data_ptr */ (u_int8_t *)data,
2679 /* dxfer_len */ len,
2680 /* sense_len */ SSD_FULL_SIZE,
2681 sizeof(struct scsi_read_toc),
2682 /* timeout */ 50000);
2683
2684 scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes;
2685 bzero (scsi_cmd, sizeof(*scsi_cmd));
2686
2687 if (mode == CD_MSF_FORMAT)
2688 scsi_cmd->byte2 |= CD_MSF;
2689 scsi_cmd->from_track = start;
2690 /* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */
2691 scsi_cmd->data_len[0] = (ntoc) >> 8;
2692 scsi_cmd->data_len[1] = (ntoc) & 0xff;
2693
2694 scsi_cmd->op_code = READ_TOC;
2695
2696 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2697 /*sense_flags*/SF_RETRY_UA);
2698
2699 xpt_release_ccb(ccb);
2700
2701 return(error);
2702}
2703
2704static int
2705cdreadsubchannel(struct cam_periph *periph, u_int32_t mode,
2706 u_int32_t format, int track,
2707 struct cd_sub_channel_info *data, u_int32_t len)
2708{
2709 struct scsi_read_subchannel *scsi_cmd;
2710 struct ccb_scsiio *csio;
2711 union ccb *ccb;
2712 int error;
2713
2714 error = 0;
2715
2716 ccb = cdgetccb(periph, /* priority */ 1);
2717
2718 csio = &ccb->csio;
2719
2720 cam_fill_csio(csio,
2721 /* retries */ 1,
2722 /* cbfcnp */ cddone,
2723 /* flags */ CAM_DIR_IN,
2724 /* tag_action */ MSG_SIMPLE_Q_TAG,
2725 /* data_ptr */ (u_int8_t *)data,
2726 /* dxfer_len */ len,
2727 /* sense_len */ SSD_FULL_SIZE,
2728 sizeof(struct scsi_read_subchannel),
2729 /* timeout */ 50000);
2730
2731 scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes;
2732 bzero (scsi_cmd, sizeof(*scsi_cmd));
2733
2734 scsi_cmd->op_code = READ_SUBCHANNEL;
2735 if (mode == CD_MSF_FORMAT)
2736 scsi_cmd->byte1 |= CD_MSF;
2737 scsi_cmd->byte2 = SRS_SUBQ;
2738 scsi_cmd->subchan_format = format;
2739 scsi_cmd->track = track;
2740 scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len);
2741 scsi_cmd->control = 0;
2742
2743 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2744 /*sense_flags*/SF_RETRY_UA);
2745
2746 xpt_release_ccb(ccb);
2747
2748 return(error);
2749}
2750
2751
2752static int
2753cdgetmode(struct cam_periph *periph, struct cd_mode_data *data, u_int32_t page)
2754{
2755 struct scsi_mode_sense_6 *scsi_cmd;
2756 struct ccb_scsiio *csio;
2757 union ccb *ccb;
2758 int error;
2759
2760 ccb = cdgetccb(periph, /* priority */ 1);
2761
2762 csio = &ccb->csio;
2763
2764 bzero(data, sizeof(*data));
2765 cam_fill_csio(csio,
2766 /* retries */ 1,
2767 /* cbfcnp */ cddone,
2768 /* flags */ CAM_DIR_IN,
2769 /* tag_action */ MSG_SIMPLE_Q_TAG,
2770 /* data_ptr */ (u_int8_t *)data,
2771 /* dxfer_len */ sizeof(*data),
2772 /* sense_len */ SSD_FULL_SIZE,
2773 sizeof(struct scsi_mode_sense_6),
2774 /* timeout */ 50000);
2775
2776 scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes;
2777 bzero (scsi_cmd, sizeof(*scsi_cmd));
2778
2779 scsi_cmd->page = page;
2780 scsi_cmd->length = sizeof(*data) & 0xff;
2781 scsi_cmd->opcode = MODE_SENSE;
2782
2783 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2784 /*sense_flags*/SF_RETRY_UA);
2785
2786 xpt_release_ccb(ccb);
2787
2788 return(error);
2789}
2790
2791static int
2792cdsetmode(struct cam_periph *periph, struct cd_mode_data *data)
2793{
2794 struct scsi_mode_select_6 *scsi_cmd;
2795 struct ccb_scsiio *csio;
2796 union ccb *ccb;
2797 int error;
2798
2799 ccb = cdgetccb(periph, /* priority */ 1);
2800
2801 csio = &ccb->csio;
2802
2803 error = 0;
2804
2805 cam_fill_csio(csio,
2806 /* retries */ 1,
2807 /* cbfcnp */ cddone,
2808 /* flags */ CAM_DIR_OUT,
2809 /* tag_action */ MSG_SIMPLE_Q_TAG,
2810 /* data_ptr */ (u_int8_t *)data,
2811 /* dxfer_len */ sizeof(*data),
2812 /* sense_len */ SSD_FULL_SIZE,
2813 sizeof(struct scsi_mode_select_6),
2814 /* timeout */ 50000);
2815
2816 scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes;
2817
2818 bzero(scsi_cmd, sizeof(*scsi_cmd));
2819 scsi_cmd->opcode = MODE_SELECT;
2820 scsi_cmd->byte2 |= SMS_PF;
2821 scsi_cmd->length = sizeof(*data) & 0xff;
2822 data->header.data_length = 0;
2823 /*
2824 * SONY drives do not allow a mode select with a medium_type
2825 * value that has just been returned by a mode sense; use a
2826 * medium_type of 0 (Default) instead.
2827 */
2828 data->header.medium_type = 0;
2829
2830 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2831 /*sense_flags*/SF_RETRY_UA);
2832
2833 xpt_release_ccb(ccb);
2834
2835 return(error);
2836}
2837
2838
2839static int
2840cdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len)
2841{
2842 struct ccb_scsiio *csio;
2843 union ccb *ccb;
2844 int error;
2845 u_int8_t cdb_len;
2846
2847 error = 0;
2848 ccb = cdgetccb(periph, /* priority */ 1);
2849 csio = &ccb->csio;
2850 /*
2851 * Use the smallest possible command to perform the operation.
2852 */
2853 if ((len & 0xffff0000) == 0) {
2854 /*
2855 * We can fit in a 10 byte cdb.
2856 */
2857 struct scsi_play_10 *scsi_cmd;
2858
2859 scsi_cmd = (struct scsi_play_10 *)&csio->cdb_io.cdb_bytes;
2860 bzero (scsi_cmd, sizeof(*scsi_cmd));
2861 scsi_cmd->op_code = PLAY_10;
2862 scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr);
2863 scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len);
2864 cdb_len = sizeof(*scsi_cmd);
2865 } else {
2866 struct scsi_play_12 *scsi_cmd;
2867
2868 scsi_cmd = (struct scsi_play_12 *)&csio->cdb_io.cdb_bytes;
2869 bzero (scsi_cmd, sizeof(*scsi_cmd));
2870 scsi_cmd->op_code = PLAY_12;
2871 scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr);
2872 scsi_ulto4b(len, (u_int8_t *)scsi_cmd->xfer_len);
2873 cdb_len = sizeof(*scsi_cmd);
2874 }
2875 cam_fill_csio(csio,
2876 /*retries*/2,
2877 cddone,
2878 /*flags*/CAM_DIR_NONE,
2879 MSG_SIMPLE_Q_TAG,
2880 /*dataptr*/NULL,
2881 /*datalen*/0,
2882 /*sense_len*/SSD_FULL_SIZE,
2883 cdb_len,
2884 /*timeout*/50 * 1000);
2885
2886 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2887 /*sense_flags*/SF_RETRY_UA);
2888
2889 xpt_release_ccb(ccb);
2890
2891 return(error);
2892}
2893
2894static int
2895cdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts,
2896 u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf)
2897{
2898 struct scsi_play_msf *scsi_cmd;
2899 struct ccb_scsiio *csio;
2900 union ccb *ccb;
2901 int error;
2902
2903 error = 0;
2904
2905 ccb = cdgetccb(periph, /* priority */ 1);
2906
2907 csio = &ccb->csio;
2908
2909 cam_fill_csio(csio,
2910 /* retries */ 1,
2911 /* cbfcnp */ cddone,
2912 /* flags */ CAM_DIR_NONE,
2913 /* tag_action */ MSG_SIMPLE_Q_TAG,
2914 /* data_ptr */ NULL,
2915 /* dxfer_len */ 0,
2916 /* sense_len */ SSD_FULL_SIZE,
2917 sizeof(struct scsi_play_msf),
2918 /* timeout */ 50000);
2919
2920 scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes;
2921 bzero (scsi_cmd, sizeof(*scsi_cmd));
2922
2923 scsi_cmd->op_code = PLAY_MSF;
2924 scsi_cmd->start_m = startm;
2925 scsi_cmd->start_s = starts;
2926 scsi_cmd->start_f = startf;
2927 scsi_cmd->end_m = endm;
2928 scsi_cmd->end_s = ends;
2929 scsi_cmd->end_f = endf;
2930
2931 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2932 /*sense_flags*/SF_RETRY_UA);
2933
2934 xpt_release_ccb(ccb);
2935
2936 return(error);
2937}
2938
2939
2940static int
2941cdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex,
2942 u_int32_t etrack, u_int32_t eindex)
2943{
2944 struct scsi_play_track *scsi_cmd;
2945 struct ccb_scsiio *csio;
2946 union ccb *ccb;
2947 int error;
2948
2949 error = 0;
2950
2951 ccb = cdgetccb(periph, /* priority */ 1);
2952
2953 csio = &ccb->csio;
2954
2955 cam_fill_csio(csio,
2956 /* retries */ 1,
2957 /* cbfcnp */ cddone,
2958 /* flags */ CAM_DIR_NONE,
2959 /* tag_action */ MSG_SIMPLE_Q_TAG,
2960 /* data_ptr */ NULL,
2961 /* dxfer_len */ 0,
2962 /* sense_len */ SSD_FULL_SIZE,
2963 sizeof(struct scsi_play_track),
2964 /* timeout */ 50000);
2965
2966 scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes;
2967 bzero (scsi_cmd, sizeof(*scsi_cmd));
2968
2969 scsi_cmd->op_code = PLAY_TRACK;
2970 scsi_cmd->start_track = strack;
2971 scsi_cmd->start_index = sindex;
2972 scsi_cmd->end_track = etrack;
2973 scsi_cmd->end_index = eindex;
2974
2975 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2976 /*sense_flags*/SF_RETRY_UA);
2977
2978 xpt_release_ccb(ccb);
2979
2980 return(error);
2981}
2982
2983static int
2984cdpause(struct cam_periph *periph, u_int32_t go)
2985{
2986 struct scsi_pause *scsi_cmd;
2987 struct ccb_scsiio *csio;
2988 union ccb *ccb;
2989 int error;
2990
2991 error = 0;
2992
2993 ccb = cdgetccb(periph, /* priority */ 1);
2994
2995 csio = &ccb->csio;
2996
2997 cam_fill_csio(csio,
2998 /* retries */ 1,
2999 /* cbfcnp */ cddone,
3000 /* flags */ CAM_DIR_NONE,
3001 /* tag_action */ MSG_SIMPLE_Q_TAG,
3002 /* data_ptr */ NULL,
3003 /* dxfer_len */ 0,
3004 /* sense_len */ SSD_FULL_SIZE,
3005 sizeof(struct scsi_pause),
3006 /* timeout */ 50000);
3007
3008 scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes;
3009 bzero (scsi_cmd, sizeof(*scsi_cmd));
3010
3011 scsi_cmd->op_code = PAUSE;
3012 scsi_cmd->resume = go;
3013
3014 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3015 /*sense_flags*/SF_RETRY_UA);
3016
3017 xpt_release_ccb(ccb);
3018
3019 return(error);
3020}
3021
3022static int
3023cdstartunit(struct cam_periph *periph)
3024{
3025 union ccb *ccb;
3026 int error;
3027
3028 error = 0;
3029
3030 ccb = cdgetccb(periph, /* priority */ 1);
3031
3032 scsi_start_stop(&ccb->csio,
3033 /* retries */ 1,
3034 /* cbfcnp */ cddone,
3035 /* tag_action */ MSG_SIMPLE_Q_TAG,
3036 /* start */ TRUE,
3037 /* load_eject */ FALSE,
3038 /* immediate */ FALSE,
3039 /* sense_len */ SSD_FULL_SIZE,
3040 /* timeout */ 50000);
3041
3042 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3043 /*sense_flags*/SF_RETRY_UA);
3044
3045 xpt_release_ccb(ccb);
3046
3047 return(error);
3048}
3049
3050static int
3051cdstopunit(struct cam_periph *periph, u_int32_t eject)
3052{
3053 union ccb *ccb;
3054 int error;
3055
3056 error = 0;
3057
3058 ccb = cdgetccb(periph, /* priority */ 1);
3059
3060 scsi_start_stop(&ccb->csio,
3061 /* retries */ 1,
3062 /* cbfcnp */ cddone,
3063 /* tag_action */ MSG_SIMPLE_Q_TAG,
3064 /* start */ FALSE,
3065 /* load_eject */ eject,
3066 /* immediate */ FALSE,
3067 /* sense_len */ SSD_FULL_SIZE,
3068 /* timeout */ 50000);
3069
3070 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3071 /*sense_flags*/SF_RETRY_UA);
3072
3073 xpt_release_ccb(ccb);
3074
3075 return(error);
3076}
3077
3078static int
3079cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo)
3080{
3081 union ccb *ccb;
3082 u_int8_t *databuf;
3083 u_int32_t lba;
3084 int error;
3085 int length;
3086
3087 error = 0;
3088 databuf = NULL;
3089 lba = 0;
3090
3091 ccb = cdgetccb(periph, /* priority */ 1);
3092
3093 switch (authinfo->format) {
3094 case DVD_REPORT_AGID:
3095 length = sizeof(struct scsi_report_key_data_agid);
3096 break;
3097 case DVD_REPORT_CHALLENGE:
3098 length = sizeof(struct scsi_report_key_data_challenge);
3099 break;
3100 case DVD_REPORT_KEY1:
3101 length = sizeof(struct scsi_report_key_data_key1_key2);
3102 break;
3103 case DVD_REPORT_TITLE_KEY:
3104 length = sizeof(struct scsi_report_key_data_title);
3105 /* The lba field is only set for the title key */
3106 lba = authinfo->lba;
3107 break;
3108 case DVD_REPORT_ASF:
3109 length = sizeof(struct scsi_report_key_data_asf);
3110 break;
3111 case DVD_REPORT_RPC:
3112 length = sizeof(struct scsi_report_key_data_rpc);
3113 break;
3114 case DVD_INVALIDATE_AGID:
3115 length = 0;
3116 break;
3117 default:
3118 error = EINVAL;
3119 goto bailout;
3120 break; /* NOTREACHED */
3121 }
3122
3123 if (length != 0) {
3124 databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3125 } else
3126 databuf = NULL;
3127
3128
3129 scsi_report_key(&ccb->csio,
3130 /* retries */ 1,
3131 /* cbfcnp */ cddone,
3132 /* tag_action */ MSG_SIMPLE_Q_TAG,
3133 /* lba */ lba,
3134 /* agid */ authinfo->agid,
3135 /* key_format */ authinfo->format,
3136 /* data_ptr */ databuf,
3137 /* dxfer_len */ length,
3138 /* sense_len */ SSD_FULL_SIZE,
3139 /* timeout */ 50000);
3140
3141 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3142 /*sense_flags*/SF_RETRY_UA);
3143
3144 if (error != 0)
3145 goto bailout;
3146
3147 if (ccb->csio.resid != 0) {
3148 xpt_print_path(periph->path);
3149 printf("warning, residual for report key command is %d\n",
3150 ccb->csio.resid);
3151 }
3152
3153 switch(authinfo->format) {
3154 case DVD_REPORT_AGID: {
3155 struct scsi_report_key_data_agid *agid_data;
3156
3157 agid_data = (struct scsi_report_key_data_agid *)databuf;
3158
3159 authinfo->agid = (agid_data->agid & RKD_AGID_MASK) >>
3160 RKD_AGID_SHIFT;
3161 break;
3162 }
3163 case DVD_REPORT_CHALLENGE: {
3164 struct scsi_report_key_data_challenge *chal_data;
3165
3166 chal_data = (struct scsi_report_key_data_challenge *)databuf;
3167
3168 bcopy(chal_data->challenge_key, authinfo->keychal,
3169 min(sizeof(chal_data->challenge_key),
3170 sizeof(authinfo->keychal)));
3171 break;
3172 }
3173 case DVD_REPORT_KEY1: {
3174 struct scsi_report_key_data_key1_key2 *key1_data;
3175
3176 key1_data = (struct scsi_report_key_data_key1_key2 *)databuf;
3177
3178 bcopy(key1_data->key1, authinfo->keychal,
3179 min(sizeof(key1_data->key1), sizeof(authinfo->keychal)));
3180 break;
3181 }
3182 case DVD_REPORT_TITLE_KEY: {
3183 struct scsi_report_key_data_title *title_data;
3184
3185 title_data = (struct scsi_report_key_data_title *)databuf;
3186
3187 authinfo->cpm = (title_data->byte0 & RKD_TITLE_CPM) >>
3188 RKD_TITLE_CPM_SHIFT;
3189 authinfo->cp_sec = (title_data->byte0 & RKD_TITLE_CP_SEC) >>
3190 RKD_TITLE_CP_SEC_SHIFT;
3191 authinfo->cgms = (title_data->byte0 & RKD_TITLE_CMGS_MASK) >>
3192 RKD_TITLE_CMGS_SHIFT;
3193 bcopy(title_data->title_key, authinfo->keychal,
3194 min(sizeof(title_data->title_key),
3195 sizeof(authinfo->keychal)));
3196 break;
3197 }
3198 case DVD_REPORT_ASF: {
3199 struct scsi_report_key_data_asf *asf_data;
3200
3201 asf_data = (struct scsi_report_key_data_asf *)databuf;
3202
3203 authinfo->asf = asf_data->success & RKD_ASF_SUCCESS;
3204 break;
3205 }
3206 case DVD_REPORT_RPC: {
3207 struct scsi_report_key_data_rpc *rpc_data;
3208
3209 rpc_data = (struct scsi_report_key_data_rpc *)databuf;
3210
3211 authinfo->reg_type = (rpc_data->byte4 & RKD_RPC_TYPE_MASK) >>
3212 RKD_RPC_TYPE_SHIFT;
3213 authinfo->vend_rsts =
3214 (rpc_data->byte4 & RKD_RPC_VENDOR_RESET_MASK) >>
3215 RKD_RPC_VENDOR_RESET_SHIFT;
3216 authinfo->user_rsts = rpc_data->byte4 & RKD_RPC_USER_RESET_MASK;
3217 authinfo->region = rpc_data->region_mask;
3218 authinfo->rpc_scheme = rpc_data->rpc_scheme1;
3219 break;
3220 }
3221 case DVD_INVALIDATE_AGID:
3222 break;
3223 default:
3224 /* This should be impossible, since we checked above */
3225 error = EINVAL;
3226 goto bailout;
3227 break; /* NOTREACHED */
3228 }
3229bailout:
3230 if (databuf != NULL)
3231 free(databuf, M_DEVBUF);
3232
3233 xpt_release_ccb(ccb);
3234
3235 return(error);
3236}
3237
3238static int
3239cdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo)
3240{
3241 union ccb *ccb;
3242 u_int8_t *databuf;
3243 int length;
3244 int error;
3245
3246 error = 0;
3247 databuf = NULL;
3248
3249 ccb = cdgetccb(periph, /* priority */ 1);
3250
3251 switch(authinfo->format) {
3252 case DVD_SEND_CHALLENGE: {
3253 struct scsi_report_key_data_challenge *challenge_data;
3254
3255 length = sizeof(*challenge_data);
3256
3257 challenge_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3258
3259 databuf = (u_int8_t *)challenge_data;
3260
3261 scsi_ulto2b(length - sizeof(challenge_data->data_len),
3262 challenge_data->data_len);
3263
3264 bcopy(authinfo->keychal, challenge_data->challenge_key,
3265 min(sizeof(authinfo->keychal),
3266 sizeof(challenge_data->challenge_key)));
3267 break;
3268 }
3269 case DVD_SEND_KEY2: {
3270 struct scsi_report_key_data_key1_key2 *key2_data;
3271
3272 length = sizeof(*key2_data);
3273
3274 key2_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3275
3276 databuf = (u_int8_t *)key2_data;
3277
3278 scsi_ulto2b(length - sizeof(key2_data->data_len),
3279 key2_data->data_len);
3280
3281 bcopy(authinfo->keychal, key2_data->key1,
3282 min(sizeof(authinfo->keychal), sizeof(key2_data->key1)));
3283
3284 break;
3285 }
3286 case DVD_SEND_RPC: {
3287 struct scsi_send_key_data_rpc *rpc_data;
3288
3289 length = sizeof(*rpc_data);
3290
3291 rpc_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3292
3293 databuf = (u_int8_t *)rpc_data;
3294
3295 scsi_ulto2b(length - sizeof(rpc_data->data_len),
3296 rpc_data->data_len);
3297
3298 rpc_data->region_code = authinfo->region;
3299 break;
3300 }
3301 default:
3302 error = EINVAL;
3303 goto bailout;
3304 break; /* NOTREACHED */
3305 }
3306
3307 scsi_send_key(&ccb->csio,
3308 /* retries */ 1,
3309 /* cbfcnp */ cddone,
3310 /* tag_action */ MSG_SIMPLE_Q_TAG,
3311 /* agid */ authinfo->agid,
3312 /* key_format */ authinfo->format,
3313 /* data_ptr */ databuf,
3314 /* dxfer_len */ length,
3315 /* sense_len */ SSD_FULL_SIZE,
3316 /* timeout */ 50000);
3317
3318 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3319 /*sense_flags*/SF_RETRY_UA);
3320
3321bailout:
3322
3323 if (databuf != NULL)
3324 free(databuf, M_DEVBUF);
3325
3326 xpt_release_ccb(ccb);
3327
3328 return(error);
3329}
3330
3331static int
3332cdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct)
3333{
3334 union ccb *ccb;
3335 u_int8_t *databuf;
3336 u_int32_t address;
3337 int error;
3338 int length;
3339
3340 error = 0;
3341 databuf = NULL;
3342 /* The address is reserved for many of the formats */
3343 address = 0;
3344
3345 ccb = cdgetccb(periph, /* priority */ 1);
3346
3347 switch(dvdstruct->format) {
3348 case DVD_STRUCT_PHYSICAL:
3349 length = sizeof(struct scsi_read_dvd_struct_data_physical);
3350 break;
3351 case DVD_STRUCT_COPYRIGHT:
3352 length = sizeof(struct scsi_read_dvd_struct_data_copyright);
3353 break;
3354 case DVD_STRUCT_DISCKEY:
3355 length = sizeof(struct scsi_read_dvd_struct_data_disc_key);
3356 break;
3357 case DVD_STRUCT_BCA:
3358 length = sizeof(struct scsi_read_dvd_struct_data_bca);
3359 break;
3360 case DVD_STRUCT_MANUFACT:
3361 length = sizeof(struct scsi_read_dvd_struct_data_manufacturer);
3362 break;
3363 case DVD_STRUCT_CMI:
3364 error = ENODEV;
3365 goto bailout;
3366#ifdef notyet
3367 length = sizeof(struct scsi_read_dvd_struct_data_copy_manage);
3368 address = dvdstruct->address;
3369#endif
3370 break; /* NOTREACHED */
3371 case DVD_STRUCT_PROTDISCID:
3372 length = sizeof(struct scsi_read_dvd_struct_data_prot_discid);
3373 break;
3374 case DVD_STRUCT_DISCKEYBLOCK:
3375 length = sizeof(struct scsi_read_dvd_struct_data_disc_key_blk);
3376 break;
3377 case DVD_STRUCT_DDS:
3378 length = sizeof(struct scsi_read_dvd_struct_data_dds);
3379 break;
3380 case DVD_STRUCT_MEDIUM_STAT:
3381 length = sizeof(struct scsi_read_dvd_struct_data_medium_status);
3382 break;
3383 case DVD_STRUCT_SPARE_AREA:
3384 length = sizeof(struct scsi_read_dvd_struct_data_spare_area);
3385 break;
3386 case DVD_STRUCT_RMD_LAST:
3387 error = ENODEV;
3388 goto bailout;
3389#ifdef notyet
3390 length = sizeof(struct scsi_read_dvd_struct_data_rmd_borderout);
3391 address = dvdstruct->address;
3392#endif
3393 break; /* NOTREACHED */
3394 case DVD_STRUCT_RMD_RMA:
3395 error = ENODEV;
3396 goto bailout;
3397#ifdef notyet
3398 length = sizeof(struct scsi_read_dvd_struct_data_rmd);
3399 address = dvdstruct->address;
3400#endif
3401 break; /* NOTREACHED */
3402 case DVD_STRUCT_PRERECORDED:
3403 length = sizeof(struct scsi_read_dvd_struct_data_leadin);
3404 break;
3405 case DVD_STRUCT_UNIQUEID:
3406 length = sizeof(struct scsi_read_dvd_struct_data_disc_id);
3407 break;
3408 case DVD_STRUCT_DCB:
3409 error = ENODEV;
3410 goto bailout;
3411#ifdef notyet
3412 length = sizeof(struct scsi_read_dvd_struct_data_dcb);
3413 address = dvdstruct->address;
3414#endif
3415 break; /* NOTREACHED */
3416 case DVD_STRUCT_LIST:
3417 /*
3418 * This is the maximum allocation length for the READ DVD
3419 * STRUCTURE command. There's nothing in the MMC3 spec
3420 * that indicates a limit in the amount of data that can
3421 * be returned from this call, other than the limits
3422 * imposed by the 2-byte length variables.
3423 */
3424 length = 65535;
3425 break;
3426 default:
3427 error = EINVAL;
3428 goto bailout;
3429 break; /* NOTREACHED */
3430 }
3431
3432 if (length != 0) {
3433 databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3434 } else
3435 databuf = NULL;
3436
3437 scsi_read_dvd_structure(&ccb->csio,
3438 /* retries */ 1,
3439 /* cbfcnp */ cddone,
3440 /* tag_action */ MSG_SIMPLE_Q_TAG,
3441 /* lba */ address,
3442 /* layer_number */ dvdstruct->layer_num,
3443 /* key_format */ dvdstruct->format,
3444 /* agid */ dvdstruct->agid,
3445 /* data_ptr */ databuf,
3446 /* dxfer_len */ length,
3447 /* sense_len */ SSD_FULL_SIZE,
3448 /* timeout */ 50000);
3449
3450 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3451 /*sense_flags*/SF_RETRY_UA);
3452
3453 if (error != 0)
3454 goto bailout;
3455
3456 switch(dvdstruct->format) {
3457 case DVD_STRUCT_PHYSICAL: {
3458 struct scsi_read_dvd_struct_data_layer_desc *inlayer;
3459 struct dvd_layer *outlayer;
3460 struct scsi_read_dvd_struct_data_physical *phys_data;
3461
3462 phys_data =
3463 (struct scsi_read_dvd_struct_data_physical *)databuf;
3464 inlayer = &phys_data->layer_desc;
3465 outlayer = (struct dvd_layer *)&dvdstruct->data;
3466
3467 dvdstruct->length = sizeof(*inlayer);
3468
3469 outlayer->book_type = (inlayer->book_type_version &
3470 RDSD_BOOK_TYPE_MASK) >> RDSD_BOOK_TYPE_SHIFT;
3471 outlayer->book_version = (inlayer->book_type_version &
3472 RDSD_BOOK_VERSION_MASK);
3473 outlayer->disc_size = (inlayer->disc_size_max_rate &
3474 RDSD_DISC_SIZE_MASK) >> RDSD_DISC_SIZE_SHIFT;
3475 outlayer->max_rate = (inlayer->disc_size_max_rate &
3476 RDSD_MAX_RATE_MASK);
3477 outlayer->nlayers = (inlayer->layer_info &
3478 RDSD_NUM_LAYERS_MASK) >> RDSD_NUM_LAYERS_SHIFT;
3479 outlayer->track_path = (inlayer->layer_info &
3480 RDSD_TRACK_PATH_MASK) >> RDSD_TRACK_PATH_SHIFT;
3481 outlayer->layer_type = (inlayer->layer_info &
3482 RDSD_LAYER_TYPE_MASK);
3483 outlayer->linear_density = (inlayer->density &
3484 RDSD_LIN_DENSITY_MASK) >> RDSD_LIN_DENSITY_SHIFT;
3485 outlayer->track_density = (inlayer->density &
3486 RDSD_TRACK_DENSITY_MASK);
3487 outlayer->bca = (inlayer->bca & RDSD_BCA_MASK) >>
3488 RDSD_BCA_SHIFT;
3489 outlayer->start_sector = scsi_3btoul(inlayer->main_data_start);
3490 outlayer->end_sector = scsi_3btoul(inlayer->main_data_end);
3491 outlayer->end_sector_l0 =
3492 scsi_3btoul(inlayer->end_sector_layer0);
3493 break;
3494 }
3495 case DVD_STRUCT_COPYRIGHT: {
3496 struct scsi_read_dvd_struct_data_copyright *copy_data;
3497
3498 copy_data = (struct scsi_read_dvd_struct_data_copyright *)
3499 databuf;
3500
3501 dvdstruct->cpst = copy_data->cps_type;
3502 dvdstruct->rmi = copy_data->region_info;
3503 dvdstruct->length = 0;
3504
3505 break;
3506 }
3507 default:
3508 /*
3509 * Tell the user what the overall length is, no matter
3510 * what we can actually fit in the data buffer.
3511 */
3512 dvdstruct->length = length - ccb->csio.resid -
3513 sizeof(struct scsi_read_dvd_struct_data_header);
3514
3515 /*
3516 * But only actually copy out the smaller of what we read
3517 * in or what the structure can take.
3518 */
3519 bcopy(databuf + sizeof(struct scsi_read_dvd_struct_data_header),
3520 dvdstruct->data,
3521 min(sizeof(dvdstruct->data), dvdstruct->length));
3522 break;
3523 }
3524bailout:
3525
3526 if (databuf != NULL)
3527 free(databuf, M_DEVBUF);
3528
3529 xpt_release_ccb(ccb);
3530
3531 return(error);
3532}
3533
3534void
3535scsi_report_key(struct ccb_scsiio *csio, u_int32_t retries,
3536 void (*cbfcnp)(struct cam_periph *, union ccb *),
3537 u_int8_t tag_action, u_int32_t lba, u_int8_t agid,
3538 u_int8_t key_format, u_int8_t *data_ptr, u_int32_t dxfer_len,
3539 u_int8_t sense_len, u_int32_t timeout)
3540{
3541 struct scsi_report_key *scsi_cmd;
3542
3543 scsi_cmd = (struct scsi_report_key *)&csio->cdb_io.cdb_bytes;
3544 bzero(scsi_cmd, sizeof(*scsi_cmd));
3545 scsi_cmd->opcode = REPORT_KEY;
3546 scsi_ulto4b(lba, scsi_cmd->lba);
3547 scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len);
3548 scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) |
3549 (key_format & RK_KF_KEYFORMAT_MASK);
3550
3551 cam_fill_csio(csio,
3552 retries,
3553 cbfcnp,
3554 /*flags*/ (dxfer_len == 0) ? CAM_DIR_NONE : CAM_DIR_IN,
3555 tag_action,
3556 /*data_ptr*/ data_ptr,
3557 /*dxfer_len*/ dxfer_len,
3558 sense_len,
3559 sizeof(*scsi_cmd),
3560 timeout);
3561}
3562
3563void
3564scsi_send_key(struct ccb_scsiio *csio, u_int32_t retries,
3565 void (*cbfcnp)(struct cam_periph *, union ccb *),
3566 u_int8_t tag_action, u_int8_t agid, u_int8_t key_format,
3567 u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
3568 u_int32_t timeout)
3569{
3570 struct scsi_send_key *scsi_cmd;
3571
3572 scsi_cmd = (struct scsi_send_key *)&csio->cdb_io.cdb_bytes;
3573 bzero(scsi_cmd, sizeof(*scsi_cmd));
3574 scsi_cmd->opcode = SEND_KEY;
3575
3576 scsi_ulto2b(dxfer_len, scsi_cmd->param_len);
3577 scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) |
3578 (key_format & RK_KF_KEYFORMAT_MASK);
3579
3580 cam_fill_csio(csio,
3581 retries,
3582 cbfcnp,
3583 /*flags*/ CAM_DIR_OUT,
3584 tag_action,
3585 /*data_ptr*/ data_ptr,
3586 /*dxfer_len*/ dxfer_len,
3587 sense_len,
3588 sizeof(*scsi_cmd),
3589 timeout);
3590}
3591
3592
3593void
3594scsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries,
3595 void (*cbfcnp)(struct cam_periph *, union ccb *),
3596 u_int8_t tag_action, u_int32_t address,
3597 u_int8_t layer_number, u_int8_t format, u_int8_t agid,
3598 u_int8_t *data_ptr, u_int32_t dxfer_len,
3599 u_int8_t sense_len, u_int32_t timeout)
3600{
3601 struct scsi_read_dvd_structure *scsi_cmd;
3602
3603 scsi_cmd = (struct scsi_read_dvd_structure *)&csio->cdb_io.cdb_bytes;
3604 bzero(scsi_cmd, sizeof(*scsi_cmd));
3605 scsi_cmd->opcode = READ_DVD_STRUCTURE;
3606
3607 scsi_ulto4b(address, scsi_cmd->address);
3608 scsi_cmd->layer_number = layer_number;
3609 scsi_cmd->format = format;
3610 scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len);
3611 /* The AGID is the top two bits of this byte */
3612 scsi_cmd->agid = agid << 6;
3613
3614 cam_fill_csio(csio,
3615 retries,
3616 cbfcnp,
3617 /*flags*/ CAM_DIR_IN,
3618 tag_action,
3619 /*data_ptr*/ data_ptr,
3620 /*dxfer_len*/ dxfer_len,
3621 sense_len,
3622 sizeof(*scsi_cmd),
3623 timeout);
3624}