FreeBSD kernel CAM code
scsi_ch.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: (BSD-2-Clause-FreeBSD AND BSD-4-Clause)
3 *
4 * Copyright (c) 1997 Justin T. Gibbs.
5 * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions, and the following disclaimer,
13 * without modification, immediately at the beginning of the file.
14 * 2. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*-
31 * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej@and.com>
32 * All rights reserved.
33 *
34 * Partially based on an autochanger driver written by Stefan Grefen
35 * and on an autochanger driver written by the Systems Programming Group
36 * at the University of Utah Computer Science Department.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgements:
48 * This product includes software developed by Jason R. Thorpe
49 * for And Communications, http://www.and.com/
50 * 4. The name of the author may not be used to endorse or promote products
51 * derived from this software without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
54 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
55 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
56 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
57 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
58 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
59 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
60 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
61 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * $NetBSD: ch.c,v 1.34 1998/08/31 22:28:06 cgd Exp $
66 */
67
68#include <sys/cdefs.h>
69__FBSDID("$FreeBSD$");
70
71#include <sys/param.h>
72#include <sys/queue.h>
73#include <sys/systm.h>
74#include <sys/kernel.h>
75#include <sys/types.h>
76#include <sys/malloc.h>
77#include <sys/fcntl.h>
78#include <sys/conf.h>
79#include <sys/chio.h>
80#include <sys/errno.h>
81#include <sys/devicestat.h>
82
83#include <cam/cam.h>
84#include <cam/cam_ccb.h>
85#include <cam/cam_periph.h>
86#include <cam/cam_xpt_periph.h>
87#include <cam/cam_debug.h>
88
89#include <cam/scsi/scsi_all.h>
91#include <cam/scsi/scsi_ch.h>
92
93/*
94 * Timeout definitions for various changer related commands. They may
95 * be too short for some devices (especially the timeout for INITIALIZE
96 * ELEMENT STATUS).
97 */
98
99static const u_int32_t CH_TIMEOUT_MODE_SENSE = 6000;
100static const u_int32_t CH_TIMEOUT_MOVE_MEDIUM = 15 * 60 * 1000;
101static const u_int32_t CH_TIMEOUT_EXCHANGE_MEDIUM = 15 * 60 * 1000;
102static const u_int32_t CH_TIMEOUT_POSITION_TO_ELEMENT = 15 * 60 * 1000;
103static const u_int32_t CH_TIMEOUT_READ_ELEMENT_STATUS = 5 * 60 * 1000;
104static const u_int32_t CH_TIMEOUT_SEND_VOLTAG = 10000;
105static const u_int32_t CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS = 500000;
106
107typedef enum {
108 CH_FLAG_INVALID = 0x001
110
111typedef enum {
115
116typedef enum {
119
120typedef enum {
121 CH_Q_NONE = 0x00,
123 CH_Q_NO_DVCID = 0x02
125
126#define CH_Q_BIT_STRING \
127 "\020" \
128 "\001NO_DBD" \
129 "\002NO_DVCID"
130
131#define ccb_state ppriv_field0
132#define ccb_bp ppriv_ptr1
133
137 union {
142};
143
144struct ch_softc {
148 struct devstat *device_stats;
149 struct cdev *dev;
151
152 int sc_picker; /* current picker */
153
154 /*
155 * The following information is obtained from the
156 * element address assignment page.
157 */
158 int sc_firsts[CHET_MAX + 1]; /* firsts */
159 int sc_counts[CHET_MAX + 1]; /* counts */
160
161 /*
162 * The following mask defines the legal combinations
163 * of elements for the MOVE MEDIUM command.
164 */
165 u_int8_t sc_movemask[CHET_MAX + 1];
166
167 /*
168 * As above, but for EXCHANGE MEDIUM.
169 */
170 u_int8_t sc_exchangemask[CHET_MAX + 1];
171
172 /*
173 * Quirks; see below. XXX KDM not implemented yet
174 */
175 int sc_settledelay; /* delay for settle */
176};
177
178static d_open_t chopen;
179static d_close_t chclose;
180static d_ioctl_t chioctl;
186static void chasync(void *callback_arg, u_int32_t code,
187 struct cam_path *path, void *arg);
188static void chdone(struct cam_periph *periph,
189 union ccb *done_ccb);
190static int cherror(union ccb *ccb, u_int32_t cam_flags,
191 u_int32_t sense_flags);
192static int chmove(struct cam_periph *periph,
193 struct changer_move *cm);
194static int chexchange(struct cam_periph *periph,
195 struct changer_exchange *ce);
196static int chposition(struct cam_periph *periph,
197 struct changer_position *cp);
198static int chgetelemstatus(struct cam_periph *periph,
199 int scsi_version, u_long cmd,
200 struct changer_element_status_request *csr);
201static int chsetvoltag(struct cam_periph *periph,
202 struct changer_set_voltag_request *csvr);
203static int chielem(struct cam_periph *periph,
204 unsigned int timeout);
205static int chgetparams(struct cam_periph *periph);
206static int chscsiversion(struct cam_periph *periph);
207
208static struct periph_driver chdriver =
209{
210 chinit, "ch",
211 TAILQ_HEAD_INITIALIZER(chdriver.units), /* generation */ 0
212};
213
215
216static struct cdevsw ch_cdevsw = {
217 .d_version = D_VERSION,
218 .d_flags = D_TRACKCLOSE,
219 .d_open = chopen,
220 .d_close = chclose,
221 .d_ioctl = chioctl,
222 .d_name = "ch",
223};
224
225static MALLOC_DEFINE(M_SCSICH, "scsi_ch", "scsi_ch buffers");
226
227static void
228chinit(void)
229{
230 cam_status status;
231
232 /*
233 * Install a global async callback. This callback will
234 * receive async callbacks like "new device found".
235 */
236 status = xpt_register_async(AC_FOUND_DEVICE, chasync, NULL, NULL);
237
238 if (status != CAM_REQ_CMP) {
239 printf("ch: Failed to attach master async callback "
240 "due to status 0x%x!\n", status);
241 }
242}
243
244static void
245chdevgonecb(void *arg)
246{
247 struct ch_softc *softc;
248 struct cam_periph *periph;
249 struct mtx *mtx;
250 int i;
251
252 periph = (struct cam_periph *)arg;
253 mtx = cam_periph_mtx(periph);
254 mtx_lock(mtx);
255
256 softc = (struct ch_softc *)periph->softc;
257 KASSERT(softc->open_count >= 0, ("Negative open count %d",
258 softc->open_count));
259
260 /*
261 * When we get this callback, we will get no more close calls from
262 * devfs. So if we have any dangling opens, we need to release the
263 * reference held for that particular context.
264 */
265 for (i = 0; i < softc->open_count; i++)
267
268 softc->open_count = 0;
269
270 /*
271 * Release the reference held for the device node, it is gone now.
272 */
274
275 /*
276 * We reference the lock directly here, instead of using
277 * cam_periph_unlock(). The reason is that the final call to
278 * cam_periph_release_locked() above could result in the periph
279 * getting freed. If that is the case, dereferencing the periph
280 * with a cam_periph_unlock() call would cause a page fault.
281 */
282 mtx_unlock(mtx);
283}
284
285static void
287{
288 struct ch_softc *softc;
289
290 softc = (struct ch_softc *)periph->softc;
291
292 /*
293 * De-register any async callbacks.
294 */
295 xpt_register_async(0, chasync, periph, periph->path);
296
297 softc->flags |= CH_FLAG_INVALID;
298
299 /*
300 * Tell devfs this device has gone away, and ask for a callback
301 * when it has cleaned up its state.
302 */
303 destroy_dev_sched_cb(softc->dev, chdevgonecb, periph);
304}
305
306static void
307chcleanup(struct cam_periph *periph)
308{
309 struct ch_softc *softc;
310
311 softc = (struct ch_softc *)periph->softc;
312
313 devstat_remove_entry(softc->device_stats);
314
315 free(softc, M_DEVBUF);
316}
317
318static void
319chasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
320{
321 struct cam_periph *periph;
322
323 periph = (struct cam_periph *)callback_arg;
324
325 switch(code) {
326 case AC_FOUND_DEVICE:
327 {
328 struct ccb_getdev *cgd;
329 cam_status status;
330
331 cgd = (struct ccb_getdev *)arg;
332 if (cgd == NULL)
333 break;
334
335 if (cgd->protocol != PROTO_SCSI)
336 break;
338 break;
339 if (SID_TYPE(&cgd->inq_data)!= T_CHANGER)
340 break;
341
342 /*
343 * Allocate a peripheral instance for
344 * this device and start the probe
345 * process.
346 */
348 chcleanup, chstart, "ch",
349 CAM_PERIPH_BIO, path,
351
352 if (status != CAM_REQ_CMP
353 && status != CAM_REQ_INPROG)
354 printf("chasync: Unable to probe new device "
355 "due to status 0x%x\n", status);
356
357 break;
358 }
359 default:
360 cam_periph_async(periph, code, path, arg);
361 break;
362 }
363}
364
365static cam_status
366chregister(struct cam_periph *periph, void *arg)
367{
368 struct ch_softc *softc;
369 struct ccb_getdev *cgd;
370 struct ccb_pathinq cpi;
371 struct make_dev_args args;
372 int error;
373
374 cgd = (struct ccb_getdev *)arg;
375 if (cgd == NULL) {
376 printf("chregister: no getdev CCB, can't register device\n");
377 return(CAM_REQ_CMP_ERR);
378 }
379
380 softc = (struct ch_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
381
382 if (softc == NULL) {
383 printf("chregister: Unable to probe new device. "
384 "Unable to allocate softc\n");
385 return(CAM_REQ_CMP_ERR);
386 }
387
388 bzero(softc, sizeof(*softc));
389 softc->state = CH_STATE_PROBE;
390 periph->softc = softc;
391 softc->quirks = CH_Q_NONE;
392
393 /*
394 * The DVCID and CURDATA bits were not introduced until the SMC
395 * spec. If this device claims SCSI-2 or earlier support, then it
396 * very likely does not support these bits.
397 */
398 if (cgd->inq_data.version <= SCSI_REV_2)
399 softc->quirks |= CH_Q_NO_DVCID;
400
401 xpt_path_inq(&cpi, periph->path);
402
403 /*
404 * Changers don't have a blocksize, and obviously don't support
405 * tagged queueing.
406 */
407 cam_periph_unlock(periph);
408 softc->device_stats = devstat_new_entry("ch",
409 periph->unit_number, 0,
410 DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS,
411 SID_TYPE(&cgd->inq_data) |
413 DEVSTAT_PRIORITY_OTHER);
414
415 /*
416 * Acquire a reference to the periph before we create the devfs
417 * instance for it. We'll release this reference once the devfs
418 * instance has been freed.
419 */
420 if (cam_periph_acquire(periph) != 0) {
421 xpt_print(periph->path, "%s: lost periph during "
422 "registration!\n", __func__);
423 cam_periph_lock(periph);
424 return (CAM_REQ_CMP_ERR);
425 }
426
427 /* Register the device */
428 make_dev_args_init(&args);
429 args.mda_devsw = &ch_cdevsw;
430 args.mda_unit = periph->unit_number;
431 args.mda_uid = UID_ROOT;
432 args.mda_gid = GID_OPERATOR;
433 args.mda_mode = 0600;
434 args.mda_si_drv1 = periph;
435 error = make_dev_s(&args, &softc->dev, "%s%d", periph->periph_name,
436 periph->unit_number);
437 cam_periph_lock(periph);
438 if (error != 0) {
440 return (CAM_REQ_CMP_ERR);
441 }
442
443 /*
444 * Add an async callback so that we get
445 * notified if this device goes away.
446 */
448
449 /*
450 * Lock this periph until we are setup.
451 * This first call can't block
452 */
453 (void)cam_periph_hold(periph, PRIBIO);
455
456 return(CAM_REQ_CMP);
457}
458
459static int
460chopen(struct cdev *dev, int flags, int fmt, struct thread *td)
461{
462 struct cam_periph *periph;
463 struct ch_softc *softc;
464 int error;
465
466 periph = (struct cam_periph *)dev->si_drv1;
467 if (cam_periph_acquire(periph) != 0)
468 return (ENXIO);
469
470 softc = (struct ch_softc *)periph->softc;
471
472 cam_periph_lock(periph);
473
474 if (softc->flags & CH_FLAG_INVALID) {
476 cam_periph_unlock(periph);
477 return(ENXIO);
478 }
479
480 if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
481 cam_periph_unlock(periph);
482 cam_periph_release(periph);
483 return (error);
484 }
485
486 /*
487 * Load information about this changer device into the softc.
488 */
489 if ((error = chgetparams(periph)) != 0) {
490 cam_periph_unhold(periph);
492 cam_periph_unlock(periph);
493 return(error);
494 }
495
496 cam_periph_unhold(periph);
497
498 softc->open_count++;
499
500 cam_periph_unlock(periph);
501
502 return(error);
503}
504
505static int
506chclose(struct cdev *dev, int flag, int fmt, struct thread *td)
507{
508 struct cam_periph *periph;
509 struct ch_softc *softc;
510 struct mtx *mtx;
511
512 periph = (struct cam_periph *)dev->si_drv1;
513 mtx = cam_periph_mtx(periph);
514 mtx_lock(mtx);
515
516 softc = (struct ch_softc *)periph->softc;
517 softc->open_count--;
518
520
521 /*
522 * We reference the lock directly here, instead of using
523 * cam_periph_unlock(). The reason is that the call to
524 * cam_periph_release_locked() above could result in the periph
525 * getting freed. If that is the case, dereferencing the periph
526 * with a cam_periph_unlock() call would cause a page fault.
527 *
528 * cam_periph_release() avoids this problem using the same method,
529 * but we're manually acquiring and dropping the lock here to
530 * protect the open count and avoid another lock acquisition and
531 * release.
532 */
533 mtx_unlock(mtx);
534
535 return(0);
536}
537
538static void
539chstart(struct cam_periph *periph, union ccb *start_ccb)
540{
541 struct ch_softc *softc;
542
543 softc = (struct ch_softc *)periph->softc;
544
545 switch (softc->state) {
546 case CH_STATE_NORMAL:
547 {
548 xpt_release_ccb(start_ccb);
549 break;
550 }
551 case CH_STATE_PROBE:
552 {
553 int mode_buffer_len;
554 void *mode_buffer;
555
556 /*
557 * Include the block descriptor when calculating the mode
558 * buffer length,
559 */
560 mode_buffer_len = sizeof(struct scsi_mode_header_6) +
561 sizeof(struct scsi_mode_blk_desc) +
562 sizeof(struct page_element_address_assignment);
563
564 mode_buffer = malloc(mode_buffer_len, M_SCSICH, M_NOWAIT);
565
566 if (mode_buffer == NULL) {
567 printf("chstart: couldn't malloc mode sense data\n");
568 break;
569 }
570 bzero(mode_buffer, mode_buffer_len);
571
572 /*
573 * Get the element address assignment page.
574 */
575 scsi_mode_sense(&start_ccb->csio,
576 /* retries */ 1,
577 /* cbfcnp */ chdone,
578 /* tag_action */ MSG_SIMPLE_Q_TAG,
579 /* dbd */ (softc->quirks & CH_Q_NO_DBD) ?
580 FALSE : TRUE,
581 /* pc */ SMS_PAGE_CTRL_CURRENT,
583 /* param_buf */ (u_int8_t *)mode_buffer,
584 /* param_len */ mode_buffer_len,
585 /* sense_len */ SSD_FULL_SIZE,
586 /* timeout */ CH_TIMEOUT_MODE_SENSE);
587
588 start_ccb->ccb_h.ccb_bp = NULL;
589 start_ccb->ccb_h.ccb_state = CH_CCB_PROBE;
590 xpt_action(start_ccb);
591 break;
592 }
593 }
594}
595
596static void
597chdone(struct cam_periph *periph, union ccb *done_ccb)
598{
599 struct ch_softc *softc;
600 struct ccb_scsiio *csio;
601
602 softc = (struct ch_softc *)periph->softc;
603 csio = &done_ccb->csio;
604
605 switch(done_ccb->ccb_h.ccb_state) {
606 case CH_CCB_PROBE:
607 {
608 struct scsi_mode_header_6 *mode_header;
610 char announce_buf[80];
611
612 mode_header = (struct scsi_mode_header_6 *)csio->data_ptr;
613
614 ea = (struct page_element_address_assignment *)
615 find_mode_page_6(mode_header);
616
617 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP){
618
619 softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea);
620 softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte);
621 softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea);
622 softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse);
623 softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea);
624 softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee);
625 softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea);
626 softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte);
627 softc->sc_picker = softc->sc_firsts[CHET_MT];
628
629#define PLURAL(c) (c) == 1 ? "" : "s"
630 snprintf(announce_buf, sizeof(announce_buf),
631 "%d slot%s, %d drive%s, "
632 "%d picker%s, %d portal%s",
633 softc->sc_counts[CHET_ST],
634 PLURAL(softc->sc_counts[CHET_ST]),
635 softc->sc_counts[CHET_DT],
636 PLURAL(softc->sc_counts[CHET_DT]),
637 softc->sc_counts[CHET_MT],
638 PLURAL(softc->sc_counts[CHET_MT]),
639 softc->sc_counts[CHET_IE],
640 PLURAL(softc->sc_counts[CHET_IE]));
641#undef PLURAL
642 if (announce_buf[0] != '\0') {
643 xpt_announce_periph(periph, announce_buf);
644 xpt_announce_quirks(periph, softc->quirks,
646 }
647 } else {
648 int error;
649
650 error = cherror(done_ccb, CAM_RETRY_SELTO,
652 /*
653 * Retry any UNIT ATTENTION type errors. They
654 * are expected at boot.
655 */
656 if (error == ERESTART) {
657 /*
658 * A retry was scheduled, so
659 * just return.
660 */
661 return;
662 } else if (error != 0) {
663 struct scsi_mode_sense_6 *sms;
664 int frozen, retry_scheduled;
665
666 sms = (struct scsi_mode_sense_6 *)
667 done_ccb->csio.cdb_io.cdb_bytes;
668 frozen = (done_ccb->ccb_h.status &
669 CAM_DEV_QFRZN) != 0;
670
671 /*
672 * Check to see if block descriptors were
673 * disabled. Some devices don't like that.
674 * We're taking advantage of the fact that
675 * the first few bytes of the 6 and 10 byte
676 * mode sense commands are the same. If
677 * block descriptors were disabled, enable
678 * them and re-send the command.
679 */
680 if ((sms->byte2 & SMS_DBD) != 0 &&
681 (periph->flags & CAM_PERIPH_INVALID) == 0) {
682 sms->byte2 &= ~SMS_DBD;
683 xpt_action(done_ccb);
684 softc->quirks |= CH_Q_NO_DBD;
685 retry_scheduled = 1;
686 } else
687 retry_scheduled = 0;
688
689 /* Don't wedge this device's queue */
690 if (frozen)
691 cam_release_devq(done_ccb->ccb_h.path,
692 /*relsim_flags*/0,
693 /*reduction*/0,
694 /*timeout*/0,
695 /*getcount_only*/0);
696
697 if (retry_scheduled)
698 return;
699
700 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK)
702 scsi_sense_print(&done_ccb->csio);
703 else {
704 xpt_print(periph->path,
705 "got CAM status %#x\n",
706 done_ccb->ccb_h.status);
707 }
708 xpt_print(periph->path, "fatal error, failed "
709 "to attach to device\n");
710
711 cam_periph_invalidate(periph);
712 }
713 }
714 softc->state = CH_STATE_NORMAL;
715 free(mode_header, M_SCSICH);
716 /*
717 * Since our peripheral may be invalidated by an error
718 * above or an external event, we must release our CCB
719 * before releasing the probe lock on the peripheral.
720 * The peripheral will only go away once the last lock
721 * is removed, and we need it around for the CCB release
722 * operation.
723 */
724 xpt_release_ccb(done_ccb);
725 cam_periph_unhold(periph);
726 return;
727 }
728 default:
729 break;
730 }
731 xpt_release_ccb(done_ccb);
732}
733
734static int
735cherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
736{
737
738 return (cam_periph_error(ccb, cam_flags, sense_flags));
739}
740
741static int
742chioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
743{
744 struct cam_periph *periph;
745 struct ch_softc *softc;
746 int error;
747
748 periph = (struct cam_periph *)dev->si_drv1;
749 cam_periph_lock(periph);
750 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering chioctl\n"));
751
752 softc = (struct ch_softc *)periph->softc;
753
754 error = 0;
755
757 ("trying to do ioctl %#lx\n", cmd));
758
759 /*
760 * If this command can change the device's state, we must
761 * have the device open for writing.
762 */
763 switch (cmd) {
764 case CHIOGPICKER:
765 case CHIOGPARAMS:
766 case OCHIOGSTATUS:
767 case CHIOGSTATUS:
768 break;
769
770 default:
771 if ((flag & FWRITE) == 0) {
772 cam_periph_unlock(periph);
773 return (EBADF);
774 }
775 }
776
777 switch (cmd) {
778 case CHIOMOVE:
779 error = chmove(periph, (struct changer_move *)addr);
780 break;
781
782 case CHIOEXCHANGE:
783 error = chexchange(periph, (struct changer_exchange *)addr);
784 break;
785
786 case CHIOPOSITION:
787 error = chposition(periph, (struct changer_position *)addr);
788 break;
789
790 case CHIOGPICKER:
791 *(int *)addr = softc->sc_picker - softc->sc_firsts[CHET_MT];
792 break;
793
794 case CHIOSPICKER:
795 {
796 int new_picker = *(int *)addr;
797
798 if (new_picker > (softc->sc_counts[CHET_MT] - 1)) {
799 error = EINVAL;
800 break;
801 }
802 softc->sc_picker = softc->sc_firsts[CHET_MT] + new_picker;
803 break;
804 }
805 case CHIOGPARAMS:
806 {
807 struct changer_params *cp = (struct changer_params *)addr;
808
809 cp->cp_npickers = softc->sc_counts[CHET_MT];
810 cp->cp_nslots = softc->sc_counts[CHET_ST];
811 cp->cp_nportals = softc->sc_counts[CHET_IE];
812 cp->cp_ndrives = softc->sc_counts[CHET_DT];
813 break;
814 }
815 case CHIOIELEM:
816 error = chielem(periph, *(unsigned int *)addr);
817 break;
818
819 case OCHIOGSTATUS:
820 {
821 error = chgetelemstatus(periph, SCSI_REV_2, cmd,
822 (struct changer_element_status_request *)addr);
823 break;
824 }
825
826 case CHIOGSTATUS:
827 {
828 int scsi_version;
829
830 scsi_version = chscsiversion(periph);
831 if (scsi_version >= SCSI_REV_0) {
832 error = chgetelemstatus(periph, scsi_version, cmd,
833 (struct changer_element_status_request *)addr);
834 }
835 else { /* unable to determine the SCSI version */
836 cam_periph_unlock(periph);
837 return (ENXIO);
838 }
839 break;
840 }
841
842 case CHIOSETVOLTAG:
843 {
844 error = chsetvoltag(periph,
845 (struct changer_set_voltag_request *) addr);
846 break;
847 }
848
849 /* Implement prevent/allow? */
850
851 default:
852 error = cam_periph_ioctl(periph, cmd, addr, cherror);
853 break;
854 }
855
856 cam_periph_unlock(periph);
857 return (error);
858}
859
860static int
861chmove(struct cam_periph *periph, struct changer_move *cm)
862{
863 struct ch_softc *softc;
864 u_int16_t fromelem, toelem;
865 union ccb *ccb;
866 int error;
867
868 error = 0;
869 softc = (struct ch_softc *)periph->softc;
870
871 /*
872 * Check arguments.
873 */
874 if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
875 return (EINVAL);
876 if ((cm->cm_fromunit > (softc->sc_counts[cm->cm_fromtype] - 1)) ||
877 (cm->cm_tounit > (softc->sc_counts[cm->cm_totype] - 1)))
878 return (ENODEV);
879
880 /*
881 * Check the request against the changer's capabilities.
882 */
883 if ((softc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
884 return (ENODEV);
885
886 /*
887 * Calculate the source and destination elements.
888 */
889 fromelem = softc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
890 toelem = softc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
891
893
895 /* retries */ 1,
896 /* cbfcnp */ chdone,
897 /* tag_action */ MSG_SIMPLE_Q_TAG,
898 /* tea */ softc->sc_picker,
899 /* src */ fromelem,
900 /* dst */ toelem,
901 /* invert */ (cm->cm_flags & CM_INVERT) ? TRUE : FALSE,
902 /* sense_len */ SSD_FULL_SIZE,
903 /* timeout */ CH_TIMEOUT_MOVE_MEDIUM);
904
905 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO,
906 /*sense_flags*/ SF_RETRY_UA,
907 softc->device_stats);
908
910
911 return(error);
912}
913
914static int
915chexchange(struct cam_periph *periph, struct changer_exchange *ce)
916{
917 struct ch_softc *softc;
918 u_int16_t src, dst1, dst2;
919 union ccb *ccb;
920 int error;
921
922 error = 0;
923 softc = (struct ch_softc *)periph->softc;
924 /*
925 * Check arguments.
926 */
927 if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
928 (ce->ce_sdsttype > CHET_DT))
929 return (EINVAL);
930 if ((ce->ce_srcunit > (softc->sc_counts[ce->ce_srctype] - 1)) ||
931 (ce->ce_fdstunit > (softc->sc_counts[ce->ce_fdsttype] - 1)) ||
932 (ce->ce_sdstunit > (softc->sc_counts[ce->ce_sdsttype] - 1)))
933 return (ENODEV);
934
935 /*
936 * Check the request against the changer's capabilities.
937 */
938 if (((softc->sc_exchangemask[ce->ce_srctype] &
939 (1 << ce->ce_fdsttype)) == 0) ||
940 ((softc->sc_exchangemask[ce->ce_fdsttype] &
941 (1 << ce->ce_sdsttype)) == 0))
942 return (ENODEV);
943
944 /*
945 * Calculate the source and destination elements.
946 */
947 src = softc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
948 dst1 = softc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
949 dst2 = softc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
950
952
954 /* retries */ 1,
955 /* cbfcnp */ chdone,
956 /* tag_action */ MSG_SIMPLE_Q_TAG,
957 /* tea */ softc->sc_picker,
958 /* src */ src,
959 /* dst1 */ dst1,
960 /* dst2 */ dst2,
961 /* invert1 */ (ce->ce_flags & CE_INVERT1) ?
962 TRUE : FALSE,
963 /* invert2 */ (ce->ce_flags & CE_INVERT2) ?
964 TRUE : FALSE,
965 /* sense_len */ SSD_FULL_SIZE,
966 /* timeout */ CH_TIMEOUT_EXCHANGE_MEDIUM);
967
968 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO,
969 /*sense_flags*/ SF_RETRY_UA,
970 softc->device_stats);
971
973
974 return(error);
975}
976
977static int
978chposition(struct cam_periph *periph, struct changer_position *cp)
979{
980 struct ch_softc *softc;
981 u_int16_t dst;
982 union ccb *ccb;
983 int error;
984
985 error = 0;
986 softc = (struct ch_softc *)periph->softc;
987
988 /*
989 * Check arguments.
990 */
991 if (cp->cp_type > CHET_DT)
992 return (EINVAL);
993 if (cp->cp_unit > (softc->sc_counts[cp->cp_type] - 1))
994 return (ENODEV);
995
996 /*
997 * Calculate the destination element.
998 */
999 dst = softc->sc_firsts[cp->cp_type] + cp->cp_unit;
1000
1002
1004 /* retries */ 1,
1005 /* cbfcnp */ chdone,
1006 /* tag_action */ MSG_SIMPLE_Q_TAG,
1007 /* tea */ softc->sc_picker,
1008 /* dst */ dst,
1009 /* invert */ (cp->cp_flags & CP_INVERT) ?
1010 TRUE : FALSE,
1011 /* sense_len */ SSD_FULL_SIZE,
1012 /* timeout */ CH_TIMEOUT_POSITION_TO_ELEMENT);
1013
1014 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1015 /*sense_flags*/ SF_RETRY_UA,
1016 softc->device_stats);
1017
1019
1020 return(error);
1021}
1022
1023/*
1024 * Copy a volume tag to a volume_tag struct, converting SCSI byte order
1025 * to host native byte order in the volume serial number. The volume
1026 * label as returned by the changer is transferred to user mode as
1027 * nul-terminated string. Volume labels are truncated at the first
1028 * space, as suggested by SCSI-2.
1029 */
1030static void
1031copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag)
1032{
1033 int i;
1034 for (i=0; i<CH_VOLTAG_MAXLEN; i++) {
1035 char c = voltag->vif[i];
1036 if (c && c != ' ')
1037 uvoltag->cv_volid[i] = c;
1038 else
1039 break;
1040 }
1041 uvoltag->cv_serial = scsi_2btoul(voltag->vsn);
1042}
1043
1044/*
1045 * Copy an element status descriptor to a user-mode
1046 * changer_element_status structure.
1047 */
1048static void
1050 u_int16_t flags,
1051 struct read_element_status_descriptor *desc,
1052 struct changer_element_status *ces,
1053 int scsi_version)
1054{
1055 u_int16_t eaddr = scsi_2btoul(desc->eaddr);
1056 u_int16_t et;
1057 struct volume_tag *pvol_tag = NULL, *avol_tag = NULL;
1058 struct read_element_status_device_id *devid = NULL;
1059
1060 ces->ces_int_addr = eaddr;
1061 /* set up logical address in element status */
1062 for (et = CHET_MT; et <= CHET_DT; et++) {
1063 if ((softc->sc_firsts[et] <= eaddr)
1064 && ((softc->sc_firsts[et] + softc->sc_counts[et])
1065 > eaddr)) {
1066 ces->ces_addr = eaddr - softc->sc_firsts[et];
1067 ces->ces_type = et;
1068 break;
1069 }
1070 }
1071
1072 ces->ces_flags = desc->flags1;
1073
1074 ces->ces_sensecode = desc->sense_code;
1075 ces->ces_sensequal = desc->sense_qual;
1076
1078 ces->ces_flags |= CES_INVERT;
1079
1080 if (desc->flags2 & READ_ELEMENT_STATUS_SVALID) {
1081 eaddr = scsi_2btoul(desc->ssea);
1082
1083 /* convert source address to logical format */
1084 for (et = CHET_MT; et <= CHET_DT; et++) {
1085 if ((softc->sc_firsts[et] <= eaddr)
1086 && ((softc->sc_firsts[et] + softc->sc_counts[et])
1087 > eaddr)) {
1088 ces->ces_source_addr =
1089 eaddr - softc->sc_firsts[et];
1090 ces->ces_source_type = et;
1091 ces->ces_flags |= CES_SOURCE_VALID;
1092 break;
1093 }
1094 }
1095
1096 if (!(ces->ces_flags & CES_SOURCE_VALID))
1097 printf("ch: warning: could not map element source "
1098 "address %ud to a valid element type\n",
1099 eaddr);
1100 }
1101
1102 /*
1103 * pvoltag and avoltag are common between SCSI-2 and later versions
1104 */
1105 if (flags & READ_ELEMENT_STATUS_PVOLTAG)
1106 pvol_tag = &desc->voltag_devid.pvoltag;
1107 if (flags & READ_ELEMENT_STATUS_AVOLTAG)
1108 avol_tag = (flags & READ_ELEMENT_STATUS_PVOLTAG) ?
1109 &desc->voltag_devid.voltag[1] :&desc->voltag_devid.pvoltag;
1110 /*
1111 * For SCSI-3 and later, element status can carry designator and
1112 * other information.
1113 */
1114 if (scsi_version >= SCSI_REV_SPC) {
1115 if ((flags & READ_ELEMENT_STATUS_PVOLTAG) ^
1117 devid = &desc->voltag_devid.pvol_and_devid.devid;
1118 else if (!(flags & READ_ELEMENT_STATUS_PVOLTAG) &&
1119 !(flags & READ_ELEMENT_STATUS_AVOLTAG))
1120 devid = &desc->voltag_devid.devid;
1121 else /* Have both PVOLTAG and AVOLTAG */
1122 devid = &desc->voltag_devid.vol_tags_and_devid.devid;
1123 }
1124
1125 if (pvol_tag)
1126 copy_voltag(&(ces->ces_pvoltag), pvol_tag);
1127 if (avol_tag)
1128 copy_voltag(&(ces->ces_pvoltag), avol_tag);
1129 if (devid != NULL) {
1130 if (devid->designator_length > 0) {
1131 bcopy((void *)devid->designator,
1132 (void *)ces->ces_designator,
1133 devid->designator_length);
1134 ces->ces_designator_length = devid->designator_length;
1135 /*
1136 * Make sure we are always NUL terminated. The
1137 * This won't matter for the binary code set,
1138 * since the user will only pay attention to the
1139 * length field.
1140 */
1141 ces->ces_designator[devid->designator_length]= '\0';
1142 }
1143 if (devid->piv_assoc_designator_type &
1145 ces->ces_flags |= CES_PIV;
1146 ces->ces_protocol_id =
1148 devid->prot_code_set);
1149 }
1150 ces->ces_code_set =
1152 ces->ces_assoc = READ_ELEMENT_STATUS_ASSOCIATION(
1154 ces->ces_designator_type = READ_ELEMENT_STATUS_DESIGNATOR_TYPE(
1156 } else if (scsi_version > SCSI_REV_2) {
1157 /* SCSI-SPC and No devid, no designator */
1158 ces->ces_designator_length = 0;
1159 ces->ces_designator[0] = '\0';
1160 ces->ces_protocol_id = CES_PROTOCOL_ID_FCP_4;
1161 }
1162
1163 if (scsi_version <= SCSI_REV_2) {
1166 ces->ces_flags |= CES_SCSIID_VALID;
1167 ces->ces_scsi_id =
1169 }
1170
1173 ces->ces_flags |= CES_LUN_VALID;
1174 ces->ces_scsi_lun =
1177 }
1178 }
1179}
1180
1181static int
1182chgetelemstatus(struct cam_periph *periph, int scsi_version, u_long cmd,
1183 struct changer_element_status_request *cesr)
1184{
1185 struct read_element_status_header *st_hdr;
1186 struct read_element_status_page_header *pg_hdr;
1187 struct read_element_status_descriptor *desc;
1188 caddr_t data = NULL;
1189 size_t size, desclen;
1190 u_int avail, i;
1191 int curdata, dvcid, sense_flags;
1192 int try_no_dvcid = 0;
1193 struct changer_element_status *user_data = NULL;
1194 struct ch_softc *softc;
1195 union ccb *ccb;
1196 int chet = cesr->cesr_element_type;
1197 int error = 0;
1198 int want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0;
1199
1200 softc = (struct ch_softc *)periph->softc;
1201
1202 /* perform argument checking */
1203
1204 /*
1205 * Perform a range check on the cesr_element_{base,count}
1206 * request argument fields.
1207 */
1208 if ((softc->sc_counts[chet] - cesr->cesr_element_base) <= 0
1209 || (cesr->cesr_element_base + cesr->cesr_element_count)
1210 > softc->sc_counts[chet])
1211 return (EINVAL);
1212
1213 /*
1214 * Request one descriptor for the given element type. This
1215 * is used to determine the size of the descriptor so that
1216 * we can allocate enough storage for all of them. We assume
1217 * that the first one can fit into 1k.
1218 */
1219 cam_periph_unlock(periph);
1220 data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
1221
1222 cam_periph_lock(periph);
1224
1225 sense_flags = SF_RETRY_UA;
1226 if (softc->quirks & CH_Q_NO_DVCID) {
1227 dvcid = 0;
1228 curdata = 0;
1229 } else {
1230 dvcid = 1;
1231 curdata = 1;
1232 /*
1233 * Don't print anything for an Illegal Request, because
1234 * these flags can cause some changers to complain. We'll
1235 * retry without them if we get an error.
1236 */
1237 sense_flags |= SF_QUIET_IR;
1238 }
1239
1240retry_einval:
1241
1243 /* retries */ 1,
1244 /* cbfcnp */ chdone,
1245 /* tag_action */ MSG_SIMPLE_Q_TAG,
1246 /* voltag */ want_voltags,
1247 /* sea */ softc->sc_firsts[chet],
1248 /* curdata */ curdata,
1249 /* dvcid */ dvcid,
1250 /* count */ 1,
1251 /* data_ptr */ data,
1252 /* dxfer_len */ 1024,
1253 /* sense_len */ SSD_FULL_SIZE,
1254 /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS);
1255
1256 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1257 /*sense_flags*/ sense_flags,
1258 softc->device_stats);
1259
1260 /*
1261 * An Illegal Request sense key (only used if there is no asc/ascq)
1262 * or 0x24,0x00 for an ASC/ASCQ both map to EINVAL. If dvcid or
1263 * curdata are set (we set both or neither), try turning them off
1264 * and see if the command is successful.
1265 */
1266 if ((error == EINVAL)
1267 && (dvcid || curdata)) {
1268 dvcid = 0;
1269 curdata = 0;
1270 error = 0;
1271 /* At this point we want to report any Illegal Request */
1272 sense_flags &= ~SF_QUIET_IR;
1273 try_no_dvcid = 1;
1274 goto retry_einval;
1275 }
1276
1277 /*
1278 * In this case, we tried a read element status with dvcid and
1279 * curdata set, and it failed. We retried without those bits, and
1280 * it succeeded. Suggest to the user that he set a quirk, so we
1281 * don't go through the retry process the first time in the future.
1282 * This should only happen on changers that claim SCSI-3 or higher,
1283 * but don't support these bits.
1284 */
1285 if ((try_no_dvcid != 0)
1286 && (error == 0))
1287 softc->quirks |= CH_Q_NO_DVCID;
1288
1289 if (error)
1290 goto done;
1291 cam_periph_unlock(periph);
1292
1293 st_hdr = (struct read_element_status_header *)data;
1294 pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr +
1295 sizeof(struct read_element_status_header));
1296 desclen = scsi_2btoul(pg_hdr->edl);
1297
1298 size = sizeof(struct read_element_status_header) +
1299 sizeof(struct read_element_status_page_header) +
1300 (desclen * cesr->cesr_element_count);
1301 /*
1302 * Reallocate storage for descriptors and get them from the
1303 * device.
1304 */
1305 free(data, M_DEVBUF);
1306 data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
1307
1308 cam_periph_lock(periph);
1310 /* retries */ 1,
1311 /* cbfcnp */ chdone,
1312 /* tag_action */ MSG_SIMPLE_Q_TAG,
1313 /* voltag */ want_voltags,
1314 /* sea */ softc->sc_firsts[chet]
1315 + cesr->cesr_element_base,
1316 /* curdata */ curdata,
1317 /* dvcid */ dvcid,
1318 /* count */ cesr->cesr_element_count,
1319 /* data_ptr */ data,
1320 /* dxfer_len */ size,
1321 /* sense_len */ SSD_FULL_SIZE,
1322 /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS);
1323
1324 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1325 /*sense_flags*/ SF_RETRY_UA,
1326 softc->device_stats);
1327
1328 if (error)
1329 goto done;
1330 cam_periph_unlock(periph);
1331
1332 /*
1333 * Fill in the user status array.
1334 */
1335 st_hdr = (struct read_element_status_header *)data;
1336 pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr +
1337 sizeof(struct read_element_status_header));
1338 avail = scsi_2btoul(st_hdr->count);
1339
1340 if (avail != cesr->cesr_element_count) {
1341 xpt_print(periph->path,
1342 "warning, READ ELEMENT STATUS avail != count\n");
1343 }
1344
1345 user_data = (struct changer_element_status *)
1346 malloc(avail * sizeof(struct changer_element_status),
1347 M_DEVBUF, M_WAITOK | M_ZERO);
1348
1349 desc = (struct read_element_status_descriptor *)((uintptr_t)data +
1350 sizeof(struct read_element_status_header) +
1351 sizeof(struct read_element_status_page_header));
1352 /*
1353 * Set up the individual element status structures
1354 */
1355 for (i = 0; i < avail; ++i) {
1356 struct changer_element_status *ces;
1357
1358 /*
1359 * In the changer_element_status structure, fields from
1360 * the beginning to the field of ces_scsi_lun are common
1361 * between SCSI-2 and SCSI-3, while all the rest are new
1362 * from SCSI-3. In order to maintain backward compatibility
1363 * of the chio command, the ces pointer, below, is computed
1364 * such that it lines up with the structure boundary
1365 * corresponding to the SCSI version.
1366 */
1367 ces = cmd == OCHIOGSTATUS ?
1368 (struct changer_element_status *)
1369 ((unsigned char *)user_data + i *
1370 (offsetof(struct changer_element_status,ces_scsi_lun)+1)):
1371 &user_data[i];
1372
1373 copy_element_status(softc, pg_hdr->flags, desc,
1374 ces, scsi_version);
1375
1376 desc = (struct read_element_status_descriptor *)
1377 ((unsigned char *)desc + desclen);
1378 }
1379
1380 /* Copy element status structures out to userspace. */
1381 if (cmd == OCHIOGSTATUS)
1382 error = copyout(user_data,
1383 cesr->cesr_element_status,
1384 avail* (offsetof(struct changer_element_status,
1385 ces_scsi_lun) + 1));
1386 else
1387 error = copyout(user_data,
1388 cesr->cesr_element_status,
1389 avail * sizeof(struct changer_element_status));
1390
1391 cam_periph_lock(periph);
1392
1393 done:
1395
1396 if (data != NULL)
1397 free(data, M_DEVBUF);
1398 if (user_data != NULL)
1399 free(user_data, M_DEVBUF);
1400
1401 return (error);
1402}
1403
1404static int
1405chielem(struct cam_periph *periph,
1406 unsigned int timeout)
1407{
1408 union ccb *ccb;
1409 struct ch_softc *softc;
1410 int error;
1411
1412 if (!timeout) {
1414 } else {
1415 timeout *= 1000;
1416 }
1417
1418 error = 0;
1419 softc = (struct ch_softc *)periph->softc;
1420
1422
1424 /* retries */ 1,
1425 /* cbfcnp */ chdone,
1426 /* tag_action */ MSG_SIMPLE_Q_TAG,
1427 /* sense_len */ SSD_FULL_SIZE,
1428 /* timeout */ timeout);
1429
1430 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1431 /*sense_flags*/ SF_RETRY_UA,
1432 softc->device_stats);
1433
1435
1436 return(error);
1437}
1438
1439static int
1441 struct changer_set_voltag_request *csvr)
1442{
1443 union ccb *ccb;
1444 struct ch_softc *softc;
1445 u_int16_t ea;
1446 u_int8_t sac;
1448 int error;
1449 int i;
1450
1451 error = 0;
1452 softc = (struct ch_softc *)periph->softc;
1453
1454 bzero(&ssvtp, sizeof(ssvtp));
1455 for (i=0; i<sizeof(ssvtp.vitf); i++) {
1456 ssvtp.vitf[i] = ' ';
1457 }
1458
1459 /*
1460 * Check arguments.
1461 */
1462 if (csvr->csvr_type > CHET_DT)
1463 return EINVAL;
1464 if (csvr->csvr_addr > (softc->sc_counts[csvr->csvr_type] - 1))
1465 return ENODEV;
1466
1467 ea = softc->sc_firsts[csvr->csvr_type] + csvr->csvr_addr;
1468
1469 if (csvr->csvr_flags & CSVR_ALTERNATE) {
1470 switch (csvr->csvr_flags & CSVR_MODE_MASK) {
1471 case CSVR_MODE_SET:
1473 break;
1474 case CSVR_MODE_REPLACE:
1476 break;
1477 case CSVR_MODE_CLEAR:
1479 break;
1480 default:
1481 error = EINVAL;
1482 goto out;
1483 }
1484 } else {
1485 switch (csvr->csvr_flags & CSVR_MODE_MASK) {
1486 case CSVR_MODE_SET:
1488 break;
1489 case CSVR_MODE_REPLACE:
1491 break;
1492 case CSVR_MODE_CLEAR:
1494 break;
1495 default:
1496 error = EINVAL;
1497 goto out;
1498 }
1499 }
1500
1501 memcpy(ssvtp.vitf, csvr->csvr_voltag.cv_volid,
1502 min(strlen(csvr->csvr_voltag.cv_volid), sizeof(ssvtp.vitf)));
1503 scsi_ulto2b(csvr->csvr_voltag.cv_serial, ssvtp.minvsn);
1504
1506
1508 /* retries */ 1,
1509 /* cbfcnp */ chdone,
1510 /* tag_action */ MSG_SIMPLE_Q_TAG,
1511 /* element_address */ ea,
1512 /* send_action_code */ sac,
1513 /* parameters */ &ssvtp,
1514 /* sense_len */ SSD_FULL_SIZE,
1515 /* timeout */ CH_TIMEOUT_SEND_VOLTAG);
1516
1517 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1518 /*sense_flags*/ SF_RETRY_UA,
1519 softc->device_stats);
1520
1522
1523 out:
1524 return error;
1525}
1526
1527static int
1529{
1530 union ccb *ccb;
1531 struct ch_softc *softc;
1532 void *mode_buffer;
1533 int mode_buffer_len;
1535 struct page_device_capabilities *cap;
1536 int error, from, dbd;
1537 u_int8_t *moves, *exchanges;
1538
1539 error = 0;
1540
1541 softc = (struct ch_softc *)periph->softc;
1542
1544
1545 /*
1546 * The scsi_mode_sense_data structure is just a convenience
1547 * structure that allows us to easily calculate the worst-case
1548 * storage size of the mode sense buffer.
1549 */
1550 mode_buffer_len = sizeof(struct scsi_mode_sense_data);
1551
1552 mode_buffer = malloc(mode_buffer_len, M_SCSICH, M_NOWAIT);
1553
1554 if (mode_buffer == NULL) {
1555 printf("chgetparams: couldn't malloc mode sense data\n");
1557 return(ENOSPC);
1558 }
1559
1560 bzero(mode_buffer, mode_buffer_len);
1561
1562 if (softc->quirks & CH_Q_NO_DBD)
1563 dbd = FALSE;
1564 else
1565 dbd = TRUE;
1566
1567 /*
1568 * Get the element address assignment page.
1569 */
1571 /* retries */ 1,
1572 /* cbfcnp */ chdone,
1573 /* tag_action */ MSG_SIMPLE_Q_TAG,
1574 /* dbd */ dbd,
1575 /* pc */ SMS_PAGE_CTRL_CURRENT,
1576 /* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE,
1577 /* param_buf */ (u_int8_t *)mode_buffer,
1578 /* param_len */ mode_buffer_len,
1579 /* sense_len */ SSD_FULL_SIZE,
1580 /* timeout */ CH_TIMEOUT_MODE_SENSE);
1581
1582 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1583 /* sense_flags */ SF_RETRY_UA|SF_NO_PRINT,
1584 softc->device_stats);
1585
1586 if (error) {
1587 if (dbd) {
1588 struct scsi_mode_sense_6 *sms;
1589
1590 sms = (struct scsi_mode_sense_6 *)
1592
1593 sms->byte2 &= ~SMS_DBD;
1594 error = cam_periph_runccb(ccb, cherror,
1595 /*cam_flags*/ CAM_RETRY_SELTO,
1596 /*sense_flags*/ SF_RETRY_UA,
1597 softc->device_stats);
1598 } else {
1599 /*
1600 * Since we disabled sense printing above, print
1601 * out the sense here since we got an error.
1602 */
1604 }
1605
1606 if (error) {
1607 xpt_print(periph->path,
1608 "chgetparams: error getting element "
1609 "address page\n");
1611 free(mode_buffer, M_SCSICH);
1612 return(error);
1613 }
1614 }
1615
1616 ea = (struct page_element_address_assignment *)
1617 find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer);
1618
1619 softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea);
1620 softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte);
1621 softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea);
1622 softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse);
1623 softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea);
1624 softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee);
1625 softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea);
1626 softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte);
1627
1628 bzero(mode_buffer, mode_buffer_len);
1629
1630 /*
1631 * Now get the device capabilities page.
1632 */
1634 /* retries */ 1,
1635 /* cbfcnp */ chdone,
1636 /* tag_action */ MSG_SIMPLE_Q_TAG,
1637 /* dbd */ dbd,
1638 /* pc */ SMS_PAGE_CTRL_CURRENT,
1639 /* page */ CH_DEVICE_CAP_PAGE,
1640 /* param_buf */ (u_int8_t *)mode_buffer,
1641 /* param_len */ mode_buffer_len,
1642 /* sense_len */ SSD_FULL_SIZE,
1643 /* timeout */ CH_TIMEOUT_MODE_SENSE);
1644
1645 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
1646 /* sense_flags */ SF_RETRY_UA | SF_NO_PRINT,
1647 softc->device_stats);
1648
1649 if (error) {
1650 if (dbd) {
1651 struct scsi_mode_sense_6 *sms;
1652
1653 sms = (struct scsi_mode_sense_6 *)
1655
1656 sms->byte2 &= ~SMS_DBD;
1657 error = cam_periph_runccb(ccb, cherror,
1658 /*cam_flags*/ CAM_RETRY_SELTO,
1659 /*sense_flags*/ SF_RETRY_UA,
1660 softc->device_stats);
1661 } else {
1662 /*
1663 * Since we disabled sense printing above, print
1664 * out the sense here since we got an error.
1665 */
1667 }
1668
1669 if (error) {
1670 xpt_print(periph->path,
1671 "chgetparams: error getting device "
1672 "capabilities page\n");
1674 free(mode_buffer, M_SCSICH);
1675 return(error);
1676 }
1677 }
1678
1680
1681 cap = (struct page_device_capabilities *)
1682 find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer);
1683
1684 bzero(softc->sc_movemask, sizeof(softc->sc_movemask));
1685 bzero(softc->sc_exchangemask, sizeof(softc->sc_exchangemask));
1686 moves = cap->move_from;
1687 exchanges = cap->exchange_with;
1688 for (from = CHET_MT; from <= CHET_MAX; ++from) {
1689 softc->sc_movemask[from] = moves[from];
1690 softc->sc_exchangemask[from] = exchanges[from];
1691 }
1692
1693 free(mode_buffer, M_SCSICH);
1694
1695 return(error);
1696}
1697
1698static int
1700{
1701 struct scsi_inquiry_data *inq_data;
1702 struct ccb_getdev *cgd;
1703 int dev_scsi_version;
1704
1705 cam_periph_assert(periph, MA_OWNED);
1706 if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) == NULL)
1707 return (-1);
1708 /*
1709 * Get the device information.
1710 */
1711 xpt_setup_ccb(&cgd->ccb_h,
1712 periph->path,
1715 xpt_action((union ccb *)cgd);
1716
1717 if (cgd->ccb_h.status != CAM_REQ_CMP) {
1718 xpt_free_ccb((union ccb *)cgd);
1719 return -1;
1720 }
1721
1722 inq_data = &cgd->inq_data;
1723 dev_scsi_version = inq_data->version;
1724 xpt_free_ccb((union ccb *)cgd);
1725
1726 return dev_scsi_version;
1727}
1728
1729void
1730scsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries,
1731 void (*cbfcnp)(struct cam_periph *, union ccb *),
1732 u_int8_t tag_action, u_int32_t tea, u_int32_t src,
1733 u_int32_t dst, int invert, u_int8_t sense_len,
1734 u_int32_t timeout)
1735{
1736 struct scsi_move_medium *scsi_cmd;
1737
1738 scsi_cmd = (struct scsi_move_medium *)&csio->cdb_io.cdb_bytes;
1739 bzero(scsi_cmd, sizeof(*scsi_cmd));
1740
1741 scsi_cmd->opcode = MOVE_MEDIUM;
1742
1743 scsi_ulto2b(tea, scsi_cmd->tea);
1744 scsi_ulto2b(src, scsi_cmd->src);
1745 scsi_ulto2b(dst, scsi_cmd->dst);
1746
1747 if (invert)
1748 scsi_cmd->invert |= MOVE_MEDIUM_INVERT;
1749
1750 cam_fill_csio(csio,
1751 retries,
1752 cbfcnp,
1753 /*flags*/ CAM_DIR_NONE,
1754 tag_action,
1755 /*data_ptr*/ NULL,
1756 /*dxfer_len*/ 0,
1757 sense_len,
1758 sizeof(*scsi_cmd),
1759 timeout);
1760}
1761
1762void
1763scsi_exchange_medium(struct ccb_scsiio *csio, u_int32_t retries,
1764 void (*cbfcnp)(struct cam_periph *, union ccb *),
1765 u_int8_t tag_action, u_int32_t tea, u_int32_t src,
1766 u_int32_t dst1, u_int32_t dst2, int invert1,
1767 int invert2, u_int8_t sense_len, u_int32_t timeout)
1768{
1769 struct scsi_exchange_medium *scsi_cmd;
1770
1771 scsi_cmd = (struct scsi_exchange_medium *)&csio->cdb_io.cdb_bytes;
1772 bzero(scsi_cmd, sizeof(*scsi_cmd));
1773
1774 scsi_cmd->opcode = EXCHANGE_MEDIUM;
1775
1776 scsi_ulto2b(tea, scsi_cmd->tea);
1777 scsi_ulto2b(src, scsi_cmd->src);
1778 scsi_ulto2b(dst1, scsi_cmd->fdst);
1779 scsi_ulto2b(dst2, scsi_cmd->sdst);
1780
1781 if (invert1)
1782 scsi_cmd->invert |= EXCHANGE_MEDIUM_INV1;
1783
1784 if (invert2)
1785 scsi_cmd->invert |= EXCHANGE_MEDIUM_INV2;
1786
1787 cam_fill_csio(csio,
1788 retries,
1789 cbfcnp,
1790 /*flags*/ CAM_DIR_NONE,
1791 tag_action,
1792 /*data_ptr*/ NULL,
1793 /*dxfer_len*/ 0,
1794 sense_len,
1795 sizeof(*scsi_cmd),
1796 timeout);
1797}
1798
1799void
1800scsi_position_to_element(struct ccb_scsiio *csio, u_int32_t retries,
1801 void (*cbfcnp)(struct cam_periph *, union ccb *),
1802 u_int8_t tag_action, u_int32_t tea, u_int32_t dst,
1803 int invert, u_int8_t sense_len, u_int32_t timeout)
1804{
1805 struct scsi_position_to_element *scsi_cmd;
1806
1807 scsi_cmd = (struct scsi_position_to_element *)&csio->cdb_io.cdb_bytes;
1808 bzero(scsi_cmd, sizeof(*scsi_cmd));
1809
1810 scsi_cmd->opcode = POSITION_TO_ELEMENT;
1811
1812 scsi_ulto2b(tea, scsi_cmd->tea);
1813 scsi_ulto2b(dst, scsi_cmd->dst);
1814
1815 if (invert)
1817
1818 cam_fill_csio(csio,
1819 retries,
1820 cbfcnp,
1821 /*flags*/ CAM_DIR_NONE,
1822 tag_action,
1823 /*data_ptr*/ NULL,
1824 /*dxfer_len*/ 0,
1825 sense_len,
1826 sizeof(*scsi_cmd),
1827 timeout);
1828}
1829
1830void
1831scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries,
1832 void (*cbfcnp)(struct cam_periph *, union ccb *),
1833 u_int8_t tag_action, int voltag, u_int32_t sea,
1834 int curdata, int dvcid,
1835 u_int32_t count, u_int8_t *data_ptr,
1836 u_int32_t dxfer_len, u_int8_t sense_len,
1837 u_int32_t timeout)
1838{
1839 struct scsi_read_element_status *scsi_cmd;
1840
1841 scsi_cmd = (struct scsi_read_element_status *)&csio->cdb_io.cdb_bytes;
1842 bzero(scsi_cmd, sizeof(*scsi_cmd));
1843
1844 scsi_cmd->opcode = READ_ELEMENT_STATUS;
1845
1846 scsi_ulto2b(sea, scsi_cmd->sea);
1847 scsi_ulto2b(count, scsi_cmd->count);
1848 scsi_ulto3b(dxfer_len, scsi_cmd->len);
1849 if (dvcid)
1850 scsi_cmd->flags |= READ_ELEMENT_STATUS_DVCID;
1851 if (curdata)
1853
1854 if (voltag)
1855 scsi_cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG;
1856
1857 cam_fill_csio(csio,
1858 retries,
1859 cbfcnp,
1860 /*flags*/ CAM_DIR_IN,
1861 tag_action,
1862 data_ptr,
1863 dxfer_len,
1864 sense_len,
1865 sizeof(*scsi_cmd),
1866 timeout);
1867}
1868
1869void
1870scsi_initialize_element_status(struct ccb_scsiio *csio, u_int32_t retries,
1871 void (*cbfcnp)(struct cam_periph *, union ccb *),
1872 u_int8_t tag_action, u_int8_t sense_len,
1873 u_int32_t timeout)
1874{
1875 struct scsi_initialize_element_status *scsi_cmd;
1876
1877 scsi_cmd = (struct scsi_initialize_element_status *)
1878 &csio->cdb_io.cdb_bytes;
1879 bzero(scsi_cmd, sizeof(*scsi_cmd));
1880
1882
1883 cam_fill_csio(csio,
1884 retries,
1885 cbfcnp,
1886 /*flags*/ CAM_DIR_NONE,
1887 tag_action,
1888 /* data_ptr */ NULL,
1889 /* dxfer_len */ 0,
1890 sense_len,
1891 sizeof(*scsi_cmd),
1892 timeout);
1893}
1894
1895void
1896scsi_send_volume_tag(struct ccb_scsiio *csio, u_int32_t retries,
1897 void (*cbfcnp)(struct cam_periph *, union ccb *),
1898 u_int8_t tag_action,
1899 u_int16_t element_address,
1900 u_int8_t send_action_code,
1901 struct scsi_send_volume_tag_parameters *parameters,
1902 u_int8_t sense_len, u_int32_t timeout)
1903{
1904 struct scsi_send_volume_tag *scsi_cmd;
1905
1906 scsi_cmd = (struct scsi_send_volume_tag *) &csio->cdb_io.cdb_bytes;
1907 bzero(scsi_cmd, sizeof(*scsi_cmd));
1908
1909 scsi_cmd->opcode = SEND_VOLUME_TAG;
1910 scsi_ulto2b(element_address, scsi_cmd->ea);
1911 scsi_cmd->sac = send_action_code;
1912 scsi_ulto2b(sizeof(*parameters), scsi_cmd->pll);
1913
1914 cam_fill_csio(csio,
1915 retries,
1916 cbfcnp,
1917 /*flags*/ CAM_DIR_OUT,
1918 tag_action,
1919 /* data_ptr */ (u_int8_t *) parameters,
1920 sizeof(*parameters),
1921 sense_len,
1922 sizeof(*scsi_cmd),
1923 timeout);
1924}
@ SF_QUIET_IR
Definition: cam.h:124
@ SF_RETRY_UA
Definition: cam.h:122
@ SF_NO_PRINT
Definition: cam.h:123
cam_flags
Definition: cam.h:115
@ CAM_RETRY_SELTO
Definition: cam.h:118
#define CAM_PRIORITY_NORMAL
Definition: cam.h:92
cam_status
Definition: cam.h:132
@ CAM_REQ_INPROG
Definition: cam.h:134
@ CAM_REQ_CMP
Definition: cam.h:137
@ CAM_REQ_CMP_ERR
Definition: cam.h:146
@ CAM_STATUS_MASK
Definition: cam.h:302
@ CAM_SCSI_STATUS_ERROR
Definition: cam.h:170
@ CAM_DEV_QFRZN
Definition: cam.h:287
#define CAM_PRIORITY_DEV
Definition: cam.h:90
@ AC_FOUND_DEVICE
Definition: cam_ccb.h:874
@ AC_LOST_DEVICE
Definition: cam_ccb.h:873
@ PROTO_SCSI
Definition: cam_ccb.h:279
@ CAM_DIR_IN
Definition: cam_ccb.h:79
@ CAM_DIR_NONE
Definition: cam_ccb.h:81
@ CAM_DIR_OUT
Definition: cam_ccb.h:80
static __BEGIN_DECLS __inline void cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries, void(*cbfcnp)(struct cam_periph *, union ccb *), u_int32_t flags, u_int8_t tag_action, u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, u_int8_t cdb_len, u_int32_t timeout)
Definition: cam_ccb.h:1389
@ XPT_GDEV_TYPE
Definition: cam_ccb.h:143
#define XPORT_DEVSTAT_TYPE(t)
Definition: cam_ccb.h:310
@ CAM_DEBUG_TRACE
Definition: cam_debug.h:41
#define CAM_DEBUG(path, flag, printfargs)
Definition: cam_debug.h:93
void cam_periph_release_locked(struct cam_periph *periph)
Definition: cam_periph.c:453
u_int32_t cam_release_devq(struct cam_path *path, u_int32_t relsim_flags, u_int32_t openings, u_int32_t arg, int getcount_only)
Definition: cam_periph.c:1342
int cam_periph_acquire(struct cam_periph *periph)
Definition: cam_periph.c:413
void cam_periph_async(struct cam_periph *periph, u_int32_t code, struct cam_path *path, void *arg)
Definition: cam_periph.c:1471
void cam_periph_release(struct cam_periph *periph)
Definition: cam_periph.c:465
void cam_periph_unhold(struct cam_periph *periph)
Definition: cam_periph.c:519
int cam_periph_hold(struct cam_periph *periph, int priority)
Definition: cam_periph.c:486
int cam_periph_runccb(union ccb *ccb, int(*error_routine)(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags), cam_flags camflags, u_int32_t sense_flags, struct devstat *ds)
Definition: cam_periph.c:1207
void cam_periph_invalidate(struct cam_periph *periph)
Definition: cam_periph.c:655
int cam_periph_error(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags)
Definition: cam_periph.c:1864
int cam_periph_ioctl(struct cam_periph *periph, u_long cmd, caddr_t addr, int(*error_routine)(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags))
Definition: cam_periph.c:1109
cam_status cam_periph_alloc(periph_ctor_t *periph_ctor, periph_oninv_t *periph_oninvalidate, periph_dtor_t *periph_dtor, periph_start_t *periph_start, char *name, cam_periph_type type, struct cam_path *path, ac_callback_t *ac_callback, ac_code code, void *arg)
Definition: cam_periph.c:197
cam_status periph_ctor_t(struct cam_periph *periph, void *arg)
Definition: cam_periph.h:115
#define CAM_PERIPH_INVALID
Definition: cam_periph.h:133
void periph_oninv_t(struct cam_periph *periph)
Definition: cam_periph.h:117
#define cam_periph_assert(periph, what)
Definition: cam_periph.h:230
#define cam_periph_lock(periph)
Definition: cam_periph.h:224
union ccb * cam_periph_getccb(struct cam_periph *periph, u_int32_t priority)
Definition: cam_xpt.c:4695
#define cam_periph_unlock(periph)
Definition: cam_periph.h:227
static __inline struct mtx * cam_periph_mtx(struct cam_periph *periph)
Definition: cam_periph.h:213
void periph_dtor_t(struct cam_periph *periph)
Definition: cam_periph.h:118
void periph_start_t(struct cam_periph *periph, union ccb *start_ccb)
Definition: cam_periph.h:113
@ CAM_PERIPH_BIO
Definition: cam_periph.h:104
void() periph_init_t(void)
Definition: cam_periph.h:85
void xpt_schedule(struct cam_periph *periph, u_int32_t new_priority)
Definition: cam_xpt.c:3243
void xpt_print(struct cam_path *path, const char *fmt,...)
Definition: cam_xpt.c:3814
void xpt_announce_periph(struct cam_periph *periph, char *announce_string)
Definition: cam_xpt.c:1049
void xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority)
Definition: cam_xpt.c:3520
void xpt_action(union ccb *start_ccb)
Definition: cam_xpt.c:2601
cam_status xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, struct cam_path *path)
Definition: cam_xpt.c:5213
union ccb * xpt_alloc_ccb_nowait(void)
Definition: cam_xpt.c:4621
void xpt_release_ccb(union ccb *free_ccb)
Definition: cam_xpt.c:3924
void xpt_announce_quirks(struct cam_periph *periph, int quirks, char *bit_string)
Definition: cam_xpt.c:1151
void xpt_free_ccb(union ccb *free_ccb)
Definition: cam_xpt.c:4630
static void xpt_path_inq(struct ccb_pathinq *cpi, struct cam_path *path)
Definition: cam_xpt.h:156
union ccb * ccb
Definition: mmc_sim_if.m:53
void scsi_mode_sense(struct ccb_scsiio *csio, uint32_t retries, void(*cbfcnp)(struct cam_periph *, union ccb *), uint8_t tag_action, int dbd, uint8_t pc, uint8_t page, uint8_t *param_buf, uint32_t param_len, uint8_t sense_len, uint32_t timeout)
Definition: scsi_all.c:7625
void scsi_sense_print(struct ccb_scsiio *csio)
Definition: scsi_all.c:5161
#define SCSI_REV_2
Definition: scsi_all.h:2222
#define POSITION_TO_ELEMENT
Definition: scsi_all.h:2098
static __inline uint32_t scsi_2btoul(const uint8_t *bytes)
Definition: scsi_all.h:4415
#define SCSI_REV_SPC
Definition: scsi_all.h:2223
#define SCSI_REV_0
Definition: scsi_all.h:2220
#define SMS_DBD
Definition: scsi_all.h:190
static __inline void scsi_ulto2b(u_int32_t val, u_int8_t *bytes)
Definition: scsi_all.h:4374
#define SID_QUAL_LU_CONNECTED
Definition: scsi_all.h:2208
#define SMS_PAGE_CTRL_CURRENT
Definition: scsi_all.h:204
#define READ_ELEMENT_STATUS
Definition: scsi_all.h:2144
#define MOVE_MEDIUM
Definition: scsi_all.h:2138
#define SID_TYPE(inq_data)
Definition: scsi_all.h:2206
static __inline void * find_mode_page_6(struct scsi_mode_header_6 *mode_header)
Definition: scsi_all.h:4479
#define SID_QUAL(inq_data)
Definition: scsi_all.h:2207
static __inline void scsi_ulto3b(u_int32_t val, u_int8_t *bytes)
Definition: scsi_all.h:4382
#define SSD_FULL_SIZE
Definition: scsi_all.h:3251
#define T_CHANGER
Definition: scsi_all.h:2178
static const u_int32_t CH_TIMEOUT_POSITION_TO_ELEMENT
Definition: scsi_ch.c:102
static const u_int32_t CH_TIMEOUT_READ_ELEMENT_STATUS
Definition: scsi_ch.c:103
static const u_int32_t CH_TIMEOUT_MOVE_MEDIUM
Definition: scsi_ch.c:100
static int chsetvoltag(struct cam_periph *periph, struct changer_set_voltag_request *csvr)
Definition: scsi_ch.c:1440
static int cherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
Definition: scsi_ch.c:735
static d_ioctl_t chioctl
Definition: scsi_ch.c:180
ch_flags
Definition: scsi_ch.c:107
@ CH_FLAG_INVALID
Definition: scsi_ch.c:108
static periph_ctor_t chregister
Definition: scsi_ch.c:182
static struct periph_driver chdriver
Definition: scsi_ch.c:208
static int chexchange(struct cam_periph *periph, struct changer_exchange *ce)
Definition: scsi_ch.c:915
static periph_dtor_t chcleanup
Definition: scsi_ch.c:184
static int chielem(struct cam_periph *periph, unsigned int timeout)
Definition: scsi_ch.c:1405
static periph_start_t chstart
Definition: scsi_ch.c:185
static periph_oninv_t choninvalidate
Definition: scsi_ch.c:183
static const u_int32_t CH_TIMEOUT_MODE_SENSE
Definition: scsi_ch.c:99
static void chdone(struct cam_periph *periph, union ccb *done_ccb)
Definition: scsi_ch.c:597
static const u_int32_t CH_TIMEOUT_EXCHANGE_MEDIUM
Definition: scsi_ch.c:101
static void copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag)
Definition: scsi_ch.c:1031
ch_state
Definition: scsi_ch.c:111
@ CH_STATE_NORMAL
Definition: scsi_ch.c:113
@ CH_STATE_PROBE
Definition: scsi_ch.c:112
static void chasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
Definition: scsi_ch.c:319
static void copy_element_status(struct ch_softc *softc, u_int16_t flags, struct read_element_status_descriptor *desc, struct changer_element_status *ces, int scsi_version)
Definition: scsi_ch.c:1049
void scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries, void(*cbfcnp)(struct cam_periph *, union ccb *), u_int8_t tag_action, int voltag, u_int32_t sea, int curdata, int dvcid, u_int32_t count, u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, u_int32_t timeout)
Definition: scsi_ch.c:1831
static d_close_t chclose
Definition: scsi_ch.c:179
static const u_int32_t CH_TIMEOUT_SEND_VOLTAG
Definition: scsi_ch.c:104
void scsi_send_volume_tag(struct ccb_scsiio *csio, u_int32_t retries, void(*cbfcnp)(struct cam_periph *, union ccb *), u_int8_t tag_action, u_int16_t element_address, u_int8_t send_action_code, struct scsi_send_volume_tag_parameters *parameters, u_int8_t sense_len, u_int32_t timeout)
Definition: scsi_ch.c:1896
void scsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries, void(*cbfcnp)(struct cam_periph *, union ccb *), u_int8_t tag_action, u_int32_t tea, u_int32_t src, u_int32_t dst, int invert, u_int8_t sense_len, u_int32_t timeout)
Definition: scsi_ch.c:1730
void scsi_position_to_element(struct ccb_scsiio *csio, u_int32_t retries, void(*cbfcnp)(struct cam_periph *, union ccb *), u_int8_t tag_action, u_int32_t tea, u_int32_t dst, int invert, u_int8_t sense_len, u_int32_t timeout)
Definition: scsi_ch.c:1800
static int chposition(struct cam_periph *periph, struct changer_position *cp)
Definition: scsi_ch.c:978
#define CH_Q_BIT_STRING
Definition: scsi_ch.c:126
static periph_init_t chinit
Definition: scsi_ch.c:181
void scsi_initialize_element_status(struct ccb_scsiio *csio, u_int32_t retries, void(*cbfcnp)(struct cam_periph *, union ccb *), u_int8_t tag_action, u_int8_t sense_len, u_int32_t timeout)
Definition: scsi_ch.c:1870
__FBSDID("$FreeBSD$")
static void chdevgonecb(void *arg)
Definition: scsi_ch.c:245
ch_ccb_types
Definition: scsi_ch.c:116
@ CH_CCB_PROBE
Definition: scsi_ch.c:117
void scsi_exchange_medium(struct ccb_scsiio *csio, u_int32_t retries, void(*cbfcnp)(struct cam_periph *, union ccb *), u_int8_t tag_action, u_int32_t tea, u_int32_t src, u_int32_t dst1, u_int32_t dst2, int invert1, int invert2, u_int8_t sense_len, u_int32_t timeout)
Definition: scsi_ch.c:1763
PERIPHDRIVER_DECLARE(ch, chdriver)
static int chscsiversion(struct cam_periph *periph)
Definition: scsi_ch.c:1699
#define PLURAL(c)
ch_quirks
Definition: scsi_ch.c:120
@ CH_Q_NO_DVCID
Definition: scsi_ch.c:123
@ CH_Q_NO_DBD
Definition: scsi_ch.c:122
@ CH_Q_NONE
Definition: scsi_ch.c:121
static MALLOC_DEFINE(M_SCSICH, "scsi_ch", "scsi_ch buffers")
static const u_int32_t CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS
Definition: scsi_ch.c:105
static int chgetelemstatus(struct cam_periph *periph, int scsi_version, u_long cmd, struct changer_element_status_request *csr)
Definition: scsi_ch.c:1182
static int chmove(struct cam_periph *periph, struct changer_move *cm)
Definition: scsi_ch.c:861
static struct cdevsw ch_cdevsw
Definition: scsi_ch.c:216
static d_open_t chopen
Definition: scsi_ch.c:178
static int chgetparams(struct cam_periph *periph)
Definition: scsi_ch.c:1528
#define READ_ELEMENT_STATUS_DT_LUVALID
Definition: scsi_ch.h:247
#define CH_DEVICE_CAP_PAGE
Definition: scsi_ch.h:174
#define READ_ELEMENT_STATUS_DESIGNATOR_TYPE(p)
Definition: scsi_ch.h:215
#define READ_ELEMENT_STATUS_PROTOCOL_ID(p)
Definition: scsi_ch.h:210
#define READ_ELEMENT_STATUS_PIV_SET
Definition: scsi_ch.h:213
#define READ_ELEMENT_STATUS_SVALID
Definition: scsi_ch.h:261
#define READ_ELEMENT_STATUS_AVOLTAG
Definition: scsi_ch.h:190
#define CH_ELEMENT_ADDR_ASSIGN_PAGE
Definition: scsi_ch.h:172
#define READ_ELEMENT_STATUS_INVERT
Definition: scsi_ch.h:260
#define READ_ELEMENT_STATUS_DT_LUNMASK
Definition: scsi_ch.h:246
#define READ_ELEMENT_STATUS_CODE_SET(p)
Definition: scsi_ch.h:209
#define READ_ELEMENT_STATUS_CURDATA
Definition: scsi_ch.h:147
#define READ_ELEMENT_STATUS_DVCID
Definition: scsi_ch.h:146
#define SEND_VOLUME_TAG_UNDEFINED_ALTERNATE
Definition: scsi_ch.h:315
#define READ_ELEMENT_STATUS_DT_IDVALID
Definition: scsi_ch.h:248
#define INITIALIZE_ELEMENT_STATUS
Definition: scsi_ch.h:98
#define EXCHANGE_MEDIUM_INV2
Definition: scsi_ch.h:88
#define SEND_VOLUME_TAG_UNDEFINED_PRIMARY
Definition: scsi_ch.h:314
#define MOVE_MEDIUM_INVERT
Definition: scsi_ch.h:116
#define EXCHANGE_MEDIUM_INV1
Definition: scsi_ch.h:87
#define SEND_VOLUME_TAG_REPLACE_ALTERNATE
Definition: scsi_ch.h:313
#define SEND_VOLUME_TAG_ASSERT_ALTERNATE
Definition: scsi_ch.h:311
#define READ_ELEMENT_STATUS_VOLTAG
Definition: scsi_ch.h:141
#define READ_ELEMENT_STATUS_PVOLTAG
Definition: scsi_ch.h:191
#define SEND_VOLUME_TAG
Definition: scsi_ch.h:304
#define READ_ELEMENT_STATUS_ASSOCIATION(p)
Definition: scsi_ch.h:214
#define POSITION_TO_ELEMENT_INVERT
Definition: scsi_ch.h:131
#define SEND_VOLUME_TAG_REPLACE_PRIMARY
Definition: scsi_ch.h:312
#define EXCHANGE_MEDIUM
Definition: scsi_ch.h:80
#define SEND_VOLUME_TAG_ASSERT_PRIMARY
Definition: scsi_ch.h:310
#define MSG_SIMPLE_Q_TAG
Definition: scsi_message.h:35
char * periph_name
Definition: cam_periph.h:123
u_int32_t unit_number
Definition: cam_periph.h:127
void * softc
Definition: cam_periph.h:125
struct cam_path * path
Definition: cam_periph.h:124
u_int32_t flags
Definition: cam_periph.h:129
cam_proto protocol
Definition: cam_ccb.h:380
struct ccb_hdr ccb_h
Definition: cam_ccb.h:379
struct scsi_inquiry_data inq_data
Definition: cam_ccb.h:381
struct cam_path * path
Definition: cam_ccb.h:364
xpt_opcode func_code
Definition: cam_ccb.h:362
u_int32_t status
Definition: cam_ccb.h:363
cam_xport transport
Definition: cam_ccb.h:682
cdb_t cdb_io
Definition: cam_ccb.h:763
u_int8_t * data_ptr
Definition: cam_ccb.h:753
int sc_counts[CHET_MAX+1]
Definition: scsi_ch.c:159
ch_quirks quirks
Definition: scsi_ch.c:147
int open_count
Definition: scsi_ch.c:150
int sc_settledelay
Definition: scsi_ch.c:175
int sc_picker
Definition: scsi_ch.c:152
u_int8_t sc_exchangemask[CHET_MAX+1]
Definition: scsi_ch.c:170
u_int8_t sc_movemask[CHET_MAX+1]
Definition: scsi_ch.c:165
ch_state state
Definition: scsi_ch.c:146
int sc_firsts[CHET_MAX+1]
Definition: scsi_ch.c:158
struct devstat * device_stats
Definition: scsi_ch.c:148
struct cdev * dev
Definition: scsi_ch.c:149
ch_flags flags
Definition: scsi_ch.c:145
u_int8_t move_from[CHET_MAX+1]
Definition: scsi_ch.h:372
u_int8_t exchange_with[CHET_MAX+1]
Definition: scsi_ch.h:383
union read_element_status_descriptor::@16 dt_or_obsolete
struct volume_tag pvoltag
Definition: scsi_ch.h:268
struct volume_tag voltag[2]
Definition: scsi_ch.h:269
struct read_element_status_descriptor::@16::@18 scsi_2
struct read_element_status_device_id devid
Definition: scsi_ch.h:270
union read_element_status_descriptor::@17 voltag_devid
struct read_element_status_descriptor::@17::@19 pvol_and_devid
struct read_element_status_descriptor::@17::@20 vol_tags_and_devid
u_int8_t piv_assoc_designator_type
Definition: scsi_ch.h:212
u_int8_t designator[256]
Definition: scsi_ch.h:219
u_int8_t invert
Definition: scsi_ch.h:86
u_int8_t src[2]
Definition: scsi_ch.h:83
u_int8_t tea[2]
Definition: scsi_ch.h:82
u_int8_t fdst[2]
Definition: scsi_ch.h:84
u_int8_t opcode
Definition: scsi_ch.h:79
u_int8_t sdst[2]
Definition: scsi_ch.h:85
u_int8_t version
Definition: scsi_all.h:2218
u_int8_t byte2
Definition: scsi_all.h:189
struct page_device_capabilities cap
Definition: scsi_ch.c:140
struct page_element_address_assignment ea
Definition: scsi_ch.c:138
union scsi_mode_sense_data::@15 pages
struct scsi_mode_header_6 header
Definition: scsi_ch.c:135
struct scsi_mode_blk_desc blk_desc
Definition: scsi_ch.c:136
struct page_transport_geometry_parameters tg
Definition: scsi_ch.c:139
u_int8_t src[2]
Definition: scsi_ch.h:112
u_int8_t opcode
Definition: scsi_ch.h:109
u_int8_t dst[2]
Definition: scsi_ch.h:113
u_int8_t invert
Definition: scsi_ch.h:115
u_int8_t tea[2]
Definition: scsi_ch.h:111
u_int8_t pll[2]
Definition: scsi_ch.h:318
u_int8_t ea[2]
Definition: scsi_ch.h:306
u_int8_t vsn[2]
Definition: scsi_ch.h:204
u_int8_t vif[32]
Definition: scsi_ch.h:202
Definition: cam_ccb.h:1345
struct ccb_hdr ccb_h
Definition: cam_ccb.h:1346
struct ccb_scsiio csio
Definition: cam_ccb.h:1347
u_int8_t cdb_bytes[IOCDBLEN]
Definition: cam_ccb.h:742