]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/cam/scsi/scsi_cd.c
MFV r262639: ncurses 5.9 20140222 snapshot.
[FreeBSD/FreeBSD.git] / sys / cam / scsi / scsi_cd.c
1 /*-
2  * Copyright (c) 1997 Justin T. Gibbs.
3  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003 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
28 /*-
29  * Portions of this driver taken from the original FreeBSD cd driver.
30  * Written by Julian Elischer (julian@tfs.com)
31  * for TRW Financial Systems for use under the MACH(2.5) operating system.
32  *
33  * TRW Financial Systems, in accordance with their agreement with Carnegie
34  * Mellon University, makes this software available to CMU to distribute
35  * or use in any manner that they see fit as long as this message is kept with
36  * the software. For this reason TFS also grants any other persons or
37  * organisations permission to use or modify this software.
38  *
39  * TFS supplies this software to be publicly redistributed
40  * on the understanding that TFS is not responsible for the correct
41  * functioning of this software in any circumstances.
42  *
43  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
44  *
45  *      from: cd.c,v 1.83 1997/05/04 15:24:22 joerg Exp $
46  */
47
48 #include <sys/cdefs.h>
49 __FBSDID("$FreeBSD$");
50
51 #include "opt_cd.h"
52
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/kernel.h>
56 #include <sys/bio.h>
57 #include <sys/conf.h>
58 #include <sys/disk.h>
59 #include <sys/malloc.h>
60 #include <sys/cdio.h>
61 #include <sys/cdrio.h>
62 #include <sys/dvdio.h>
63 #include <sys/devicestat.h>
64 #include <sys/sysctl.h>
65 #include <sys/taskqueue.h>
66 #include <geom/geom_disk.h>
67
68 #include <cam/cam.h>
69 #include <cam/cam_ccb.h>
70 #include <cam/cam_periph.h>
71 #include <cam/cam_xpt_periph.h>
72 #include <cam/cam_queue.h>
73 #include <cam/cam_sim.h>
74
75 #include <cam/scsi/scsi_message.h>
76 #include <cam/scsi/scsi_da.h>
77 #include <cam/scsi/scsi_cd.h>
78
79 #define LEADOUT         0xaa            /* leadout toc entry */
80
81 struct cd_params {
82         u_int32_t blksize;
83         u_long    disksize;
84 };
85
86 typedef enum {
87         CD_Q_NONE               = 0x00,
88         CD_Q_NO_TOUCH           = 0x01,
89         CD_Q_BCD_TRACKS         = 0x02,
90         CD_Q_NO_CHANGER         = 0x04,
91         CD_Q_CHANGER            = 0x08,
92         CD_Q_10_BYTE_ONLY       = 0x10
93 } cd_quirks;
94
95 #define CD_Q_BIT_STRING         \
96         "\020"                  \
97         "\001NO_TOUCH"          \
98         "\002BCD_TRACKS"        \
99         "\003NO_CHANGER"        \
100         "\004CHANGER"           \
101         "\00510_BYTE_ONLY"
102
103 typedef enum {
104         CD_FLAG_INVALID         = 0x0001,
105         CD_FLAG_NEW_DISC        = 0x0002,
106         CD_FLAG_DISC_LOCKED     = 0x0004,
107         CD_FLAG_DISC_REMOVABLE  = 0x0008,
108         CD_FLAG_SAW_MEDIA       = 0x0010,
109         CD_FLAG_CHANGER         = 0x0040,
110         CD_FLAG_ACTIVE          = 0x0080,
111         CD_FLAG_SCHED_ON_COMP   = 0x0100,
112         CD_FLAG_RETRY_UA        = 0x0200,
113         CD_FLAG_VALID_MEDIA     = 0x0400,
114         CD_FLAG_VALID_TOC       = 0x0800,
115         CD_FLAG_SCTX_INIT       = 0x1000
116 } cd_flags;
117
118 typedef enum {
119         CD_CCB_PROBE            = 0x01,
120         CD_CCB_BUFFER_IO        = 0x02,
121         CD_CCB_TUR              = 0x04,
122         CD_CCB_TYPE_MASK        = 0x0F,
123         CD_CCB_RETRY_UA         = 0x10
124 } cd_ccb_state;
125
126 typedef enum {
127         CHANGER_TIMEOUT_SCHED           = 0x01,
128         CHANGER_SHORT_TMOUT_SCHED       = 0x02,
129         CHANGER_MANUAL_CALL             = 0x04,
130         CHANGER_NEED_TIMEOUT            = 0x08
131 } cd_changer_flags;
132
133 #define ccb_state ppriv_field0
134 #define ccb_bp ppriv_ptr1
135
136 struct cd_tocdata {
137         struct ioc_toc_header header;
138         struct cd_toc_entry entries[100];
139 };
140
141 struct cd_toc_single {
142         struct ioc_toc_header header;
143         struct cd_toc_entry entry;
144 };
145
146 typedef enum {
147         CD_STATE_PROBE,
148         CD_STATE_NORMAL
149 } cd_state;
150
151 struct cd_softc {
152         cam_pinfo               pinfo;
153         cd_state                state;
154         volatile cd_flags       flags;
155         struct bio_queue_head   bio_queue;
156         LIST_HEAD(, ccb_hdr)    pending_ccbs;
157         struct cd_params        params;
158         union ccb               saved_ccb;
159         cd_quirks               quirks;
160         STAILQ_ENTRY(cd_softc)  changer_links;
161         struct cdchanger        *changer;
162         int                     bufs_left;
163         struct cam_periph       *periph;
164         int                     minimum_command_size;
165         int                     outstanding_cmds;
166         int                     tur;
167         struct task             sysctl_task;
168         struct sysctl_ctx_list  sysctl_ctx;
169         struct sysctl_oid       *sysctl_tree;
170         STAILQ_HEAD(, cd_mode_params)   mode_queue;
171         struct cd_tocdata       toc;
172         struct disk             *disk;
173         struct callout          mediapoll_c;
174 };
175
176 struct cd_page_sizes {
177         int page;
178         int page_size;
179 };
180
181 static struct cd_page_sizes cd_page_size_table[] =
182 {
183         { AUDIO_PAGE, sizeof(struct cd_audio_page)}
184 };
185
186 struct cd_quirk_entry {
187         struct scsi_inquiry_pattern inq_pat;
188         cd_quirks quirks;
189 };
190
191 /*
192  * The changer quirk entries aren't strictly necessary.  Basically, what
193  * they do is tell cdregister() up front that a device is a changer.
194  * Otherwise, it will figure that fact out once it sees a LUN on the device
195  * that is greater than 0.  If it is known up front that a device is a changer,
196  * all I/O to the device will go through the changer scheduling routines, as
197  * opposed to the "normal" CD code.
198  *
199  * NOTE ON 10_BYTE_ONLY quirks:  Any 10_BYTE_ONLY quirks MUST be because
200  * your device hangs when it gets a 10 byte command.  Adding a quirk just
201  * to get rid of the informative diagnostic message is not acceptable.  All
202  * 10_BYTE_ONLY quirks must be documented in full in a PR (which should be
203  * referenced in a comment along with the quirk) , and must be approved by
204  * ken@FreeBSD.org.  Any quirks added that don't adhere to this policy may
205  * be removed until the submitter can explain why they are needed.
206  * 10_BYTE_ONLY quirks will be removed (as they will no longer be necessary)
207  * when the CAM_NEW_TRAN_CODE work is done.
208  */
209 static struct cd_quirk_entry cd_quirk_table[] =
210 {
211         {
212                 { T_CDROM, SIP_MEDIA_REMOVABLE, "NRC", "MBR-7", "*"},
213                  /*quirks*/ CD_Q_CHANGER
214         },
215         {
216                 { T_CDROM, SIP_MEDIA_REMOVABLE, "PIONEER", "CD-ROM DRM*",
217                   "*"}, /* quirks */ CD_Q_CHANGER
218         },
219         {
220                 { T_CDROM, SIP_MEDIA_REMOVABLE, "NAKAMICH", "MJ-*", "*"},
221                  /* quirks */ CD_Q_CHANGER
222         },
223         {
224                 { T_CDROM, SIP_MEDIA_REMOVABLE, "CHINON", "CD-ROM CDS-535","*"},
225                 /* quirks */ CD_Q_BCD_TRACKS
226         }
227 };
228
229 static  disk_open_t     cdopen;
230 static  disk_close_t    cdclose;
231 static  disk_ioctl_t    cdioctl;
232 static  disk_strategy_t cdstrategy;
233
234 static  periph_init_t   cdinit;
235 static  periph_ctor_t   cdregister;
236 static  periph_dtor_t   cdcleanup;
237 static  periph_start_t  cdstart;
238 static  periph_oninv_t  cdoninvalidate;
239 static  void            cdasync(void *callback_arg, u_int32_t code,
240                                 struct cam_path *path, void *arg);
241 static  int             cdcmdsizesysctl(SYSCTL_HANDLER_ARGS);
242 static  void            cdshorttimeout(void *arg);
243 static  void            cdschedule(struct cam_periph *periph, int priority);
244 static  void            cdrunchangerqueue(void *arg);
245 static  void            cdchangerschedule(struct cd_softc *softc);
246 static  int             cdrunccb(union ccb *ccb,
247                                  int (*error_routine)(union ccb *ccb,
248                                                       u_int32_t cam_flags,
249                                                       u_int32_t sense_flags),
250                                  u_int32_t cam_flags, u_int32_t sense_flags);
251 static  union ccb       *cdgetccb(struct cam_periph *periph,
252                                   u_int32_t priority);
253 static  void            cddone(struct cam_periph *periph,
254                                union ccb *start_ccb);
255 static  union cd_pages  *cdgetpage(struct cd_mode_params *mode_params);
256 static  int             cdgetpagesize(int page_num);
257 static  void            cdprevent(struct cam_periph *periph, int action);
258 static  int             cdcheckmedia(struct cam_periph *periph);
259 static  int             cdsize(struct cam_periph *periph, u_int32_t *size);
260 static  int             cd6byteworkaround(union ccb *ccb);
261 static  int             cderror(union ccb *ccb, u_int32_t cam_flags,
262                                 u_int32_t sense_flags);
263 static  int             cdreadtoc(struct cam_periph *periph, u_int32_t mode, 
264                                   u_int32_t start, u_int8_t *data, 
265                                   u_int32_t len, u_int32_t sense_flags);
266 static  int             cdgetmode(struct cam_periph *periph, 
267                                   struct cd_mode_params *data, u_int32_t page);
268 static  int             cdsetmode(struct cam_periph *periph,
269                                   struct cd_mode_params *data);
270 static  int             cdplay(struct cam_periph *periph, u_int32_t blk, 
271                                u_int32_t len);
272 static  int             cdreadsubchannel(struct cam_periph *periph, 
273                                          u_int32_t mode, u_int32_t format, 
274                                          int track, 
275                                          struct cd_sub_channel_info *data, 
276                                          u_int32_t len);
277 static  int             cdplaymsf(struct cam_periph *periph, u_int32_t startm, 
278                                   u_int32_t starts, u_int32_t startf, 
279                                   u_int32_t endm, u_int32_t ends, 
280                                   u_int32_t endf);
281 static  int             cdplaytracks(struct cam_periph *periph, 
282                                      u_int32_t strack, u_int32_t sindex,
283                                      u_int32_t etrack, u_int32_t eindex);
284 static  int             cdpause(struct cam_periph *periph, u_int32_t go);
285 static  int             cdstopunit(struct cam_periph *periph, u_int32_t eject);
286 static  int             cdstartunit(struct cam_periph *periph, int load);
287 static  int             cdsetspeed(struct cam_periph *periph,
288                                    u_int32_t rdspeed, u_int32_t wrspeed);
289 static  int             cdreportkey(struct cam_periph *periph,
290                                     struct dvd_authinfo *authinfo);
291 static  int             cdsendkey(struct cam_periph *periph,
292                                   struct dvd_authinfo *authinfo);
293 static  int             cdreaddvdstructure(struct cam_periph *periph,
294                                            struct dvd_struct *dvdstruct);
295 static timeout_t        cdmediapoll;
296
297 static struct periph_driver cddriver =
298 {
299         cdinit, "cd",
300         TAILQ_HEAD_INITIALIZER(cddriver.units), /* generation */ 0
301 };
302
303 PERIPHDRIVER_DECLARE(cd, cddriver);
304
305 #ifndef CD_DEFAULT_POLL_PERIOD
306 #define CD_DEFAULT_POLL_PERIOD  3
307 #endif
308 #ifndef CD_DEFAULT_RETRY
309 #define CD_DEFAULT_RETRY        4
310 #endif
311 #ifndef CD_DEFAULT_TIMEOUT
312 #define CD_DEFAULT_TIMEOUT      30000
313 #endif
314 #ifndef CHANGER_MIN_BUSY_SECONDS
315 #define CHANGER_MIN_BUSY_SECONDS        5
316 #endif
317 #ifndef CHANGER_MAX_BUSY_SECONDS
318 #define CHANGER_MAX_BUSY_SECONDS        15
319 #endif
320
321 static int cd_poll_period = CD_DEFAULT_POLL_PERIOD;
322 static int cd_retry_count = CD_DEFAULT_RETRY;
323 static int cd_timeout = CD_DEFAULT_TIMEOUT;
324 static int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS;
325 static int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS;
326
327 static SYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver");
328 static SYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0,
329     "CD Changer");
330 SYSCTL_INT(_kern_cam_cd, OID_AUTO, poll_period, CTLFLAG_RW,
331            &cd_poll_period, 0, "Media polling period in seconds");
332 TUNABLE_INT("kern.cam.cd.poll_period", &cd_poll_period);
333 SYSCTL_INT(_kern_cam_cd, OID_AUTO, retry_count, CTLFLAG_RW,
334            &cd_retry_count, 0, "Normal I/O retry count");
335 TUNABLE_INT("kern.cam.cd.retry_count", &cd_retry_count);
336 SYSCTL_INT(_kern_cam_cd, OID_AUTO, timeout, CTLFLAG_RW,
337            &cd_timeout, 0, "Timeout, in us, for read operations");
338 TUNABLE_INT("kern.cam.cd.timeout", &cd_timeout);
339 SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW,
340            &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum");
341 TUNABLE_INT("kern.cam.cd.changer.min_busy_seconds", &changer_min_busy_seconds);
342 SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, max_busy_seconds, CTLFLAG_RW,
343            &changer_max_busy_seconds, 0, "Maximum changer scheduling quantum");
344 TUNABLE_INT("kern.cam.cd.changer.max_busy_seconds", &changer_max_busy_seconds);
345
346 struct cdchanger {
347         path_id_t                        path_id;
348         target_id_t                      target_id;
349         int                              num_devices;
350         struct camq                      devq;
351         struct timeval                   start_time;
352         struct cd_softc                  *cur_device;
353         struct callout                   short_handle;
354         struct callout                   long_handle;
355         volatile cd_changer_flags        flags;
356         STAILQ_ENTRY(cdchanger)          changer_links;
357         STAILQ_HEAD(chdevlist, cd_softc) chluns;
358 };
359
360 static struct mtx changerq_mtx;
361 static STAILQ_HEAD(changerlist, cdchanger) changerq;
362 static int num_changers;
363
364 static MALLOC_DEFINE(M_SCSICD, "scsi_cd", "scsi_cd buffers");
365
366 static void
367 cdinit(void)
368 {
369         cam_status status;
370
371         mtx_init(&changerq_mtx, "cdchangerq", "SCSI CD Changer List", MTX_DEF);
372         STAILQ_INIT(&changerq);
373
374         /*
375          * Install a global async callback.  This callback will
376          * receive async callbacks like "new device found".
377          */
378         status = xpt_register_async(AC_FOUND_DEVICE, cdasync, NULL, NULL);
379
380         if (status != CAM_REQ_CMP) {
381                 printf("cd: Failed to attach master async callback "
382                        "due to status 0x%x!\n", status);
383         }
384 }
385
386 /*
387  * Callback from GEOM, called when it has finished cleaning up its
388  * resources.
389  */
390 static void
391 cddiskgonecb(struct disk *dp)
392 {
393         struct cam_periph *periph;
394
395         periph = (struct cam_periph *)dp->d_drv1;
396         cam_periph_release(periph);
397 }
398
399 static void
400 cdoninvalidate(struct cam_periph *periph)
401 {
402         struct cd_softc *softc;
403
404         softc = (struct cd_softc *)periph->softc;
405
406         /*
407          * De-register any async callbacks.
408          */
409         xpt_register_async(0, cdasync, periph, periph->path);
410
411         softc->flags |= CD_FLAG_INVALID;
412
413         /*
414          * Return all queued I/O with ENXIO.
415          * XXX Handle any transactions queued to the card
416          *     with XPT_ABORT_CCB.
417          */
418         bioq_flush(&softc->bio_queue, NULL, ENXIO);
419
420         /*
421          * If this device is part of a changer, and it was scheduled
422          * to run, remove it from the run queue since we just nuked
423          * all of its scheduled I/O.
424          */
425         if ((softc->flags & CD_FLAG_CHANGER)
426          && (softc->pinfo.index != CAM_UNQUEUED_INDEX))
427                 camq_remove(&softc->changer->devq, softc->pinfo.index);
428
429         disk_gone(softc->disk);
430 }
431
432 static void
433 cdcleanup(struct cam_periph *periph)
434 {
435         struct cd_softc *softc;
436
437         softc = (struct cd_softc *)periph->softc;
438
439         /*
440          * In the queued, non-active case, the device in question
441          * has already been removed from the changer run queue.  Since this
442          * device is active, we need to de-activate it, and schedule
443          * another device to run.  (if there is another one to run)
444          */
445         if ((softc->flags & CD_FLAG_CHANGER)
446          && (softc->flags & CD_FLAG_ACTIVE)) {
447
448                 /*
449                  * The purpose of the short timeout is soley to determine
450                  * whether the current device has finished or not.  Well,
451                  * since we're removing the active device, we know that it
452                  * is finished.  So, get rid of the short timeout.
453                  * Otherwise, if we're in the time period before the short
454                  * timeout fires, and there are no other devices in the
455                  * queue to run, there won't be any other device put in the
456                  * active slot.  i.e., when we call cdrunchangerqueue()
457                  * below, it won't do anything.  Then, when the short
458                  * timeout fires, it'll look at the "current device", which
459                  * we are free below, and possibly panic the kernel on a
460                  * bogus pointer reference.
461                  *
462                  * The long timeout doesn't really matter, since we
463                  * decrement the qfrozen_cnt to indicate that there is
464                  * nothing in the active slot now.  Therefore, there won't
465                  * be any bogus pointer references there.
466                  */
467                 if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
468                         callout_stop(&softc->changer->short_handle);
469                         softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
470                 }
471                 softc->changer->devq.qfrozen_cnt--;
472                 softc->changer->flags |= CHANGER_MANUAL_CALL;
473                 cdrunchangerqueue(softc->changer);
474         }
475
476         /*
477          * If we're removing the last device on the changer, go ahead and
478          * remove the changer device structure.
479          */
480         if ((softc->flags & CD_FLAG_CHANGER)
481          && (--softc->changer->num_devices == 0)) {
482
483                 /*
484                  * Theoretically, there shouldn't be any timeouts left, but
485                  * I'm not completely sure that that will be the case.  So,
486                  * it won't hurt to check and see if there are any left.
487                  */
488                 if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) {
489                         callout_stop(&softc->changer->long_handle);
490                         softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED;
491                 }
492
493                 if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
494                         callout_stop(&softc->changer->short_handle);
495                         softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
496                 }
497
498                 mtx_lock(&changerq_mtx);
499                 STAILQ_REMOVE(&changerq, softc->changer, cdchanger,
500                               changer_links);
501                 num_changers--;
502                 mtx_unlock(&changerq_mtx);
503                 xpt_print(periph->path, "removing changer entry\n");
504                 free(softc->changer, M_DEVBUF);
505         }
506         cam_periph_unlock(periph);
507         if ((softc->flags & CD_FLAG_SCTX_INIT) != 0
508             && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
509                 xpt_print(periph->path, "can't remove sysctl context\n");
510         }
511
512         callout_drain(&softc->mediapoll_c);
513         disk_destroy(softc->disk);
514         free(softc, M_DEVBUF);
515         cam_periph_lock(periph);
516 }
517
518 static void
519 cdasync(void *callback_arg, u_int32_t code,
520         struct cam_path *path, void *arg)
521 {
522         struct cam_periph *periph;
523         struct cd_softc *softc;
524
525         periph = (struct cam_periph *)callback_arg;
526         switch (code) {
527         case AC_FOUND_DEVICE:
528         {
529                 struct ccb_getdev *cgd;
530                 cam_status status;
531
532                 cgd = (struct ccb_getdev *)arg;
533                 if (cgd == NULL)
534                         break;
535
536                 if (cgd->protocol != PROTO_SCSI)
537                         break;
538
539                 if (SID_TYPE(&cgd->inq_data) != T_CDROM
540                     && SID_TYPE(&cgd->inq_data) != T_WORM)
541                         break;
542
543                 /*
544                  * Allocate a peripheral instance for
545                  * this device and start the probe
546                  * process.
547                  */
548                 status = cam_periph_alloc(cdregister, cdoninvalidate,
549                                           cdcleanup, cdstart,
550                                           "cd", CAM_PERIPH_BIO,
551                                           path, cdasync,
552                                           AC_FOUND_DEVICE, cgd);
553
554                 if (status != CAM_REQ_CMP
555                  && status != CAM_REQ_INPROG)
556                         printf("cdasync: Unable to attach new device "
557                                "due to status 0x%x\n", status);
558
559                 break;
560         }
561         case AC_UNIT_ATTENTION:
562         {
563                 union ccb *ccb;
564                 int error_code, sense_key, asc, ascq;
565
566                 softc = (struct cd_softc *)periph->softc;
567                 ccb = (union ccb *)arg;
568
569                 /*
570                  * Handle all media change UNIT ATTENTIONs except
571                  * our own, as they will be handled by cderror().
572                  */
573                 if (xpt_path_periph(ccb->ccb_h.path) != periph &&
574                     scsi_extract_sense_ccb(ccb,
575                      &error_code, &sense_key, &asc, &ascq)) {
576                         if (asc == 0x28 && ascq == 0x00)
577                                 disk_media_changed(softc->disk, M_NOWAIT);
578                 }
579                 cam_periph_async(periph, code, path, arg);
580                 break;
581         }
582         case AC_SCSI_AEN:
583                 softc = (struct cd_softc *)periph->softc;
584                 if (softc->state == CD_STATE_NORMAL && !softc->tur) {
585                         if (cam_periph_acquire(periph) == CAM_REQ_CMP) {
586                                 softc->tur = 1;
587                                 xpt_schedule(periph, CAM_PRIORITY_NORMAL);
588                         }
589                 }
590                 /* FALLTHROUGH */
591         case AC_SENT_BDR:
592         case AC_BUS_RESET:
593         {
594                 struct ccb_hdr *ccbh;
595
596                 softc = (struct cd_softc *)periph->softc;
597                 /*
598                  * Don't fail on the expected unit attention
599                  * that will occur.
600                  */
601                 softc->flags |= CD_FLAG_RETRY_UA;
602                 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
603                         ccbh->ccb_state |= CD_CCB_RETRY_UA;
604                 /* FALLTHROUGH */
605         }
606         default:
607                 cam_periph_async(periph, code, path, arg);
608                 break;
609         }
610 }
611
612 static void
613 cdsysctlinit(void *context, int pending)
614 {
615         struct cam_periph *periph;
616         struct cd_softc *softc;
617         char tmpstr[80], tmpstr2[80];
618
619         periph = (struct cam_periph *)context;
620         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
621                 return;
622
623         softc = (struct cd_softc *)periph->softc;
624         snprintf(tmpstr, sizeof(tmpstr), "CAM CD unit %d", periph->unit_number);
625         snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
626
627         sysctl_ctx_init(&softc->sysctl_ctx);
628         softc->flags |= CD_FLAG_SCTX_INIT;
629         softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx,
630                 SYSCTL_STATIC_CHILDREN(_kern_cam_cd), OID_AUTO,
631                 tmpstr2, CTLFLAG_RD, 0, tmpstr);
632
633         if (softc->sysctl_tree == NULL) {
634                 printf("cdsysctlinit: unable to allocate sysctl tree\n");
635                 cam_periph_release(periph);
636                 return;
637         }
638
639         /*
640          * Now register the sysctl handler, so the user can the value on
641          * the fly.
642          */
643         SYSCTL_ADD_PROC(&softc->sysctl_ctx,SYSCTL_CHILDREN(softc->sysctl_tree),
644                 OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW,
645                 &softc->minimum_command_size, 0, cdcmdsizesysctl, "I",
646                 "Minimum CDB size");
647
648         cam_periph_release(periph);
649 }
650
651 /*
652  * We have a handler function for this so we can check the values when the
653  * user sets them, instead of every time we look at them.
654  */
655 static int
656 cdcmdsizesysctl(SYSCTL_HANDLER_ARGS)
657 {
658         int error, value;
659
660         value = *(int *)arg1;
661
662         error = sysctl_handle_int(oidp, &value, 0, req);
663
664         if ((error != 0)
665          || (req->newptr == NULL))
666                 return (error);
667
668         /*
669          * The only real values we can have here are 6 or 10.  I don't
670          * really forsee having 12 be an option at any time in the future.
671          * So if the user sets something less than or equal to 6, we'll set
672          * it to 6.  If he sets something greater than 6, we'll set it to 10.
673          *
674          * I suppose we could just return an error here for the wrong values,
675          * but I don't think it's necessary to do so, as long as we can
676          * determine the user's intent without too much trouble.
677          */
678         if (value < 6)
679                 value = 6;
680         else if (value > 6)
681                 value = 10;
682
683         *(int *)arg1 = value;
684
685         return (0);
686 }
687
688 static cam_status
689 cdregister(struct cam_periph *periph, void *arg)
690 {
691         struct cd_softc *softc;
692         struct ccb_pathinq cpi;
693         struct ccb_getdev *cgd;
694         char tmpstr[80];
695         caddr_t match;
696
697         cgd = (struct ccb_getdev *)arg;
698         if (cgd == NULL) {
699                 printf("cdregister: no getdev CCB, can't register device\n");
700                 return(CAM_REQ_CMP_ERR);
701         }
702
703         softc = (struct cd_softc *)malloc(sizeof(*softc),M_DEVBUF,
704             M_NOWAIT | M_ZERO);
705         if (softc == NULL) {
706                 printf("cdregister: Unable to probe new device. "
707                        "Unable to allocate softc\n");                           
708                 return(CAM_REQ_CMP_ERR);
709         }
710
711         LIST_INIT(&softc->pending_ccbs);
712         STAILQ_INIT(&softc->mode_queue);
713         softc->state = CD_STATE_PROBE;
714         bioq_init(&softc->bio_queue);
715         if (SID_IS_REMOVABLE(&cgd->inq_data))
716                 softc->flags |= CD_FLAG_DISC_REMOVABLE;
717
718         periph->softc = softc;
719         softc->periph = periph;
720
721         /*
722          * See if this device has any quirks.
723          */
724         match = cam_quirkmatch((caddr_t)&cgd->inq_data,
725                                (caddr_t)cd_quirk_table,
726                                sizeof(cd_quirk_table)/sizeof(*cd_quirk_table),
727                                sizeof(*cd_quirk_table), scsi_inquiry_match);
728
729         if (match != NULL)
730                 softc->quirks = ((struct cd_quirk_entry *)match)->quirks;
731         else
732                 softc->quirks = CD_Q_NONE;
733
734         /* Check if the SIM does not want 6 byte commands */
735         bzero(&cpi, sizeof(cpi));
736         xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
737         cpi.ccb_h.func_code = XPT_PATH_INQ;
738         xpt_action((union ccb *)&cpi);
739         if (cpi.ccb_h.status == CAM_REQ_CMP && (cpi.hba_misc & PIM_NO_6_BYTE))
740                 softc->quirks |= CD_Q_10_BYTE_ONLY;
741
742         TASK_INIT(&softc->sysctl_task, 0, cdsysctlinit, periph);
743
744         /* The default is 6 byte commands, unless quirked otherwise */
745         if (softc->quirks & CD_Q_10_BYTE_ONLY)
746                 softc->minimum_command_size = 10;
747         else
748                 softc->minimum_command_size = 6;
749
750         /*
751          * Refcount and block open attempts until we are setup
752          * Can't block
753          */
754         (void)cam_periph_hold(periph, PRIBIO);
755         cam_periph_unlock(periph);
756         /*
757          * Load the user's default, if any.
758          */
759         snprintf(tmpstr, sizeof(tmpstr), "kern.cam.cd.%d.minimum_cmd_size",
760                  periph->unit_number);
761         TUNABLE_INT_FETCH(tmpstr, &softc->minimum_command_size);
762
763         /* 6 and 10 are the only permissible values here. */
764         if (softc->minimum_command_size < 6)
765                 softc->minimum_command_size = 6;
766         else if (softc->minimum_command_size > 6)
767                 softc->minimum_command_size = 10;
768
769         /*
770          * We need to register the statistics structure for this device,
771          * but we don't have the blocksize yet for it.  So, we register
772          * the structure and indicate that we don't have the blocksize
773          * yet.  Unlike other SCSI peripheral drivers, we explicitly set
774          * the device type here to be CDROM, rather than just ORing in
775          * the device type.  This is because this driver can attach to either
776          * CDROM or WORM devices, and we want this peripheral driver to
777          * show up in the devstat list as a CD peripheral driver, not a
778          * WORM peripheral driver.  WORM drives will also have the WORM
779          * driver attached to them.
780          */
781         softc->disk = disk_alloc();
782         softc->disk->d_devstat = devstat_new_entry("cd",
783                           periph->unit_number, 0,
784                           DEVSTAT_BS_UNAVAILABLE,
785                           DEVSTAT_TYPE_CDROM |
786                           XPORT_DEVSTAT_TYPE(cpi.transport),
787                           DEVSTAT_PRIORITY_CD);
788         softc->disk->d_open = cdopen;
789         softc->disk->d_close = cdclose;
790         softc->disk->d_strategy = cdstrategy;
791         softc->disk->d_gone = cddiskgonecb;
792         softc->disk->d_ioctl = cdioctl;
793         softc->disk->d_name = "cd";
794         cam_strvis(softc->disk->d_descr, cgd->inq_data.vendor,
795             sizeof(cgd->inq_data.vendor), sizeof(softc->disk->d_descr));
796         strlcat(softc->disk->d_descr, " ", sizeof(softc->disk->d_descr));
797         cam_strvis(&softc->disk->d_descr[strlen(softc->disk->d_descr)],
798             cgd->inq_data.product, sizeof(cgd->inq_data.product),
799             sizeof(softc->disk->d_descr) - strlen(softc->disk->d_descr));
800         softc->disk->d_unit = periph->unit_number;
801         softc->disk->d_drv1 = periph;
802         if (cpi.maxio == 0)
803                 softc->disk->d_maxsize = DFLTPHYS;      /* traditional default */
804         else if (cpi.maxio > MAXPHYS)
805                 softc->disk->d_maxsize = MAXPHYS;       /* for safety */
806         else
807                 softc->disk->d_maxsize = cpi.maxio;
808         softc->disk->d_flags = 0;
809         softc->disk->d_hba_vendor = cpi.hba_vendor;
810         softc->disk->d_hba_device = cpi.hba_device;
811         softc->disk->d_hba_subvendor = cpi.hba_subvendor;
812         softc->disk->d_hba_subdevice = cpi.hba_subdevice;
813
814         /*
815          * Acquire a reference to the periph before we register with GEOM.
816          * We'll release this reference once GEOM calls us back (via
817          * dadiskgonecb()) telling us that our provider has been freed.
818          */
819         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
820                 xpt_print(periph->path, "%s: lost periph during "
821                           "registration!\n", __func__);
822                 cam_periph_lock(periph);
823                 return (CAM_REQ_CMP_ERR);
824         }
825
826         disk_create(softc->disk, DISK_VERSION);
827         cam_periph_lock(periph);
828
829         /*
830          * Add an async callback so that we get
831          * notified if this device goes away.
832          */
833         xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE |
834             AC_SCSI_AEN | AC_UNIT_ATTENTION, cdasync, periph, periph->path);
835
836         /*
837          * If the target lun is greater than 0, we most likely have a CD
838          * changer device.  Check the quirk entries as well, though, just
839          * in case someone has a CD tower with one lun per drive or
840          * something like that.  Also, if we know up front that a
841          * particular device is a changer, we can mark it as such starting
842          * with lun 0, instead of lun 1.  It shouldn't be necessary to have
843          * a quirk entry to define something as a changer, however.
844          */
845         if (((cgd->ccb_h.target_lun > 0)
846           && ((softc->quirks & CD_Q_NO_CHANGER) == 0))
847          || ((softc->quirks & CD_Q_CHANGER) != 0)) {
848                 struct cdchanger *nchanger;
849                 struct cam_periph *nperiph;
850                 struct cam_path *path;
851                 cam_status status;
852                 int found;
853
854                 /* Set the changer flag in the current device's softc */
855                 softc->flags |= CD_FLAG_CHANGER;
856
857                 /*
858                  * Now, look around for an existing changer device with the
859                  * same path and target ID as the current device.
860                  */
861                 mtx_lock(&changerq_mtx);
862                 for (found = 0,
863                      nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq);
864                      nchanger != NULL;
865                      nchanger = STAILQ_NEXT(nchanger, changer_links)){
866                         if ((nchanger->path_id == cgd->ccb_h.path_id) 
867                          && (nchanger->target_id == cgd->ccb_h.target_id)) {
868                                 found = 1;
869                                 break;
870                         }
871                 }
872                 mtx_unlock(&changerq_mtx);
873
874                 /*
875                  * If we found a matching entry, just add this device to
876                  * the list of devices on this changer.
877                  */
878                 if (found == 1) {
879                         struct chdevlist *chlunhead;
880
881                         chlunhead = &nchanger->chluns;
882
883                         /*
884                          * XXX KDM look at consolidating this code with the
885                          * code below in a separate function.
886                          */
887
888                         /*
889                          * Create a path with lun id 0, and see if we can
890                          * find a matching device
891                          */
892                         status = xpt_create_path(&path, /*periph*/ periph,
893                                                  cgd->ccb_h.path_id,
894                                                  cgd->ccb_h.target_id, 0);
895
896                         if ((status == CAM_REQ_CMP)
897                          && ((nperiph = cam_periph_find(path, "cd")) != NULL)){
898                                 struct cd_softc *nsoftc;
899
900                                 nsoftc = (struct cd_softc *)nperiph->softc;
901
902                                 if ((nsoftc->flags & CD_FLAG_CHANGER) == 0){
903                                         nsoftc->flags |= CD_FLAG_CHANGER;
904                                         nchanger->num_devices++;
905                                         if (camq_resize(&nchanger->devq,
906                                            nchanger->num_devices)!=CAM_REQ_CMP){
907                                                 printf("cdregister: "
908                                                        "camq_resize "
909                                                        "failed, changer "
910                                                        "support may "
911                                                        "be messed up\n");
912                                         }
913                                         nsoftc->changer = nchanger;
914                                         nsoftc->pinfo.index =CAM_UNQUEUED_INDEX;
915
916                                         STAILQ_INSERT_TAIL(&nchanger->chluns,
917                                                           nsoftc,changer_links);
918                                 }
919                                 xpt_free_path(path);
920                         } else if (status == CAM_REQ_CMP)
921                                 xpt_free_path(path);
922                         else {
923                                 printf("cdregister: unable to allocate path\n"
924                                        "cdregister: changer support may be "
925                                        "broken\n");
926                         }
927
928                         nchanger->num_devices++;
929
930                         softc->changer = nchanger;
931                         softc->pinfo.index = CAM_UNQUEUED_INDEX;
932
933                         if (camq_resize(&nchanger->devq,
934                             nchanger->num_devices) != CAM_REQ_CMP) {
935                                 printf("cdregister: camq_resize "
936                                        "failed, changer support may "
937                                        "be messed up\n");
938                         }
939
940                         STAILQ_INSERT_TAIL(chlunhead, softc, changer_links);
941                 }
942                 /*
943                  * In this case, we don't already have an entry for this
944                  * particular changer, so we need to create one, add it to
945                  * the queue, and queue this device on the list for this
946                  * changer.  Before we queue this device, however, we need
947                  * to search for lun id 0 on this target, and add it to the
948                  * queue first, if it exists.  (and if it hasn't already
949                  * been marked as part of the changer.)
950                  */
951                 else {
952                         nchanger = malloc(sizeof(struct cdchanger),
953                                 M_DEVBUF, M_NOWAIT | M_ZERO);
954                         if (nchanger == NULL) {
955                                 softc->flags &= ~CD_FLAG_CHANGER;
956                                 printf("cdregister: unable to malloc "
957                                        "changer structure\ncdregister: "
958                                        "changer support disabled\n");
959
960                                 /*
961                                  * Yes, gotos can be gross but in this case
962                                  * I think it's justified..
963                                  */
964                                 goto cdregisterexit;
965                         }
966                         if (camq_init(&nchanger->devq, 1) != 0) {
967                                 softc->flags &= ~CD_FLAG_CHANGER;
968                                 printf("cdregister: changer support "
969                                        "disabled\n");
970                                 goto cdregisterexit;
971                         }
972
973                         nchanger->path_id = cgd->ccb_h.path_id;
974                         nchanger->target_id = cgd->ccb_h.target_id;
975
976                         /* this is superfluous, but it makes things clearer */
977                         nchanger->num_devices = 0;
978
979                         STAILQ_INIT(&nchanger->chluns);
980
981                         callout_init_mtx(&nchanger->long_handle,
982                             cam_periph_mtx(periph), 0);
983                         callout_init_mtx(&nchanger->short_handle,
984                             cam_periph_mtx(periph), 0);
985
986                         mtx_lock(&changerq_mtx);
987                         num_changers++;
988                         STAILQ_INSERT_TAIL(&changerq, nchanger,
989                                            changer_links);
990                         mtx_unlock(&changerq_mtx);
991                         
992                         /*
993                          * Create a path with lun id 0, and see if we can
994                          * find a matching device
995                          */
996                         status = xpt_create_path(&path, /*periph*/ periph,
997                                                  cgd->ccb_h.path_id,
998                                                  cgd->ccb_h.target_id, 0);
999
1000                         /*
1001                          * If we were able to allocate the path, and if we
1002                          * find a matching device and it isn't already
1003                          * marked as part of a changer, then we add it to
1004                          * the current changer.
1005                          */
1006                         if ((status == CAM_REQ_CMP)
1007                          && ((nperiph = cam_periph_find(path, "cd")) != NULL)
1008                          && ((((struct cd_softc *)periph->softc)->flags &
1009                                CD_FLAG_CHANGER) == 0)) {
1010                                 struct cd_softc *nsoftc;
1011
1012                                 nsoftc = (struct cd_softc *)nperiph->softc;
1013
1014                                 nsoftc->flags |= CD_FLAG_CHANGER;
1015                                 nchanger->num_devices++;
1016                                 if (camq_resize(&nchanger->devq,
1017                                     nchanger->num_devices) != CAM_REQ_CMP) {
1018                                         printf("cdregister: camq_resize "
1019                                                "failed, changer support may "
1020                                                "be messed up\n");
1021                                 }
1022                                 nsoftc->changer = nchanger;
1023                                 nsoftc->pinfo.index = CAM_UNQUEUED_INDEX;
1024
1025                                 STAILQ_INSERT_TAIL(&nchanger->chluns,
1026                                                    nsoftc, changer_links);
1027                                 xpt_free_path(path);
1028                         } else if (status == CAM_REQ_CMP)
1029                                 xpt_free_path(path);
1030                         else {
1031                                 printf("cdregister: unable to allocate path\n"
1032                                        "cdregister: changer support may be "
1033                                        "broken\n");
1034                         }
1035
1036                         softc->changer = nchanger;
1037                         softc->pinfo.index = CAM_UNQUEUED_INDEX;
1038                         nchanger->num_devices++;
1039                         if (camq_resize(&nchanger->devq,
1040                             nchanger->num_devices) != CAM_REQ_CMP) {
1041                                 printf("cdregister: camq_resize "
1042                                        "failed, changer support may "
1043                                        "be messed up\n");
1044                         }
1045                         STAILQ_INSERT_TAIL(&nchanger->chluns, softc,
1046                                            changer_links);
1047                 }
1048         }
1049
1050         /*
1051          * Schedule a periodic media polling events.
1052          */
1053         callout_init_mtx(&softc->mediapoll_c, cam_periph_mtx(periph), 0);
1054         if ((softc->flags & CD_FLAG_DISC_REMOVABLE) &&
1055             (softc->flags & CD_FLAG_CHANGER) == 0 &&
1056             (cgd->inq_flags & SID_AEN) == 0 &&
1057             cd_poll_period != 0)
1058                 callout_reset(&softc->mediapoll_c, cd_poll_period * hz,
1059                     cdmediapoll, periph);
1060
1061 cdregisterexit:
1062
1063         if ((softc->flags & CD_FLAG_CHANGER) == 0)
1064                 xpt_schedule(periph, CAM_PRIORITY_DEV);
1065         else
1066                 cdschedule(periph, CAM_PRIORITY_DEV);
1067
1068         return(CAM_REQ_CMP);
1069 }
1070
1071 static int
1072 cdopen(struct disk *dp)
1073 {
1074         struct cam_periph *periph;
1075         struct cd_softc *softc;
1076         int error;
1077
1078         periph = (struct cam_periph *)dp->d_drv1;
1079         softc = (struct cd_softc *)periph->softc;
1080
1081         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
1082                 return(ENXIO);
1083
1084         cam_periph_lock(periph);
1085
1086         if (softc->flags & CD_FLAG_INVALID) {
1087                 cam_periph_release_locked(periph);
1088                 cam_periph_unlock(periph);
1089                 return(ENXIO);
1090         }
1091
1092         if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
1093                 cam_periph_release_locked(periph);
1094                 cam_periph_unlock(periph);
1095                 return (error);
1096         }
1097
1098         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
1099             ("cdopen\n"));
1100
1101         /*
1102          * Check for media, and set the appropriate flags.  We don't bail
1103          * if we don't have media, but then we don't allow anything but the
1104          * CDIOCEJECT/CDIOCCLOSE ioctls if there is no media.
1105          */
1106         cdcheckmedia(periph);
1107
1108         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n"));
1109         cam_periph_unhold(periph);
1110
1111         cam_periph_unlock(periph);
1112
1113         return (0);
1114 }
1115
1116 static int
1117 cdclose(struct disk *dp)
1118 {
1119         struct  cam_periph *periph;
1120         struct  cd_softc *softc;
1121
1122         periph = (struct cam_periph *)dp->d_drv1;
1123         softc = (struct cd_softc *)periph->softc;
1124
1125         cam_periph_lock(periph);
1126         if (cam_periph_hold(periph, PRIBIO) != 0) {
1127                 cam_periph_unlock(periph);
1128                 cam_periph_release(periph);
1129                 return (0);
1130         }
1131
1132         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
1133             ("cdclose\n"));
1134
1135         if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0)
1136                 cdprevent(periph, PR_ALLOW);
1137
1138         /*
1139          * Since we're closing this CD, mark the blocksize as unavailable.
1140          * It will be marked as available when the CD is opened again.
1141          */
1142         softc->disk->d_devstat->flags |= DEVSTAT_BS_UNAVAILABLE;
1143
1144         /*
1145          * We'll check the media and toc again at the next open().
1146          */
1147         softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC);
1148
1149         cam_periph_unhold(periph);
1150         cam_periph_release_locked(periph);
1151         cam_periph_unlock(periph);
1152
1153         return (0);
1154 }
1155
1156 static void
1157 cdshorttimeout(void *arg)
1158 {
1159         struct cdchanger *changer;
1160
1161         changer = (struct cdchanger *)arg;
1162
1163         /* Always clear the short timeout flag, since that's what we're in */
1164         changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
1165
1166         /*
1167          * Check to see if there is any more pending or outstanding I/O for
1168          * this device.  If not, move it out of the active slot.
1169          */
1170         if ((bioq_first(&changer->cur_device->bio_queue) == NULL)
1171          && (changer->cur_device->outstanding_cmds == 0)) {
1172                 changer->flags |= CHANGER_MANUAL_CALL;
1173                 cdrunchangerqueue(changer);
1174         }
1175 }
1176
1177 /*
1178  * This is a wrapper for xpt_schedule.  It only applies to changers.
1179  */
1180 static void
1181 cdschedule(struct cam_periph *periph, int priority)
1182 {
1183         struct cd_softc *softc;
1184
1185         softc = (struct cd_softc *)periph->softc;
1186
1187         /*
1188          * If this device isn't currently queued, and if it isn't
1189          * the active device, then we queue this device and run the
1190          * changer queue if there is no timeout scheduled to do it.
1191          * If this device is the active device, just schedule it
1192          * to run again.  If this device is queued, there should be
1193          * a timeout in place already that will make sure it runs.
1194          */
1195         if ((softc->pinfo.index == CAM_UNQUEUED_INDEX) 
1196          && ((softc->flags & CD_FLAG_ACTIVE) == 0)) {
1197                 /*
1198                  * We don't do anything with the priority here.
1199                  * This is strictly a fifo queue.
1200                  */
1201                 softc->pinfo.priority = CAM_PRIORITY_NORMAL;
1202                 softc->pinfo.generation = ++softc->changer->devq.generation;
1203                 camq_insert(&softc->changer->devq, (cam_pinfo *)softc);
1204
1205                 /*
1206                  * Since we just put a device in the changer queue,
1207                  * check and see if there is a timeout scheduled for
1208                  * this changer.  If so, let the timeout handle
1209                  * switching this device into the active slot.  If
1210                  * not, manually call the timeout routine to
1211                  * bootstrap things.
1212                  */
1213                 if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0)
1214                  && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0)
1215                  && ((softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED)==0)){
1216                         softc->changer->flags |= CHANGER_MANUAL_CALL;
1217                         cdrunchangerqueue(softc->changer);
1218                 }
1219         } else if ((softc->flags & CD_FLAG_ACTIVE)
1220                 && ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0))
1221                 xpt_schedule(periph, priority);
1222 }
1223
1224 static void
1225 cdrunchangerqueue(void *arg)
1226 {
1227         struct cd_softc *softc;
1228         struct cdchanger *changer;
1229         int called_from_timeout;
1230
1231         changer = (struct cdchanger *)arg;
1232
1233         /*
1234          * If we have NOT been called from cdstrategy() or cddone(), and
1235          * instead from a timeout routine, go ahead and clear the
1236          * timeout flag.
1237          */
1238         if ((changer->flags & CHANGER_MANUAL_CALL) == 0) {
1239                 changer->flags &= ~CHANGER_TIMEOUT_SCHED;
1240                 called_from_timeout = 1;
1241         } else
1242                 called_from_timeout = 0;
1243
1244         /* Always clear the manual call flag */
1245         changer->flags &= ~CHANGER_MANUAL_CALL;
1246
1247         /* nothing to do if the queue is empty */
1248         if (changer->devq.entries <= 0) {
1249                 return;
1250         }
1251
1252         /*
1253          * If the changer queue is frozen, that means we have an active
1254          * device.
1255          */
1256         if (changer->devq.qfrozen_cnt > 0) {
1257
1258                 /*
1259                  * We always need to reset the frozen count and clear the
1260                  * active flag.
1261                  */
1262                 changer->devq.qfrozen_cnt--;
1263                 changer->cur_device->flags &= ~CD_FLAG_ACTIVE;
1264                 changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP;
1265
1266                 if (changer->cur_device->outstanding_cmds > 0) {
1267                         changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP;
1268                         changer->cur_device->bufs_left = 
1269                                 changer->cur_device->outstanding_cmds;
1270                         if (called_from_timeout) {
1271                                 callout_reset(&changer->long_handle,
1272                                     changer_max_busy_seconds * hz,
1273                                     cdrunchangerqueue, changer);
1274                                 changer->flags |= CHANGER_TIMEOUT_SCHED;
1275                         }
1276                         return;
1277                 }
1278
1279                 /*
1280                  * Check to see whether the current device has any I/O left
1281                  * to do.  If so, requeue it at the end of the queue.  If
1282                  * not, there is no need to requeue it.
1283                  */
1284                 if (bioq_first(&changer->cur_device->bio_queue) != NULL) {
1285
1286                         changer->cur_device->pinfo.generation =
1287                                 ++changer->devq.generation;
1288                         camq_insert(&changer->devq,
1289                                 (cam_pinfo *)changer->cur_device);
1290                 } 
1291         }
1292
1293         softc = (struct cd_softc *)camq_remove(&changer->devq, CAMQ_HEAD);
1294
1295         changer->cur_device = softc;
1296
1297         changer->devq.qfrozen_cnt++;
1298         softc->flags |= CD_FLAG_ACTIVE;
1299
1300         /* Just in case this device is waiting */
1301         wakeup(&softc->changer);
1302         xpt_schedule(softc->periph, CAM_PRIORITY_NORMAL);
1303
1304         /*
1305          * Get rid of any pending timeouts, and set a flag to schedule new
1306          * ones so this device gets its full time quantum.
1307          */
1308         if (changer->flags & CHANGER_TIMEOUT_SCHED) {
1309                 callout_stop(&changer->long_handle);
1310                 changer->flags &= ~CHANGER_TIMEOUT_SCHED;
1311         }
1312
1313         if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
1314                 callout_stop(&changer->short_handle);
1315                 changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
1316         }
1317
1318         /*
1319          * We need to schedule timeouts, but we only do this after the
1320          * first transaction has completed.  This eliminates the changer
1321          * switch time.
1322          */
1323         changer->flags |= CHANGER_NEED_TIMEOUT;
1324 }
1325
1326 static void
1327 cdchangerschedule(struct cd_softc *softc)
1328 {
1329         struct cdchanger *changer;
1330
1331         changer = softc->changer;
1332
1333         /*
1334          * If this is a changer, and this is the current device,
1335          * and this device has at least the minimum time quantum to
1336          * run, see if we can switch it out.
1337          */
1338         if ((softc->flags & CD_FLAG_ACTIVE) 
1339          && ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0)
1340          && ((changer->flags & CHANGER_NEED_TIMEOUT) == 0)) {
1341                 /*
1342                  * We try three things here.  The first is that we
1343                  * check to see whether the schedule on completion
1344                  * flag is set.  If it is, we decrement the number
1345                  * of buffers left, and if it's zero, we reschedule.
1346                  * Next, we check to see whether the pending buffer
1347                  * queue is empty and whether there are no
1348                  * outstanding transactions.  If so, we reschedule.
1349                  * Next, we see if the pending buffer queue is empty.
1350                  * If it is, we set the number of buffers left to
1351                  * the current active buffer count and set the
1352                  * schedule on complete flag.
1353                  */
1354                 if (softc->flags & CD_FLAG_SCHED_ON_COMP) {
1355                         if (--softc->bufs_left == 0) {
1356                                 softc->changer->flags |=
1357                                         CHANGER_MANUAL_CALL;
1358                                 softc->flags &= ~CD_FLAG_SCHED_ON_COMP;
1359                                 cdrunchangerqueue(softc->changer);
1360                         }
1361                 } else if ((bioq_first(&softc->bio_queue) == NULL)
1362                         && (softc->outstanding_cmds == 0)) {
1363                         softc->changer->flags |= CHANGER_MANUAL_CALL;
1364                         cdrunchangerqueue(softc->changer);
1365                 }
1366         } else if ((softc->changer->flags & CHANGER_NEED_TIMEOUT) 
1367                 && (softc->flags & CD_FLAG_ACTIVE)) {
1368
1369                 /*
1370                  * Now that the first transaction to this
1371                  * particular device has completed, we can go ahead
1372                  * and schedule our timeouts.
1373                  */
1374                 if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) {
1375                         callout_reset(&changer->long_handle,
1376                             changer_max_busy_seconds * hz,
1377                             cdrunchangerqueue, changer);
1378                         changer->flags |= CHANGER_TIMEOUT_SCHED;
1379                 } else
1380                         printf("cdchangerschedule: already have a long"
1381                                " timeout!\n");
1382
1383                 if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) {
1384                         callout_reset(&changer->short_handle,
1385                             changer_min_busy_seconds * hz,
1386                             cdshorttimeout, changer);
1387                         changer->flags |= CHANGER_SHORT_TMOUT_SCHED;
1388                 } else
1389                         printf("cdchangerschedule: already have a short "
1390                                "timeout!\n");
1391
1392                 /*
1393                  * We just scheduled timeouts, no need to schedule
1394                  * more.
1395                  */
1396                 changer->flags &= ~CHANGER_NEED_TIMEOUT;
1397
1398         }
1399 }
1400
1401 static int
1402 cdrunccb(union ccb *ccb, int (*error_routine)(union ccb *ccb,
1403                                               u_int32_t cam_flags,
1404                                               u_int32_t sense_flags),
1405          u_int32_t cam_flags, u_int32_t sense_flags)
1406 {
1407         struct cd_softc *softc;
1408         struct cam_periph *periph;
1409         int error;
1410
1411         periph = xpt_path_periph(ccb->ccb_h.path);
1412         softc = (struct cd_softc *)periph->softc;
1413
1414         error = cam_periph_runccb(ccb, error_routine, cam_flags, sense_flags,
1415                                   softc->disk->d_devstat);
1416
1417         if (softc->flags & CD_FLAG_CHANGER)
1418                 cdchangerschedule(softc);
1419
1420         return(error);
1421 }
1422
1423 static union ccb *
1424 cdgetccb(struct cam_periph *periph, u_int32_t priority)
1425 {
1426         struct cd_softc *softc;
1427
1428         softc = (struct cd_softc *)periph->softc;
1429
1430         if (softc->flags & CD_FLAG_CHANGER) {
1431                 /*
1432                  * This should work the first time this device is woken up,
1433                  * but just in case it doesn't, we use a while loop.
1434                  */
1435                 while ((softc->flags & CD_FLAG_ACTIVE) == 0) {
1436                         /*
1437                          * If this changer isn't already queued, queue it up.
1438                          */
1439                         if (softc->pinfo.index == CAM_UNQUEUED_INDEX) {
1440                                 softc->pinfo.priority = CAM_PRIORITY_NORMAL;
1441                                 softc->pinfo.generation =
1442                                         ++softc->changer->devq.generation;
1443                                 camq_insert(&softc->changer->devq,
1444                                             (cam_pinfo *)softc);
1445                         }
1446                         if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0)
1447                          && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0)
1448                          && ((softc->changer->flags
1449                               & CHANGER_SHORT_TMOUT_SCHED)==0)) {
1450                                 softc->changer->flags |= CHANGER_MANUAL_CALL;
1451                                 cdrunchangerqueue(softc->changer);
1452                         } else
1453                                 cam_periph_sleep(periph, &softc->changer,
1454                                     PRIBIO, "cgticb", 0);
1455                 }
1456         }
1457         return(cam_periph_getccb(periph, priority));
1458 }
1459
1460
1461 /*
1462  * Actually translate the requested transfer into one the physical driver
1463  * can understand.  The transfer is described by a buf and will include
1464  * only one physical transfer.
1465  */
1466 static void
1467 cdstrategy(struct bio *bp)
1468 {
1469         struct cam_periph *periph;
1470         struct cd_softc *softc;
1471
1472         periph = (struct cam_periph *)bp->bio_disk->d_drv1;
1473         cam_periph_lock(periph);
1474         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
1475             ("cdstrategy(%p)\n", bp));
1476
1477         softc = (struct cd_softc *)periph->softc;
1478
1479         /*
1480          * If the device has been made invalid, error out
1481          */
1482         if ((softc->flags & CD_FLAG_INVALID)) {
1483                 cam_periph_unlock(periph);
1484                 biofinish(bp, NULL, ENXIO);
1485                 return;
1486         }
1487
1488         /*
1489          * If we don't have valid media, look for it before trying to
1490          * schedule the I/O.
1491          */
1492         if ((softc->flags & CD_FLAG_VALID_MEDIA) == 0) {
1493                 int error;
1494
1495                 error = cdcheckmedia(periph);
1496                 if (error != 0) {
1497                         cam_periph_unlock(periph);
1498                         biofinish(bp, NULL, error);
1499                         return;
1500                 }
1501         }
1502
1503         /*
1504          * Place it in the queue of disk activities for this disk
1505          */
1506         bioq_disksort(&softc->bio_queue, bp);
1507
1508         /*
1509          * Schedule ourselves for performing the work.  We do things
1510          * differently for changers.
1511          */
1512         if ((softc->flags & CD_FLAG_CHANGER) == 0)
1513                 xpt_schedule(periph, CAM_PRIORITY_NORMAL);
1514         else
1515                 cdschedule(periph, CAM_PRIORITY_NORMAL);
1516
1517         cam_periph_unlock(periph);
1518         return;
1519 }
1520
1521 static void
1522 cdstart(struct cam_periph *periph, union ccb *start_ccb)
1523 {
1524         struct cd_softc *softc;
1525         struct bio *bp;
1526         struct ccb_scsiio *csio;
1527         struct scsi_read_capacity_data *rcap;
1528
1529         softc = (struct cd_softc *)periph->softc;
1530
1531         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n"));
1532
1533         switch (softc->state) {
1534         case CD_STATE_NORMAL:
1535         {
1536                 bp = bioq_first(&softc->bio_queue);
1537                 if (bp == NULL) {
1538                         if (softc->tur) {
1539                                 softc->tur = 0;
1540                                 csio = &start_ccb->csio;
1541                                 scsi_test_unit_ready(csio,
1542                                      /*retries*/ cd_retry_count,
1543                                      cddone,
1544                                      MSG_SIMPLE_Q_TAG,
1545                                      SSD_FULL_SIZE,
1546                                      cd_timeout);
1547                                 start_ccb->ccb_h.ccb_bp = NULL;
1548                                 start_ccb->ccb_h.ccb_state = CD_CCB_TUR;
1549                                 xpt_action(start_ccb);
1550                         } else
1551                                 xpt_release_ccb(start_ccb);
1552                 } else {
1553                         if (softc->tur) {
1554                                 softc->tur = 0;
1555                                 cam_periph_release_locked(periph);
1556                         }
1557                         bioq_remove(&softc->bio_queue, bp);
1558
1559                         scsi_read_write(&start_ccb->csio,
1560                                         /*retries*/ cd_retry_count,
1561                                         /* cbfcnp */ cddone,
1562                                         MSG_SIMPLE_Q_TAG,
1563                                         /* read */bp->bio_cmd == BIO_READ ?
1564                                         SCSI_RW_READ : SCSI_RW_WRITE,
1565                                         /* byte2 */ 0,
1566                                         /* minimum_cmd_size */ 10,
1567                                         /* lba */ bp->bio_offset /
1568                                           softc->params.blksize,
1569                                         bp->bio_bcount / softc->params.blksize,
1570                                         /* data_ptr */ bp->bio_data,
1571                                         /* dxfer_len */ bp->bio_bcount,
1572                                         /* sense_len */ cd_retry_count ?
1573                                           SSD_FULL_SIZE : SF_NO_PRINT,
1574                                         /* timeout */ cd_timeout);
1575                         /* Use READ CD command for audio tracks. */
1576                         if (softc->params.blksize == 2352) {
1577                                 start_ccb->csio.cdb_io.cdb_bytes[0] = READ_CD;
1578                                 start_ccb->csio.cdb_io.cdb_bytes[9] = 0xf8;
1579                                 start_ccb->csio.cdb_io.cdb_bytes[10] = 0;
1580                                 start_ccb->csio.cdb_io.cdb_bytes[11] = 0;
1581                                 start_ccb->csio.cdb_len = 12;
1582                         }
1583                         start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO;
1584
1585                         
1586                         LIST_INSERT_HEAD(&softc->pending_ccbs,
1587                                          &start_ccb->ccb_h, periph_links.le);
1588                         softc->outstanding_cmds++;
1589
1590                         /* We expect a unit attention from this device */
1591                         if ((softc->flags & CD_FLAG_RETRY_UA) != 0) {
1592                                 start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA;
1593                                 softc->flags &= ~CD_FLAG_RETRY_UA;
1594                         }
1595
1596                         start_ccb->ccb_h.ccb_bp = bp;
1597                         bp = bioq_first(&softc->bio_queue);
1598
1599                         xpt_action(start_ccb);
1600                 }
1601                 if (bp != NULL || softc->tur) {
1602                         /* Have more work to do, so ensure we stay scheduled */
1603                         xpt_schedule(periph, CAM_PRIORITY_NORMAL);
1604                 }
1605                 break;
1606         }
1607         case CD_STATE_PROBE:
1608         {
1609
1610                 rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap),
1611                     M_SCSICD, M_NOWAIT | M_ZERO);
1612                 if (rcap == NULL) {
1613                         xpt_print(periph->path,
1614                             "cdstart: Couldn't malloc read_capacity data\n");
1615                         /* cd_free_periph??? */
1616                         break;
1617                 }
1618                 csio = &start_ccb->csio;
1619                 scsi_read_capacity(csio,
1620                                    /*retries*/ cd_retry_count,
1621                                    cddone,
1622                                    MSG_SIMPLE_Q_TAG,
1623                                    rcap,
1624                                    SSD_FULL_SIZE,
1625                                    /*timeout*/20000);
1626                 start_ccb->ccb_h.ccb_bp = NULL;
1627                 start_ccb->ccb_h.ccb_state = CD_CCB_PROBE;
1628                 xpt_action(start_ccb);
1629                 break;
1630         }
1631         }
1632 }
1633
1634 static void
1635 cddone(struct cam_periph *periph, union ccb *done_ccb)
1636
1637         struct cd_softc *softc;
1638         struct ccb_scsiio *csio;
1639
1640         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n"));
1641
1642         softc = (struct cd_softc *)periph->softc;
1643         csio = &done_ccb->csio;
1644
1645         switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) {
1646         case CD_CCB_BUFFER_IO:
1647         {
1648                 struct bio      *bp;
1649                 int             error;
1650
1651                 bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
1652                 error = 0;
1653
1654                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1655                         int sf;
1656
1657                         if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0)
1658                                 sf = SF_RETRY_UA;
1659                         else
1660                                 sf = 0;
1661
1662                         error = cderror(done_ccb, CAM_RETRY_SELTO, sf);
1663                         if (error == ERESTART) {
1664                                 /*
1665                                  * A retry was scheuled, so
1666                                  * just return.
1667                                  */
1668                                 return;
1669                         }
1670                 }
1671
1672                 if (error != 0) {
1673                         xpt_print(periph->path,
1674                             "cddone: got error %#x back\n", error);
1675                         bioq_flush(&softc->bio_queue, NULL, EIO);
1676                         bp->bio_resid = bp->bio_bcount;
1677                         bp->bio_error = error;
1678                         bp->bio_flags |= BIO_ERROR;
1679                         if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1680                                 cam_release_devq(done_ccb->ccb_h.path,
1681                                          /*relsim_flags*/0,
1682                                          /*reduction*/0,
1683                                          /*timeout*/0,
1684                                          /*getcount_only*/0);
1685
1686                 } else {
1687                         bp->bio_resid = csio->resid;
1688                         bp->bio_error = 0;
1689                         if (bp->bio_resid != 0) {
1690                                 /*
1691                                  * Short transfer ??? 
1692                                  * XXX: not sure this is correct for partial
1693                                  * transfers at EOM
1694                                  */
1695                                 bp->bio_flags |= BIO_ERROR;
1696                         }
1697                 }
1698
1699                 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
1700                 softc->outstanding_cmds--;
1701
1702                 if (softc->flags & CD_FLAG_CHANGER)
1703                         cdchangerschedule(softc);
1704
1705                 biofinish(bp, NULL, 0);
1706                 break;
1707         }
1708         case CD_CCB_PROBE:
1709         {
1710                 struct     scsi_read_capacity_data *rdcap;
1711                 char       announce_buf[120]; /*
1712                                                * Currently (9/30/97) the 
1713                                                * longest possible announce 
1714                                                * buffer is 108 bytes, for the 
1715                                                * first error case below.  
1716                                                * That is 39 bytes for the 
1717                                                * basic string, 16 bytes for the
1718                                                * biggest sense key (hardware 
1719                                                * error), 52 bytes for the
1720                                                * text of the largest sense 
1721                                                * qualifier valid for a CDROM,
1722                                                * (0x72, 0x03 or 0x04,
1723                                                * 0x03), and one byte for the
1724                                                * null terminating character.
1725                                                * To allow for longer strings, 
1726                                                * the announce buffer is 120
1727                                                * bytes.
1728                                                */
1729                 struct     cd_params *cdp;
1730                 int error;
1731
1732                 cdp = &softc->params;
1733
1734                 rdcap = (struct scsi_read_capacity_data *)csio->data_ptr;
1735                 
1736                 cdp->disksize = scsi_4btoul (rdcap->addr) + 1;
1737                 cdp->blksize = scsi_4btoul (rdcap->length);
1738
1739                 /*
1740                  * Retry any UNIT ATTENTION type errors.  They
1741                  * are expected at boot.
1742                  */
1743                 if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP ||
1744                     (error = cderror(done_ccb, CAM_RETRY_SELTO,
1745                                 SF_RETRY_UA | SF_NO_PRINT)) == 0) {
1746
1747                         snprintf(announce_buf, sizeof(announce_buf),
1748                                 "cd present [%lu x %lu byte records]",
1749                                 cdp->disksize, (u_long)cdp->blksize);
1750
1751                 } else {
1752                         if (error == ERESTART) {
1753                                 /*
1754                                  * A retry was scheuled, so
1755                                  * just return.
1756                                  */
1757                                 return;
1758                         } else {
1759                                 int asc, ascq;
1760                                 int sense_key, error_code;
1761                                 int have_sense;
1762                                 cam_status status;
1763                                 struct ccb_getdev cgd;
1764
1765                                 /* Don't wedge this device's queue */
1766                                 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1767                                         cam_release_devq(done_ccb->ccb_h.path,
1768                                                  /*relsim_flags*/0,
1769                                                  /*reduction*/0,
1770                                                  /*timeout*/0,
1771                                                  /*getcount_only*/0);
1772
1773                                 status = done_ccb->ccb_h.status;
1774
1775                                 xpt_setup_ccb(&cgd.ccb_h, 
1776                                               done_ccb->ccb_h.path,
1777                                               CAM_PRIORITY_NORMAL);
1778                                 cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1779                                 xpt_action((union ccb *)&cgd);
1780
1781                                 if (scsi_extract_sense_ccb(done_ccb,
1782                                     &error_code, &sense_key, &asc, &ascq))
1783                                         have_sense = TRUE;
1784                                 else
1785                                         have_sense = FALSE;
1786
1787                                 /*
1788                                  * Attach to anything that claims to be a
1789                                  * CDROM or WORM device, as long as it
1790                                  * doesn't return a "Logical unit not
1791                                  * supported" (0x25) error.
1792                                  */
1793                                 if ((have_sense) && (asc != 0x25)
1794                                  && (error_code == SSD_CURRENT_ERROR)) {
1795                                         const char *sense_key_desc;
1796                                         const char *asc_desc;
1797
1798                                         scsi_sense_desc(sense_key, asc, ascq,
1799                                                         &cgd.inq_data,
1800                                                         &sense_key_desc,
1801                                                         &asc_desc);
1802                                         snprintf(announce_buf,
1803                                             sizeof(announce_buf),
1804                                                 "Attempt to query device "
1805                                                 "size failed: %s, %s",
1806                                                 sense_key_desc,
1807                                                 asc_desc);
1808                                 } else if ((have_sense == 0) 
1809                                       && ((status & CAM_STATUS_MASK) ==
1810                                            CAM_SCSI_STATUS_ERROR)
1811                                       && (csio->scsi_status ==
1812                                           SCSI_STATUS_BUSY)) {
1813                                         snprintf(announce_buf,
1814                                             sizeof(announce_buf),
1815                                             "Attempt to query device "
1816                                             "size failed: SCSI Status: %s",
1817                                             scsi_status_string(csio));
1818                                 } else if (SID_TYPE(&cgd.inq_data) == T_CDROM) {
1819                                         /*
1820                                          * We only print out an error for
1821                                          * CDROM type devices.  For WORM
1822                                          * devices, we don't print out an
1823                                          * error since a few WORM devices
1824                                          * don't support CDROM commands.
1825                                          * If we have sense information, go
1826                                          * ahead and print it out.
1827                                          * Otherwise, just say that we 
1828                                          * couldn't attach.
1829                                          */
1830
1831                                         /*
1832                                          * Just print out the error, not
1833                                          * the full probe message, when we
1834                                          * don't attach.
1835                                          */
1836                                         if (have_sense)
1837                                                 scsi_sense_print(
1838                                                         &done_ccb->csio);
1839                                         else {
1840                                                 xpt_print(periph->path,
1841                                                     "got CAM status %#x\n",
1842                                                     done_ccb->ccb_h.status);
1843                                         }
1844                                         xpt_print(periph->path, "fatal error, "
1845                                             "failed to attach to device\n");
1846                                         /*
1847                                          * Invalidate this peripheral.
1848                                          */
1849                                         cam_periph_invalidate(periph);
1850
1851                                         announce_buf[0] = '\0';
1852                                 } else {
1853
1854                                         /*
1855                                          * Invalidate this peripheral.
1856                                          */
1857                                         cam_periph_invalidate(periph);
1858                                         announce_buf[0] = '\0';
1859                                 }
1860                         }
1861                 }
1862                 free(rdcap, M_SCSICD);
1863                 if (announce_buf[0] != '\0') {
1864                         xpt_announce_periph(periph, announce_buf);
1865                         xpt_announce_quirks(periph, softc->quirks,
1866                             CD_Q_BIT_STRING);
1867                         if (softc->flags & CD_FLAG_CHANGER)
1868                                 cdchangerschedule(softc);
1869                         /*
1870                          * Create our sysctl variables, now that we know
1871                          * we have successfully attached.
1872                          */
1873                         taskqueue_enqueue(taskqueue_thread,&softc->sysctl_task);
1874                 }
1875                 softc->state = CD_STATE_NORMAL;         
1876                 /*
1877                  * Since our peripheral may be invalidated by an error
1878                  * above or an external event, we must release our CCB
1879                  * before releasing the probe lock on the peripheral.
1880                  * The peripheral will only go away once the last lock
1881                  * is removed, and we need it around for the CCB release
1882                  * operation.
1883                  */
1884                 xpt_release_ccb(done_ccb);
1885                 cam_periph_unhold(periph);
1886                 return;
1887         }
1888         case CD_CCB_TUR:
1889         {
1890                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1891
1892                         if (cderror(done_ccb, CAM_RETRY_SELTO,
1893                             SF_RETRY_UA | SF_NO_RECOVERY | SF_NO_PRINT) ==
1894                             ERESTART)
1895                                 return;
1896                         if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1897                                 cam_release_devq(done_ccb->ccb_h.path,
1898                                                  /*relsim_flags*/0,
1899                                                  /*reduction*/0,
1900                                                  /*timeout*/0,
1901                                                  /*getcount_only*/0);
1902                 }
1903                 xpt_release_ccb(done_ccb);
1904                 cam_periph_release_locked(periph);
1905                 return;
1906         }
1907         default:
1908                 break;
1909         }
1910         xpt_release_ccb(done_ccb);
1911 }
1912
1913 static union cd_pages *
1914 cdgetpage(struct cd_mode_params *mode_params)
1915 {
1916         union cd_pages *page;
1917
1918         if (mode_params->cdb_size == 10)
1919                 page = (union cd_pages *)find_mode_page_10(
1920                         (struct scsi_mode_header_10 *)mode_params->mode_buf);
1921         else
1922                 page = (union cd_pages *)find_mode_page_6(
1923                         (struct scsi_mode_header_6 *)mode_params->mode_buf);
1924
1925         return (page);
1926 }
1927
1928 static int
1929 cdgetpagesize(int page_num)
1930 {
1931         int i;
1932
1933         for (i = 0; i < (sizeof(cd_page_size_table)/
1934              sizeof(cd_page_size_table[0])); i++) {
1935                 if (cd_page_size_table[i].page == page_num)
1936                         return (cd_page_size_table[i].page_size);
1937         }
1938
1939         return (-1);
1940 }
1941
1942 static int
1943 cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
1944 {
1945
1946         struct  cam_periph *periph;
1947         struct  cd_softc *softc;
1948         int     nocopyout, error = 0;
1949
1950         periph = (struct cam_periph *)dp->d_drv1;
1951         cam_periph_lock(periph);
1952
1953         softc = (struct cd_softc *)periph->softc;
1954
1955         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
1956             ("cdioctl(%#lx)\n", cmd));
1957
1958         if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
1959                 cam_periph_unlock(periph);
1960                 cam_periph_release(periph);
1961                 return (error);
1962         }
1963
1964         /*
1965          * If we don't have media loaded, check for it.  If still don't
1966          * have media loaded, we can only do a load or eject.
1967          *
1968          * We only care whether media is loaded if this is a cd-specific ioctl
1969          * (thus the IOCGROUP check below).  Note that this will break if
1970          * anyone adds any ioctls into the switch statement below that don't
1971          * have their ioctl group set to 'c'.
1972          */
1973         if (((softc->flags & CD_FLAG_VALID_MEDIA) == 0)
1974          && ((cmd != CDIOCCLOSE)
1975           && (cmd != CDIOCEJECT))
1976          && (IOCGROUP(cmd) == 'c')) {
1977                 error = cdcheckmedia(periph);
1978                 if (error != 0) {
1979                         cam_periph_unhold(periph);
1980                         cam_periph_unlock(periph);
1981                         return (error);
1982                 }
1983         }
1984         /*
1985          * Drop the lock here so later mallocs can use WAITOK.  The periph
1986          * is essentially locked still with the cam_periph_hold call above.
1987          */
1988         cam_periph_unlock(periph);
1989
1990         nocopyout = 0;
1991         switch (cmd) {
1992
1993         case CDIOCPLAYTRACKS:
1994                 {
1995                         struct ioc_play_track *args
1996                             = (struct ioc_play_track *) addr;
1997                         struct cd_mode_params params;
1998                         union cd_pages *page;
1999
2000                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2001                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
2002                                                  M_WAITOK | M_ZERO);
2003
2004                         cam_periph_lock(periph);
2005                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2006                                   ("trying to do CDIOCPLAYTRACKS\n"));
2007
2008                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2009                         if (error) {
2010                                 free(params.mode_buf, M_SCSICD);
2011                                 cam_periph_unlock(periph);
2012                                 break;
2013                         }
2014                         page = cdgetpage(&params);
2015
2016                         page->audio.flags &= ~CD_PA_SOTC;
2017                         page->audio.flags |= CD_PA_IMMED;
2018                         error = cdsetmode(periph, &params);
2019                         free(params.mode_buf, M_SCSICD);
2020                         if (error) {
2021                                 cam_periph_unlock(periph);
2022                                 break;
2023                         }
2024
2025                         /*
2026                          * This was originally implemented with the PLAY
2027                          * AUDIO TRACK INDEX command, but that command was
2028                          * deprecated after SCSI-2.  Most (all?) SCSI CDROM
2029                          * drives support it but ATAPI and ATAPI-derivative
2030                          * drives don't seem to support it.  So we keep a
2031                          * cache of the table of contents and translate
2032                          * track numbers to MSF format.
2033                          */
2034                         if (softc->flags & CD_FLAG_VALID_TOC) {
2035                                 union msf_lba *sentry, *eentry;
2036                                 int st, et;
2037
2038                                 if (args->end_track <
2039                                     softc->toc.header.ending_track + 1)
2040                                         args->end_track++;
2041                                 if (args->end_track >
2042                                     softc->toc.header.ending_track + 1)
2043                                         args->end_track =
2044                                             softc->toc.header.ending_track + 1;
2045                                 st = args->start_track -
2046                                         softc->toc.header.starting_track;
2047                                 et = args->end_track -
2048                                         softc->toc.header.starting_track;
2049                                 if ((st < 0)
2050                                  || (et < 0)
2051                                  || (st > (softc->toc.header.ending_track -
2052                                      softc->toc.header.starting_track))) {
2053                                         error = EINVAL;
2054                                         cam_periph_unlock(periph);
2055                                         break;
2056                                 }
2057                                 sentry = &softc->toc.entries[st].addr;
2058                                 eentry = &softc->toc.entries[et].addr;
2059                                 error = cdplaymsf(periph,
2060                                                   sentry->msf.minute,
2061                                                   sentry->msf.second,
2062                                                   sentry->msf.frame,
2063                                                   eentry->msf.minute,
2064                                                   eentry->msf.second,
2065                                                   eentry->msf.frame);
2066                         } else {
2067                                 /*
2068                                  * If we don't have a valid TOC, try the
2069                                  * play track index command.  It is part of
2070                                  * the SCSI-2 spec, but was removed in the
2071                                  * MMC specs.  ATAPI and ATAPI-derived
2072                                  * drives don't support it.
2073                                  */
2074                                 if (softc->quirks & CD_Q_BCD_TRACKS) {
2075                                         args->start_track =
2076                                                 bin2bcd(args->start_track);
2077                                         args->end_track =
2078                                                 bin2bcd(args->end_track);
2079                                 }
2080                                 error = cdplaytracks(periph,
2081                                                      args->start_track,
2082                                                      args->start_index,
2083                                                      args->end_track,
2084                                                      args->end_index);
2085                         }
2086                         cam_periph_unlock(periph);
2087                 }
2088                 break;
2089         case CDIOCPLAYMSF:
2090                 {
2091                         struct ioc_play_msf *args
2092                                 = (struct ioc_play_msf *) addr;
2093                         struct cd_mode_params params;
2094                         union cd_pages *page;
2095
2096                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2097                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
2098                                                  M_WAITOK | M_ZERO);
2099
2100                         cam_periph_lock(periph);
2101                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2102                                   ("trying to do CDIOCPLAYMSF\n"));
2103
2104                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2105                         if (error) {
2106                                 free(params.mode_buf, M_SCSICD);
2107                                 cam_periph_unlock(periph);
2108                                 break;
2109                         }
2110                         page = cdgetpage(&params);
2111
2112                         page->audio.flags &= ~CD_PA_SOTC;
2113                         page->audio.flags |= CD_PA_IMMED;
2114                         error = cdsetmode(periph, &params);
2115                         free(params.mode_buf, M_SCSICD);
2116                         if (error) {
2117                                 cam_periph_unlock(periph);
2118                                 break;
2119                         }
2120                         error = cdplaymsf(periph,
2121                                           args->start_m,
2122                                           args->start_s,
2123                                           args->start_f,
2124                                           args->end_m,
2125                                           args->end_s,
2126                                           args->end_f);
2127                         cam_periph_unlock(periph);
2128                 }
2129                 break;
2130         case CDIOCPLAYBLOCKS:
2131                 {
2132                         struct ioc_play_blocks *args
2133                                 = (struct ioc_play_blocks *) addr;
2134                         struct cd_mode_params params;
2135                         union cd_pages *page;
2136
2137                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2138                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
2139                                                  M_WAITOK | M_ZERO);
2140
2141                         cam_periph_lock(periph);
2142                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2143                                   ("trying to do CDIOCPLAYBLOCKS\n"));
2144
2145
2146                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2147                         if (error) {
2148                                 free(params.mode_buf, M_SCSICD);
2149                                 cam_periph_unlock(periph);
2150                                 break;
2151                         }
2152                         page = cdgetpage(&params);
2153
2154                         page->audio.flags &= ~CD_PA_SOTC;
2155                         page->audio.flags |= CD_PA_IMMED;
2156                         error = cdsetmode(periph, &params);
2157                         free(params.mode_buf, M_SCSICD);
2158                         if (error) {
2159                                 cam_periph_unlock(periph);
2160                                 break;
2161                         }
2162                         error = cdplay(periph, args->blk, args->len);
2163                         cam_periph_unlock(periph);
2164                 }
2165                 break;
2166         case CDIOCREADSUBCHANNEL_SYSSPACE:
2167                 nocopyout = 1;
2168                 /* Fallthrough */
2169         case CDIOCREADSUBCHANNEL:
2170                 {
2171                         struct ioc_read_subchannel *args
2172                                 = (struct ioc_read_subchannel *) addr;
2173                         struct cd_sub_channel_info *data;
2174                         u_int32_t len = args->data_len;
2175
2176                         data = malloc(sizeof(struct cd_sub_channel_info), 
2177                                       M_SCSICD, M_WAITOK | M_ZERO);
2178
2179                         cam_periph_lock(periph);
2180                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2181                                   ("trying to do CDIOCREADSUBCHANNEL\n"));
2182
2183                         if ((len > sizeof(struct cd_sub_channel_info)) ||
2184                             (len < sizeof(struct cd_sub_channel_header))) {
2185                                 printf(
2186                                         "scsi_cd: cdioctl: "
2187                                         "cdioreadsubchannel: error, len=%d\n",
2188                                         len);
2189                                 error = EINVAL;
2190                                 free(data, M_SCSICD);
2191                                 cam_periph_unlock(periph);
2192                                 break;
2193                         }
2194
2195                         if (softc->quirks & CD_Q_BCD_TRACKS)
2196                                 args->track = bin2bcd(args->track);
2197
2198                         error = cdreadsubchannel(periph, args->address_format,
2199                                 args->data_format, args->track, data, len);
2200
2201                         if (error) {
2202                                 free(data, M_SCSICD);
2203                                 cam_periph_unlock(periph);
2204                                 break;
2205                         }
2206                         if (softc->quirks & CD_Q_BCD_TRACKS)
2207                                 data->what.track_info.track_number =
2208                                     bcd2bin(data->what.track_info.track_number);
2209                         len = min(len, ((data->header.data_len[0] << 8) +
2210                                 data->header.data_len[1] +
2211                                 sizeof(struct cd_sub_channel_header)));
2212                         cam_periph_unlock(periph);
2213                         if (nocopyout == 0) {
2214                                 if (copyout(data, args->data, len) != 0) {
2215                                         error = EFAULT;
2216                                 }
2217                         } else {
2218                                 bcopy(data, args->data, len);
2219                         }
2220                         free(data, M_SCSICD);
2221                 }
2222                 break;
2223
2224         case CDIOREADTOCHEADER:
2225                 {
2226                         struct ioc_toc_header *th;
2227
2228                         th = malloc(sizeof(struct ioc_toc_header), M_SCSICD,
2229                                     M_WAITOK | M_ZERO);
2230
2231                         cam_periph_lock(periph);
2232                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2233                                   ("trying to do CDIOREADTOCHEADER\n"));
2234
2235                         error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, 
2236                                           sizeof (*th), /*sense_flags*/SF_NO_PRINT);
2237                         if (error) {
2238                                 free(th, M_SCSICD);
2239                                 cam_periph_unlock(periph);
2240                                 break;
2241                         }
2242                         if (softc->quirks & CD_Q_BCD_TRACKS) {
2243                                 /* we are going to have to convert the BCD
2244                                  * encoding on the cd to what is expected
2245                                  */
2246                                 th->starting_track = 
2247                                         bcd2bin(th->starting_track);
2248                                 th->ending_track = bcd2bin(th->ending_track);
2249                         }
2250                         th->len = ntohs(th->len);
2251                         bcopy(th, addr, sizeof(*th));
2252                         free(th, M_SCSICD);
2253                         cam_periph_unlock(periph);
2254                 }
2255                 break;
2256         case CDIOREADTOCENTRYS:
2257                 {
2258                         struct cd_tocdata *data;
2259                         struct cd_toc_single *lead;
2260                         struct ioc_read_toc_entry *te =
2261                                 (struct ioc_read_toc_entry *) addr;
2262                         struct ioc_toc_header *th;
2263                         u_int32_t len, readlen, idx, num;
2264                         u_int32_t starting_track = te->starting_track;
2265
2266                         data = malloc(sizeof(*data), M_SCSICD, M_WAITOK | M_ZERO);
2267                         lead = malloc(sizeof(*lead), M_SCSICD, M_WAITOK | M_ZERO);
2268
2269                         cam_periph_lock(periph);
2270                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2271                                   ("trying to do CDIOREADTOCENTRYS\n"));
2272
2273                         if (te->data_len < sizeof(struct cd_toc_entry)
2274                          || (te->data_len % sizeof(struct cd_toc_entry)) != 0
2275                          || (te->address_format != CD_MSF_FORMAT
2276                           && te->address_format != CD_LBA_FORMAT)) {
2277                                 error = EINVAL;
2278                                 printf("scsi_cd: error in readtocentries, "
2279                                        "returning EINVAL\n");
2280                                 free(data, M_SCSICD);
2281                                 free(lead, M_SCSICD);
2282                                 cam_periph_unlock(periph);
2283                                 break;
2284                         }
2285
2286                         th = &data->header;
2287                         error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, 
2288                                           sizeof (*th), /*sense_flags*/0);
2289                         if (error) {
2290                                 free(data, M_SCSICD);
2291                                 free(lead, M_SCSICD);
2292                                 cam_periph_unlock(periph);
2293                                 break;
2294                         }
2295
2296                         if (softc->quirks & CD_Q_BCD_TRACKS) {
2297                                 /* we are going to have to convert the BCD
2298                                  * encoding on the cd to what is expected
2299                                  */
2300                                 th->starting_track =
2301                                     bcd2bin(th->starting_track);
2302                                 th->ending_track = bcd2bin(th->ending_track);
2303                         }
2304
2305                         if (starting_track == 0)
2306                                 starting_track = th->starting_track;
2307                         else if (starting_track == LEADOUT)
2308                                 starting_track = th->ending_track + 1;
2309                         else if (starting_track < th->starting_track ||
2310                                  starting_track > th->ending_track + 1) {
2311                                 printf("scsi_cd: error in readtocentries, "
2312                                        "returning EINVAL\n");
2313                                 free(data, M_SCSICD);
2314                                 free(lead, M_SCSICD);
2315                                 cam_periph_unlock(periph);
2316                                 error = EINVAL;
2317                                 break;
2318                         }
2319
2320                         /* calculate reading length without leadout entry */
2321                         readlen = (th->ending_track - starting_track + 1) *
2322                                   sizeof(struct cd_toc_entry);
2323
2324                         /* and with leadout entry */
2325                         len = readlen + sizeof(struct cd_toc_entry);
2326                         if (te->data_len < len) {
2327                                 len = te->data_len;
2328                                 if (readlen > len)
2329                                         readlen = len;
2330                         }
2331                         if (len > sizeof(data->entries)) {
2332                                 printf("scsi_cd: error in readtocentries, "
2333                                        "returning EINVAL\n");
2334                                 error = EINVAL;
2335                                 free(data, M_SCSICD);
2336                                 free(lead, M_SCSICD);
2337                                 cam_periph_unlock(periph);
2338                                 break;
2339                         }
2340                         num = len / sizeof(struct cd_toc_entry);
2341
2342                         if (readlen > 0) {
2343                                 error = cdreadtoc(periph, te->address_format,
2344                                                   starting_track,
2345                                                   (u_int8_t *)data,
2346                                                   readlen + sizeof (*th),
2347                                                   /*sense_flags*/0);
2348                                 if (error) {
2349                                         free(data, M_SCSICD);
2350                                         free(lead, M_SCSICD);
2351                                         cam_periph_unlock(periph);
2352                                         break;
2353                                 }
2354                         }
2355
2356                         /* make leadout entry if needed */
2357                         idx = starting_track + num - 1;
2358                         if (softc->quirks & CD_Q_BCD_TRACKS)
2359                                 th->ending_track = bcd2bin(th->ending_track);
2360                         if (idx == th->ending_track + 1) {
2361                                 error = cdreadtoc(periph, te->address_format,
2362                                                   LEADOUT, (u_int8_t *)lead,
2363                                                   sizeof(*lead),
2364                                                   /*sense_flags*/0);
2365                                 if (error) {
2366                                         free(data, M_SCSICD);
2367                                         free(lead, M_SCSICD);
2368                                         cam_periph_unlock(periph);
2369                                         break;
2370                                 }
2371                                 data->entries[idx - starting_track] = 
2372                                         lead->entry;
2373                         }
2374                         if (softc->quirks & CD_Q_BCD_TRACKS) {
2375                                 for (idx = 0; idx < num - 1; idx++) {
2376                                         data->entries[idx].track =
2377                                             bcd2bin(data->entries[idx].track);
2378                                 }
2379                         }
2380
2381                         cam_periph_unlock(periph);
2382                         error = copyout(data->entries, te->data, len);
2383                         free(data, M_SCSICD);
2384                         free(lead, M_SCSICD);
2385                 }
2386                 break;
2387         case CDIOREADTOCENTRY:
2388                 {
2389                         struct cd_toc_single *data;
2390                         struct ioc_read_toc_single_entry *te =
2391                                 (struct ioc_read_toc_single_entry *) addr;
2392                         struct ioc_toc_header *th;
2393                         u_int32_t track;
2394
2395                         data = malloc(sizeof(*data), M_SCSICD, M_WAITOK | M_ZERO);
2396
2397                         cam_periph_lock(periph);
2398                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2399                                   ("trying to do CDIOREADTOCENTRY\n"));
2400
2401                         if (te->address_format != CD_MSF_FORMAT
2402                             && te->address_format != CD_LBA_FORMAT) {
2403                                 printf("error in readtocentry, "
2404                                        " returning EINVAL\n");
2405                                 free(data, M_SCSICD);
2406                                 error = EINVAL;
2407                                 cam_periph_unlock(periph);
2408                                 break;
2409                         }
2410
2411                         th = &data->header;
2412                         error = cdreadtoc(periph, 0, 0, (u_int8_t *)th,
2413                                           sizeof (*th), /*sense_flags*/0);
2414                         if (error) {
2415                                 free(data, M_SCSICD);
2416                                 cam_periph_unlock(periph);
2417                                 break;
2418                         }
2419
2420                         if (softc->quirks & CD_Q_BCD_TRACKS) {
2421                                 /* we are going to have to convert the BCD
2422                                  * encoding on the cd to what is expected
2423                                  */
2424                                 th->starting_track =
2425                                     bcd2bin(th->starting_track);
2426                                 th->ending_track = bcd2bin(th->ending_track);
2427                         }
2428                         track = te->track;
2429                         if (track == 0)
2430                                 track = th->starting_track;
2431                         else if (track == LEADOUT)
2432                                 /* OK */;
2433                         else if (track < th->starting_track ||
2434                                  track > th->ending_track + 1) {
2435                                 printf("error in readtocentry, "
2436                                        " returning EINVAL\n");
2437                                 free(data, M_SCSICD);
2438                                 error = EINVAL;
2439                                 cam_periph_unlock(periph);
2440                                 break;
2441                         }
2442
2443                         error = cdreadtoc(periph, te->address_format, track,
2444                                           (u_int8_t *)data, sizeof(*data),
2445                                           /*sense_flags*/0);
2446                         if (error) {
2447                                 free(data, M_SCSICD);
2448                                 cam_periph_unlock(periph);
2449                                 break;
2450                         }
2451
2452                         if (softc->quirks & CD_Q_BCD_TRACKS)
2453                                 data->entry.track = bcd2bin(data->entry.track);
2454                         bcopy(&data->entry, &te->entry,
2455                               sizeof(struct cd_toc_entry));
2456                         free(data, M_SCSICD);
2457                         cam_periph_unlock(periph);
2458                 }
2459                 break;
2460         case CDIOCSETPATCH:
2461                 {
2462                         struct ioc_patch *arg = (struct ioc_patch *)addr;
2463                         struct cd_mode_params params;
2464                         union cd_pages *page;
2465
2466                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2467                         params.mode_buf = malloc(params.alloc_len, M_SCSICD, 
2468                                                  M_WAITOK | M_ZERO);
2469
2470                         cam_periph_lock(periph);
2471                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2472                                   ("trying to do CDIOCSETPATCH\n"));
2473
2474                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2475                         if (error) {
2476                                 free(params.mode_buf, M_SCSICD);
2477                                 cam_periph_unlock(periph);
2478                                 break;
2479                         }
2480                         page = cdgetpage(&params);
2481
2482                         page->audio.port[LEFT_PORT].channels = 
2483                                 arg->patch[0];
2484                         page->audio.port[RIGHT_PORT].channels = 
2485                                 arg->patch[1];
2486                         page->audio.port[2].channels = arg->patch[2];
2487                         page->audio.port[3].channels = arg->patch[3];
2488                         error = cdsetmode(periph, &params);
2489                         free(params.mode_buf, M_SCSICD);
2490                         cam_periph_unlock(periph);
2491                 }
2492                 break;
2493         case CDIOCGETVOL:
2494                 {
2495                         struct ioc_vol *arg = (struct ioc_vol *) addr;
2496                         struct cd_mode_params params;
2497                         union cd_pages *page;
2498
2499                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2500                         params.mode_buf = malloc(params.alloc_len, M_SCSICD, 
2501                                                  M_WAITOK | M_ZERO);
2502
2503                         cam_periph_lock(periph);
2504                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2505                                   ("trying to do CDIOCGETVOL\n"));
2506
2507                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2508                         if (error) {
2509                                 free(params.mode_buf, M_SCSICD);
2510                                 cam_periph_unlock(periph);
2511                                 break;
2512                         }
2513                         page = cdgetpage(&params);
2514
2515                         arg->vol[LEFT_PORT] = 
2516                                 page->audio.port[LEFT_PORT].volume;
2517                         arg->vol[RIGHT_PORT] = 
2518                                 page->audio.port[RIGHT_PORT].volume;
2519                         arg->vol[2] = page->audio.port[2].volume;
2520                         arg->vol[3] = page->audio.port[3].volume;
2521                         free(params.mode_buf, M_SCSICD);
2522                         cam_periph_unlock(periph);
2523                 }
2524                 break;
2525         case CDIOCSETVOL:
2526                 {
2527                         struct ioc_vol *arg = (struct ioc_vol *) addr;
2528                         struct cd_mode_params params;
2529                         union cd_pages *page;
2530
2531                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2532                         params.mode_buf = malloc(params.alloc_len, M_SCSICD, 
2533                                                  M_WAITOK | M_ZERO);
2534
2535                         cam_periph_lock(periph);
2536                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2537                                   ("trying to do CDIOCSETVOL\n"));
2538
2539                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2540                         if (error) {
2541                                 free(params.mode_buf, M_SCSICD);
2542                                 cam_periph_unlock(periph);
2543                                 break;
2544                         }
2545                         page = cdgetpage(&params);
2546
2547                         page->audio.port[LEFT_PORT].channels = CHANNEL_0;
2548                         page->audio.port[LEFT_PORT].volume = 
2549                                 arg->vol[LEFT_PORT];
2550                         page->audio.port[RIGHT_PORT].channels = CHANNEL_1;
2551                         page->audio.port[RIGHT_PORT].volume = 
2552                                 arg->vol[RIGHT_PORT];
2553                         page->audio.port[2].volume = arg->vol[2];
2554                         page->audio.port[3].volume = arg->vol[3];
2555                         error = cdsetmode(periph, &params);
2556                         cam_periph_unlock(periph);
2557                         free(params.mode_buf, M_SCSICD);
2558                 }
2559                 break;
2560         case CDIOCSETMONO:
2561                 {
2562                         struct cd_mode_params params;
2563                         union cd_pages *page;
2564
2565                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2566                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
2567                                                  M_WAITOK | M_ZERO);
2568
2569                         cam_periph_lock(periph);
2570                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2571                                   ("trying to do CDIOCSETMONO\n"));
2572
2573                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2574                         if (error) {
2575                                 free(params.mode_buf, M_SCSICD);
2576                                 cam_periph_unlock(periph);
2577                                 break;
2578                         }
2579                         page = cdgetpage(&params);
2580
2581                         page->audio.port[LEFT_PORT].channels = 
2582                                 LEFT_CHANNEL | RIGHT_CHANNEL;
2583                         page->audio.port[RIGHT_PORT].channels = 
2584                                 LEFT_CHANNEL | RIGHT_CHANNEL;
2585                         page->audio.port[2].channels = 0;
2586                         page->audio.port[3].channels = 0;
2587                         error = cdsetmode(periph, &params);
2588                         cam_periph_unlock(periph);
2589                         free(params.mode_buf, M_SCSICD);
2590                 }
2591                 break;
2592         case CDIOCSETSTEREO:
2593                 {
2594                         struct cd_mode_params params;
2595                         union cd_pages *page;
2596
2597                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2598                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
2599                                                  M_WAITOK | M_ZERO);
2600
2601                         cam_periph_lock(periph);
2602                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2603                                   ("trying to do CDIOCSETSTEREO\n"));
2604
2605                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2606                         if (error) {
2607                                 free(params.mode_buf, M_SCSICD);
2608                                 cam_periph_unlock(periph);
2609                                 break;
2610                         }
2611                         page = cdgetpage(&params);
2612
2613                         page->audio.port[LEFT_PORT].channels = 
2614                                 LEFT_CHANNEL;
2615                         page->audio.port[RIGHT_PORT].channels = 
2616                                 RIGHT_CHANNEL;
2617                         page->audio.port[2].channels = 0;
2618                         page->audio.port[3].channels = 0;
2619                         error = cdsetmode(periph, &params);
2620                         free(params.mode_buf, M_SCSICD);
2621                         cam_periph_unlock(periph);
2622                 }
2623                 break;
2624         case CDIOCSETMUTE:
2625                 {
2626                         struct cd_mode_params params;
2627                         union cd_pages *page;
2628
2629                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2630                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
2631                                                  M_WAITOK | M_ZERO);
2632
2633                         cam_periph_lock(periph);
2634                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2635                                   ("trying to do CDIOCSETMUTE\n"));
2636
2637                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2638                         if (error) {
2639                                 free(params.mode_buf, M_SCSICD);
2640                                 cam_periph_unlock(periph);
2641                                 break;
2642                         }
2643                         page = cdgetpage(&params);
2644
2645                         page->audio.port[LEFT_PORT].channels = 0;
2646                         page->audio.port[RIGHT_PORT].channels = 0;
2647                         page->audio.port[2].channels = 0;
2648                         page->audio.port[3].channels = 0;
2649                         error = cdsetmode(periph, &params);
2650                         free(params.mode_buf, M_SCSICD);
2651                         cam_periph_unlock(periph);
2652                 }
2653                 break;
2654         case CDIOCSETLEFT:
2655                 {
2656                         struct cd_mode_params params;
2657                         union cd_pages *page;
2658
2659                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2660                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
2661                                                  M_WAITOK | M_ZERO);
2662
2663                         cam_periph_lock(periph);
2664                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2665                                   ("trying to do CDIOCSETLEFT\n"));
2666
2667                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2668                         if (error) {
2669                                 free(params.mode_buf, M_SCSICD);
2670                                 cam_periph_unlock(periph);
2671                                 break;
2672                         }
2673                         page = cdgetpage(&params);
2674
2675                         page->audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
2676                         page->audio.port[RIGHT_PORT].channels = LEFT_CHANNEL;
2677                         page->audio.port[2].channels = 0;
2678                         page->audio.port[3].channels = 0;
2679                         error = cdsetmode(periph, &params);
2680                         free(params.mode_buf, M_SCSICD);
2681                         cam_periph_unlock(periph);
2682                 }
2683                 break;
2684         case CDIOCSETRIGHT:
2685                 {
2686                         struct cd_mode_params params;
2687                         union cd_pages *page;
2688
2689                         params.alloc_len = sizeof(union cd_mode_data_6_10);
2690                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
2691                                                  M_WAITOK | M_ZERO);
2692
2693                         cam_periph_lock(periph);
2694                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
2695                                   ("trying to do CDIOCSETRIGHT\n"));
2696
2697                         error = cdgetmode(periph, &params, AUDIO_PAGE);
2698                         if (error) {
2699                                 free(params.mode_buf, M_SCSICD);
2700                                 cam_periph_unlock(periph);
2701                                 break;
2702                         }
2703                         page = cdgetpage(&params);
2704
2705                         page->audio.port[LEFT_PORT].channels = RIGHT_CHANNEL;
2706                         page->audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
2707                         page->audio.port[2].channels = 0;
2708                         page->audio.port[3].channels = 0;
2709                         error = cdsetmode(periph, &params);
2710                         free(params.mode_buf, M_SCSICD);
2711                         cam_periph_unlock(periph);
2712                 }
2713                 break;
2714         case CDIOCRESUME:
2715                 cam_periph_lock(periph);
2716                 error = cdpause(periph, 1);
2717                 cam_periph_unlock(periph);
2718                 break;
2719         case CDIOCPAUSE:
2720                 cam_periph_lock(periph);
2721                 error = cdpause(periph, 0);
2722                 cam_periph_unlock(periph);
2723                 break;
2724         case CDIOCSTART:
2725                 cam_periph_lock(periph);
2726                 error = cdstartunit(periph, 0);
2727                 cam_periph_unlock(periph);
2728                 break;
2729         case CDIOCCLOSE:
2730                 cam_periph_lock(periph);
2731                 error = cdstartunit(periph, 1);
2732                 cam_periph_unlock(periph);
2733                 break;
2734         case CDIOCSTOP:
2735                 cam_periph_lock(periph);
2736                 error = cdstopunit(periph, 0);
2737                 cam_periph_unlock(periph);
2738                 break;
2739         case CDIOCEJECT:
2740                 cam_periph_lock(periph);
2741                 error = cdstopunit(periph, 1);
2742                 cam_periph_unlock(periph);
2743                 break;
2744         case CDIOCALLOW:
2745                 cam_periph_lock(periph);
2746                 cdprevent(periph, PR_ALLOW);
2747                 cam_periph_unlock(periph);
2748                 break;
2749         case CDIOCPREVENT:
2750                 cam_periph_lock(periph);
2751                 cdprevent(periph, PR_PREVENT);
2752                 cam_periph_unlock(periph);
2753                 break;
2754         case CDIOCSETDEBUG:
2755                 /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */
2756                 error = ENOTTY;
2757                 break;
2758         case CDIOCCLRDEBUG:
2759                 /* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */
2760                 error = ENOTTY;
2761                 break;
2762         case CDIOCRESET:
2763                 /* return (cd_reset(periph)); */
2764                 error = ENOTTY;
2765                 break;
2766         case CDRIOCREADSPEED:
2767                 cam_periph_lock(periph);
2768                 error = cdsetspeed(periph, *(u_int32_t *)addr, CDR_MAX_SPEED);
2769                 cam_periph_unlock(periph);
2770                 break;
2771         case CDRIOCWRITESPEED:
2772                 cam_periph_lock(periph);
2773                 error = cdsetspeed(periph, CDR_MAX_SPEED, *(u_int32_t *)addr);
2774                 cam_periph_unlock(periph);
2775                 break;
2776         case CDRIOCGETBLOCKSIZE:
2777                 *(int *)addr = softc->params.blksize;
2778                 break;
2779         case CDRIOCSETBLOCKSIZE:
2780                 if (*(int *)addr <= 0) {
2781                         error = EINVAL;
2782                         break;
2783                 }
2784                 softc->disk->d_sectorsize = softc->params.blksize = *(int *)addr;
2785                 break;
2786         case DVDIOCSENDKEY:
2787         case DVDIOCREPORTKEY: {
2788                 struct dvd_authinfo *authinfo;
2789
2790                 authinfo = (struct dvd_authinfo *)addr;
2791
2792                 if (cmd == DVDIOCREPORTKEY)
2793                         error = cdreportkey(periph, authinfo);
2794                 else
2795                         error = cdsendkey(periph, authinfo);
2796                 break;
2797                 }
2798         case DVDIOCREADSTRUCTURE: {
2799                 struct dvd_struct *dvdstruct;
2800
2801                 dvdstruct = (struct dvd_struct *)addr;
2802
2803                 error = cdreaddvdstructure(periph, dvdstruct);
2804
2805                 break;
2806         }
2807         default:
2808                 cam_periph_lock(periph);
2809                 error = cam_periph_ioctl(periph, cmd, addr, cderror);
2810                 cam_periph_unlock(periph);
2811                 break;
2812         }
2813
2814         cam_periph_lock(periph);
2815         cam_periph_unhold(periph);
2816         
2817         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n"));
2818         if (error && bootverbose) {
2819                 printf("scsi_cd.c::ioctl cmd=%08lx error=%d\n", cmd, error);
2820         }
2821         cam_periph_unlock(periph);
2822
2823         return (error);
2824 }
2825
2826 static void
2827 cdprevent(struct cam_periph *periph, int action)
2828 {
2829         union   ccb *ccb;
2830         struct  cd_softc *softc;
2831         int     error;
2832
2833         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n"));
2834
2835         softc = (struct cd_softc *)periph->softc;
2836         
2837         if (((action == PR_ALLOW)
2838           && (softc->flags & CD_FLAG_DISC_LOCKED) == 0)
2839          || ((action == PR_PREVENT)
2840           && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) {
2841                 return;
2842         }
2843             
2844         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
2845
2846         scsi_prevent(&ccb->csio, 
2847                      /*retries*/ cd_retry_count,
2848                      cddone,
2849                      MSG_SIMPLE_Q_TAG,
2850                      action,
2851                      SSD_FULL_SIZE,
2852                      /* timeout */60000);
2853         
2854         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
2855                         /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT);
2856
2857         xpt_release_ccb(ccb);
2858
2859         if (error == 0) {
2860                 if (action == PR_ALLOW)
2861                         softc->flags &= ~CD_FLAG_DISC_LOCKED;
2862                 else
2863                         softc->flags |= CD_FLAG_DISC_LOCKED;
2864         }
2865 }
2866
2867 /*
2868  * XXX: the disk media and sector size is only really able to change
2869  * XXX: while the device is closed.
2870  */
2871 static int
2872 cdcheckmedia(struct cam_periph *periph)
2873 {
2874         struct cd_softc *softc;
2875         struct ioc_toc_header *toch;
2876         struct cd_toc_single leadout;
2877         u_int32_t size, toclen;
2878         int error, num_entries, cdindex;
2879
2880         softc = (struct cd_softc *)periph->softc;
2881
2882         cdprevent(periph, PR_PREVENT);
2883         softc->disk->d_sectorsize = 2048;
2884         softc->disk->d_mediasize = 0;
2885
2886         /*
2887          * Get the disc size and block size.  If we can't get it, we don't
2888          * have media, most likely.
2889          */
2890         if ((error = cdsize(periph, &size)) != 0) {
2891                 softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC);
2892                 cdprevent(periph, PR_ALLOW);
2893                 return (error);
2894         } else {
2895                 softc->flags |= CD_FLAG_SAW_MEDIA | CD_FLAG_VALID_MEDIA;
2896                 softc->disk->d_sectorsize = softc->params.blksize;
2897                 softc->disk->d_mediasize =
2898                     (off_t)softc->params.blksize * softc->params.disksize;
2899         }
2900
2901         /*
2902          * Now we check the table of contents.  This (currently) is only
2903          * used for the CDIOCPLAYTRACKS ioctl.  It may be used later to do
2904          * things like present a separate entry in /dev for each track,
2905          * like that acd(4) driver does.
2906          */
2907         bzero(&softc->toc, sizeof(softc->toc));
2908         toch = &softc->toc.header;
2909         /*
2910          * We will get errors here for media that doesn't have a table of
2911          * contents.  According to the MMC-3 spec: "When a Read TOC/PMA/ATIP
2912          * command is presented for a DDCD/CD-R/RW media, where the first TOC
2913          * has not been recorded (no complete session) and the Format codes
2914          * 0000b, 0001b, or 0010b are specified, this command shall be rejected
2915          * with an INVALID FIELD IN CDB.  Devices that are not capable of
2916          * reading an incomplete session on DDC/CD-R/RW media shall report
2917          * CANNOT READ MEDIUM - INCOMPATIBLE FORMAT."
2918          *
2919          * So this isn't fatal if we can't read the table of contents, it
2920          * just means that the user won't be able to issue the play tracks
2921          * ioctl, and likely lots of other stuff won't work either.  They
2922          * need to burn the CD before we can do a whole lot with it.  So
2923          * we don't print anything here if we get an error back.
2924          */
2925         error = cdreadtoc(periph, 0, 0, (u_int8_t *)toch, sizeof(*toch),
2926                           SF_NO_PRINT);
2927         /*
2928          * Errors in reading the table of contents aren't fatal, we just
2929          * won't have a valid table of contents cached.
2930          */
2931         if (error != 0) {
2932                 error = 0;
2933                 bzero(&softc->toc, sizeof(softc->toc));
2934                 goto bailout;
2935         }
2936
2937         if (softc->quirks & CD_Q_BCD_TRACKS) {
2938                 toch->starting_track = bcd2bin(toch->starting_track);
2939                 toch->ending_track = bcd2bin(toch->ending_track);
2940         }
2941
2942         /* Number of TOC entries, plus leadout */
2943         num_entries = (toch->ending_track - toch->starting_track) + 2;
2944
2945         if (num_entries <= 0)
2946                 goto bailout;
2947
2948         toclen = num_entries * sizeof(struct cd_toc_entry);
2949
2950         error = cdreadtoc(periph, CD_MSF_FORMAT, toch->starting_track,
2951                           (u_int8_t *)&softc->toc, toclen + sizeof(*toch),
2952                           SF_NO_PRINT);
2953         if (error != 0) {
2954                 error = 0;
2955                 bzero(&softc->toc, sizeof(softc->toc));
2956                 goto bailout;
2957         }
2958
2959         if (softc->quirks & CD_Q_BCD_TRACKS) {
2960                 toch->starting_track = bcd2bin(toch->starting_track);
2961                 toch->ending_track = bcd2bin(toch->ending_track);
2962         }
2963         /*
2964          * XXX KDM is this necessary?  Probably only if the drive doesn't
2965          * return leadout information with the table of contents.
2966          */
2967         cdindex = toch->starting_track + num_entries -1;
2968         if (cdindex == toch->ending_track + 1) {
2969
2970                 error = cdreadtoc(periph, CD_MSF_FORMAT, LEADOUT, 
2971                                   (u_int8_t *)&leadout, sizeof(leadout),
2972                                   SF_NO_PRINT);
2973                 if (error != 0) {
2974                         error = 0;
2975                         goto bailout;
2976                 }
2977                 softc->toc.entries[cdindex - toch->starting_track] =
2978                         leadout.entry;
2979         }
2980         if (softc->quirks & CD_Q_BCD_TRACKS) {
2981                 for (cdindex = 0; cdindex < num_entries - 1; cdindex++) {
2982                         softc->toc.entries[cdindex].track =
2983                                 bcd2bin(softc->toc.entries[cdindex].track);
2984                 }
2985         }
2986
2987         softc->flags |= CD_FLAG_VALID_TOC;
2988
2989         /* If the first track is audio, correct sector size. */
2990         if ((softc->toc.entries[0].control & 4) == 0) {
2991                 softc->disk->d_sectorsize = softc->params.blksize = 2352;
2992                 softc->disk->d_mediasize =
2993                     (off_t)softc->params.blksize * softc->params.disksize;
2994         }
2995
2996 bailout:
2997
2998         /*
2999          * We unconditionally (re)set the blocksize each time the
3000          * CD device is opened.  This is because the CD can change,
3001          * and therefore the blocksize might change.
3002          * XXX problems here if some slice or partition is still
3003          * open with the old size?
3004          */
3005         if ((softc->disk->d_devstat->flags & DEVSTAT_BS_UNAVAILABLE) != 0)
3006                 softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE;
3007         softc->disk->d_devstat->block_size = softc->params.blksize;
3008
3009         return (error);
3010 }
3011
3012 static int
3013 cdsize(struct cam_periph *periph, u_int32_t *size)
3014 {
3015         struct cd_softc *softc;
3016         union ccb *ccb;
3017         struct scsi_read_capacity_data *rcap_buf;
3018         int error;
3019
3020         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n"));
3021
3022         softc = (struct cd_softc *)periph->softc;
3023              
3024         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3025
3026         /* XXX Should be M_WAITOK */
3027         rcap_buf = malloc(sizeof(struct scsi_read_capacity_data), 
3028                           M_SCSICD, M_NOWAIT | M_ZERO);
3029         if (rcap_buf == NULL)
3030                 return (ENOMEM);
3031
3032         scsi_read_capacity(&ccb->csio, 
3033                            /*retries*/ cd_retry_count,
3034                            cddone,
3035                            MSG_SIMPLE_Q_TAG,
3036                            rcap_buf,
3037                            SSD_FULL_SIZE,
3038                            /* timeout */20000);
3039
3040         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3041                          /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT);
3042
3043         xpt_release_ccb(ccb);
3044
3045         softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1;
3046         softc->params.blksize  = scsi_4btoul(rcap_buf->length);
3047         /* Make sure we got at least some block size. */
3048         if (error == 0 && softc->params.blksize == 0)
3049                 error = EIO;
3050         /*
3051          * SCSI-3 mandates that the reported blocksize shall be 2048.
3052          * Older drives sometimes report funny values, trim it down to
3053          * 2048, or other parts of the kernel will get confused.
3054          *
3055          * XXX we leave drives alone that might report 512 bytes, as
3056          * well as drives reporting more weird sizes like perhaps 4K.
3057          */
3058         if (softc->params.blksize > 2048 && softc->params.blksize <= 2352)
3059                 softc->params.blksize = 2048;
3060
3061         free(rcap_buf, M_SCSICD);
3062         *size = softc->params.disksize;
3063
3064         return (error);
3065
3066 }
3067
3068 static int
3069 cd6byteworkaround(union ccb *ccb)
3070 {
3071         u_int8_t *cdb;
3072         struct cam_periph *periph;
3073         struct cd_softc *softc;
3074         struct cd_mode_params *params;
3075         int frozen, found;
3076
3077         periph = xpt_path_periph(ccb->ccb_h.path);
3078         softc = (struct cd_softc *)periph->softc;
3079
3080         cdb = ccb->csio.cdb_io.cdb_bytes;
3081
3082         if ((ccb->ccb_h.flags & CAM_CDB_POINTER)
3083          || ((cdb[0] != MODE_SENSE_6)
3084           && (cdb[0] != MODE_SELECT_6)))
3085                 return (0);
3086
3087         /*
3088          * Because there is no convenient place to stash the overall
3089          * cd_mode_params structure pointer, we have to grab it like this.
3090          * This means that ALL MODE_SENSE and MODE_SELECT requests in the
3091          * cd(4) driver MUST go through cdgetmode() and cdsetmode()!
3092          *
3093          * XXX It would be nice if, at some point, we could increase the
3094          * number of available peripheral private pointers.  Both pointers
3095          * are currently used in most every peripheral driver.
3096          */
3097         found = 0;
3098
3099         STAILQ_FOREACH(params, &softc->mode_queue, links) {
3100                 if (params->mode_buf == ccb->csio.data_ptr) {
3101                         found = 1;
3102                         break;
3103                 }
3104         }
3105
3106         /*
3107          * This shouldn't happen.  All mode sense and mode select
3108          * operations in the cd(4) driver MUST go through cdgetmode() and
3109          * cdsetmode()!
3110          */
3111         if (found == 0) {
3112                 xpt_print(periph->path,
3113                     "mode buffer not found in mode queue!\n");
3114                 return (0);
3115         }
3116
3117         params->cdb_size = 10;
3118         softc->minimum_command_size = 10;
3119         xpt_print(ccb->ccb_h.path,
3120             "%s(6) failed, increasing minimum CDB size to 10 bytes\n",
3121             (cdb[0] == MODE_SENSE_6) ? "MODE_SENSE" : "MODE_SELECT");
3122
3123         if (cdb[0] == MODE_SENSE_6) {
3124                 struct scsi_mode_sense_10 ms10;
3125                 struct scsi_mode_sense_6 *ms6;
3126                 int len;
3127
3128                 ms6 = (struct scsi_mode_sense_6 *)cdb;
3129
3130                 bzero(&ms10, sizeof(ms10));
3131                 ms10.opcode = MODE_SENSE_10;
3132                 ms10.byte2 = ms6->byte2;
3133                 ms10.page = ms6->page;
3134
3135                 /*
3136                  * 10 byte mode header, block descriptor,
3137                  * sizeof(union cd_pages)
3138                  */
3139                 len = sizeof(struct cd_mode_data_10);
3140                 ccb->csio.dxfer_len = len;
3141
3142                 scsi_ulto2b(len, ms10.length);
3143                 ms10.control = ms6->control;
3144                 bcopy(&ms10, cdb, 10);
3145                 ccb->csio.cdb_len = 10;
3146         } else {
3147                 struct scsi_mode_select_10 ms10;
3148                 struct scsi_mode_select_6 *ms6;
3149                 struct scsi_mode_header_6 *header6;
3150                 struct scsi_mode_header_10 *header10;
3151                 struct scsi_mode_page_header *page_header;
3152                 int blk_desc_len, page_num, page_size, len;
3153
3154                 ms6 = (struct scsi_mode_select_6 *)cdb;
3155
3156                 bzero(&ms10, sizeof(ms10));
3157                 ms10.opcode = MODE_SELECT_10;
3158                 ms10.byte2 = ms6->byte2;
3159
3160                 header6 = (struct scsi_mode_header_6 *)params->mode_buf;
3161                 header10 = (struct scsi_mode_header_10 *)params->mode_buf;
3162
3163                 page_header = find_mode_page_6(header6);
3164                 page_num = page_header->page_code;
3165
3166                 blk_desc_len = header6->blk_desc_len;
3167
3168                 page_size = cdgetpagesize(page_num);
3169
3170                 if (page_size != (page_header->page_length +
3171                     sizeof(*page_header)))
3172                         page_size = page_header->page_length +
3173                                 sizeof(*page_header);
3174
3175                 len = sizeof(*header10) + blk_desc_len + page_size;
3176
3177                 len = min(params->alloc_len, len);
3178
3179                 /*
3180                  * Since the 6 byte parameter header is shorter than the 10
3181                  * byte parameter header, we need to copy the actual mode
3182                  * page data, and the block descriptor, if any, so things wind
3183                  * up in the right place.  The regions will overlap, but
3184                  * bcopy() does the right thing.
3185                  */
3186                 bcopy(params->mode_buf + sizeof(*header6),
3187                       params->mode_buf + sizeof(*header10),
3188                       len - sizeof(*header10));
3189
3190                 /* Make sure these fields are set correctly. */
3191                 scsi_ulto2b(0, header10->data_length);
3192                 header10->medium_type = 0;
3193                 scsi_ulto2b(blk_desc_len, header10->blk_desc_len);
3194
3195                 ccb->csio.dxfer_len = len;
3196
3197                 scsi_ulto2b(len, ms10.length);
3198                 ms10.control = ms6->control;
3199                 bcopy(&ms10, cdb, 10);
3200                 ccb->csio.cdb_len = 10;
3201         }
3202
3203         frozen = (ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
3204         ccb->ccb_h.status = CAM_REQUEUE_REQ;
3205         xpt_action(ccb);
3206         if (frozen) {
3207                 cam_release_devq(ccb->ccb_h.path,
3208                                  /*relsim_flags*/0,
3209                                  /*openings*/0,
3210                                  /*timeout*/0,
3211                                  /*getcount_only*/0);
3212         }
3213
3214         return (ERESTART);
3215 }
3216
3217 static int
3218 cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
3219 {
3220         struct cd_softc *softc;
3221         struct cam_periph *periph;
3222         int error, error_code, sense_key, asc, ascq;
3223
3224         periph = xpt_path_periph(ccb->ccb_h.path);
3225         softc = (struct cd_softc *)periph->softc;
3226
3227         error = 0;
3228
3229         /*
3230          * We use a status of CAM_REQ_INVALID as shorthand -- if a 6 byte
3231          * CDB comes back with this particular error, try transforming it
3232          * into the 10 byte version.
3233          */
3234         if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) {
3235                 error = cd6byteworkaround(ccb);
3236         } else if (scsi_extract_sense_ccb(ccb,
3237             &error_code, &sense_key, &asc, &ascq)) {
3238                 if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
3239                         error = cd6byteworkaround(ccb);
3240                 else if (sense_key == SSD_KEY_UNIT_ATTENTION &&
3241                     asc == 0x28 && ascq == 0x00)
3242                         disk_media_changed(softc->disk, M_NOWAIT);
3243                 else if (sense_key == SSD_KEY_NOT_READY &&
3244                     asc == 0x3a && (softc->flags & CD_FLAG_SAW_MEDIA)) {
3245                         softc->flags &= ~CD_FLAG_SAW_MEDIA;
3246                         disk_media_gone(softc->disk, M_NOWAIT);
3247                 }
3248         }
3249
3250         if (error == ERESTART)
3251                 return (error);
3252
3253         /*
3254          * XXX
3255          * Until we have a better way of doing pack validation,
3256          * don't treat UAs as errors.
3257          */
3258         sense_flags |= SF_RETRY_UA;
3259         return (cam_periph_error(ccb, cam_flags, sense_flags, 
3260                                  &softc->saved_ccb));
3261 }
3262
3263 static void
3264 cdmediapoll(void *arg)
3265 {
3266         struct cam_periph *periph = arg;
3267         struct cd_softc *softc = periph->softc;
3268
3269         if (softc->flags & CD_FLAG_CHANGER)
3270                 return;
3271
3272         if (softc->state == CD_STATE_NORMAL && !softc->tur &&
3273             softc->outstanding_cmds == 0) {
3274                 if (cam_periph_acquire(periph) == CAM_REQ_CMP) {
3275                         softc->tur = 1;
3276                         xpt_schedule(periph, CAM_PRIORITY_NORMAL);
3277                 }
3278         }
3279         /* Queue us up again */
3280         if (cd_poll_period != 0)
3281                 callout_schedule(&softc->mediapoll_c, cd_poll_period * hz);
3282 }
3283
3284 /*
3285  * Read table of contents
3286  */
3287 static int 
3288 cdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start, 
3289           u_int8_t *data, u_int32_t len, u_int32_t sense_flags)
3290 {
3291         struct scsi_read_toc *scsi_cmd;
3292         u_int32_t ntoc;
3293         struct ccb_scsiio *csio;
3294         union ccb *ccb;
3295         int error;
3296
3297         ntoc = len;
3298         error = 0;
3299
3300         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3301
3302         csio = &ccb->csio;
3303
3304         cam_fill_csio(csio, 
3305                       /* retries */ cd_retry_count, 
3306                       /* cbfcnp */ cddone, 
3307                       /* flags */ CAM_DIR_IN,
3308                       /* tag_action */ MSG_SIMPLE_Q_TAG,
3309                       /* data_ptr */ data,
3310                       /* dxfer_len */ len,
3311                       /* sense_len */ SSD_FULL_SIZE,
3312                       sizeof(struct scsi_read_toc),
3313                       /* timeout */ 50000);
3314
3315         scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes;
3316         bzero (scsi_cmd, sizeof(*scsi_cmd));
3317
3318         if (mode == CD_MSF_FORMAT)
3319                 scsi_cmd->byte2 |= CD_MSF;
3320         scsi_cmd->from_track = start;
3321         /* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */
3322         scsi_cmd->data_len[0] = (ntoc) >> 8;
3323         scsi_cmd->data_len[1] = (ntoc) & 0xff;
3324
3325         scsi_cmd->op_code = READ_TOC;
3326
3327         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3328                          /*sense_flags*/SF_RETRY_UA | sense_flags);
3329
3330         xpt_release_ccb(ccb);
3331
3332         return(error);
3333 }
3334
3335 static int
3336 cdreadsubchannel(struct cam_periph *periph, u_int32_t mode, 
3337                  u_int32_t format, int track, 
3338                  struct cd_sub_channel_info *data, u_int32_t len) 
3339 {
3340         struct scsi_read_subchannel *scsi_cmd;
3341         struct ccb_scsiio *csio;
3342         union ccb *ccb;
3343         int error;
3344
3345         error = 0;
3346
3347         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3348
3349         csio = &ccb->csio;
3350
3351         cam_fill_csio(csio, 
3352                       /* retries */ cd_retry_count, 
3353                       /* cbfcnp */ cddone, 
3354                       /* flags */ CAM_DIR_IN,
3355                       /* tag_action */ MSG_SIMPLE_Q_TAG,
3356                       /* data_ptr */ (u_int8_t *)data,
3357                       /* dxfer_len */ len,
3358                       /* sense_len */ SSD_FULL_SIZE,
3359                       sizeof(struct scsi_read_subchannel),
3360                       /* timeout */ 50000);
3361
3362         scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes;
3363         bzero (scsi_cmd, sizeof(*scsi_cmd));
3364
3365         scsi_cmd->op_code = READ_SUBCHANNEL;
3366         if (mode == CD_MSF_FORMAT)
3367                 scsi_cmd->byte1 |= CD_MSF;
3368         scsi_cmd->byte2 = SRS_SUBQ;
3369         scsi_cmd->subchan_format = format;
3370         scsi_cmd->track = track;
3371         scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len);
3372         scsi_cmd->control = 0;
3373
3374         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3375                          /*sense_flags*/SF_RETRY_UA);
3376
3377         xpt_release_ccb(ccb);
3378
3379         return(error);
3380 }
3381
3382
3383 /*
3384  * All MODE_SENSE requests in the cd(4) driver MUST go through this
3385  * routine.  See comments in cd6byteworkaround() for details.
3386  */
3387 static int
3388 cdgetmode(struct cam_periph *periph, struct cd_mode_params *data,
3389           u_int32_t page)
3390 {
3391         struct ccb_scsiio *csio;
3392         struct cd_softc *softc;
3393         union ccb *ccb;
3394         int param_len;
3395         int error;
3396
3397         softc = (struct cd_softc *)periph->softc;
3398
3399         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3400
3401         csio = &ccb->csio;
3402
3403         data->cdb_size = softc->minimum_command_size;
3404         if (data->cdb_size < 10)
3405                 param_len = sizeof(struct cd_mode_data);
3406         else
3407                 param_len = sizeof(struct cd_mode_data_10);
3408
3409         /* Don't say we've got more room than we actually allocated */
3410         param_len = min(param_len, data->alloc_len);
3411
3412         scsi_mode_sense_len(csio,
3413                             /* retries */ cd_retry_count,
3414                             /* cbfcnp */ cddone,
3415                             /* tag_action */ MSG_SIMPLE_Q_TAG,
3416                             /* dbd */ 0,
3417                             /* page_code */ SMS_PAGE_CTRL_CURRENT,
3418                             /* page */ page,
3419                             /* param_buf */ data->mode_buf,
3420                             /* param_len */ param_len,
3421                             /* minimum_cmd_size */ softc->minimum_command_size,
3422                             /* sense_len */ SSD_FULL_SIZE,
3423                             /* timeout */ 50000);
3424
3425         /*
3426          * It would be nice not to have to do this, but there's no
3427          * available pointer in the CCB that would allow us to stuff the
3428          * mode params structure in there and retrieve it in
3429          * cd6byteworkaround(), so we can set the cdb size.  The cdb size
3430          * lets the caller know what CDB size we ended up using, so they
3431          * can find the actual mode page offset.
3432          */
3433         STAILQ_INSERT_TAIL(&softc->mode_queue, data, links);
3434
3435         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3436                          /*sense_flags*/SF_RETRY_UA);
3437
3438         xpt_release_ccb(ccb);
3439
3440         STAILQ_REMOVE(&softc->mode_queue, data, cd_mode_params, links);
3441
3442         /*
3443          * This is a bit of belt-and-suspenders checking, but if we run
3444          * into a situation where the target sends back multiple block
3445          * descriptors, we might not have enough space in the buffer to
3446          * see the whole mode page.  Better to return an error than
3447          * potentially access memory beyond our malloced region.
3448          */
3449         if (error == 0) {
3450                 u_int32_t data_len;
3451
3452                 if (data->cdb_size == 10) {
3453                         struct scsi_mode_header_10 *hdr10;
3454
3455                         hdr10 = (struct scsi_mode_header_10 *)data->mode_buf;
3456                         data_len = scsi_2btoul(hdr10->data_length);
3457                         data_len += sizeof(hdr10->data_length);
3458                 } else {
3459                         struct scsi_mode_header_6 *hdr6;
3460
3461                         hdr6 = (struct scsi_mode_header_6 *)data->mode_buf;
3462                         data_len = hdr6->data_length;
3463                         data_len += sizeof(hdr6->data_length);
3464                 }
3465
3466                 /*
3467                  * Complain if there is more mode data available than we
3468                  * allocated space for.  This could potentially happen if
3469                  * we miscalculated the page length for some reason, if the
3470                  * drive returns multiple block descriptors, or if it sets
3471                  * the data length incorrectly.
3472                  */
3473                 if (data_len > data->alloc_len) {
3474                         xpt_print(periph->path, "allocated modepage %d length "
3475                             "%d < returned length %d\n", page, data->alloc_len,
3476                             data_len);
3477                         error = ENOSPC;
3478                 }
3479         }
3480         return (error);
3481 }
3482
3483 /*
3484  * All MODE_SELECT requests in the cd(4) driver MUST go through this
3485  * routine.  See comments in cd6byteworkaround() for details.
3486  */
3487 static int
3488 cdsetmode(struct cam_periph *periph, struct cd_mode_params *data)
3489 {
3490         struct ccb_scsiio *csio;
3491         struct cd_softc *softc;
3492         union ccb *ccb;
3493         int cdb_size, param_len;
3494         int error;
3495
3496         softc = (struct cd_softc *)periph->softc;
3497
3498         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3499
3500         csio = &ccb->csio;
3501
3502         error = 0;
3503
3504         /*
3505          * If the data is formatted for the 10 byte version of the mode
3506          * select parameter list, we need to use the 10 byte CDB.
3507          * Otherwise, we use whatever the stored minimum command size.
3508          */
3509         if (data->cdb_size == 10)
3510                 cdb_size = data->cdb_size;
3511         else
3512                 cdb_size = softc->minimum_command_size;
3513
3514         if (cdb_size >= 10) {
3515                 struct scsi_mode_header_10 *mode_header;
3516                 u_int32_t data_len;
3517
3518                 mode_header = (struct scsi_mode_header_10 *)data->mode_buf;
3519
3520                 data_len = scsi_2btoul(mode_header->data_length);
3521
3522                 scsi_ulto2b(0, mode_header->data_length);
3523                 /*
3524                  * SONY drives do not allow a mode select with a medium_type
3525                  * value that has just been returned by a mode sense; use a
3526                  * medium_type of 0 (Default) instead.
3527                  */
3528                 mode_header->medium_type = 0;
3529
3530                 /*
3531                  * Pass back whatever the drive passed to us, plus the size
3532                  * of the data length field.
3533                  */
3534                 param_len = data_len + sizeof(mode_header->data_length);
3535
3536         } else {
3537                 struct scsi_mode_header_6 *mode_header;
3538
3539                 mode_header = (struct scsi_mode_header_6 *)data->mode_buf;
3540
3541                 param_len = mode_header->data_length + 1;
3542
3543                 mode_header->data_length = 0;
3544                 /*
3545                  * SONY drives do not allow a mode select with a medium_type
3546                  * value that has just been returned by a mode sense; use a
3547                  * medium_type of 0 (Default) instead.
3548                  */
3549                 mode_header->medium_type = 0;
3550         }
3551
3552         /* Don't say we've got more room than we actually allocated */
3553         param_len = min(param_len, data->alloc_len);
3554
3555         scsi_mode_select_len(csio,
3556                              /* retries */ cd_retry_count,
3557                              /* cbfcnp */ cddone,
3558                              /* tag_action */ MSG_SIMPLE_Q_TAG,
3559                              /* scsi_page_fmt */ 1,
3560                              /* save_pages */ 0,
3561                              /* param_buf */ data->mode_buf,
3562                              /* param_len */ param_len,
3563                              /* minimum_cmd_size */ cdb_size,
3564                              /* sense_len */ SSD_FULL_SIZE,
3565                              /* timeout */ 50000);
3566
3567         /* See comments in cdgetmode() and cd6byteworkaround(). */
3568         STAILQ_INSERT_TAIL(&softc->mode_queue, data, links);
3569
3570         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3571                          /*sense_flags*/SF_RETRY_UA);
3572
3573         xpt_release_ccb(ccb);
3574
3575         STAILQ_REMOVE(&softc->mode_queue, data, cd_mode_params, links);
3576
3577         return (error);
3578 }
3579
3580
3581 static int 
3582 cdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len)
3583 {
3584         struct ccb_scsiio *csio;
3585         union ccb *ccb;
3586         int error;
3587         u_int8_t cdb_len;
3588
3589         error = 0;
3590         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3591         csio = &ccb->csio;
3592         /*
3593          * Use the smallest possible command to perform the operation.
3594          */
3595         if ((len & 0xffff0000) == 0) {
3596                 /*
3597                  * We can fit in a 10 byte cdb.
3598                  */
3599                 struct scsi_play_10 *scsi_cmd;
3600
3601                 scsi_cmd = (struct scsi_play_10 *)&csio->cdb_io.cdb_bytes;
3602                 bzero (scsi_cmd, sizeof(*scsi_cmd));
3603                 scsi_cmd->op_code = PLAY_10;
3604                 scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr);
3605                 scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len);
3606                 cdb_len = sizeof(*scsi_cmd);
3607         } else  {
3608                 struct scsi_play_12 *scsi_cmd;
3609
3610                 scsi_cmd = (struct scsi_play_12 *)&csio->cdb_io.cdb_bytes;
3611                 bzero (scsi_cmd, sizeof(*scsi_cmd));
3612                 scsi_cmd->op_code = PLAY_12;
3613                 scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr);
3614                 scsi_ulto4b(len, (u_int8_t *)scsi_cmd->xfer_len);
3615                 cdb_len = sizeof(*scsi_cmd);
3616         }
3617         cam_fill_csio(csio,
3618                       /*retries*/ cd_retry_count,
3619                       cddone,
3620                       /*flags*/CAM_DIR_NONE,
3621                       MSG_SIMPLE_Q_TAG,
3622                       /*dataptr*/NULL,
3623                       /*datalen*/0,
3624                       /*sense_len*/SSD_FULL_SIZE,
3625                       cdb_len,
3626                       /*timeout*/50 * 1000);
3627
3628         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3629                          /*sense_flags*/SF_RETRY_UA);
3630
3631         xpt_release_ccb(ccb);
3632
3633         return(error);
3634 }
3635
3636 static int
3637 cdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts,
3638           u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf)
3639 {
3640         struct scsi_play_msf *scsi_cmd;
3641         struct ccb_scsiio *csio;
3642         union ccb *ccb;
3643         int error;
3644
3645         error = 0;
3646
3647         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3648
3649         csio = &ccb->csio;
3650
3651         cam_fill_csio(csio, 
3652                       /* retries */ cd_retry_count, 
3653                       /* cbfcnp */ cddone, 
3654                       /* flags */ CAM_DIR_NONE,
3655                       /* tag_action */ MSG_SIMPLE_Q_TAG,
3656                       /* data_ptr */ NULL,
3657                       /* dxfer_len */ 0,
3658                       /* sense_len */ SSD_FULL_SIZE,
3659                       sizeof(struct scsi_play_msf),
3660                       /* timeout */ 50000);
3661
3662         scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes;
3663         bzero (scsi_cmd, sizeof(*scsi_cmd));
3664
3665         scsi_cmd->op_code = PLAY_MSF;
3666         scsi_cmd->start_m = startm;
3667         scsi_cmd->start_s = starts;
3668         scsi_cmd->start_f = startf;
3669         scsi_cmd->end_m = endm;
3670         scsi_cmd->end_s = ends;
3671         scsi_cmd->end_f = endf; 
3672
3673         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3674                          /*sense_flags*/SF_RETRY_UA);
3675         
3676         xpt_release_ccb(ccb);
3677
3678         return(error);
3679 }
3680
3681
3682 static int
3683 cdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex,
3684              u_int32_t etrack, u_int32_t eindex)
3685 {
3686         struct scsi_play_track *scsi_cmd;
3687         struct ccb_scsiio *csio;
3688         union ccb *ccb;
3689         int error;
3690
3691         error = 0;
3692
3693         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3694
3695         csio = &ccb->csio;
3696
3697         cam_fill_csio(csio, 
3698                       /* retries */ cd_retry_count, 
3699                       /* cbfcnp */ cddone, 
3700                       /* flags */ CAM_DIR_NONE,
3701                       /* tag_action */ MSG_SIMPLE_Q_TAG,
3702                       /* data_ptr */ NULL,
3703                       /* dxfer_len */ 0,
3704                       /* sense_len */ SSD_FULL_SIZE,
3705                       sizeof(struct scsi_play_track),
3706                       /* timeout */ 50000);
3707
3708         scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes;
3709         bzero (scsi_cmd, sizeof(*scsi_cmd));
3710
3711         scsi_cmd->op_code = PLAY_TRACK;
3712         scsi_cmd->start_track = strack;
3713         scsi_cmd->start_index = sindex;
3714         scsi_cmd->end_track = etrack;
3715         scsi_cmd->end_index = eindex;
3716
3717         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3718                          /*sense_flags*/SF_RETRY_UA);
3719
3720         xpt_release_ccb(ccb);
3721
3722         return(error);
3723 }
3724
3725 static int
3726 cdpause(struct cam_periph *periph, u_int32_t go)
3727 {
3728         struct scsi_pause *scsi_cmd;
3729         struct ccb_scsiio *csio;
3730         union ccb *ccb;
3731         int error;
3732
3733         error = 0;
3734
3735         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3736
3737         csio = &ccb->csio;
3738
3739         cam_fill_csio(csio, 
3740                       /* retries */ cd_retry_count, 
3741                       /* cbfcnp */ cddone, 
3742                       /* flags */ CAM_DIR_NONE,
3743                       /* tag_action */ MSG_SIMPLE_Q_TAG,
3744                       /* data_ptr */ NULL,
3745                       /* dxfer_len */ 0,
3746                       /* sense_len */ SSD_FULL_SIZE,
3747                       sizeof(struct scsi_pause),
3748                       /* timeout */ 50000);
3749
3750         scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes;
3751         bzero (scsi_cmd, sizeof(*scsi_cmd));
3752
3753         scsi_cmd->op_code = PAUSE;
3754         scsi_cmd->resume = go;
3755
3756         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3757                          /*sense_flags*/SF_RETRY_UA);
3758
3759         xpt_release_ccb(ccb);
3760
3761         return(error);
3762 }
3763
3764 static int
3765 cdstartunit(struct cam_periph *periph, int load)
3766 {
3767         union ccb *ccb;
3768         int error;
3769
3770         error = 0;
3771
3772         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3773
3774         scsi_start_stop(&ccb->csio,
3775                         /* retries */ cd_retry_count,
3776                         /* cbfcnp */ cddone,
3777                         /* tag_action */ MSG_SIMPLE_Q_TAG,
3778                         /* start */ TRUE,
3779                         /* load_eject */ load,
3780                         /* immediate */ FALSE,
3781                         /* sense_len */ SSD_FULL_SIZE,
3782                         /* timeout */ 50000);
3783
3784         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3785                          /*sense_flags*/SF_RETRY_UA);
3786
3787         xpt_release_ccb(ccb);
3788
3789         return(error);
3790 }
3791
3792 static int
3793 cdstopunit(struct cam_periph *periph, u_int32_t eject)
3794 {
3795         union ccb *ccb;
3796         int error;
3797
3798         error = 0;
3799
3800         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3801
3802         scsi_start_stop(&ccb->csio,
3803                         /* retries */ cd_retry_count,
3804                         /* cbfcnp */ cddone,
3805                         /* tag_action */ MSG_SIMPLE_Q_TAG,
3806                         /* start */ FALSE,
3807                         /* load_eject */ eject,
3808                         /* immediate */ FALSE,
3809                         /* sense_len */ SSD_FULL_SIZE,
3810                         /* timeout */ 50000);
3811
3812         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3813                          /*sense_flags*/SF_RETRY_UA);
3814
3815         xpt_release_ccb(ccb);
3816
3817         return(error);
3818 }
3819
3820 static int
3821 cdsetspeed(struct cam_periph *periph, u_int32_t rdspeed, u_int32_t wrspeed)
3822 {
3823         struct scsi_set_speed *scsi_cmd;
3824         struct ccb_scsiio *csio;
3825         union ccb *ccb;
3826         int error;
3827
3828         error = 0;
3829         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3830         csio = &ccb->csio;
3831
3832         /* Preserve old behavior: units in multiples of CDROM speed */
3833         if (rdspeed < 177)
3834                 rdspeed *= 177;
3835         if (wrspeed < 177)
3836                 wrspeed *= 177;
3837
3838         cam_fill_csio(csio,
3839                       /* retries */ cd_retry_count,
3840                       /* cbfcnp */ cddone,
3841                       /* flags */ CAM_DIR_NONE,
3842                       /* tag_action */ MSG_SIMPLE_Q_TAG,
3843                       /* data_ptr */ NULL,
3844                       /* dxfer_len */ 0,
3845                       /* sense_len */ SSD_FULL_SIZE,
3846                       sizeof(struct scsi_set_speed),
3847                       /* timeout */ 50000);
3848
3849         scsi_cmd = (struct scsi_set_speed *)&csio->cdb_io.cdb_bytes;
3850         bzero(scsi_cmd, sizeof(*scsi_cmd));
3851
3852         scsi_cmd->opcode = SET_CD_SPEED;
3853         scsi_ulto2b(rdspeed, scsi_cmd->readspeed);
3854         scsi_ulto2b(wrspeed, scsi_cmd->writespeed);
3855
3856         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3857                          /*sense_flags*/SF_RETRY_UA);
3858
3859         xpt_release_ccb(ccb);
3860
3861         return(error);
3862 }
3863
3864 static int
3865 cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo)
3866 {
3867         union ccb *ccb;
3868         u_int8_t *databuf;
3869         u_int32_t lba;
3870         int error;
3871         int length;
3872
3873         error = 0;
3874         databuf = NULL;
3875         lba = 0;
3876
3877         switch (authinfo->format) {
3878         case DVD_REPORT_AGID:
3879                 length = sizeof(struct scsi_report_key_data_agid);
3880                 break;
3881         case DVD_REPORT_CHALLENGE:
3882                 length = sizeof(struct scsi_report_key_data_challenge);
3883                 break;
3884         case DVD_REPORT_KEY1:
3885                 length = sizeof(struct scsi_report_key_data_key1_key2);
3886                 break;
3887         case DVD_REPORT_TITLE_KEY:
3888                 length = sizeof(struct scsi_report_key_data_title);
3889                 /* The lba field is only set for the title key */
3890                 lba = authinfo->lba;
3891                 break;
3892         case DVD_REPORT_ASF:
3893                 length = sizeof(struct scsi_report_key_data_asf);
3894                 break;
3895         case DVD_REPORT_RPC:
3896                 length = sizeof(struct scsi_report_key_data_rpc);
3897                 break;
3898         case DVD_INVALIDATE_AGID:
3899                 length = 0;
3900                 break;
3901         default:
3902                 return (EINVAL);
3903         }
3904
3905         if (length != 0) {
3906                 databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
3907         } else
3908                 databuf = NULL;
3909
3910         cam_periph_lock(periph);
3911         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
3912
3913         scsi_report_key(&ccb->csio,
3914                         /* retries */ cd_retry_count,
3915                         /* cbfcnp */ cddone,
3916                         /* tag_action */ MSG_SIMPLE_Q_TAG,
3917                         /* lba */ lba,
3918                         /* agid */ authinfo->agid,
3919                         /* key_format */ authinfo->format,
3920                         /* data_ptr */ databuf,
3921                         /* dxfer_len */ length,
3922                         /* sense_len */ SSD_FULL_SIZE,
3923                         /* timeout */ 50000);
3924
3925         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
3926                          /*sense_flags*/SF_RETRY_UA);
3927
3928         if (error != 0)
3929                 goto bailout;
3930
3931         if (ccb->csio.resid != 0) {
3932                 xpt_print(periph->path, "warning, residual for report key "
3933                     "command is %d\n", ccb->csio.resid);
3934         }
3935
3936         switch(authinfo->format) {
3937         case DVD_REPORT_AGID: {
3938                 struct scsi_report_key_data_agid *agid_data;
3939
3940                 agid_data = (struct scsi_report_key_data_agid *)databuf;
3941
3942                 authinfo->agid = (agid_data->agid & RKD_AGID_MASK) >>
3943                         RKD_AGID_SHIFT;
3944                 break;
3945         }
3946         case DVD_REPORT_CHALLENGE: {
3947                 struct scsi_report_key_data_challenge *chal_data;
3948
3949                 chal_data = (struct scsi_report_key_data_challenge *)databuf;
3950
3951                 bcopy(chal_data->challenge_key, authinfo->keychal,
3952                       min(sizeof(chal_data->challenge_key),
3953                           sizeof(authinfo->keychal)));
3954                 break;
3955         }
3956         case DVD_REPORT_KEY1: {
3957                 struct scsi_report_key_data_key1_key2 *key1_data;
3958
3959                 key1_data = (struct scsi_report_key_data_key1_key2 *)databuf;
3960
3961                 bcopy(key1_data->key1, authinfo->keychal,
3962                       min(sizeof(key1_data->key1), sizeof(authinfo->keychal)));
3963                 break;
3964         }
3965         case DVD_REPORT_TITLE_KEY: {
3966                 struct scsi_report_key_data_title *title_data;
3967
3968                 title_data = (struct scsi_report_key_data_title *)databuf;
3969
3970                 authinfo->cpm = (title_data->byte0 & RKD_TITLE_CPM) >>
3971                         RKD_TITLE_CPM_SHIFT;
3972                 authinfo->cp_sec = (title_data->byte0 & RKD_TITLE_CP_SEC) >>
3973                         RKD_TITLE_CP_SEC_SHIFT;
3974                 authinfo->cgms = (title_data->byte0 & RKD_TITLE_CMGS_MASK) >>
3975                         RKD_TITLE_CMGS_SHIFT;
3976                 bcopy(title_data->title_key, authinfo->keychal,
3977                       min(sizeof(title_data->title_key),
3978                           sizeof(authinfo->keychal)));
3979                 break;
3980         }
3981         case DVD_REPORT_ASF: {
3982                 struct scsi_report_key_data_asf *asf_data;
3983
3984                 asf_data = (struct scsi_report_key_data_asf *)databuf;
3985
3986                 authinfo->asf = asf_data->success & RKD_ASF_SUCCESS;
3987                 break;
3988         }
3989         case DVD_REPORT_RPC: {
3990                 struct scsi_report_key_data_rpc *rpc_data;
3991
3992                 rpc_data = (struct scsi_report_key_data_rpc *)databuf;
3993
3994                 authinfo->reg_type = (rpc_data->byte4 & RKD_RPC_TYPE_MASK) >>
3995                         RKD_RPC_TYPE_SHIFT;
3996                 authinfo->vend_rsts =
3997                         (rpc_data->byte4 & RKD_RPC_VENDOR_RESET_MASK) >>
3998                         RKD_RPC_VENDOR_RESET_SHIFT;
3999                 authinfo->user_rsts = rpc_data->byte4 & RKD_RPC_USER_RESET_MASK;
4000                 authinfo->region = rpc_data->region_mask;
4001                 authinfo->rpc_scheme = rpc_data->rpc_scheme1;
4002                 break;
4003         }
4004         case DVD_INVALIDATE_AGID:
4005                 break;
4006         default:
4007                 /* This should be impossible, since we checked above */
4008                 error = EINVAL;
4009                 goto bailout;
4010                 break; /* NOTREACHED */
4011         }
4012
4013 bailout:
4014         xpt_release_ccb(ccb);
4015         cam_periph_unlock(periph);
4016
4017         if (databuf != NULL)
4018                 free(databuf, M_DEVBUF);
4019
4020         return(error);
4021 }
4022
4023 static int
4024 cdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo)
4025 {
4026         union ccb *ccb;
4027         u_int8_t *databuf;
4028         int length;
4029         int error;
4030
4031         error = 0;
4032         databuf = NULL;
4033
4034         switch(authinfo->format) {
4035         case DVD_SEND_CHALLENGE: {
4036                 struct scsi_report_key_data_challenge *challenge_data;
4037
4038                 length = sizeof(*challenge_data);
4039
4040                 challenge_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
4041
4042                 databuf = (u_int8_t *)challenge_data;
4043
4044                 scsi_ulto2b(length - sizeof(challenge_data->data_len),
4045                             challenge_data->data_len);
4046
4047                 bcopy(authinfo->keychal, challenge_data->challenge_key,
4048                       min(sizeof(authinfo->keychal),
4049                           sizeof(challenge_data->challenge_key)));
4050                 break;
4051         }
4052         case DVD_SEND_KEY2: {
4053                 struct scsi_report_key_data_key1_key2 *key2_data;
4054
4055                 length = sizeof(*key2_data);
4056
4057                 key2_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
4058
4059                 databuf = (u_int8_t *)key2_data;
4060
4061                 scsi_ulto2b(length - sizeof(key2_data->data_len),
4062                             key2_data->data_len);
4063
4064                 bcopy(authinfo->keychal, key2_data->key1,
4065                       min(sizeof(authinfo->keychal), sizeof(key2_data->key1)));
4066
4067                 break;
4068         }
4069         case DVD_SEND_RPC: {
4070                 struct scsi_send_key_data_rpc *rpc_data;
4071
4072                 length = sizeof(*rpc_data);
4073
4074                 rpc_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
4075
4076                 databuf = (u_int8_t *)rpc_data;
4077
4078                 scsi_ulto2b(length - sizeof(rpc_data->data_len),
4079                             rpc_data->data_len);
4080
4081                 rpc_data->region_code = authinfo->region;
4082                 break;
4083         }
4084         default:
4085                 return (EINVAL);
4086         }
4087
4088         cam_periph_lock(periph);
4089         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
4090
4091         scsi_send_key(&ccb->csio,
4092                       /* retries */ cd_retry_count,
4093                       /* cbfcnp */ cddone,
4094                       /* tag_action */ MSG_SIMPLE_Q_TAG,
4095                       /* agid */ authinfo->agid,
4096                       /* key_format */ authinfo->format,
4097                       /* data_ptr */ databuf,
4098                       /* dxfer_len */ length,
4099                       /* sense_len */ SSD_FULL_SIZE,
4100                       /* timeout */ 50000);
4101
4102         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
4103                          /*sense_flags*/SF_RETRY_UA);
4104
4105         xpt_release_ccb(ccb);
4106         cam_periph_unlock(periph);
4107
4108         if (databuf != NULL)
4109                 free(databuf, M_DEVBUF);
4110
4111         return(error);
4112 }
4113
4114 static int
4115 cdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct)
4116 {
4117         union ccb *ccb;
4118         u_int8_t *databuf;
4119         u_int32_t address;
4120         int error;
4121         int length;
4122
4123         error = 0;
4124         databuf = NULL;
4125         /* The address is reserved for many of the formats */
4126         address = 0;
4127
4128         switch(dvdstruct->format) {
4129         case DVD_STRUCT_PHYSICAL:
4130                 length = sizeof(struct scsi_read_dvd_struct_data_physical);
4131                 break;
4132         case DVD_STRUCT_COPYRIGHT:
4133                 length = sizeof(struct scsi_read_dvd_struct_data_copyright);
4134                 break;
4135         case DVD_STRUCT_DISCKEY:
4136                 length = sizeof(struct scsi_read_dvd_struct_data_disc_key);
4137                 break;
4138         case DVD_STRUCT_BCA:
4139                 length = sizeof(struct scsi_read_dvd_struct_data_bca);
4140                 break;
4141         case DVD_STRUCT_MANUFACT:
4142                 length = sizeof(struct scsi_read_dvd_struct_data_manufacturer);
4143                 break;
4144         case DVD_STRUCT_CMI:
4145                 return (ENODEV);
4146         case DVD_STRUCT_PROTDISCID:
4147                 length = sizeof(struct scsi_read_dvd_struct_data_prot_discid);
4148                 break;
4149         case DVD_STRUCT_DISCKEYBLOCK:
4150                 length = sizeof(struct scsi_read_dvd_struct_data_disc_key_blk);
4151                 break;
4152         case DVD_STRUCT_DDS:
4153                 length = sizeof(struct scsi_read_dvd_struct_data_dds);
4154                 break;
4155         case DVD_STRUCT_MEDIUM_STAT:
4156                 length = sizeof(struct scsi_read_dvd_struct_data_medium_status);
4157                 break;
4158         case DVD_STRUCT_SPARE_AREA:
4159                 length = sizeof(struct scsi_read_dvd_struct_data_spare_area);
4160                 break;
4161         case DVD_STRUCT_RMD_LAST:
4162                 return (ENODEV);
4163         case DVD_STRUCT_RMD_RMA:
4164                 return (ENODEV);
4165         case DVD_STRUCT_PRERECORDED:
4166                 length = sizeof(struct scsi_read_dvd_struct_data_leadin);
4167                 break;
4168         case DVD_STRUCT_UNIQUEID:
4169                 length = sizeof(struct scsi_read_dvd_struct_data_disc_id);
4170                 break;
4171         case DVD_STRUCT_DCB:
4172                 return (ENODEV);
4173         case DVD_STRUCT_LIST:
4174                 /*
4175                  * This is the maximum allocation length for the READ DVD
4176                  * STRUCTURE command.  There's nothing in the MMC3 spec
4177                  * that indicates a limit in the amount of data that can
4178                  * be returned from this call, other than the limits
4179                  * imposed by the 2-byte length variables.
4180                  */
4181                 length = 65535;
4182                 break;
4183         default:
4184                 return (EINVAL);
4185         }
4186
4187         if (length != 0) {
4188                 databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
4189         } else
4190                 databuf = NULL;
4191
4192         cam_periph_lock(periph);
4193         ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
4194
4195         scsi_read_dvd_structure(&ccb->csio,
4196                                 /* retries */ cd_retry_count,
4197                                 /* cbfcnp */ cddone,
4198                                 /* tag_action */ MSG_SIMPLE_Q_TAG,
4199                                 /* lba */ address,
4200                                 /* layer_number */ dvdstruct->layer_num,
4201                                 /* key_format */ dvdstruct->format,
4202                                 /* agid */ dvdstruct->agid,
4203                                 /* data_ptr */ databuf,
4204                                 /* dxfer_len */ length,
4205                                 /* sense_len */ SSD_FULL_SIZE,
4206                                 /* timeout */ 50000);
4207
4208         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
4209                          /*sense_flags*/SF_RETRY_UA);
4210
4211         if (error != 0)
4212                 goto bailout;
4213
4214         switch(dvdstruct->format) {
4215         case DVD_STRUCT_PHYSICAL: {
4216                 struct scsi_read_dvd_struct_data_layer_desc *inlayer;
4217                 struct dvd_layer *outlayer;
4218                 struct scsi_read_dvd_struct_data_physical *phys_data;
4219
4220                 phys_data =
4221                         (struct scsi_read_dvd_struct_data_physical *)databuf;
4222                 inlayer = &phys_data->layer_desc;
4223                 outlayer = (struct dvd_layer *)&dvdstruct->data;
4224
4225                 dvdstruct->length = sizeof(*inlayer);
4226
4227                 outlayer->book_type = (inlayer->book_type_version &
4228                         RDSD_BOOK_TYPE_MASK) >> RDSD_BOOK_TYPE_SHIFT;
4229                 outlayer->book_version = (inlayer->book_type_version &
4230                         RDSD_BOOK_VERSION_MASK);
4231                 outlayer->disc_size = (inlayer->disc_size_max_rate &
4232                         RDSD_DISC_SIZE_MASK) >> RDSD_DISC_SIZE_SHIFT;
4233                 outlayer->max_rate = (inlayer->disc_size_max_rate &
4234                         RDSD_MAX_RATE_MASK);
4235                 outlayer->nlayers = (inlayer->layer_info &
4236                         RDSD_NUM_LAYERS_MASK) >> RDSD_NUM_LAYERS_SHIFT;
4237                 outlayer->track_path = (inlayer->layer_info &
4238                         RDSD_TRACK_PATH_MASK) >> RDSD_TRACK_PATH_SHIFT;
4239                 outlayer->layer_type = (inlayer->layer_info &
4240                         RDSD_LAYER_TYPE_MASK);
4241                 outlayer->linear_density = (inlayer->density &
4242                         RDSD_LIN_DENSITY_MASK) >> RDSD_LIN_DENSITY_SHIFT;
4243                 outlayer->track_density = (inlayer->density &
4244                         RDSD_TRACK_DENSITY_MASK);
4245                 outlayer->bca = (inlayer->bca & RDSD_BCA_MASK) >>
4246                         RDSD_BCA_SHIFT;
4247                 outlayer->start_sector = scsi_3btoul(inlayer->main_data_start);
4248                 outlayer->end_sector = scsi_3btoul(inlayer->main_data_end);
4249                 outlayer->end_sector_l0 =
4250                         scsi_3btoul(inlayer->end_sector_layer0);
4251                 break;
4252         }
4253         case DVD_STRUCT_COPYRIGHT: {
4254                 struct scsi_read_dvd_struct_data_copyright *copy_data;
4255
4256                 copy_data = (struct scsi_read_dvd_struct_data_copyright *)
4257                         databuf;
4258
4259                 dvdstruct->cpst = copy_data->cps_type;
4260                 dvdstruct->rmi = copy_data->region_info;
4261                 dvdstruct->length = 0;
4262
4263                 break;
4264         }
4265         default:
4266                 /*
4267                  * Tell the user what the overall length is, no matter
4268                  * what we can actually fit in the data buffer.
4269                  */
4270                 dvdstruct->length = length - ccb->csio.resid - 
4271                         sizeof(struct scsi_read_dvd_struct_data_header);
4272
4273                 /*
4274                  * But only actually copy out the smaller of what we read
4275                  * in or what the structure can take.
4276                  */
4277                 bcopy(databuf + sizeof(struct scsi_read_dvd_struct_data_header),
4278                       dvdstruct->data,
4279                       min(sizeof(dvdstruct->data), dvdstruct->length));
4280                 break;
4281         }
4282
4283 bailout:
4284         xpt_release_ccb(ccb);
4285         cam_periph_unlock(periph);
4286
4287         if (databuf != NULL)
4288                 free(databuf, M_DEVBUF);
4289
4290         return(error);
4291 }
4292
4293 void
4294 scsi_report_key(struct ccb_scsiio *csio, u_int32_t retries,
4295                 void (*cbfcnp)(struct cam_periph *, union ccb *),
4296                 u_int8_t tag_action, u_int32_t lba, u_int8_t agid,
4297                 u_int8_t key_format, u_int8_t *data_ptr, u_int32_t dxfer_len,
4298                 u_int8_t sense_len, u_int32_t timeout)
4299 {
4300         struct scsi_report_key *scsi_cmd;
4301
4302         scsi_cmd = (struct scsi_report_key *)&csio->cdb_io.cdb_bytes;
4303         bzero(scsi_cmd, sizeof(*scsi_cmd));
4304         scsi_cmd->opcode = REPORT_KEY;
4305         scsi_ulto4b(lba, scsi_cmd->lba);
4306         scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len);
4307         scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) |
4308                 (key_format & RK_KF_KEYFORMAT_MASK);
4309
4310         cam_fill_csio(csio,
4311                       retries,
4312                       cbfcnp,
4313                       /*flags*/ (dxfer_len == 0) ? CAM_DIR_NONE : CAM_DIR_IN,
4314                       tag_action,
4315                       /*data_ptr*/ data_ptr,
4316                       /*dxfer_len*/ dxfer_len,
4317                       sense_len,
4318                       sizeof(*scsi_cmd),
4319                       timeout);
4320 }
4321
4322 void
4323 scsi_send_key(struct ccb_scsiio *csio, u_int32_t retries,
4324               void (*cbfcnp)(struct cam_periph *, union ccb *),
4325               u_int8_t tag_action, u_int8_t agid, u_int8_t key_format,
4326               u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
4327               u_int32_t timeout)
4328 {
4329         struct scsi_send_key *scsi_cmd;
4330
4331         scsi_cmd = (struct scsi_send_key *)&csio->cdb_io.cdb_bytes;
4332         bzero(scsi_cmd, sizeof(*scsi_cmd));
4333         scsi_cmd->opcode = SEND_KEY;
4334
4335         scsi_ulto2b(dxfer_len, scsi_cmd->param_len);
4336         scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) |
4337                 (key_format & RK_KF_KEYFORMAT_MASK);
4338
4339         cam_fill_csio(csio,
4340                       retries,
4341                       cbfcnp,
4342                       /*flags*/ CAM_DIR_OUT,
4343                       tag_action,
4344                       /*data_ptr*/ data_ptr,
4345                       /*dxfer_len*/ dxfer_len,
4346                       sense_len,
4347                       sizeof(*scsi_cmd),
4348                       timeout);
4349 }
4350
4351
4352 void
4353 scsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries,
4354                         void (*cbfcnp)(struct cam_periph *, union ccb *),
4355                         u_int8_t tag_action, u_int32_t address,
4356                         u_int8_t layer_number, u_int8_t format, u_int8_t agid,
4357                         u_int8_t *data_ptr, u_int32_t dxfer_len,
4358                         u_int8_t sense_len, u_int32_t timeout)
4359 {
4360         struct scsi_read_dvd_structure *scsi_cmd;
4361
4362         scsi_cmd = (struct scsi_read_dvd_structure *)&csio->cdb_io.cdb_bytes;
4363         bzero(scsi_cmd, sizeof(*scsi_cmd));
4364         scsi_cmd->opcode = READ_DVD_STRUCTURE;
4365
4366         scsi_ulto4b(address, scsi_cmd->address);
4367         scsi_cmd->layer_number = layer_number;
4368         scsi_cmd->format = format;
4369         scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len);
4370         /* The AGID is the top two bits of this byte */
4371         scsi_cmd->agid = agid << 6;
4372
4373         cam_fill_csio(csio,
4374                       retries,
4375                       cbfcnp,
4376                       /*flags*/ CAM_DIR_IN,
4377                       tag_action,
4378                       /*data_ptr*/ data_ptr,
4379                       /*dxfer_len*/ dxfer_len,
4380                       sense_len,
4381                       sizeof(*scsi_cmd),
4382                       timeout);
4383 }