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