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