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