FreeBSD/Linux Kernel Cross Reference
sys/cam/scsi/scsi_cd.c
1 /*-
2 * Copyright (c) 1997 Justin T. Gibbs.
3 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Kenneth D. Merry.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer,
11 * without modification, immediately at the beginning of the file.
12 * 2. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*-
29 * Portions of this driver taken from the original FreeBSD cd driver.
30 * Written by Julian Elischer (julian@tfs.com)
31 * for TRW Financial Systems for use under the MACH(2.5) operating system.
32 *
33 * TRW Financial Systems, in accordance with their agreement with Carnegie
34 * Mellon University, makes this software available to CMU to distribute
35 * or use in any manner that they see fit as long as this message is kept with
36 * the software. For this reason TFS also grants any other persons or
37 * organisations permission to use or modify this software.
38 *
39 * TFS supplies this software to be publicly redistributed
40 * on the understanding that TFS is not responsible for the correct
41 * functioning of this software in any circumstances.
42 *
43 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
44 *
45 * from: cd.c,v 1.83 1997/05/04 15:24:22 joerg Exp $
46 */
47
48 #include <sys/cdefs.h>
49 __FBSDID("$FreeBSD: 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 }
|