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 76362 2001-05-08 08:30:48Z 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 biofinish(bp, NULL, ENXIO);
1370 return;
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 biofinish(bp, NULL, ENXIO);
1390 return;
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;
1410}
1411
1412static void
1413cdstart(struct cam_periph *periph, union ccb *start_ccb)
1414{
1415 struct cd_softc *softc;
1416 struct bio *bp;
1417 struct ccb_scsiio *csio;
1418 struct scsi_read_capacity_data *rcap;
1419 int s;
1420
1421 softc = (struct cd_softc *)periph->softc;
1422
1423 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n"));
1424
1425 switch (softc->state) {
1426 case CD_STATE_NORMAL:
1427 {
1428 int oldspl;
1429
1430 s = splbio();
1431 bp = bioq_first(&softc->bio_queue);
1432 if (periph->immediate_priority <= periph->pinfo.priority) {
1433 start_ccb->ccb_h.ccb_state = CD_CCB_WAITING;
1434
1435 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
1436 periph_links.sle);
1437 periph->immediate_priority = CAM_PRIORITY_NONE;
1438 splx(s);
1439 wakeup(&periph->ccb_list);
1440 } else if (bp == NULL) {
1441 splx(s);
1442 xpt_release_ccb(start_ccb);
1443 } else {
1444 bioq_remove(&softc->bio_queue, bp);
1445
1446 devstat_start_transaction(&softc->device_stats);
1447
1448 scsi_read_write(&start_ccb->csio,
1449 /*retries*/4,
1450 /* cbfcnp */ cddone,
1451 (bp->bio_flags & BIO_ORDERED) != 0 ?
1452 MSG_ORDERED_Q_TAG :
1453 MSG_SIMPLE_Q_TAG,
1454 /* read */bp->bio_cmd == BIO_READ,
1455 /* byte2 */ 0,
1456 /* minimum_cmd_size */ 10,
1457 /* lba */ bp->bio_pblkno,
1458 bp->bio_bcount / softc->params.blksize,
1459 /* data_ptr */ bp->bio_data,
1460 /* dxfer_len */ bp->bio_bcount,
1461 /* sense_len */ SSD_FULL_SIZE,
1462 /* timeout */ 30000);
1463 start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO;
1464
1465
1466 /*
1467 * Block out any asyncronous callbacks
1468 * while we touch the pending ccb list.
1469 */
1470 oldspl = splcam();
1471 LIST_INSERT_HEAD(&softc->pending_ccbs,
1472 &start_ccb->ccb_h, periph_links.le);
1473 splx(oldspl);
1474
1475 /* We expect a unit attention from this device */
1476 if ((softc->flags & CD_FLAG_RETRY_UA) != 0) {
1477 start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA;
1478 softc->flags &= ~CD_FLAG_RETRY_UA;
1479 }
1480
1481 start_ccb->ccb_h.ccb_bp = bp;
1482 bp = bioq_first(&softc->bio_queue);
1483 splx(s);
1484
1485 xpt_action(start_ccb);
1486 }
1487 if (bp != NULL) {
1488 /* Have more work to do, so ensure we stay scheduled */
1489 xpt_schedule(periph, /* XXX priority */1);
1490 }
1491 break;
1492 }
1493 case CD_STATE_PROBE:
1494 {
1495
1496 rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap),
1497 M_TEMP,
1498 M_NOWAIT);
1499 if (rcap == NULL) {
1500 xpt_print_path(periph->path);
1501 printf("cdstart: Couldn't malloc read_capacity data\n");
1502 /* cd_free_periph??? */
1503 break;
1504 }
1505 csio = &start_ccb->csio;
1506 scsi_read_capacity(csio,
1507 /*retries*/1,
1508 cddone,
1509 MSG_SIMPLE_Q_TAG,
1510 rcap,
1511 SSD_FULL_SIZE,
1512 /*timeout*/20000);
1513 start_ccb->ccb_h.ccb_bp = NULL;
1514 start_ccb->ccb_h.ccb_state = CD_CCB_PROBE;
1515 xpt_action(start_ccb);
1516 break;
1517 }
1518 }
1519}
1520
1521static void
1522cddone(struct cam_periph *periph, union ccb *done_ccb)
1523{
1524 struct cd_softc *softc;
1525 struct ccb_scsiio *csio;
1526
1527 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n"));
1528
1529 softc = (struct cd_softc *)periph->softc;
1530 csio = &done_ccb->csio;
1531
1532 switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) {
1533 case CD_CCB_BUFFER_IO:
1534 {
1535 struct bio *bp;
1536 int error;
1537 int oldspl;
1538
1539 bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
1540 error = 0;
1541
1542 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1543 int sf;
1544
1545 if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0)
1546 sf = SF_RETRY_UA;
1547 else
1548 sf = 0;
1549
1550 error = cderror(done_ccb, CAM_RETRY_SELTO, sf);
1551 if (error == ERESTART) {
1552 /*
1553 * A retry was scheuled, so
1554 * just return.
1555 */
1556 return;
1557 }
1558 }
1559
1560 if (error != 0) {
1561 int s;
1562 struct bio *q_bp;
1563
1564 xpt_print_path(periph->path);
1565 printf("cddone: got error %#x back\n", error);
1566 s = splbio();
1567 while ((q_bp = bioq_first(&softc->bio_queue)) != NULL) {
1568 bioq_remove(&softc->bio_queue, q_bp);
1569 q_bp->bio_resid = q_bp->bio_bcount;
1570 biofinish(q_bp, NULL, EIO);
1571 }
1572 splx(s);
1573 bp->bio_resid = bp->bio_bcount;
1574 bp->bio_error = error;
1575 bp->bio_flags |= BIO_ERROR;
1576 cam_release_devq(done_ccb->ccb_h.path,
1577 /*relsim_flags*/0,
1578 /*reduction*/0,
1579 /*timeout*/0,
1580 /*getcount_only*/0);
1581
1582 } else {
1583 bp->bio_resid = csio->resid;
1584 bp->bio_error = 0;
1585 if (bp->bio_resid != 0) {
1586 /* Short transfer ??? */
1587 bp->bio_flags |= BIO_ERROR;
1588 }
1589 }
1590
1591 /*
1592 * Block out any asyncronous callbacks
1593 * while we touch the pending ccb list.
1594 */
1595 oldspl = splcam();
1596 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
1597 splx(oldspl);
1598
1599 if (softc->flags & CD_FLAG_CHANGER)
1600 cdchangerschedule(softc);
1601
1602 biofinish(bp, &softc->device_stats, 0);
1603 break;
1604 }
1605 case CD_CCB_PROBE:
1606 {
1607 struct scsi_read_capacity_data *rdcap;
1608 char announce_buf[120]; /*
1609 * Currently (9/30/97) the
1610 * longest possible announce
1611 * buffer is 108 bytes, for the
1612 * first error case below.
1613 * That is 39 bytes for the
1614 * basic string, 16 bytes for the
1615 * biggest sense key (hardware
1616 * error), 52 bytes for the
1617 * text of the largest sense
1618 * qualifier valid for a CDROM,
1619 * (0x72, 0x03 or 0x04,
1620 * 0x03), and one byte for the
1621 * null terminating character.
1622 * To allow for longer strings,
1623 * the announce buffer is 120
1624 * bytes.
1625 */
1626 struct cd_params *cdp;
1627
1628 cdp = &softc->params;
1629
1630 rdcap = (struct scsi_read_capacity_data *)csio->data_ptr;
1631
1632 cdp->disksize = scsi_4btoul (rdcap->addr) + 1;
1633 cdp->blksize = scsi_4btoul (rdcap->length);
1634
1635 if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
1636
1637 snprintf(announce_buf, sizeof(announce_buf),
1638 "cd present [%lu x %lu byte records]",
1639 cdp->disksize, (u_long)cdp->blksize);
1640
1641 } else {
1642 int error;
1643 /*
1644 * Retry any UNIT ATTENTION type errors. They
1645 * are expected at boot.
1646 */
1647 error = cderror(done_ccb, CAM_RETRY_SELTO,
1648 SF_RETRY_UA | SF_NO_PRINT);
1649 if (error == ERESTART) {
1650 /*
1651 * A retry was scheuled, so
1652 * just return.
1653 */
1654 return;
1655 } else if (error != 0) {
1656
1657 struct scsi_sense_data *sense;
1658 int asc, ascq;
1659 int sense_key, error_code;
1660 int have_sense;
1661 cam_status status;
1662 struct ccb_getdev cgd;
1663
1664 /* Don't wedge this device's queue */
1665 cam_release_devq(done_ccb->ccb_h.path,
1666 /*relsim_flags*/0,
1667 /*reduction*/0,
1668 /*timeout*/0,
1669 /*getcount_only*/0);
1670
1671 status = done_ccb->ccb_h.status;
1672
1673 xpt_setup_ccb(&cgd.ccb_h,
1674 done_ccb->ccb_h.path,
1675 /* priority */ 1);
1676 cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1677 xpt_action((union ccb *)&cgd);
1678
1679 if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0)
1680 || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0)
1681 || ((status & CAM_AUTOSNS_VALID) == 0))
1682 have_sense = FALSE;
1683 else
1684 have_sense = TRUE;
1685
1686 if (have_sense) {
1687 sense = &csio->sense_data;
1688 scsi_extract_sense(sense, &error_code,
1689 &sense_key,
1690 &asc, &ascq);
1691 }
1692 /*
1693 * Attach to anything that claims to be a
1694 * CDROM or WORM device, as long as it
1695 * doesn't return a "Logical unit not
1696 * supported" (0x25) error.
1697 */
1698 if ((have_sense) && (asc != 0x25)
1699 && (error_code == SSD_CURRENT_ERROR)) {
1700 const char *sense_key_desc;
1701 const char *asc_desc;
1702
1703 scsi_sense_desc(sense_key, asc, ascq,
1704 &cgd.inq_data,
1705 &sense_key_desc,
1706 &asc_desc);
1707 snprintf(announce_buf,
1708 sizeof(announce_buf),
1709 "Attempt to query device "
1710 "size failed: %s, %s",
1711 sense_key_desc,
1712 asc_desc);
1713 } else if (SID_TYPE(&cgd.inq_data) == T_CDROM) {
1714 /*
1715 * We only print out an error for
1716 * CDROM type devices. For WORM
1717 * devices, we don't print out an
1718 * error since a few WORM devices
1719 * don't support CDROM commands.
1720 * If we have sense information, go
1721 * ahead and print it out.
1722 * Otherwise, just say that we
1723 * couldn't attach.
1724 */
1725
1726 /*
1727 * Just print out the error, not
1728 * the full probe message, when we
1729 * don't attach.
1730 */
1731 if (have_sense)
1732 scsi_sense_print(
1733 &done_ccb->csio);
1734 else {
1735 xpt_print_path(periph->path);
1736 printf("got CAM status %#x\n",
1737 done_ccb->ccb_h.status);
1738 }
1739 xpt_print_path(periph->path);
1740 printf("fatal error, failed"
1741 " to attach to device\n");
1742
1743 /*
1744 * Invalidate this peripheral.
1745 */
1746 cam_periph_invalidate(periph);
1747
1748 announce_buf[0] = '\0';
1749 } else {
1750
1751 /*
1752 * Invalidate this peripheral.
1753 */
1754 cam_periph_invalidate(periph);
1755 announce_buf[0] = '\0';
1756 }
1757 }
1758 }
1759 free(rdcap, M_TEMP);
1760 if (announce_buf[0] != '\0') {
1761 xpt_announce_periph(periph, announce_buf);
1762 if (softc->flags & CD_FLAG_CHANGER)
1763 cdchangerschedule(softc);
1764 }
1765 softc->state = CD_STATE_NORMAL;
1766 /*
1767 * Since our peripheral may be invalidated by an error
1768 * above or an external event, we must release our CCB
1769 * before releasing the probe lock on the peripheral.
1770 * The peripheral will only go away once the last lock
1771 * is removed, and we need it around for the CCB release
1772 * operation.
1773 */
1774 xpt_release_ccb(done_ccb);
1775 cam_periph_unlock(periph);
1776 return;
1777 }
1778 case CD_CCB_WAITING:
1779 {
1780 /* Caller will release the CCB */
1781 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
1782 ("trying to wakeup ccbwait\n"));
1783
1784 wakeup(&done_ccb->ccb_h.cbfcnp);
1785 return;
1786 }
1787 default:
1788 break;
1789 }
1790 xpt_release_ccb(done_ccb);
1791}
1792
1793static int
1794cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
1795{
1796
1797 struct cam_periph *periph;
1798 struct cd_softc *softc;
1799 int error, unit;
1800
1801 unit = dkunit(dev);
1802
1803 periph = cam_extend_get(cdperiphs, unit);
1804 if (periph == NULL)
1805 return(ENXIO);
1806
1807 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n"));
1808
1809 softc = (struct cd_softc *)periph->softc;
1810
1811 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
1812 ("trying to do ioctl %#lx\n", cmd));
1813
1814 error = cam_periph_lock(periph, PRIBIO | PCATCH);
1815
1816 if (error != 0)
1817 return(error);
1818
1819 switch (cmd) {
1820
1821 case CDIOCPLAYTRACKS:
1822 {
1823 struct ioc_play_track *args
1824 = (struct ioc_play_track *) addr;
1825 struct cd_mode_data *data;
1826
1827 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
1828 M_WAITOK);
1829
1830 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1831 ("trying to do CDIOCPLAYTRACKS\n"));
1832
1833 error = cdgetmode(periph, data, AUDIO_PAGE);
1834 if (error) {
1835 free(data, M_TEMP);
1836 break;
1837 }
1838 data->page.audio.flags &= ~CD_PA_SOTC;
1839 data->page.audio.flags |= CD_PA_IMMED;
1840 error = cdsetmode(periph, data);
1841 free(data, M_TEMP);
1842 if (error)
1843 break;
1844 if (softc->quirks & CD_Q_BCD_TRACKS) {
1845 args->start_track = bin2bcd(args->start_track);
1846 args->end_track = bin2bcd(args->end_track);
1847 }
1848 error = cdplaytracks(periph,
1849 args->start_track,
1850 args->start_index,
1851 args->end_track,
1852 args->end_index);
1853 }
1854 break;
1855 case CDIOCPLAYMSF:
1856 {
1857 struct ioc_play_msf *args
1858 = (struct ioc_play_msf *) addr;
1859 struct cd_mode_data *data;
1860
1861 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
1862 M_WAITOK);
1863
1864 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1865 ("trying to do CDIOCPLAYMSF\n"));
1866
1867 error = cdgetmode(periph, data, AUDIO_PAGE);
1868 if (error) {
1869 free(data, M_TEMP);
1870 break;
1871 }
1872 data->page.audio.flags &= ~CD_PA_SOTC;
1873 data->page.audio.flags |= CD_PA_IMMED;
1874 error = cdsetmode(periph, data);
1875 free(data, M_TEMP);
1876 if (error)
1877 break;
1878 error = cdplaymsf(periph,
1879 args->start_m,
1880 args->start_s,
1881 args->start_f,
1882 args->end_m,
1883 args->end_s,
1884 args->end_f);
1885 }
1886 break;
1887 case CDIOCPLAYBLOCKS:
1888 {
1889 struct ioc_play_blocks *args
1890 = (struct ioc_play_blocks *) addr;
1891 struct cd_mode_data *data;
1892
1893 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1894 ("trying to do CDIOCPLAYBLOCKS\n"));
1895
1896 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
1897 M_WAITOK);
1898
1899 error = cdgetmode(periph, data, AUDIO_PAGE);
1900 if (error) {
1901 free(data, M_TEMP);
1902 break;
1903 }
1904 data->page.audio.flags &= ~CD_PA_SOTC;
1905 data->page.audio.flags |= CD_PA_IMMED;
1906 error = cdsetmode(periph, data);
1907 free(data, M_TEMP);
1908 if (error)
1909 break;
1910 error = cdplay(periph, args->blk, args->len);
1911 }
1912 break;
1913 case CDIOCREADSUBCHANNEL:
1914 {
1915 struct ioc_read_subchannel *args
1916 = (struct ioc_read_subchannel *) addr;
1917 struct cd_sub_channel_info *data;
1918 u_int32_t len = args->data_len;
1919
1920 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1921 ("trying to do CDIOCREADSUBCHANNEL\n"));
1922
1923 data = malloc(sizeof(struct cd_sub_channel_info),
1924 M_TEMP, M_WAITOK);
1925
1926 if ((len > sizeof(struct cd_sub_channel_info)) ||
1927 (len < sizeof(struct cd_sub_channel_header))) {
1928 printf(
1929 "scsi_cd: cdioctl: "
1930 "cdioreadsubchannel: error, len=%d\n",
1931 len);
1932 error = EINVAL;
1933 free(data, M_TEMP);
1934 break;
1935 }
1936
1937 if (softc->quirks & CD_Q_BCD_TRACKS)
1938 args->track = bin2bcd(args->track);
1939
1940 error = cdreadsubchannel(periph, args->address_format,
1941 args->data_format, args->track, data, len);
1942
1943 if (error) {
1944 free(data, M_TEMP);
1945 break;
1946 }
1947 if (softc->quirks & CD_Q_BCD_TRACKS)
1948 data->what.track_info.track_number =
1949 bcd2bin(data->what.track_info.track_number);
1950 len = min(len, ((data->header.data_len[0] << 8) +
1951 data->header.data_len[1] +
1952 sizeof(struct cd_sub_channel_header)));
1953 if (copyout(data, args->data, len) != 0) {
1954 error = EFAULT;
1955 }
1956 free(data, M_TEMP);
1957 }
1958 break;
1959
1960 case CDIOREADTOCHEADER:
1961 {
1962 struct ioc_toc_header *th;
1963
1964 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1965 ("trying to do CDIOREADTOCHEADER\n"));
1966
1967 th = malloc(sizeof(struct ioc_toc_header), M_TEMP,
1968 M_WAITOK);
1969 error = cdreadtoc(periph, 0, 0,
1970 (struct cd_toc_entry *)th,
1971 sizeof (*th));
1972 if (error) {
1973 free(th, M_TEMP);
1974 break;
1975 }
1976 if (softc->quirks & CD_Q_BCD_TRACKS) {
1977 /* we are going to have to convert the BCD
1978 * encoding on the cd to what is expected
1979 */
1980 th->starting_track =
1981 bcd2bin(th->starting_track);
1982 th->ending_track = bcd2bin(th->ending_track);
1983 }
1984 NTOHS(th->len);
1985 bcopy(th, addr, sizeof(*th));
1986 free(th, M_TEMP);
1987 }
1988 break;
1989 case CDIOREADTOCENTRYS:
1990 {
1991 typedef struct {
1992 struct ioc_toc_header header;
1993 struct cd_toc_entry entries[100];
1994 } data_t;
1995 typedef struct {
1996 struct ioc_toc_header header;
1997 struct cd_toc_entry entry;
1998 } lead_t;
1999
2000 data_t *data;
2001 lead_t *lead;
2002 struct ioc_read_toc_entry *te =
2003 (struct ioc_read_toc_entry *) addr;
2004 struct ioc_toc_header *th;
2005 u_int32_t len, readlen, idx, num;
2006 u_int32_t starting_track = te->starting_track;
2007
2008 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2009 ("trying to do CDIOREADTOCENTRYS\n"));
2010
2011 data = malloc(sizeof(data_t), M_TEMP, M_WAITOK);
2012 lead = malloc(sizeof(lead_t), M_TEMP, M_WAITOK);
2013
2014 if (te->data_len < sizeof(struct cd_toc_entry)
2015 || (te->data_len % sizeof(struct cd_toc_entry)) != 0
2016 || (te->address_format != CD_MSF_FORMAT
2017 && te->address_format != CD_LBA_FORMAT)) {
2018 error = EINVAL;
2019 printf("scsi_cd: error in readtocentries, "
2020 "returning EINVAL\n");
2021 free(data, M_TEMP);
2022 free(lead, M_TEMP);
2023 break;
2024 }
2025
2026 th = &data->header;
2027 error = cdreadtoc(periph, 0, 0,
2028 (struct cd_toc_entry *)th,
2029 sizeof (*th));
2030 if (error) {
2031 free(data, M_TEMP);
2032 free(lead, M_TEMP);
2033 break;
2034 }
2035
2036 if (softc->quirks & CD_Q_BCD_TRACKS) {
2037 /* we are going to have to convert the BCD
2038 * encoding on the cd to what is expected
2039 */
2040 th->starting_track =
2041 bcd2bin(th->starting_track);
2042 th->ending_track = bcd2bin(th->ending_track);
2043 }
2044
2045 if (starting_track == 0)
2046 starting_track = th->starting_track;
2047 else if (starting_track == LEADOUT)
2048 starting_track = th->ending_track + 1;
2049 else if (starting_track < th->starting_track ||
2050 starting_track > th->ending_track + 1) {
2051 printf("scsi_cd: error in readtocentries, "
2052 "returning EINVAL\n");
2053 free(data, M_TEMP);
2054 free(lead, M_TEMP);
2055 error = EINVAL;
2056 break;
2057 }
2058
2059 /* calculate reading length without leadout entry */
2060 readlen = (th->ending_track - starting_track + 1) *
2061 sizeof(struct cd_toc_entry);
2062
2063 /* and with leadout entry */
2064 len = readlen + sizeof(struct cd_toc_entry);
2065 if (te->data_len < len) {
2066 len = te->data_len;
2067 if (readlen > len)
2068 readlen = len;
2069 }
2070 if (len > sizeof(data->entries)) {
2071 printf("scsi_cd: error in readtocentries, "
2072 "returning EINVAL\n");
2073 error = EINVAL;
2074 free(data, M_TEMP);
2075 free(lead, M_TEMP);
2076 break;
2077 }
2078 num = len / sizeof(struct cd_toc_entry);
2079
2080 if (readlen > 0) {
2081 error = cdreadtoc(periph, te->address_format,
2082 starting_track,
2083 (struct cd_toc_entry *)data,
2084 readlen + sizeof (*th));
2085 if (error) {
2086 free(data, M_TEMP);
2087 free(lead, M_TEMP);
2088 break;
2089 }
2090 }
2091
2092 /* make leadout entry if needed */
2093 idx = starting_track + num - 1;
2094 if (softc->quirks & CD_Q_BCD_TRACKS)
2095 th->ending_track = bcd2bin(th->ending_track);
2096 if (idx == th->ending_track + 1) {
2097 error = cdreadtoc(periph, te->address_format,
2098 LEADOUT,
2099 (struct cd_toc_entry *)lead,
2100 sizeof(*lead));
2101 if (error) {
2102 free(data, M_TEMP);
2103 free(lead, M_TEMP);
2104 break;
2105 }
2106 data->entries[idx - starting_track] =
2107 lead->entry;
2108 }
2109 if (softc->quirks & CD_Q_BCD_TRACKS) {
2110 for (idx = 0; idx < num - 1; idx++) {
2111 data->entries[idx].track =
2112 bcd2bin(data->entries[idx].track);
2113 }
2114 }
2115
2116 error = copyout(data->entries, te->data, len);
2117 free(data, M_TEMP);
2118 free(lead, M_TEMP);
2119 }
2120 break;
2121 case CDIOREADTOCENTRY:
2122 {
2123 /* yeah yeah, this is ugly */
2124 typedef struct {
2125 struct ioc_toc_header header;
2126 struct cd_toc_entry entry;
2127 } data_t;
2128
2129 data_t *data;
2130 struct ioc_read_toc_single_entry *te =
2131 (struct ioc_read_toc_single_entry *) addr;
2132 struct ioc_toc_header *th;
2133 u_int32_t track;
2134
2135 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2136 ("trying to do CDIOREADTOCENTRY\n"));
2137
2138 data = malloc(sizeof(data_t), M_TEMP, M_WAITOK);
2139
2140 if (te->address_format != CD_MSF_FORMAT
2141 && te->address_format != CD_LBA_FORMAT) {
2142 printf("error in readtocentry, "
2143 " returning EINVAL\n");
2144 free(data, M_TEMP);
2145 error = EINVAL;
2146 break;
2147 }
2148
2149 th = &data->header;
2150 error = cdreadtoc(periph, 0, 0,
2151 (struct cd_toc_entry *)th,
2152 sizeof (*th));
2153 if (error) {
2154 free(data, M_TEMP);
2155 break;
2156 }
2157
2158 if (softc->quirks & CD_Q_BCD_TRACKS) {
2159 /* we are going to have to convert the BCD
2160 * encoding on the cd to what is expected
2161 */
2162 th->starting_track =
2163 bcd2bin(th->starting_track);
2164 th->ending_track = bcd2bin(th->ending_track);
2165 }
2166 track = te->track;
2167 if (track == 0)
2168 track = th->starting_track;
2169 else if (track == LEADOUT)
2170 /* OK */;
2171 else if (track < th->starting_track ||
2172 track > th->ending_track + 1) {
2173 printf("error in readtocentry, "
2174 " returning EINVAL\n");
2175 free(data, M_TEMP);
2176 error = EINVAL;
2177 break;
2178 }
2179
2180 error = cdreadtoc(periph, te->address_format, track,
2181 (struct cd_toc_entry *)data,
2182 sizeof(data_t));
2183 if (error) {
2184 free(data, M_TEMP);
2185 break;
2186 }
2187
2188 if (softc->quirks & CD_Q_BCD_TRACKS)
2189 data->entry.track = bcd2bin(data->entry.track);
2190 bcopy(&data->entry, &te->entry,
2191 sizeof(struct cd_toc_entry));
2192 free(data, M_TEMP);
2193 }
2194 break;
2195 case CDIOCSETPATCH:
2196 {
2197 struct ioc_patch *arg = (struct ioc_patch *) addr;
2198 struct cd_mode_data *data;
2199
2200 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2201 ("trying to do CDIOCSETPATCH\n"));
2202
2203 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2204 M_WAITOK);
2205 error = cdgetmode(periph, data, AUDIO_PAGE);
2206 if (error) {
2207 free(data, M_TEMP);
2208 break;
2209 }
2210 data->page.audio.port[LEFT_PORT].channels =
2211 arg->patch[0];
2212 data->page.audio.port[RIGHT_PORT].channels =
2213 arg->patch[1];
2214 data->page.audio.port[2].channels = arg->patch[2];
2215 data->page.audio.port[3].channels = arg->patch[3];
2216 error = cdsetmode(periph, data);
2217 free(data, M_TEMP);
2218 }
2219 break;
2220 case CDIOCGETVOL:
2221 {
2222 struct ioc_vol *arg = (struct ioc_vol *) addr;
2223 struct cd_mode_data *data;
2224
2225 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2226 ("trying to do CDIOCGETVOL\n"));
2227
2228 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2229 M_WAITOK);
2230 error = cdgetmode(periph, data, AUDIO_PAGE);
2231 if (error) {
2232 free(data, M_TEMP);
2233 break;
2234 }
2235 arg->vol[LEFT_PORT] =
2236 data->page.audio.port[LEFT_PORT].volume;
2237 arg->vol[RIGHT_PORT] =
2238 data->page.audio.port[RIGHT_PORT].volume;
2239 arg->vol[2] = data->page.audio.port[2].volume;
2240 arg->vol[3] = data->page.audio.port[3].volume;
2241 free(data, M_TEMP);
2242 }
2243 break;
2244 case CDIOCSETVOL:
2245 {
2246 struct ioc_vol *arg = (struct ioc_vol *) addr;
2247 struct cd_mode_data *data;
2248
2249 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2250 ("trying to do CDIOCSETVOL\n"));
2251
2252 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2253 M_WAITOK);
2254 error = cdgetmode(periph, data, AUDIO_PAGE);
2255 if (error) {
2256 free(data, M_TEMP);
2257 break;
2258 }
2259 data->page.audio.port[LEFT_PORT].channels = CHANNEL_0;
2260 data->page.audio.port[LEFT_PORT].volume =
2261 arg->vol[LEFT_PORT];
2262 data->page.audio.port[RIGHT_PORT].channels = CHANNEL_1;
2263 data->page.audio.port[RIGHT_PORT].volume =
2264 arg->vol[RIGHT_PORT];
2265 data->page.audio.port[2].volume = arg->vol[2];
2266 data->page.audio.port[3].volume = arg->vol[3];
2267 error = cdsetmode(periph, data);
2268 free(data, M_TEMP);
2269 }
2270 break;
2271 case CDIOCSETMONO:
2272 {
2273 struct cd_mode_data *data;
2274
2275 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2276 ("trying to do CDIOCSETMONO\n"));
2277
2278 data = malloc(sizeof(struct cd_mode_data),
2279 M_TEMP, M_WAITOK);
2280 error = cdgetmode(periph, data, AUDIO_PAGE);
2281 if (error) {
2282 free(data, M_TEMP);
2283 break;
2284 }
2285 data->page.audio.port[LEFT_PORT].channels =
2286 LEFT_CHANNEL | RIGHT_CHANNEL;
2287 data->page.audio.port[RIGHT_PORT].channels =
2288 LEFT_CHANNEL | RIGHT_CHANNEL;
2289 data->page.audio.port[2].channels = 0;
2290 data->page.audio.port[3].channels = 0;
2291 error = cdsetmode(periph, data);
2292 free(data, M_TEMP);
2293 }
2294 break;
2295 case CDIOCSETSTEREO:
2296 {
2297 struct cd_mode_data *data;
2298
2299 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2300 ("trying to do CDIOCSETSTEREO\n"));
2301
2302 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2303 M_WAITOK);
2304 error = cdgetmode(periph, data, AUDIO_PAGE);
2305 if (error) {
2306 free(data, M_TEMP);
2307 break;
2308 }
2309 data->page.audio.port[LEFT_PORT].channels =
2310 LEFT_CHANNEL;
2311 data->page.audio.port[RIGHT_PORT].channels =
2312 RIGHT_CHANNEL;
2313 data->page.audio.port[2].channels = 0;
2314 data->page.audio.port[3].channels = 0;
2315 error = cdsetmode(periph, data);
2316 free(data, M_TEMP);
2317 }
2318 break;
2319 case CDIOCSETMUTE:
2320 {
2321 struct cd_mode_data *data;
2322
2323 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2324 ("trying to do CDIOCSETMUTE\n"));
2325
2326 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2327 M_WAITOK);
2328 error = cdgetmode(periph, data, AUDIO_PAGE);
2329 if (error) {
2330 free(data, M_TEMP);
2331 break;
2332 }
2333 data->page.audio.port[LEFT_PORT].channels = 0;
2334 data->page.audio.port[RIGHT_PORT].channels = 0;
2335 data->page.audio.port[2].channels = 0;
2336 data->page.audio.port[3].channels = 0;
2337 error = cdsetmode(periph, data);
2338 free(data, M_TEMP);
2339 }
2340 break;
2341 case CDIOCSETLEFT:
2342 {
2343 struct cd_mode_data *data;
2344
2345 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2346 ("trying to do CDIOCSETLEFT\n"));
2347
2348 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2349 M_WAITOK);
2350 error = cdgetmode(periph, data, AUDIO_PAGE);
2351 if (error) {
2352 free(data, M_TEMP);
2353 break;
2354 }
2355 data->page.audio.port[LEFT_PORT].channels =
2356 LEFT_CHANNEL;
2357 data->page.audio.port[RIGHT_PORT].channels =
2358 LEFT_CHANNEL;
2359 data->page.audio.port[2].channels = 0;
2360 data->page.audio.port[3].channels = 0;
2361 error = cdsetmode(periph, data);
2362 free(data, M_TEMP);
2363 }
2364 break;
2365 case CDIOCSETRIGHT:
2366 {
2367 struct cd_mode_data *data;
2368
2369 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2370 ("trying to do CDIOCSETRIGHT\n"));
2371
2372 data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2373 M_WAITOK);
2374 error = cdgetmode(periph, data, AUDIO_PAGE);
2375 if (error) {
2376 free(data, M_TEMP);
2377 break;
2378 }
2379 data->page.audio.port[LEFT_PORT].channels =
2380 RIGHT_CHANNEL;
2381 data->page.audio.port[RIGHT_PORT].channels =
2382 RIGHT_CHANNEL;
2383 data->page.audio.port[2].channels = 0;
2384 data->page.audio.port[3].channels = 0;
2385 error = cdsetmode(periph, data);
2386 free(data, M_TEMP);
2387 }
2388 break;
2389 case CDIOCRESUME:
2390 error = cdpause(periph, 1);
2391 break;
2392 case CDIOCPAUSE:
2393 error = cdpause(periph, 0);
2394 break;
2395 case CDIOCSTART:
2396 error = cdstartunit(periph);
2397 break;
2398 case CDIOCSTOP:
2399 error = cdstopunit(periph, 0);
2400 break;
2401 case CDIOCEJECT:
2402 error = cdstopunit(periph, 1);
2403 break;
2404 case CDIOCALLOW:
2405 cdprevent(periph, PR_ALLOW);
2406 break;
2407 case CDIOCPREVENT:
2408 cdprevent(periph, PR_PREVENT);
2409 break;
2410 case CDIOCSETDEBUG:
2411 /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */
2412 error = ENOTTY;
2413 break;
2414 case CDIOCCLRDEBUG:
2415 /* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */
2416 error = ENOTTY;
2417 break;
2418 case CDIOCRESET:
2419 /* return (cd_reset(periph)); */
2420 error = ENOTTY;
2421 break;
2422 case DVDIOCSENDKEY:
2423 case DVDIOCREPORTKEY: {
2424 struct dvd_authinfo *authinfo;
2425
2426 authinfo = (struct dvd_authinfo *)addr;
2427
2428 if (cmd == DVDIOCREPORTKEY)
2429 error = cdreportkey(periph, authinfo);
2430 else
2431 error = cdsendkey(periph, authinfo);
2432 break;
2433 }
2434 case DVDIOCREADSTRUCTURE: {
2435 struct dvd_struct *dvdstruct;
2436
2437 dvdstruct = (struct dvd_struct *)addr;
2438
2439 error = cdreaddvdstructure(periph, dvdstruct);
2440
2441 break;
2442 }
2443 default:
2444 error = cam_periph_ioctl(periph, cmd, addr, cderror);
2445 break;
2446 }
2447
2448 cam_periph_unlock(periph);
2449
2450 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n"));
2451
2452 return (error);
2453}
2454
2455static void
2456cdprevent(struct cam_periph *periph, int action)
2457{
2458 union ccb *ccb;
2459 struct cd_softc *softc;
2460 int error;
2461
2462 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n"));
2463
2464 softc = (struct cd_softc *)periph->softc;
2465
2466 if (((action == PR_ALLOW)
2467 && (softc->flags & CD_FLAG_DISC_LOCKED) == 0)
2468 || ((action == PR_PREVENT)
2469 && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) {
2470 return;
2471 }
2472
2473 ccb = cdgetccb(periph, /* priority */ 1);
2474
2475 scsi_prevent(&ccb->csio,
2476 /*retries*/ 1,
2477 cddone,
2478 MSG_SIMPLE_Q_TAG,
2479 action,
2480 SSD_FULL_SIZE,
2481 /* timeout */60000);
2482
2483 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2484 /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT);
2485
2486 xpt_release_ccb(ccb);
2487
2488 if (error == 0) {
2489 if (action == PR_ALLOW)
2490 softc->flags &= ~CD_FLAG_DISC_LOCKED;
2491 else
2492 softc->flags |= CD_FLAG_DISC_LOCKED;
2493 }
2494}
2495
2496static int
2497cdsize(dev_t dev, u_int32_t *size)
2498{
2499 struct cam_periph *periph;
2500 struct cd_softc *softc;
2501 union ccb *ccb;
2502 struct scsi_read_capacity_data *rcap_buf;
2503 int error;
2504
2505 periph = cam_extend_get(cdperiphs, dkunit(dev));
2506
2507 if (periph == NULL)
2508 return (ENXIO);
2509
2510 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n"));
2511
2512 softc = (struct cd_softc *)periph->softc;
2513
2514 ccb = cdgetccb(periph, /* priority */ 1);
2515
2516 rcap_buf = malloc(sizeof(struct scsi_read_capacity_data),
2517 M_TEMP, M_WAITOK);
2518
2519 scsi_read_capacity(&ccb->csio,
2520 /*retries*/ 1,
2521 cddone,
2522 MSG_SIMPLE_Q_TAG,
2523 rcap_buf,
2524 SSD_FULL_SIZE,
2525 /* timeout */20000);
2526
2527 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2528 /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT);
2529
2530 xpt_release_ccb(ccb);
2531
2532 softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1;
2533 softc->params.blksize = scsi_4btoul(rcap_buf->length);
2534 /*
2535 * SCSI-3 mandates that the reported blocksize shall be 2048.
2536 * Older drives sometimes report funny values, trim it down to
2537 * 2048, or other parts of the kernel will get confused.
2538 *
2539 * XXX we leave drives alone that might report 512 bytes, as
2540 * well as drives reporting more weird sizes like perhaps 4K.
2541 */
2542 if (softc->params.blksize > 2048 && softc->params.blksize <= 2352)
2543 softc->params.blksize = 2048;
2544
2545 free(rcap_buf, M_TEMP);
2546 *size = softc->params.disksize;
2547
2548 return (error);
2549
2550}
2551
2552/*
2553 * The idea here is to try to figure out whether the first track is data or
2554 * audio. If it is data, we can at least attempt to read a disklabel off
2555 * the first sector of the disk. If it is audio, there won't be a
2556 * disklabel.
2557 *
2558 * This routine returns 0 if the first track is data, and non-zero if there
2559 * is an error or the first track is audio. (If either non-zero case, we
2560 * should not attempt to read the disklabel.)
2561 */
2562static int
2563cdfirsttrackisdata(struct cam_periph *periph)
2564{
2565 struct cdtocdata {
2566 struct ioc_toc_header header;
2567 struct cd_toc_entry entries[100];
2568 };
2569 struct cd_softc *softc;
2570 struct ioc_toc_header *th;
2571 struct cdtocdata *data;
2572 int num_entries, i;
2573 int error, first_track_audio;
2574
2575 error = 0;
2576 first_track_audio = -1;
2577
2578 softc = (struct cd_softc *)periph->softc;
2579
2580 data = malloc(sizeof(struct cdtocdata), M_TEMP, M_WAITOK);
2581
2582 th = &data->header;
2583 error = cdreadtoc(periph, 0, 0, (struct cd_toc_entry *)data,
2584 sizeof(*data));
2585
2586 if (error)
2587 goto bailout;
2588
2589 if (softc->quirks & CD_Q_BCD_TRACKS) {
2590 /* we are going to have to convert the BCD
2591 * encoding on the cd to what is expected
2592 */
2593 th->starting_track =
2594 bcd2bin(th->starting_track);
2595 th->ending_track = bcd2bin(th->ending_track);
2596 }
2597 th->len = scsi_2btoul((u_int8_t *)&th->len);
2598
2599 if ((th->len - 2) > 0)
2600 num_entries = (th->len - 2) / sizeof(struct cd_toc_entry);
2601 else
2602 num_entries = 0;
2603
2604 for (i = 0; i < num_entries; i++) {
2605 if (data->entries[i].track == th->starting_track) {
2606 if (data->entries[i].control & 0x4)
2607 first_track_audio = 0;
2608 else
2609 first_track_audio = 1;
2610 break;
2611 }
2612 }
2613
2614 if (first_track_audio == -1)
2615 error = ENOENT;
2616 else if (first_track_audio == 1)
2617 error = EINVAL;
2618 else
2619 error = 0;
2620bailout:
2621 free(data, M_TEMP);
2622
2623 return(error);
2624}
2625
2626static int
2627cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
2628{
2629 struct cd_softc *softc;
2630 struct cam_periph *periph;
2631
2632 periph = xpt_path_periph(ccb->ccb_h.path);
2633 softc = (struct cd_softc *)periph->softc;
2634
2635 /*
2636 * XXX
2637 * Until we have a better way of doing pack validation,
2638 * don't treat UAs as errors.
2639 */
2640 sense_flags |= SF_RETRY_UA;
2641 return (cam_periph_error(ccb, cam_flags, sense_flags,
2642 &softc->saved_ccb));
2643}
2644
2645/*
2646 * Read table of contents
2647 */
2648static int
2649cdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start,
2650 struct cd_toc_entry *data, u_int32_t len)
2651{
2652 struct scsi_read_toc *scsi_cmd;
2653 u_int32_t ntoc;
2654 struct ccb_scsiio *csio;
2655 union ccb *ccb;
2656 int error;
2657
2658 ntoc = len;
2659 error = 0;
2660
2661 ccb = cdgetccb(periph, /* priority */ 1);
2662
2663 csio = &ccb->csio;
2664
2665 cam_fill_csio(csio,
2666 /* retries */ 1,
2667 /* cbfcnp */ cddone,
2668 /* flags */ CAM_DIR_IN,
2669 /* tag_action */ MSG_SIMPLE_Q_TAG,
2670 /* data_ptr */ (u_int8_t *)data,
2671 /* dxfer_len */ len,
2672 /* sense_len */ SSD_FULL_SIZE,
2673 sizeof(struct scsi_read_toc),
2674 /* timeout */ 50000);
2675
2676 scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes;
2677 bzero (scsi_cmd, sizeof(*scsi_cmd));
2678
2679 if (mode == CD_MSF_FORMAT)
2680 scsi_cmd->byte2 |= CD_MSF;
2681 scsi_cmd->from_track = start;
2682 /* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */
2683 scsi_cmd->data_len[0] = (ntoc) >> 8;
2684 scsi_cmd->data_len[1] = (ntoc) & 0xff;
2685
2686 scsi_cmd->op_code = READ_TOC;
2687
2688 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2689 /*sense_flags*/SF_RETRY_UA);
2690
2691 xpt_release_ccb(ccb);
2692
2693 return(error);
2694}
2695
2696static int
2697cdreadsubchannel(struct cam_periph *periph, u_int32_t mode,
2698 u_int32_t format, int track,
2699 struct cd_sub_channel_info *data, u_int32_t len)
2700{
2701 struct scsi_read_subchannel *scsi_cmd;
2702 struct ccb_scsiio *csio;
2703 union ccb *ccb;
2704 int error;
2705
2706 error = 0;
2707
2708 ccb = cdgetccb(periph, /* priority */ 1);
2709
2710 csio = &ccb->csio;
2711
2712 cam_fill_csio(csio,
2713 /* retries */ 1,
2714 /* cbfcnp */ cddone,
2715 /* flags */ CAM_DIR_IN,
2716 /* tag_action */ MSG_SIMPLE_Q_TAG,
2717 /* data_ptr */ (u_int8_t *)data,
2718 /* dxfer_len */ len,
2719 /* sense_len */ SSD_FULL_SIZE,
2720 sizeof(struct scsi_read_subchannel),
2721 /* timeout */ 50000);
2722
2723 scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes;
2724 bzero (scsi_cmd, sizeof(*scsi_cmd));
2725
2726 scsi_cmd->op_code = READ_SUBCHANNEL;
2727 if (mode == CD_MSF_FORMAT)
2728 scsi_cmd->byte1 |= CD_MSF;
2729 scsi_cmd->byte2 = SRS_SUBQ;
2730 scsi_cmd->subchan_format = format;
2731 scsi_cmd->track = track;
2732 scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len);
2733 scsi_cmd->control = 0;
2734
2735 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2736 /*sense_flags*/SF_RETRY_UA);
2737
2738 xpt_release_ccb(ccb);
2739
2740 return(error);
2741}
2742
2743
2744static int
2745cdgetmode(struct cam_periph *periph, struct cd_mode_data *data, u_int32_t page)
2746{
2747 struct scsi_mode_sense_6 *scsi_cmd;
2748 struct ccb_scsiio *csio;
2749 union ccb *ccb;
2750 int error;
2751
2752 ccb = cdgetccb(periph, /* priority */ 1);
2753
2754 csio = &ccb->csio;
2755
2756 bzero(data, sizeof(*data));
2757 cam_fill_csio(csio,
2758 /* retries */ 1,
2759 /* cbfcnp */ cddone,
2760 /* flags */ CAM_DIR_IN,
2761 /* tag_action */ MSG_SIMPLE_Q_TAG,
2762 /* data_ptr */ (u_int8_t *)data,
2763 /* dxfer_len */ sizeof(*data),
2764 /* sense_len */ SSD_FULL_SIZE,
2765 sizeof(struct scsi_mode_sense_6),
2766 /* timeout */ 50000);
2767
2768 scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes;
2769 bzero (scsi_cmd, sizeof(*scsi_cmd));
2770
2771 scsi_cmd->page = page;
2772 scsi_cmd->length = sizeof(*data) & 0xff;
2773 scsi_cmd->opcode = MODE_SENSE;
2774
2775 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2776 /*sense_flags*/SF_RETRY_UA);
2777
2778 xpt_release_ccb(ccb);
2779
2780 return(error);
2781}
2782
2783static int
2784cdsetmode(struct cam_periph *periph, struct cd_mode_data *data)
2785{
2786 struct scsi_mode_select_6 *scsi_cmd;
2787 struct ccb_scsiio *csio;
2788 union ccb *ccb;
2789 int error;
2790
2791 ccb = cdgetccb(periph, /* priority */ 1);
2792
2793 csio = &ccb->csio;
2794
2795 error = 0;
2796
2797 cam_fill_csio(csio,
2798 /* retries */ 1,
2799 /* cbfcnp */ cddone,
2800 /* flags */ CAM_DIR_OUT,
2801 /* tag_action */ MSG_SIMPLE_Q_TAG,
2802 /* data_ptr */ (u_int8_t *)data,
2803 /* dxfer_len */ sizeof(*data),
2804 /* sense_len */ SSD_FULL_SIZE,
2805 sizeof(struct scsi_mode_select_6),
2806 /* timeout */ 50000);
2807
2808 scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes;
2809
2810 bzero(scsi_cmd, sizeof(*scsi_cmd));
2811 scsi_cmd->opcode = MODE_SELECT;
2812 scsi_cmd->byte2 |= SMS_PF;
2813 scsi_cmd->length = sizeof(*data) & 0xff;
2814 data->header.data_length = 0;
2815 /*
2816 * SONY drives do not allow a mode select with a medium_type
2817 * value that has just been returned by a mode sense; use a
2818 * medium_type of 0 (Default) instead.
2819 */
2820 data->header.medium_type = 0;
2821
2822 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2823 /*sense_flags*/SF_RETRY_UA);
2824
2825 xpt_release_ccb(ccb);
2826
2827 return(error);
2828}
2829
2830
2831static int
2832cdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len)
2833{
2834 struct ccb_scsiio *csio;
2835 union ccb *ccb;
2836 int error;
2837 u_int8_t cdb_len;
2838
2839 error = 0;
2840 ccb = cdgetccb(periph, /* priority */ 1);
2841 csio = &ccb->csio;
2842 /*
2843 * Use the smallest possible command to perform the operation.
2844 */
2845 if ((len & 0xffff0000) == 0) {
2846 /*
2847 * We can fit in a 10 byte cdb.
2848 */
2849 struct scsi_play_10 *scsi_cmd;
2850
2851 scsi_cmd = (struct scsi_play_10 *)&csio->cdb_io.cdb_bytes;
2852 bzero (scsi_cmd, sizeof(*scsi_cmd));
2853 scsi_cmd->op_code = PLAY_10;
2854 scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr);
2855 scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len);
2856 cdb_len = sizeof(*scsi_cmd);
2857 } else {
2858 struct scsi_play_12 *scsi_cmd;
2859
2860 scsi_cmd = (struct scsi_play_12 *)&csio->cdb_io.cdb_bytes;
2861 bzero (scsi_cmd, sizeof(*scsi_cmd));
2862 scsi_cmd->op_code = PLAY_12;
2863 scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr);
2864 scsi_ulto4b(len, (u_int8_t *)scsi_cmd->xfer_len);
2865 cdb_len = sizeof(*scsi_cmd);
2866 }
2867 cam_fill_csio(csio,
2868 /*retries*/2,
2869 cddone,
2870 /*flags*/CAM_DIR_NONE,
2871 MSG_SIMPLE_Q_TAG,
2872 /*dataptr*/NULL,
2873 /*datalen*/0,
2874 /*sense_len*/SSD_FULL_SIZE,
2875 cdb_len,
2876 /*timeout*/50 * 1000);
2877
2878 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2879 /*sense_flags*/SF_RETRY_UA);
2880
2881 xpt_release_ccb(ccb);
2882
2883 return(error);
2884}
2885
2886static int
2887cdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts,
2888 u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf)
2889{
2890 struct scsi_play_msf *scsi_cmd;
2891 struct ccb_scsiio *csio;
2892 union ccb *ccb;
2893 int error;
2894
2895 error = 0;
2896
2897 ccb = cdgetccb(periph, /* priority */ 1);
2898
2899 csio = &ccb->csio;
2900
2901 cam_fill_csio(csio,
2902 /* retries */ 1,
2903 /* cbfcnp */ cddone,
2904 /* flags */ CAM_DIR_NONE,
2905 /* tag_action */ MSG_SIMPLE_Q_TAG,
2906 /* data_ptr */ NULL,
2907 /* dxfer_len */ 0,
2908 /* sense_len */ SSD_FULL_SIZE,
2909 sizeof(struct scsi_play_msf),
2910 /* timeout */ 50000);
2911
2912 scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes;
2913 bzero (scsi_cmd, sizeof(*scsi_cmd));
2914
2915 scsi_cmd->op_code = PLAY_MSF;
2916 scsi_cmd->start_m = startm;
2917 scsi_cmd->start_s = starts;
2918 scsi_cmd->start_f = startf;
2919 scsi_cmd->end_m = endm;
2920 scsi_cmd->end_s = ends;
2921 scsi_cmd->end_f = endf;
2922
2923 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2924 /*sense_flags*/SF_RETRY_UA);
2925
2926 xpt_release_ccb(ccb);
2927
2928 return(error);
2929}
2930
2931
2932static int
2933cdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex,
2934 u_int32_t etrack, u_int32_t eindex)
2935{
2936 struct scsi_play_track *scsi_cmd;
2937 struct ccb_scsiio *csio;
2938 union ccb *ccb;
2939 int error;
2940
2941 error = 0;
2942
2943 ccb = cdgetccb(periph, /* priority */ 1);
2944
2945 csio = &ccb->csio;
2946
2947 cam_fill_csio(csio,
2948 /* retries */ 1,
2949 /* cbfcnp */ cddone,
2950 /* flags */ CAM_DIR_NONE,
2951 /* tag_action */ MSG_SIMPLE_Q_TAG,
2952 /* data_ptr */ NULL,
2953 /* dxfer_len */ 0,
2954 /* sense_len */ SSD_FULL_SIZE,
2955 sizeof(struct scsi_play_track),
2956 /* timeout */ 50000);
2957
2958 scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes;
2959 bzero (scsi_cmd, sizeof(*scsi_cmd));
2960
2961 scsi_cmd->op_code = PLAY_TRACK;
2962 scsi_cmd->start_track = strack;
2963 scsi_cmd->start_index = sindex;
2964 scsi_cmd->end_track = etrack;
2965 scsi_cmd->end_index = eindex;
2966
2967 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2968 /*sense_flags*/SF_RETRY_UA);
2969
2970 xpt_release_ccb(ccb);
2971
2972 return(error);
2973}
2974
2975static int
2976cdpause(struct cam_periph *periph, u_int32_t go)
2977{
2978 struct scsi_pause *scsi_cmd;
2979 struct ccb_scsiio *csio;
2980 union ccb *ccb;
2981 int error;
2982
2983 error = 0;
2984
2985 ccb = cdgetccb(periph, /* priority */ 1);
2986
2987 csio = &ccb->csio;
2988
2989 cam_fill_csio(csio,
2990 /* retries */ 1,
2991 /* cbfcnp */ cddone,
2992 /* flags */ CAM_DIR_NONE,
2993 /* tag_action */ MSG_SIMPLE_Q_TAG,
2994 /* data_ptr */ NULL,
2995 /* dxfer_len */ 0,
2996 /* sense_len */ SSD_FULL_SIZE,
2997 sizeof(struct scsi_pause),
2998 /* timeout */ 50000);
2999
3000 scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes;
3001 bzero (scsi_cmd, sizeof(*scsi_cmd));
3002
3003 scsi_cmd->op_code = PAUSE;
3004 scsi_cmd->resume = go;
3005
3006 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3007 /*sense_flags*/SF_RETRY_UA);
3008
3009 xpt_release_ccb(ccb);
3010
3011 return(error);
3012}
3013
3014static int
3015cdstartunit(struct cam_periph *periph)
3016{
3017 union ccb *ccb;
3018 int error;
3019
3020 error = 0;
3021
3022 ccb = cdgetccb(periph, /* priority */ 1);
3023
3024 scsi_start_stop(&ccb->csio,
3025 /* retries */ 1,
3026 /* cbfcnp */ cddone,
3027 /* tag_action */ MSG_SIMPLE_Q_TAG,
3028 /* start */ TRUE,
3029 /* load_eject */ FALSE,
3030 /* immediate */ FALSE,
3031 /* sense_len */ SSD_FULL_SIZE,
3032 /* timeout */ 50000);
3033
3034 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3035 /*sense_flags*/SF_RETRY_UA);
3036
3037 xpt_release_ccb(ccb);
3038
3039 return(error);
3040}
3041
3042static int
3043cdstopunit(struct cam_periph *periph, u_int32_t eject)
3044{
3045 union ccb *ccb;
3046 int error;
3047
3048 error = 0;
3049
3050 ccb = cdgetccb(periph, /* priority */ 1);
3051
3052 scsi_start_stop(&ccb->csio,
3053 /* retries */ 1,
3054 /* cbfcnp */ cddone,
3055 /* tag_action */ MSG_SIMPLE_Q_TAG,
3056 /* start */ FALSE,
3057 /* load_eject */ eject,
3058 /* immediate */ FALSE,
3059 /* sense_len */ SSD_FULL_SIZE,
3060 /* timeout */ 50000);
3061
3062 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3063 /*sense_flags*/SF_RETRY_UA);
3064
3065 xpt_release_ccb(ccb);
3066
3067 return(error);
3068}
3069
3070static int
3071cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo)
3072{
3073 union ccb *ccb;
3074 u_int8_t *databuf;
3075 u_int32_t lba;
3076 int error;
3077 int length;
3078
3079 error = 0;
3080 databuf = NULL;
3081 lba = 0;
3082
3083 ccb = cdgetccb(periph, /* priority */ 1);
3084
3085 switch (authinfo->format) {
3086 case DVD_REPORT_AGID:
3087 length = sizeof(struct scsi_report_key_data_agid);
3088 break;
3089 case DVD_REPORT_CHALLENGE:
3090 length = sizeof(struct scsi_report_key_data_challenge);
3091 break;
3092 case DVD_REPORT_KEY1:
3093 length = sizeof(struct scsi_report_key_data_key1_key2);
3094 break;
3095 case DVD_REPORT_TITLE_KEY:
3096 length = sizeof(struct scsi_report_key_data_title);
3097 /* The lba field is only set for the title key */
3098 lba = authinfo->lba;
3099 break;
3100 case DVD_REPORT_ASF:
3101 length = sizeof(struct scsi_report_key_data_asf);
3102 break;
3103 case DVD_REPORT_RPC:
3104 length = sizeof(struct scsi_report_key_data_rpc);
3105 break;
3106 case DVD_INVALIDATE_AGID:
3107 length = 0;
3108 break;
3109 default:
3110 error = EINVAL;
3111 goto bailout;
3112 break; /* NOTREACHED */
3113 }
3114
3115 if (length != 0) {
3116 databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3117 } else
3118 databuf = NULL;
3119
3120
3121 scsi_report_key(&ccb->csio,
3122 /* retries */ 1,
3123 /* cbfcnp */ cddone,
3124 /* tag_action */ MSG_SIMPLE_Q_TAG,
3125 /* lba */ lba,
3126 /* agid */ authinfo->agid,
3127 /* key_format */ authinfo->format,
3128 /* data_ptr */ databuf,
3129 /* dxfer_len */ length,
3130 /* sense_len */ SSD_FULL_SIZE,
3131 /* timeout */ 50000);
3132
3133 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3134 /*sense_flags*/SF_RETRY_UA);
3135
3136 if (error != 0)
3137 goto bailout;
3138
3139 if (ccb->csio.resid != 0) {
3140 xpt_print_path(periph->path);
3141 printf("warning, residual for report key command is %d\n",
3142 ccb->csio.resid);
3143 }
3144
3145 switch(authinfo->format) {
3146 case DVD_REPORT_AGID: {
3147 struct scsi_report_key_data_agid *agid_data;
3148
3149 agid_data = (struct scsi_report_key_data_agid *)databuf;
3150
3151 authinfo->agid = (agid_data->agid & RKD_AGID_MASK) >>
3152 RKD_AGID_SHIFT;
3153 break;
3154 }
3155 case DVD_REPORT_CHALLENGE: {
3156 struct scsi_report_key_data_challenge *chal_data;
3157
3158 chal_data = (struct scsi_report_key_data_challenge *)databuf;
3159
3160 bcopy(chal_data->challenge_key, authinfo->keychal,
3161 min(sizeof(chal_data->challenge_key),
3162 sizeof(authinfo->keychal)));
3163 break;
3164 }
3165 case DVD_REPORT_KEY1: {
3166 struct scsi_report_key_data_key1_key2 *key1_data;
3167
3168 key1_data = (struct scsi_report_key_data_key1_key2 *)databuf;
3169
3170 bcopy(key1_data->key1, authinfo->keychal,
3171 min(sizeof(key1_data->key1), sizeof(authinfo->keychal)));
3172 break;
3173 }
3174 case DVD_REPORT_TITLE_KEY: {
3175 struct scsi_report_key_data_title *title_data;
3176
3177 title_data = (struct scsi_report_key_data_title *)databuf;
3178
3179 authinfo->cpm = (title_data->byte0 & RKD_TITLE_CPM) >>
3180 RKD_TITLE_CPM_SHIFT;
3181 authinfo->cp_sec = (title_data->byte0 & RKD_TITLE_CP_SEC) >>
3182 RKD_TITLE_CP_SEC_SHIFT;
3183 authinfo->cgms = (title_data->byte0 & RKD_TITLE_CMGS_MASK) >>
3184 RKD_TITLE_CMGS_SHIFT;
3185 bcopy(title_data->title_key, authinfo->keychal,
3186 min(sizeof(title_data->title_key),
3187 sizeof(authinfo->keychal)));
3188 break;
3189 }
3190 case DVD_REPORT_ASF: {
3191 struct scsi_report_key_data_asf *asf_data;
3192
3193 asf_data = (struct scsi_report_key_data_asf *)databuf;
3194
3195 authinfo->asf = asf_data->success & RKD_ASF_SUCCESS;
3196 break;
3197 }
3198 case DVD_REPORT_RPC: {
3199 struct scsi_report_key_data_rpc *rpc_data;
3200
3201 rpc_data = (struct scsi_report_key_data_rpc *)databuf;
3202
3203 authinfo->reg_type = (rpc_data->byte4 & RKD_RPC_TYPE_MASK) >>
3204 RKD_RPC_TYPE_SHIFT;
3205 authinfo->vend_rsts =
3206 (rpc_data->byte4 & RKD_RPC_VENDOR_RESET_MASK) >>
3207 RKD_RPC_VENDOR_RESET_SHIFT;
3208 authinfo->user_rsts = rpc_data->byte4 & RKD_RPC_USER_RESET_MASK;
3209 authinfo->region = rpc_data->region_mask;
3210 authinfo->rpc_scheme = rpc_data->rpc_scheme1;
3211 break;
3212 }
3213 case DVD_INVALIDATE_AGID:
3214 break;
3215 default:
3216 /* This should be impossible, since we checked above */
3217 error = EINVAL;
3218 goto bailout;
3219 break; /* NOTREACHED */
3220 }
3221bailout:
3222 if (databuf != NULL)
3223 free(databuf, M_DEVBUF);
3224
3225 xpt_release_ccb(ccb);
3226
3227 return(error);
3228}
3229
3230static int
3231cdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo)
3232{
3233 union ccb *ccb;
3234 u_int8_t *databuf;
3235 int length;
3236 int error;
3237
3238 error = 0;
3239 databuf = NULL;
3240
3241 ccb = cdgetccb(periph, /* priority */ 1);
3242
3243 switch(authinfo->format) {
3244 case DVD_SEND_CHALLENGE: {
3245 struct scsi_report_key_data_challenge *challenge_data;
3246
3247 length = sizeof(*challenge_data);
3248
3249 challenge_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3250
3251 databuf = (u_int8_t *)challenge_data;
3252
3253 scsi_ulto2b(length - sizeof(challenge_data->data_len),
3254 challenge_data->data_len);
3255
3256 bcopy(authinfo->keychal, challenge_data->challenge_key,
3257 min(sizeof(authinfo->keychal),
3258 sizeof(challenge_data->challenge_key)));
3259 break;
3260 }
3261 case DVD_SEND_KEY2: {
3262 struct scsi_report_key_data_key1_key2 *key2_data;
3263
3264 length = sizeof(*key2_data);
3265
3266 key2_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3267
3268 databuf = (u_int8_t *)key2_data;
3269
3270 scsi_ulto2b(length - sizeof(key2_data->data_len),
3271 key2_data->data_len);
3272
3273 bcopy(authinfo->keychal, key2_data->key1,
3274 min(sizeof(authinfo->keychal), sizeof(key2_data->key1)));
3275
3276 break;
3277 }
3278 case DVD_SEND_RPC: {
3279 struct scsi_send_key_data_rpc *rpc_data;
3280
3281 length = sizeof(*rpc_data);
3282
3283 rpc_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3284
3285 databuf = (u_int8_t *)rpc_data;
3286
3287 scsi_ulto2b(length - sizeof(rpc_data->data_len),
3288 rpc_data->data_len);
3289
3290 rpc_data->region_code = authinfo->region;
3291 break;
3292 }
3293 default:
3294 error = EINVAL;
3295 goto bailout;
3296 break; /* NOTREACHED */
3297 }
3298
3299 scsi_send_key(&ccb->csio,
3300 /* retries */ 1,
3301 /* cbfcnp */ cddone,
3302 /* tag_action */ MSG_SIMPLE_Q_TAG,
3303 /* agid */ authinfo->agid,
3304 /* key_format */ authinfo->format,
3305 /* data_ptr */ databuf,
3306 /* dxfer_len */ length,
3307 /* sense_len */ SSD_FULL_SIZE,
3308 /* timeout */ 50000);
3309
3310 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3311 /*sense_flags*/SF_RETRY_UA);
3312
3313bailout:
3314
3315 if (databuf != NULL)
3316 free(databuf, M_DEVBUF);
3317
3318 xpt_release_ccb(ccb);
3319
3320 return(error);
3321}
3322
3323static int
3324cdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct)
3325{
3326 union ccb *ccb;
3327 u_int8_t *databuf;
3328 u_int32_t address;
3329 int error;
3330 int length;
3331
3332 error = 0;
3333 databuf = NULL;
3334 /* The address is reserved for many of the formats */
3335 address = 0;
3336
3337 ccb = cdgetccb(periph, /* priority */ 1);
3338
3339 switch(dvdstruct->format) {
3340 case DVD_STRUCT_PHYSICAL:
3341 length = sizeof(struct scsi_read_dvd_struct_data_physical);
3342 break;
3343 case DVD_STRUCT_COPYRIGHT:
3344 length = sizeof(struct scsi_read_dvd_struct_data_copyright);
3345 break;
3346 case DVD_STRUCT_DISCKEY:
3347 length = sizeof(struct scsi_read_dvd_struct_data_disc_key);
3348 break;
3349 case DVD_STRUCT_BCA:
3350 length = sizeof(struct scsi_read_dvd_struct_data_bca);
3351 break;
3352 case DVD_STRUCT_MANUFACT:
3353 length = sizeof(struct scsi_read_dvd_struct_data_manufacturer);
3354 break;
3355 case DVD_STRUCT_CMI:
3356 error = ENODEV;
3357 goto bailout;
3358#ifdef notyet
3359 length = sizeof(struct scsi_read_dvd_struct_data_copy_manage);
3360 address = dvdstruct->address;
3361#endif
3362 break; /* NOTREACHED */
3363 case DVD_STRUCT_PROTDISCID:
3364 length = sizeof(struct scsi_read_dvd_struct_data_prot_discid);
3365 break;
3366 case DVD_STRUCT_DISCKEYBLOCK:
3367 length = sizeof(struct scsi_read_dvd_struct_data_disc_key_blk);
3368 break;
3369 case DVD_STRUCT_DDS:
3370 length = sizeof(struct scsi_read_dvd_struct_data_dds);
3371 break;
3372 case DVD_STRUCT_MEDIUM_STAT:
3373 length = sizeof(struct scsi_read_dvd_struct_data_medium_status);
3374 break;
3375 case DVD_STRUCT_SPARE_AREA:
3376 length = sizeof(struct scsi_read_dvd_struct_data_spare_area);
3377 break;
3378 case DVD_STRUCT_RMD_LAST:
3379 error = ENODEV;
3380 goto bailout;
3381#ifdef notyet
3382 length = sizeof(struct scsi_read_dvd_struct_data_rmd_borderout);
3383 address = dvdstruct->address;
3384#endif
3385 break; /* NOTREACHED */
3386 case DVD_STRUCT_RMD_RMA:
3387 error = ENODEV;
3388 goto bailout;
3389#ifdef notyet
3390 length = sizeof(struct scsi_read_dvd_struct_data_rmd);
3391 address = dvdstruct->address;
3392#endif
3393 break; /* NOTREACHED */
3394 case DVD_STRUCT_PRERECORDED:
3395 length = sizeof(struct scsi_read_dvd_struct_data_leadin);
3396 break;
3397 case DVD_STRUCT_UNIQUEID:
3398 length = sizeof(struct scsi_read_dvd_struct_data_disc_id);
3399 break;
3400 case DVD_STRUCT_DCB:
3401 error = ENODEV;
3402 goto bailout;
3403#ifdef notyet
3404 length = sizeof(struct scsi_read_dvd_struct_data_dcb);
3405 address = dvdstruct->address;
3406#endif
3407 break; /* NOTREACHED */
3408 case DVD_STRUCT_LIST:
3409 /*
3410 * This is the maximum allocation length for the READ DVD
3411 * STRUCTURE command. There's nothing in the MMC3 spec
3412 * that indicates a limit in the amount of data that can
3413 * be returned from this call, other than the limits
3414 * imposed by the 2-byte length variables.
3415 */
3416 length = 65535;
3417 break;
3418 default:
3419 error = EINVAL;
3420 goto bailout;
3421 break; /* NOTREACHED */
3422 }
3423
3424 if (length != 0) {
3425 databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3426 } else
3427 databuf = NULL;
3428
3429 scsi_read_dvd_structure(&ccb->csio,
3430 /* retries */ 1,
3431 /* cbfcnp */ cddone,
3432 /* tag_action */ MSG_SIMPLE_Q_TAG,
3433 /* lba */ address,
3434 /* layer_number */ dvdstruct->layer_num,
3435 /* key_format */ dvdstruct->format,
3436 /* agid */ dvdstruct->agid,
3437 /* data_ptr */ databuf,
3438 /* dxfer_len */ length,
3439 /* sense_len */ SSD_FULL_SIZE,
3440 /* timeout */ 50000);
3441
3442 error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3443 /*sense_flags*/SF_RETRY_UA);
3444
3445 if (error != 0)
3446 goto bailout;
3447
3448 switch(dvdstruct->format) {
3449 case DVD_STRUCT_PHYSICAL: {
3450 struct scsi_read_dvd_struct_data_layer_desc *inlayer;
3451 struct dvd_layer *outlayer;
3452 struct scsi_read_dvd_struct_data_physical *phys_data;
3453
3454 phys_data =
3455 (struct scsi_read_dvd_struct_data_physical *)databuf;
3456 inlayer = &phys_data->layer_desc;
3457 outlayer = (struct dvd_layer *)&dvdstruct->data;
3458
3459 dvdstruct->length = sizeof(*inlayer);
3460
3461 outlayer->book_type = (inlayer->book_type_version &
3462 RDSD_BOOK_TYPE_MASK) >> RDSD_BOOK_TYPE_SHIFT;
3463 outlayer->book_version = (inlayer->book_type_version &
3464 RDSD_BOOK_VERSION_MASK);
3465 outlayer->disc_size = (inlayer->disc_size_max_rate &
3466 RDSD_DISC_SIZE_MASK) >> RDSD_DISC_SIZE_SHIFT;
3467 outlayer->max_rate = (inlayer->disc_size_max_rate &
3468 RDSD_MAX_RATE_MASK);
3469 outlayer->nlayers = (inlayer->layer_info &
3470 RDSD_NUM_LAYERS_MASK) >> RDSD_NUM_LAYERS_SHIFT;
3471 outlayer->track_path = (inlayer->layer_info &
3472 RDSD_TRACK_PATH_MASK) >> RDSD_TRACK_PATH_SHIFT;
3473 outlayer->layer_type = (inlayer->layer_info &
3474 RDSD_LAYER_TYPE_MASK);
3475 outlayer->linear_density = (inlayer->density &
3476 RDSD_LIN_DENSITY_MASK) >> RDSD_LIN_DENSITY_SHIFT;
3477 outlayer->track_density = (inlayer->density &
3478 RDSD_TRACK_DENSITY_MASK);
3479 outlayer->bca = (inlayer->bca & RDSD_BCA_MASK) >>
3480 RDSD_BCA_SHIFT;
3481 outlayer->start_sector = scsi_3btoul(inlayer->main_data_start);
3482 outlayer->end_sector = scsi_3btoul(inlayer->main_data_end);
3483 outlayer->end_sector_l0 =
3484 scsi_3btoul(inlayer->end_sector_layer0);
3485 break;
3486 }
3487 case DVD_STRUCT_COPYRIGHT: {
3488 struct scsi_read_dvd_struct_data_copyright *copy_data;
3489
3490 copy_data = (struct scsi_read_dvd_struct_data_copyright *)
3491 databuf;
3492
3493 dvdstruct->cpst = copy_data->cps_type;
3494 dvdstruct->rmi = copy_data->region_info;
3495 dvdstruct->length = 0;
3496
3497 break;
3498 }
3499 default:
3500 /*
3501 * Tell the user what the overall length is, no matter
3502 * what we can actually fit in the data buffer.
3503 */
3504 dvdstruct->length = length - ccb->csio.resid -
3505 sizeof(struct scsi_read_dvd_struct_data_header);
3506
3507 /*
3508 * But only actually copy out the smaller of what we read
3509 * in or what the structure can take.
3510 */
3511 bcopy(databuf + sizeof(struct scsi_read_dvd_struct_data_header),
3512 dvdstruct->data,
3513 min(sizeof(dvdstruct->data), dvdstruct->length));
3514 break;
3515 }
3516bailout:
3517
3518 if (databuf != NULL)
3519 free(databuf, M_DEVBUF);
3520
3521 xpt_release_ccb(ccb);
3522
3523 return(error);
3524}
3525
3526void
3527scsi_report_key(struct ccb_scsiio *csio, u_int32_t retries,
3528 void (*cbfcnp)(struct cam_periph *, union ccb *),
3529 u_int8_t tag_action, u_int32_t lba, u_int8_t agid,
3530 u_int8_t key_format, u_int8_t *data_ptr, u_int32_t dxfer_len,
3531 u_int8_t sense_len, u_int32_t timeout)
3532{
3533 struct scsi_report_key *scsi_cmd;
3534
3535 scsi_cmd = (struct scsi_report_key *)&csio->cdb_io.cdb_bytes;
3536 bzero(scsi_cmd, sizeof(*scsi_cmd));
3537 scsi_cmd->opcode = REPORT_KEY;
3538 scsi_ulto4b(lba, scsi_cmd->lba);
3539 scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len);
3540 scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) |
3541 (key_format & RK_KF_KEYFORMAT_MASK);
3542
3543 cam_fill_csio(csio,
3544 retries,
3545 cbfcnp,
3546 /*flags*/ (dxfer_len == 0) ? CAM_DIR_NONE : CAM_DIR_IN,
3547 tag_action,
3548 /*data_ptr*/ data_ptr,
3549 /*dxfer_len*/ dxfer_len,
3550 sense_len,
3551 sizeof(*scsi_cmd),
3552 timeout);
3553}
3554
3555void
3556scsi_send_key(struct ccb_scsiio *csio, u_int32_t retries,
3557 void (*cbfcnp)(struct cam_periph *, union ccb *),
3558 u_int8_t tag_action, u_int8_t agid, u_int8_t key_format,
3559 u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
3560 u_int32_t timeout)
3561{
3562 struct scsi_send_key *scsi_cmd;
3563
3564 scsi_cmd = (struct scsi_send_key *)&csio->cdb_io.cdb_bytes;
3565 bzero(scsi_cmd, sizeof(*scsi_cmd));
3566 scsi_cmd->opcode = SEND_KEY;
3567
3568 scsi_ulto2b(dxfer_len, scsi_cmd->param_len);
3569 scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) |
3570 (key_format & RK_KF_KEYFORMAT_MASK);
3571
3572 cam_fill_csio(csio,
3573 retries,
3574 cbfcnp,
3575 /*flags*/ CAM_DIR_OUT,
3576 tag_action,
3577 /*data_ptr*/ data_ptr,
3578 /*dxfer_len*/ dxfer_len,
3579 sense_len,
3580 sizeof(*scsi_cmd),
3581 timeout);
3582}
3583
3584
3585void
3586scsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries,
3587 void (*cbfcnp)(struct cam_periph *, union ccb *),
3588 u_int8_t tag_action, u_int32_t address,
3589 u_int8_t layer_number, u_int8_t format, u_int8_t agid,
3590 u_int8_t *data_ptr, u_int32_t dxfer_len,
3591 u_int8_t sense_len, u_int32_t timeout)
3592{
3593 struct scsi_read_dvd_structure *scsi_cmd;
3594
3595 scsi_cmd = (struct scsi_read_dvd_structure *)&csio->cdb_io.cdb_bytes;
3596 bzero(scsi_cmd, sizeof(*scsi_cmd));
3597 scsi_cmd->opcode = READ_DVD_STRUCTURE;
3598
3599 scsi_ulto4b(address, scsi_cmd->address);
3600 scsi_cmd->layer_number = layer_number;
3601 scsi_cmd->format = format;
3602 scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len);
3603 /* The AGID is the top two bits of this byte */
3604 scsi_cmd->agid = agid << 6;
3605
3606 cam_fill_csio(csio,
3607 retries,
3608 cbfcnp,
3609 /*flags*/ CAM_DIR_IN,
3610 tag_action,
3611 /*data_ptr*/ data_ptr,
3612 /*dxfer_len*/ dxfer_len,
3613 sense_len,
3614 sizeof(*scsi_cmd),
3615 timeout);
3616}