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