[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/cam/scsi/scsi_cd.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*-
  2  * Copyright (c) 1997 Justin T. Gibbs.
  3  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Kenneth D. Merry.
  4  * All rights reserved.
  5  *
  6  * Redistribution and use in source and binary forms, with or without
  7  * modification, are permitted provided that the following conditions
  8  * are met:
  9  * 1. Redistributions of source code must retain the above copyright
 10  *    notice, this list of conditions, and the following disclaimer,
 11  *    without modification, immediately at the beginning of the file.
 12  * 2. The name of the author may not be used to endorse or promote products
 13  *    derived from this software without specific prior written permission.
 14  *
 15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 25  * SUCH DAMAGE.
 26  */
 27 
 28 /*-
 29  * Portions of this driver taken from the original FreeBSD cd driver.
 30  * Written by Julian Elischer (julian@tfs.com)
 31  * for TRW Financial Systems for use under the MACH(2.5) operating system.
 32  *
 33  * TRW Financial Systems, in accordance with their agreement with Carnegie
 34  * Mellon University, makes this software available to CMU to distribute
 35  * or use in any manner that they see fit as long as this message is kept with
 36  * the software. For this reason TFS also grants any other persons or
 37  * organisations permission to use or modify this software.
 38  *
 39  * TFS supplies this software to be publicly redistributed
 40  * on the understanding that TFS is not responsible for the correct
 41  * functioning of this software in any circumstances.
 42  *
 43  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
 44  *
 45  *      from: cd.c,v 1.83 1997/05/04 15:24:22 joerg Exp $
 46  */
 47 
 48 #include <sys/cdefs.h>
 49 __FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_cd.c,v 1.104 2009/01/08 00:45:47 imp Exp $");
 50 
 51 #include "opt_cd.h"
 52 
 53 #include <sys/param.h>
 54 #include <sys/systm.h>
 55 #include <sys/kernel.h>
 56 #include <sys/bio.h>
 57 #include <sys/conf.h>
 58 #include <sys/disk.h>
 59 #include <sys/malloc.h>
 60 #include <sys/cdio.h>
 61 #include <sys/cdrio.h>
 62 #include <sys/dvdio.h>
 63 #include <sys/devicestat.h>
 64 #include <sys/sysctl.h>
 65 #include <sys/taskqueue.h>
 66 #include <geom/geom_disk.h>
 67 
 68 #include <cam/cam.h>
 69 #include <cam/cam_ccb.h>
 70 #include <cam/cam_periph.h>
 71 #include <cam/cam_xpt_periph.h>
 72 #include <cam/cam_queue.h>
 73 #include <cam/cam_sim.h>
 74 
 75 #include <cam/scsi/scsi_message.h>
 76 #include <cam/scsi/scsi_da.h>
 77 #include <cam/scsi/scsi_cd.h>
 78 
 79 #define LEADOUT         0xaa            /* leadout toc entry */
 80 
 81 struct cd_params {
 82         u_int32_t blksize;
 83         u_long    disksize;
 84 };
 85 
 86 typedef enum {
 87         CD_Q_NONE               = 0x00,
 88         CD_Q_NO_TOUCH           = 0x01,
 89         CD_Q_BCD_TRACKS         = 0x02,
 90         CD_Q_NO_CHANGER         = 0x04,
 91         CD_Q_CHANGER            = 0x08,
 92         CD_Q_10_BYTE_ONLY       = 0x10
 93 } cd_quirks;
 94 
 95 typedef enum {
 96         CD_FLAG_INVALID         = 0x0001,
 97         CD_FLAG_NEW_DISC        = 0x0002,
 98         CD_FLAG_DISC_LOCKED     = 0x0004,
 99         CD_FLAG_DISC_REMOVABLE  = 0x0008,
100         CD_FLAG_TAGGED_QUEUING  = 0x0010,
101         CD_FLAG_CHANGER         = 0x0040,
102         CD_FLAG_ACTIVE          = 0x0080,
103         CD_FLAG_SCHED_ON_COMP   = 0x0100,
104         CD_FLAG_RETRY_UA        = 0x0200,
105         CD_FLAG_VALID_MEDIA     = 0x0400,
106         CD_FLAG_VALID_TOC       = 0x0800,
107         CD_FLAG_SCTX_INIT       = 0x1000,
108         CD_FLAG_OPEN            = 0x2000
109 } cd_flags;
110 
111 typedef enum {
112         CD_CCB_PROBE            = 0x01,
113         CD_CCB_BUFFER_IO        = 0x02,
114         CD_CCB_WAITING          = 0x03,
115         CD_CCB_TYPE_MASK        = 0x0F,
116         CD_CCB_RETRY_UA         = 0x10
117 } cd_ccb_state;
118 
119 typedef enum {
120         CHANGER_TIMEOUT_SCHED           = 0x01,
121         CHANGER_SHORT_TMOUT_SCHED       = 0x02,
122         CHANGER_MANUAL_CALL             = 0x04,
123         CHANGER_NEED_TIMEOUT            = 0x08
124 } cd_changer_flags;
125 
126 #define ccb_state ppriv_field0
127 #define ccb_bp ppriv_ptr1
128 
129 struct cd_tocdata {
130         struct ioc_toc_header header;
131         struct cd_toc_entry entries[100];
132 };
133 
134 struct cd_toc_single {
135         struct ioc_toc_header header;
136         struct cd_toc_entry entry;
137 };
138 
139 typedef enum {
140         CD_STATE_PROBE,
141         CD_STATE_NORMAL
142 } cd_state;
143 
144 struct cd_softc {
145         cam_pinfo               pinfo;
146         cd_state                state;
147         volatile cd_flags       flags;
148         struct bio_queue_head   bio_queue;
149         LIST_HEAD(, ccb_hdr)    pending_ccbs;
150         struct cd_params        params;
151         union ccb               saved_ccb;
152         cd_quirks               quirks;
153         STAILQ_ENTRY(cd_softc)  changer_links;
154         struct cdchanger        *changer;
155         int                     bufs_left;
156         struct cam_periph       *periph;
157         int                     minimum_command_size;
158         int                     outstanding_cmds;
159         struct task             sysctl_task;
160         struct sysctl_ctx_list  sysctl_ctx;
161         struct sysctl_oid       *sysctl_tree;
162         STAILQ_HEAD(, cd_mode_params)   mode_queue;
163         struct cd_tocdata       toc;
164         struct disk             *disk;
165 };
166 
167 struct cd_page_sizes {
168         int page;
169         int page_size;
170 };
171 
172 static struct cd_page_sizes cd_page_size_table[] =
173 {
174         { AUDIO_PAGE, sizeof(struct cd_audio_page)}
175 };
176 
177 struct cd_quirk_entry {
178         struct scsi_inquiry_pattern inq_pat;
179         cd_quirks quirks;
180 };
181 
182 /*
183  * The changer quirk entries aren't strictly necessary.  Basically, what
184  * they do is tell cdregister() up front that a device is a changer.
185  * Otherwise, it will figure that fact out once it sees a LUN on the device
186  * that is greater than 0.  If it is known up front that a device is a changer,
187  * all I/O to the device will go through the changer scheduling routines, as
188  * opposed to the "normal" CD code.
189  *
190  * NOTE ON 10_BYTE_ONLY quirks:  Any 10_BYTE_ONLY quirks MUST be because
191  * your device hangs when it gets a 10 byte command.  Adding a quirk just
192  * to get rid of the informative diagnostic message is not acceptable.  All
193  * 10_BYTE_ONLY quirks must be documented in full in a PR (which should be
194  * referenced in a comment along with the quirk) , and must be approved by
195  * ken@FreeBSD.org.  Any quirks added that don't adhere to this policy may
196  * be removed until the submitter can explain why they are needed.
197  * 10_BYTE_ONLY quirks will be removed (as they will no longer be necessary)
198  * when the CAM_NEW_TRAN_CODE work is done.
199  */
200 static struct cd_quirk_entry cd_quirk_table[] =
201 {
202         {
203                 { T_CDROM, SIP_MEDIA_REMOVABLE, "NRC", "MBR-7", "*"},
204                  /*quirks*/ CD_Q_CHANGER
205         },
206         {
207                 { T_CDROM, SIP_MEDIA_REMOVABLE, "PIONEER", "CD-ROM DRM*",
208                   "*"}, /* quirks */ CD_Q_CHANGER
209         },
210         {
211                 { T_CDROM, SIP_MEDIA_REMOVABLE, "NAKAMICH", "MJ-*", "*"},
212                  /* quirks */ CD_Q_CHANGER
213         },
214         {
215                 { T_CDROM, SIP_MEDIA_REMOVABLE, "CHINON", "CD-ROM CDS-535","*"},
216                 /* quirks */ CD_Q_BCD_TRACKS
217         }
218 };
219 
220 static  disk_open_t     cdopen;
221 static  disk_close_t    cdclose;
222 static  disk_ioctl_t    cdioctl;
223 static  disk_strategy_t cdstrategy;
224 
225 static  periph_init_t   cdinit;
226 static  periph_ctor_t   cdregister;
227 static  periph_dtor_t   cdcleanup;
228 static  periph_start_t  cdstart;
229 static  periph_oninv_t  cdoninvalidate;
230 static  void            cdasync(void *callback_arg, u_int32_t code,
231                                 struct cam_path *path, void *arg);
232 static  int             cdcmdsizesysctl(SYSCTL_HANDLER_ARGS);
233 static  void            cdshorttimeout(void *arg);
234 static  void            cdschedule(struct cam_periph *periph, int priority);
235 static  void            cdrunchangerqueue(void *arg);
236 static  void            cdchangerschedule(struct cd_softc *softc);
237 static  int             cdrunccb(union ccb *ccb,
238                                  int (*error_routine)(union ccb *ccb,
239                                                       u_int32_t cam_flags,
240                                                       u_int32_t sense_flags),
241                                  u_int32_t cam_flags, u_int32_t sense_flags);
242 static  union ccb       *cdgetccb(struct cam_periph *periph,
243                                   u_int32_t priority);
244 static  void            cddone(struct cam_periph *periph,
245                                union ccb *start_ccb);
246 static  union cd_pages  *cdgetpage(struct cd_mode_params *mode_params);
247 static  int             cdgetpagesize(int page_num);
248 static  void            cdprevent(struct cam_periph *periph, int action);
249 static  int             cdcheckmedia(struct cam_periph *periph);
250 static  int             cdsize(struct cam_periph *periph, u_int32_t *size);
251 static  int             cd6byteworkaround(union ccb *ccb);
252 static  int             cderror(union ccb *ccb, u_int32_t cam_flags,
253                                 u_int32_t sense_flags);
254 static  int             cdreadtoc(struct cam_periph *periph, u_int32_t mode, 
255                                   u_int32_t start, u_int8_t *data, 
256                                   u_int32_t len, u_int32_t sense_flags);
257 static  int             cdgetmode(struct cam_periph *periph, 
258                                   struct cd_mode_params *data, u_int32_t page);
259 static  int             cdsetmode(struct cam_periph *periph,
260                                   struct cd_mode_params *data);
261 static  int             cdplay(struct cam_periph *periph, u_int32_t blk, 
262                                u_int32_t len);
263 static  int             cdreadsubchannel(struct cam_periph *periph, 
264                                          u_int32_t mode, u_int32_t format, 
265                                          int track, 
266                                          struct cd_sub_channel_info *data, 
267                                          u_int32_t len);
268 static  int             cdplaymsf(struct cam_periph *periph, u_int32_t startm, 
269                                   u_int32_t starts, u_int32_t startf, 
270                                   u_int32_t endm, u_int32_t ends, 
271                                   u_int32_t endf);
272 static  int             cdplaytracks(struct cam_periph *periph, 
273                                      u_int32_t strack, u_int32_t sindex,
274                                      u_int32_t etrack, u_int32_t eindex);
275 static  int             cdpause(struct cam_periph *periph, u_int32_t go);
276 static  int             cdstopunit(struct cam_periph *periph, u_int32_t eject);
277 static  int             cdstartunit(struct cam_periph *periph, int load);
278 static  int             cdsetspeed(struct cam_periph *periph,
279                                    u_int32_t rdspeed, u_int32_t wrspeed);
280 static  int             cdreportkey(struct cam_periph *periph,
281                                     struct dvd_authinfo *authinfo);
282 static  int             cdsendkey(struct cam_periph *periph,
283                                   struct dvd_authinfo *authinfo);
284 static  int             cdreaddvdstructure(struct cam_periph *periph,
285                                            struct dvd_struct *dvdstruct);
286 
287 static struct periph_driver cddriver =
288 {
289         cdinit, "cd",
290         TAILQ_HEAD_INITIALIZER(cddriver.units), /* generation */ 0
291 };
292 
293 PERIPHDRIVER_DECLARE(cd, cddriver);
294 
295 #ifndef CD_DEFAULT_RETRY
296 #define CD_DEFAULT_RETRY        4
297 #endif
298 #ifndef CHANGER_MIN_BUSY_SECONDS
299 #define CHANGER_MIN_BUSY_SECONDS        5
300 #endif
301 #ifndef CHANGER_MAX_BUSY_SECONDS
302 #define CHANGER_MAX_BUSY_SECONDS        15
303 #endif
304 
305 static int cd_retry_count = CD_DEFAULT_RETRY;
306 static int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS;
307 static int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS;
308 
309 SYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver");
310 SYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0, "CD Changer");
311 SYSCTL_INT(_kern_cam_cd, OID_AUTO, retry_count, CTLFLAG_RW,
312            &cd_retry_count, 0, "Normal I/O retry count");
313 TUNABLE_INT("kern.cam.cd.retry_count", &cd_retry_count);
314 SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW,
315            &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum");
316 TUNABLE_INT("kern.cam.cd.changer.min_busy_seconds", &changer_min_busy_seconds);
317 SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, max_busy_seconds, CTLFLAG_RW,
318            &changer_max_busy_seconds, 0, "Maximum changer scheduling quantum");
319 TUNABLE_INT("kern.cam.cd.changer.max_busy_seconds", &changer_max_busy_seconds);
320 
321 struct cdchanger {
322         path_id_t                        path_id;
323         target_id_t                      target_id;
324         int                              num_devices;
325         struct camq                      devq;
326         struct timeval                   start_time;
327         struct cd_softc                  *cur_device;
328         struct callout                   short_handle;
329         struct callout                   long_handle;
330         volatile cd_changer_flags        flags;
331         STAILQ_ENTRY(cdchanger)          changer_links;
332         STAILQ_HEAD(chdevlist, cd_softc) chluns;
333 };
334 
335 static struct mtx changerq_mtx;
336 static STAILQ_HEAD(changerlist, cdchanger) changerq;
337 static int num_changers;
338 
339 MALLOC_DEFINE(M_SCSICD, "scsi_cd", "scsi_cd buffers");
340 
341 static void
342 cdinit(void)
343 {
344         cam_status status;
345 
346         mtx_init(&changerq_mtx, "cdchangerq", "SCSI CD Changer List", MTX_DEF);
347         STAILQ_INIT(&changerq);
348 
349         /*
350          * Install a global async callback.  This callback will
351          * receive async callbacks like "new device found".
352          */
353         status = xpt_register_async(AC_FOUND_DEVICE, cdasync, NULL, NULL);
354 
355         if (status != CAM_REQ_CMP) {
356                 printf("cd: Failed to attach master async callback "
357                        "due to status 0x%x!\n", status);
358         }
359 }
360 
361 static void
362 cdoninvalidate(struct cam_periph *periph)
363 {
364         struct cd_softc *softc;
365 
366         softc = (struct cd_softc *)periph->softc;
367 
368         /*
369          * De-register any async callbacks.
370          */
371         xpt_register_async(0, cdasync, periph, periph->path);
372 
373         softc->flags |= CD_FLAG_INVALID;
374 
375         /*
376          * Return all queued I/O with ENXIO.
377          * XXX Handle any transactions queued to the card
378          *     with XPT_ABORT_CCB.
379          */
380         bioq_flush(&softc->bio_queue, NULL, ENXIO);
381 
382         /*
383          * If this device is part of a changer, and it was scheduled
384          * to run, remove it from the run queue since we just nuked
385          * all of its scheduled I/O.
386          */
387         if ((softc->flags & CD_FLAG_CHANGER)
388          && (softc->pinfo.index != CAM_UNQUEUED_INDEX))
389                 camq_remove(&softc->changer->devq, softc->pinfo.index);
390 
391         disk_gone(softc->disk);
392         xpt_print(periph->path, "lost device\n");
393 }
394 
395 static void
396 cdcleanup(struct cam_periph *periph)
397 {
398         struct cd_softc *softc;
399 
400         softc = (struct cd_softc *)periph->softc;
401 
402         xpt_print(periph->path, "removing device entry\n");
403 
404         if ((softc->flags & CD_FLAG_SCTX_INIT) != 0
405             && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
406                 xpt_print(periph->path, "can't remove sysctl context\n");
407         }
408 
409         /*
410          * In the queued, non-active case, the device in question
411          * has already been removed from the changer run queue.  Since this
412          * device is active, we need to de-activate it, and schedule
413          * another device to run.  (if there is another one to run)
414          */
415         if ((softc->flags & CD_FLAG_CHANGER)
416          && (softc->flags & CD_FLAG_ACTIVE)) {
417 
418                 /*
419                  * The purpose of the short timeout is soley to determine
420                  * whether the current device has finished or not.  Well,
421                  * since we're removing the active device, we know that it
422                  * is finished.  So, get rid of the short timeout.
423                  * Otherwise, if we're in the time period before the short
424                  * timeout fires, and there are no other devices in the
425                  * queue to run, there won't be any other device put in the
426                  * active slot.  i.e., when we call cdrunchangerqueue()
427                  * below, it won't do anything.  Then, when the short
428                  * timeout fires, it'll look at the "current device", which
429                  * we are free below, and possibly panic the kernel on a
430                  * bogus pointer reference.
431                  *
432                  * The long timeout doesn't really matter, since we
433                  * decrement the qfrozen_cnt to indicate that there is
434                  * nothing in the active slot now.  Therefore, there won't
435                  * be any bogus pointer references there.
436                  */
437                 if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
438                         callout_stop(&softc->changer->short_handle);
439                         softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
440                 }
441                 softc->changer->devq.qfrozen_cnt--;
442                 softc->changer->flags |= CHANGER_MANUAL_CALL;
443                 cdrunchangerqueue(softc->changer);
444         }
445 
446         /*
447          * If we're removing the last device on the changer, go ahead and
448          * remove the changer device structure.
449          */
450         if ((softc->flags & CD_FLAG_CHANGER)
451          && (--softc->changer->num_devices == 0)) {
452 
453                 /*
454                  * Theoretically, there shouldn't be any timeouts left, but
455                  * I'm not completely sure that that will be the case.  So,
456                  * it won't hurt to check and see if there are any left.
457                  */
458                 if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) {
459                         callout_stop(&softc->changer->long_handle);
460                         softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED;
461                 }
462 
463                 if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
464                         callout_stop(&softc->changer->short_handle);
465                         softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
466                 }
467 
468                 mtx_lock(&changerq_mtx);
469                 STAILQ_REMOVE(&changerq, softc->changer, cdchanger,
470                               changer_links);
471                 num_changers--;
472                 mtx_unlock(&changerq_mtx);
473                 xpt_print(periph->path, "removing changer entry\n");
474                 free(softc->changer, M_DEVBUF);
475         }
476         cam_periph_unlock(periph);
477         disk_destroy(softc->disk);
478         cam_periph_lock(periph);
479         free(softc, M_DEVBUF);
480 }
481 
482 static void
483 cdasync(void *callback_arg, u_int32_t code,
484         struct cam_path *path, void *arg)
485 {
486         struct cam_periph *periph;
487 
488         periph = (struct cam_periph *)callback_arg;
489         switch (code) {
490         case AC_FOUND_DEVICE:
491         {
492                 struct ccb_getdev *cgd;
493                 cam_status status;
494 
495                 cgd = (struct ccb_getdev *)arg;
496                 if (cgd == NULL)
497                         break;
498 
499                 if (SID_TYPE(&cgd->inq_data) != T_CDROM
500                     && SID_TYPE(&cgd->inq_data) != T_WORM)
501                         break;
502 
503                 /*
504                  * Allocate a peripheral instance for
505                  * this device and start the probe
506                  * process.
507                  */
508                 status = cam_periph_alloc(cdregister, cdoninvalidate,
509                                           cdcleanup, cdstart,
510                                           "cd", CAM_PERIPH_BIO,
511                                           cgd->ccb_h.path, cdasync,
512                                           AC_FOUND_DEVICE, cgd);
513 
514                 if (status != CAM_REQ_CMP
515                  && status != CAM_REQ_INPROG)
516                         printf("cdasync: Unable to attach new device "
517                                "due to status 0x%x\n", status);
518 
519                 break;
520         }
521         case AC_SENT_BDR:
522         case AC_BUS_RESET:
523         {
524                 struct cd_softc *softc;
525                 struct ccb_hdr *ccbh;
526 
527                 softc = (struct cd_softc *)periph->softc;
528                 /*
529                  * Don't fail on the expected unit attention
530                  * that will occur.
531                  */
532                 softc->flags |= CD_FLAG_RETRY_UA;
533                 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
534                         ccbh->ccb_state |= CD_CCB_RETRY_UA;
535                 /* FALLTHROUGH */
536         }
537         default:
538                 cam_periph_async(periph, code, path, arg);
539                 break;
540         }
541 }
542 
543 static void
544 cdsysctlinit(void *context, int pending)
545 {
546         struct cam_periph *periph;
547         struct cd_softc *softc;
548         char tmpstr[80], tmpstr2[80];
549 
550         periph = (struct cam_periph *)context;
551         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
552                 return;
553 
554         softc = (struct cd_softc *)periph->softc;
555         snprintf(tmpstr, sizeof(tmpstr), "CAM CD unit %d", periph->unit_number);
556         snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
557 
558         mtx_lock(&Giant);
559 
560         sysctl_ctx_init(&softc->sysctl_ctx);
561         softc->flags |= CD_FLAG_SCTX_INIT;
562         softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx,
563                 SYSCTL_STATIC_CHILDREN(_kern_cam_cd), OID_AUTO,
564                 tmpstr2, CTLFLAG_RD, 0, tmpstr);
565 
566         if (softc->sysctl_tree == NULL) {
567                 printf("cdsysctlinit: unable to allocate sysctl tree\n");
568                 mtx_unlock(&Giant);
569                 cam_periph_release(periph);
570                 return;
571         }
572 
573         /*
574          * Now register the sysctl handler, so the user can the value on
575          * the fly.
576          */
577         SYSCTL_ADD_PROC(&softc->sysctl_ctx,SYSCTL_CHILDREN(softc->sysctl_tree),
578                 OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW,
579                 &softc->minimum_command_size, 0, cdcmdsizesysctl, "I",
580                 "Minimum CDB size");
581 
582         mtx_unlock(&Giant);
583         cam_periph_release(periph);
584 }
585 
586 /*
587  * We have a handler function for this so we can check the values when the
588  * user sets them, instead of every time we look at them.
589  */
590 static int
591 cdcmdsizesysctl(SYSCTL_HANDLER_ARGS)
592 {
593         int error, value;
594 
595         value = *(int *)arg1;
596 
597         error = sysctl_handle_int(oidp, &value, 0, req);
598 
599         if ((error != 0)
600          || (req->newptr == NULL))
601                 return (error);
602 
603         /*
604          * The only real values we can have here are 6 or 10.  I don't
605          * really forsee having 12 be an option at any time in the future.
606          * So if the user sets something less than or equal to 6, we'll set
607          * it to 6.  If he sets something greater than 6, we'll set it to 10.
608          *
609          * I suppose we could just return an error here for the wrong values,
610          * but I don't think it's necessary to do so, as long as we can
611          * determine the user's intent without too much trouble.
612          */
613         if (value < 6)
614                 value = 6;
615         else if (value > 6)
616                 value = 10;
617 
618         *(int *)arg1 = value;
619 
620         return (0);
621 }
622 
623 static cam_status
624 cdregister(struct cam_periph *periph, void *arg)
625 {
626         struct cd_softc *softc;
627         struct ccb_pathinq cpi;
628         struct ccb_getdev *cgd;
629         char tmpstr[80];
630         caddr_t match;
631 
632         cgd = (struct ccb_getdev *)arg;
633         if (periph == NULL) {
634                 printf("cdregister: periph was NULL!!\n");
635                 return(CAM_REQ_CMP_ERR);
636         }
637         if (cgd == NULL) {
638                 printf("cdregister: no getdev CCB, can't register device\n");
639                 return(CAM_REQ_CMP_ERR);
640         }
641 
642         softc = (struct cd_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
643 
644         if (softc == NULL) {
645                 printf("cdregister: Unable to probe new device. "
646                        "Unable to allocate softc\n");                           
647                 return(CAM_REQ_CMP_ERR);
648         }
649 
650         bzero(softc, sizeof(*softc));
651         LIST_INIT(&softc->pending_ccbs);
652         STAILQ_INIT(&softc->mode_queue);
653         softc->state = CD_STATE_PROBE;
654         bioq_init(&softc->bio_queue);
655         if (SID_IS_REMOVABLE(&cgd->inq_data))
656                 softc->flags |= CD_FLAG_DISC_REMOVABLE;
657         if ((cgd->inq_data.flags & SID_CmdQue) != 0)
658                 softc->flags |= CD_FLAG_TAGGED_QUEUING;
659 
660         periph->softc = softc;
661         softc->periph = periph;
662 
663         /*
664          * See if this device has any quirks.
665          */
666         match = cam_quirkmatch((caddr_t)&cgd->inq_data,
667                                (caddr_t)cd_quirk_table,
668                                sizeof(cd_quirk_table)/sizeof(*cd_quirk_table),
669                                sizeof(*cd_quirk_table), scsi_inquiry_match);
670 
671         if (match != NULL)
672                 softc->quirks = ((struct cd_quirk_entry *)match)->quirks;
673         else
674                 softc->quirks = CD_Q_NONE;
675 
676         /* Check if the SIM does not want 6 byte commands */
677         xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1);
678         cpi.ccb_h.func_code = XPT_PATH_INQ;
679         xpt_action((union ccb *)&cpi);
680         if (cpi.ccb_h.status == CAM_REQ_CMP && (cpi.hba_misc & PIM_NO_6_BYTE))
681                 softc->quirks |= CD_Q_10_BYTE_ONLY;
682 
683         TASK_INIT(&softc->sysctl_task, 0, cdsysctlinit, periph);
684 
685         /* The default is 6 byte commands, unless quirked otherwise */
686         if (softc->quirks & CD_Q_10_BYTE_ONLY)
687                 softc->minimum_command_size = 10;
688         else
689                 softc->minimum_command_size = 6;
690 
691         /*
692          * Load the user's default, if any.
693          */
694         snprintf(tmpstr, sizeof(tmpstr), "kern.cam.cd.%d.minimum_cmd_size",
695                  periph->unit_number);
696         TUNABLE_INT_FETCH(tmpstr, &softc->minimum_command_size);
697 
698         /* 6 and 10 are the only permissible values here. */
699         if (softc->minimum_command_size < 6)
700                 softc->minimum_command_size = 6;
701         else if (softc->minimum_command_size > 6)
702                 softc->minimum_command_size = 10;
703 
704         /*
705          * We need to register the statistics structure for this device,
706          * but we don't have the blocksize yet for it.  So, we register
707          * the structure and indicate that we don't have the blocksize
708          * yet.  Unlike other SCSI peripheral drivers, we explicitly set
709          * the device type here to be CDROM, rather than just ORing in
710          * the device type.  This is because this driver can attach to either
711          * CDROM or WORM devices, and we want this peripheral driver to
712          * show up in the devstat list as a CD peripheral driver, not a
713          * WORM peripheral driver.  WORM drives will also have the WORM
714          * driver attached to them.
715          */
716         cam_periph_unlock(periph);
717         softc->disk = disk_alloc();
718         softc->disk->d_devstat = devstat_new_entry("cd", 
719                           periph->unit_number, 0,
720                           DEVSTAT_BS_UNAVAILABLE,
721                           DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_SCSI,
722                           DEVSTAT_PRIORITY_CD);
723         softc->disk->d_open = cdopen;
724         softc->disk->d_close = cdclose;
725         softc->disk->d_strategy = cdstrategy;
726         softc->disk->d_ioctl = cdioctl;
727         softc->disk->d_name = "cd";
728         softc->disk->d_unit = periph->unit_number;
729         softc->disk->d_drv1 = periph;
730         softc->disk->d_flags = 0;
731         disk_create(softc->disk, DISK_VERSION);
732         cam_periph_lock(periph);
733 
734         /*
735          * Add an async callback so that we get
736          * notified if this device goes away.
737          */
738         xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
739                            cdasync, periph, periph->path);
740 
741         /*
742          * If the target lun is greater than 0, we most likely have a CD
743          * changer device.  Check the quirk entries as well, though, just
744          * in case someone has a CD tower with one lun per drive or
745          * something like that.  Also, if we know up front that a
746          * particular device is a changer, we can mark it as such starting
747          * with lun 0, instead of lun 1.  It shouldn't be necessary to have
748          * a quirk entry to define something as a changer, however.
749          */
750         if (((cgd->ccb_h.target_lun > 0)
751           && ((softc->quirks & CD_Q_NO_CHANGER) == 0))
752          || ((softc->quirks & CD_Q_CHANGER) != 0)) {
753                 struct cdchanger *nchanger;
754                 struct cam_periph *nperiph;
755                 struct cam_path *path;
756                 cam_status status;
757                 int found;
758 
759                 /* Set the changer flag in the current device's softc */
760                 softc->flags |= CD_FLAG_CHANGER;
761 
762                 /*
763                  * Now, look around for an existing changer device with the
764                  * same path and target ID as the current device.
765                  */
766                 mtx_lock(&changerq_mtx);
767                 for (found = 0,
768                      nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq);
769                      nchanger != NULL;
770                      nchanger = STAILQ_NEXT(nchanger, changer_links)){
771                         if ((nchanger->path_id == cgd->ccb_h.path_id) 
772                          && (nchanger->target_id == cgd->ccb_h.target_id)) {
773                                 found = 1;
774                                 break;
775                         }
776                 }
777                 mtx_unlock(&changerq_mtx);
778 
779                 /*
780                  * If we found a matching entry, just add this device to
781                  * the list of devices on this changer.
782                  */
783                 if (found == 1) {
784                         struct chdevlist *chlunhead;
785 
786                         chlunhead = &nchanger->chluns;
787 
788                         /*
789                          * XXX KDM look at consolidating this code with the
790                          * code below in a separate function.
791                          */
792 
793                         /*
794                          * Create a path with lun id 0, and see if we can
795                          * find a matching device
796                          */
797                         status = xpt_create_path(&path, /*periph*/ periph,
798                                                  cgd->ccb_h.path_id,
799                                                  cgd->ccb_h.target_id, 0);
800 
801                         if ((status == CAM_REQ_CMP)
802                          && ((nperiph = cam_periph_find(path, "cd")) != NULL)){
803                                 struct cd_softc *nsoftc;
804 
805                                 nsoftc = (struct cd_softc *)nperiph->softc;
806 
807                                 if ((nsoftc->flags & CD_FLAG_CHANGER) == 0){
808                                         nsoftc->flags |= CD_FLAG_CHANGER;
809                                         nchanger->num_devices++;
810                                         if (camq_resize(&nchanger->devq,
811                                            nchanger->num_devices)!=CAM_REQ_CMP){
812                                                 printf("cdregister: "
813                                                        "camq_resize "
814                                                        "failed, changer "
815                                                        "support may "
816                                                        "be messed up\n");
817                                         }
818                                         nsoftc->changer = nchanger;
819                                         nsoftc->pinfo.index =CAM_UNQUEUED_INDEX;
820 
821                                         STAILQ_INSERT_TAIL(&nchanger->chluns,
822                                                           nsoftc,changer_links);
823                                 }
824                                 xpt_free_path(path);
825                         } else if (status == CAM_REQ_CMP)
826                                 xpt_free_path(path);
827                         else {
828                                 printf("cdregister: unable to allocate path\n"
829                                        "cdregister: changer support may be "
830                                        "broken\n");
831                         }
832 
833                         nchanger->num_devices++;
834 
835                         softc->changer = nchanger;
836                         softc->pinfo.index = CAM_UNQUEUED_INDEX;
837 
838                         if (camq_resize(&nchanger->devq,
839                             nchanger->num_devices) != CAM_REQ_CMP) {
840                                 printf("cdregister: camq_resize "
841                                        "failed, changer support may "
842                                        "be messed up\n");
843                         }
844 
845                         STAILQ_INSERT_TAIL(chlunhead, softc, changer_links);
846                 }
847                 /*
848                  * In this case, we don't already have an entry for this
849                  * particular changer, so we need to create one, add it to
850                  * the queue, and queue this device on the list for this
851                  * changer.  Before we queue this device, however, we need
852                  * to search for lun id 0 on this target, and add it to the
853                  * queue first, if it exists.  (and if it hasn't already
854                  * been marked as part of the changer.)
855                  */
856                 else {
857                         nchanger = malloc(sizeof(struct cdchanger),
858                                 M_DEVBUF, M_NOWAIT);
859 
860                         if (nchanger == NULL) {
861                                 softc->flags &= ~CD_FLAG_CHANGER;
862                                 printf("cdregister: unable to malloc "
863                                        "changer structure\ncdregister: "
864                                        "changer support disabled\n");
865 
866                                 /*
867                                  * Yes, gotos can be gross but in this case
868                                  * I think it's justified..
869                                  */
870                                 goto cdregisterexit;
871                         }
872 
873                         /* zero the structure */
874                         bzero(nchanger, sizeof(struct cdchanger));
875 
876                         if (camq_init(&nchanger->devq, 1) != 0) {
877                                 softc->flags &= ~CD_FLAG_CHANGER;
878                                 printf("cdregister: changer support "
879                                        "disabled\n");
880                                 goto cdregisterexit;
881                         }
882 
883                         nchanger->path_id = cgd->ccb_h.path_id;
884                         nchanger->target_id = cgd->ccb_h.target_id;
885 
886                         /* this is superfluous, but it makes things clearer */
887                         nchanger->num_devices = 0;
888 
889                         STAILQ_INIT(&nchanger->chluns);
890 
891                         callout_init_mtx(&nchanger->long_handle,
892                             periph->sim->mtx, 0);
893                         callout_init_mtx(&nchanger->short_handle,
894                             periph->sim->mtx, 0);
895 
896                         mtx_lock(&changerq_mtx);
897                         num_changers++;
898                         STAILQ_INSERT_TAIL(&changerq, nchanger,
899                                            changer_links);
900                         mtx_unlock(&changerq_mtx);
901                         
902                         /*
903                          * Create a path with lun id 0, and see if we can
904                          * find a matching device
905                          */
906                         status = xpt_create_path(&path, /*periph*/ periph,
907                                                  cgd->ccb_h.path_id,
908                                                  cgd->ccb_h.target_id, 0);
909 
910                         /*
911                          * If we were able to allocate the path, and if we
912                          * find a matching device and it isn't already
913                          * marked as part of a changer, then we add it to
914                          * the current changer.
915                          */
916                         if ((status == CAM_REQ_CMP)
917                          && ((nperiph = cam_periph_find(path, "cd")) != NULL)
918                          && ((((struct cd_softc *)periph->softc)->flags &
919                                CD_FLAG_CHANGER) == 0)) {
920                                 struct cd_softc *nsoftc;
921 
922                                 nsoftc = (struct cd_softc *)nperiph->softc;
923 
924                                 nsoftc->flags |= CD_FLAG_CHANGER;
925                                 nchanger->num_devices++;
926                                 if (camq_resize(&nchanger->devq,
927                                     nchanger->num_devices) != CAM_REQ_CMP) {
928                                         printf("cdregister: camq_resize "
929                                                "failed, changer support may "
930                                                "be messed up\n");
931                                 }
932                                 nsoftc->changer = nchanger;
933                                 nsoftc->pinfo.index = CAM_UNQUEUED_INDEX;
934 
935                                 STAILQ_INSERT_TAIL(&nchanger->chluns,
936                                                    nsoftc, changer_links);
937                                 xpt_free_path(path);
938                         } else if (status == CAM_REQ_CMP)
939                                 xpt_free_path(path);
940                         else {
941                                 printf("cdregister: unable to allocate path\n"
942                                        "cdregister: changer support may be "
943                                        "broken\n");
944                         }
945 
946                         softc->changer = nchanger;
947                         softc->pinfo.index = CAM_UNQUEUED_INDEX;
948                         nchanger->num_devices++;
949                         if (camq_resize(&nchanger->devq,
950                             nchanger->num_devices) != CAM_REQ_CMP) {
951                                 printf("cdregister: camq_resize "
952                                        "failed, changer support may "
953                                        "be messed up\n");
954                         }
955                         STAILQ_INSERT_TAIL(&nchanger->chluns, softc,
956                                            changer_links);
957                 }
958         }