1 /* $NetBSD: ch.c,v 1.85 2009/10/21 21:12:05 rmind Exp $ */
4 * Copyright (c) 1996, 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: ch.c,v 1.85 2009/10/21 21:12:05 rmind Exp $");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/errno.h>
40 #include <sys/ioctl.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
47 #include <sys/fcntl.h>
48 #include <sys/vnode.h>
50 #include <sys/select.h>
53 #include <dev/scsipi/scsipi_all.h>
54 #include <dev/scsipi/scsi_all.h>
55 #include <dev/scsipi/scsi_changer.h>
56 #include <dev/scsipi/scsiconf.h>
59 #define CHUNIT(x) (minor((x)))
62 struct device sc_dev
; /* generic device info */
63 struct scsipi_periph
*sc_periph
;/* our periph data */
65 u_int sc_events
; /* event bitmask */
66 struct selinfo sc_selq
; /* select/poll queue for events */
68 int sc_flags
; /* misc. info */
70 int sc_picker
; /* current picker */
73 * The following information is obtained from the
74 * element address assignment page.
76 int sc_firsts
[4]; /* firsts, indexed by CHET_* */
77 int sc_counts
[4]; /* counts, indexed by CHET_* */
80 * The following mask defines the legal combinations
81 * of elements for the MOVE MEDIUM command.
83 u_int8_t sc_movemask
[4];
86 * As above, but for EXCHANGE MEDIUM.
88 u_int8_t sc_exchangemask
[4];
93 int sc_settledelay
; /* delay for settle */
98 #define CHF_ROTATE 0x01 /* picker can rotate */
100 /* Autoconfiguration glue */
101 static int chmatch(device_t
, cfdata_t
, void *);
102 static void chattach(device_t
, device_t
, void *);
104 CFATTACH_DECL(ch
, sizeof(struct ch_softc
),
105 chmatch
, chattach
, NULL
, NULL
);
107 extern struct cfdriver ch_cd
;
109 static struct scsipi_inquiry_pattern ch_patterns
[] = {
114 static dev_type_open(chopen
);
115 static dev_type_close(chclose
);
116 static dev_type_read(chread
);
117 static dev_type_ioctl(chioctl
);
118 static dev_type_poll(chpoll
);
119 static dev_type_kqfilter(chkqfilter
);
121 const struct cdevsw ch_cdevsw
= {
122 chopen
, chclose
, chread
, nowrite
, chioctl
,
123 nostop
, notty
, chpoll
, nommap
, chkqfilter
, D_OTHER
127 static int ch_interpret_sense(struct scsipi_xfer
*);
129 static const struct scsipi_periphsw ch_switch
= {
130 ch_interpret_sense
, /* check our error handler first */
131 NULL
, /* no queue; our commands are synchronous */
132 NULL
, /* have no async handler */
133 NULL
, /* nothing to be done when xfer is done */
136 static int ch_move(struct ch_softc
*, struct changer_move_request
*);
137 static int ch_exchange(struct ch_softc
*,
138 struct changer_exchange_request
*);
139 static int ch_position(struct ch_softc
*,
140 struct changer_position_request
*);
141 static int ch_ielem(struct ch_softc
*);
142 static int ch_ousergetelemstatus(struct ch_softc
*, int, u_int8_t
*);
143 static int ch_usergetelemstatus(struct ch_softc
*,
144 struct changer_element_status_request
*);
145 static int ch_getelemstatus(struct ch_softc
*, int, int, void *,
147 static int ch_setvoltag(struct ch_softc
*,
148 struct changer_set_voltag_request
*);
149 static int ch_get_params(struct ch_softc
*, int);
150 static void ch_get_quirks(struct ch_softc
*,
151 struct scsipi_inquiry_pattern
*);
152 static void ch_event(struct ch_softc
*, u_int
);
153 static int ch_map_element(struct ch_softc
*, u_int16_t
, int *, int *);
155 static void ch_voltag_convert_in(const struct changer_volume_tag
*,
156 struct changer_voltag
*);
157 static int ch_voltag_convert_out(const struct changer_voltag
*,
158 struct changer_volume_tag
*);
161 * SCSI changer quirks.
164 struct scsipi_inquiry_pattern cq_match
; /* device id pattern */
165 int cq_settledelay
; /* settle delay, in seconds */
168 static const struct chquirk chquirks
[] = {
169 {{T_CHANGER
, T_REMOV
,
170 "SPECTRA", "9000", "0200"},
175 chmatch(device_t parent
, cfdata_t match
,
178 struct scsipibus_attach_args
*sa
= aux
;
181 (void)scsipi_inqmatch(&sa
->sa_inqbuf
,
182 (void *)ch_patterns
, sizeof(ch_patterns
) / sizeof(ch_patterns
[0]),
183 sizeof(ch_patterns
[0]), &priority
);
189 chattach(device_t parent
, device_t self
, void *aux
)
191 struct ch_softc
*sc
= device_private(self
);
192 struct scsipibus_attach_args
*sa
= aux
;
193 struct scsipi_periph
*periph
= sa
->sa_periph
;
195 selinit(&sc
->sc_selq
);
197 /* Glue into the SCSI bus */
198 sc
->sc_periph
= periph
;
199 periph
->periph_dev
= &sc
->sc_dev
;
200 periph
->periph_switch
= &ch_switch
;
205 * Find out our device's quirks.
207 ch_get_quirks(sc
, &sa
->sa_inqbuf
);
210 * Some changers require a long time to settle out, to do
211 * tape inventory, for instance.
213 if (sc
->sc_settledelay
) {
214 printf("%s: waiting %d seconds for changer to settle...\n",
215 device_xname(&sc
->sc_dev
), sc
->sc_settledelay
);
216 delay(1000000 * sc
->sc_settledelay
);
220 * Get information about the device. Note we can't use
223 if (ch_get_params(sc
, XS_CTL_DISCOVERY
|XS_CTL_IGNORE_MEDIA_CHANGE
))
224 printf("%s: offline\n", device_xname(&sc
->sc_dev
));
226 #define PLURAL(c) (c) == 1 ? "" : "s"
227 printf("%s: %d slot%s, %d drive%s, %d picker%s, %d portal%s\n",
228 device_xname(&sc
->sc_dev
),
229 sc
->sc_counts
[CHET_ST
], PLURAL(sc
->sc_counts
[CHET_ST
]),
230 sc
->sc_counts
[CHET_DT
], PLURAL(sc
->sc_counts
[CHET_DT
]),
231 sc
->sc_counts
[CHET_MT
], PLURAL(sc
->sc_counts
[CHET_MT
]),
232 sc
->sc_counts
[CHET_IE
], PLURAL(sc
->sc_counts
[CHET_IE
]));
235 printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n",
236 device_xname(&sc
->sc_dev
),
237 sc
->sc_movemask
[CHET_MT
], sc
->sc_movemask
[CHET_ST
],
238 sc
->sc_movemask
[CHET_IE
], sc
->sc_movemask
[CHET_DT
]);
239 printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n",
240 device_xname(&sc
->sc_dev
),
241 sc
->sc_exchangemask
[CHET_MT
], sc
->sc_exchangemask
[CHET_ST
],
242 sc
->sc_exchangemask
[CHET_IE
], sc
->sc_exchangemask
[CHET_DT
]);
243 #endif /* CHANGER_DEBUG */
246 /* Default the current picker. */
247 sc
->sc_picker
= sc
->sc_firsts
[CHET_MT
];
251 chopen(dev_t dev
, int flags
, int fmt
, struct lwp
*l
)
254 struct scsipi_periph
*periph
;
255 struct scsipi_adapter
*adapt
;
259 sc
= device_lookup_private(&ch_cd
, unit
);
263 periph
= sc
->sc_periph
;
264 adapt
= periph
->periph_channel
->chan_adapter
;
267 * Only allow one open at a time.
269 if (periph
->periph_flags
& PERIPH_OPEN
)
272 if ((error
= scsipi_adapter_addref(adapt
)) != 0)
276 * Make sure the unit is on-line. If a UNIT ATTENTION
277 * occurs, we will mark that an Init-Element-Status is
278 * needed in ch_get_params().
280 * We ignore NOT READY in case e.g a magazine isn't actually
281 * loaded into the changer or a tape isn't in the drive.
283 error
= scsipi_test_unit_ready(periph
, XS_CTL_IGNORE_NOT_READY
);
287 periph
->periph_flags
|= PERIPH_OPEN
;
290 * Make sure our parameters are up to date.
292 if ((error
= ch_get_params(sc
, 0)) != 0)
298 scsipi_adapter_delref(adapt
);
299 periph
->periph_flags
&= ~PERIPH_OPEN
;
304 chclose(dev_t dev
, int flags
, int fmt
, struct lwp
*l
)
306 struct ch_softc
*sc
= device_lookup_private(&ch_cd
, CHUNIT(dev
));
307 struct scsipi_periph
*periph
= sc
->sc_periph
;
308 struct scsipi_adapter
*adapt
= periph
->periph_channel
->chan_adapter
;
310 scsipi_wait_drain(periph
);
312 scsipi_adapter_delref(adapt
);
316 periph
->periph_flags
&= ~PERIPH_OPEN
;
321 chread(dev_t dev
, struct uio
*uio
, int flags
)
323 struct ch_softc
*sc
= device_lookup_private(&ch_cd
, CHUNIT(dev
));
326 if (uio
->uio_resid
!= CHANGER_EVENT_SIZE
)
330 * Read never blocks; if there are no events pending, we just
331 * return an all-clear bitmask.
333 error
= uiomove(&sc
->sc_events
, CHANGER_EVENT_SIZE
, uio
);
340 chioctl(dev_t dev
, u_long cmd
, void *data
, int flags
, struct lwp
*l
)
342 struct ch_softc
*sc
= device_lookup_private(&ch_cd
, CHUNIT(dev
));
346 * If this command can change the device's state, we must
347 * have the device open for writing.
356 if ((flags
& FWRITE
) == 0)
362 error
= ch_move(sc
, (struct changer_move_request
*)data
);
366 error
= ch_exchange(sc
,
367 (struct changer_exchange_request
*)data
);
371 error
= ch_position(sc
,
372 (struct changer_position_request
*)data
);
376 *(int *)data
= sc
->sc_picker
- sc
->sc_firsts
[CHET_MT
];
381 int new_picker
= *(int *)data
;
383 if (new_picker
> (sc
->sc_counts
[CHET_MT
] - 1))
385 sc
->sc_picker
= sc
->sc_firsts
[CHET_MT
] + new_picker
;
391 struct changer_params
*cp
= (struct changer_params
*)data
;
393 cp
->cp_curpicker
= sc
->sc_picker
- sc
->sc_firsts
[CHET_MT
];
394 cp
->cp_npickers
= sc
->sc_counts
[CHET_MT
];
395 cp
->cp_nslots
= sc
->sc_counts
[CHET_ST
];
396 cp
->cp_nportals
= sc
->sc_counts
[CHET_IE
];
397 cp
->cp_ndrives
= sc
->sc_counts
[CHET_DT
];
402 error
= ch_ielem(sc
);
404 sc
->sc_periph
->periph_flags
|= PERIPH_MEDIA_LOADED
;
410 struct ochanger_element_status_request
*cesr
=
411 (struct ochanger_element_status_request
*)data
;
413 error
= ch_ousergetelemstatus(sc
, cesr
->cesr_type
,
419 error
= ch_usergetelemstatus(sc
,
420 (struct changer_element_status_request
*)data
);
424 error
= ch_setvoltag(sc
,
425 (struct changer_set_voltag_request
*)data
);
428 /* Implement prevent/allow? */
431 error
= scsipi_do_ioctl(sc
->sc_periph
, dev
, cmd
, data
,
440 chpoll(dev_t dev
, int events
, struct lwp
*l
)
442 struct ch_softc
*sc
= device_lookup_private(&ch_cd
, CHUNIT(dev
));
445 revents
= events
& (POLLOUT
| POLLWRNORM
);
447 if ((events
& (POLLIN
| POLLRDNORM
)) == 0)
450 if (sc
->sc_events
== 0)
451 revents
|= events
& (POLLIN
| POLLRDNORM
);
453 selrecord(l
, &sc
->sc_selq
);
459 filt_chdetach(struct knote
*kn
)
461 struct ch_softc
*sc
= kn
->kn_hook
;
463 SLIST_REMOVE(&sc
->sc_selq
.sel_klist
, kn
, knote
, kn_selnext
);
467 filt_chread(struct knote
*kn
, long hint
)
469 struct ch_softc
*sc
= kn
->kn_hook
;
471 if (sc
->sc_events
== 0)
473 kn
->kn_data
= CHANGER_EVENT_SIZE
;
477 static const struct filterops chread_filtops
=
478 { 1, NULL
, filt_chdetach
, filt_chread
};
480 static const struct filterops chwrite_filtops
=
481 { 1, NULL
, filt_chdetach
, filt_seltrue
};
484 chkqfilter(dev_t dev
, struct knote
*kn
)
486 struct ch_softc
*sc
= device_lookup_private(&ch_cd
, CHUNIT(dev
));
489 switch (kn
->kn_filter
) {
491 klist
= &sc
->sc_selq
.sel_klist
;
492 kn
->kn_fop
= &chread_filtops
;
496 klist
= &sc
->sc_selq
.sel_klist
;
497 kn
->kn_fop
= &chwrite_filtops
;
506 SLIST_INSERT_HEAD(klist
, kn
, kn_selnext
);
512 ch_interpret_sense(struct scsipi_xfer
*xs
)
514 struct scsipi_periph
*periph
= xs
->xs_periph
;
515 struct scsi_sense_data
*sense
= &xs
->sense
.scsi_sense
;
516 struct ch_softc
*sc
= (void *)periph
->periph_dev
;
520 * If the periph is already recovering, just do the
521 * normal error recovering.
523 if (periph
->periph_flags
& PERIPH_RECOVERING
)
524 return (EJUSTRETURN
);
527 * If it isn't an extended or extended/deferred error, let
528 * the generic code handle it.
530 if (SSD_RCODE(sense
->response_code
) != SSD_RCODE_CURRENT
&&
531 SSD_RCODE(sense
->response_code
) != SSD_RCODE_DEFERRED
)
532 return (EJUSTRETURN
);
535 * We're only interested in condtions that
536 * indicate potential inventory violation.
538 * We use ASC/ASCQ codes for this.
541 asc_ascq
= (((u_int16_t
) sense
->asc
) << 8) |
546 /* "Not Ready To Ready Transition (Medium May Have Changed)" */
548 /* "Power On, Reset, or Bus Device Reset Occurred" */
549 sc
->sc_periph
->periph_flags
&= ~PERIPH_MEDIA_LOADED
;
551 * Enqueue an Element-Status-Changed event, and wake up
552 * any processes waiting for them.
554 if ((xs
->xs_control
& XS_CTL_IGNORE_MEDIA_CHANGE
) == 0)
555 ch_event(sc
, CHEV_ELEMENT_STATUS_CHANGED
);
561 return (EJUSTRETURN
);
565 ch_event(struct ch_softc
*sc
, u_int event
)
568 sc
->sc_events
|= event
;
569 selnotify(&sc
->sc_selq
, 0, 0);
573 ch_move(struct ch_softc
*sc
, struct changer_move_request
*cm
)
575 struct scsi_move_medium cmd
;
576 u_int16_t fromelem
, toelem
;
581 if ((cm
->cm_fromtype
> CHET_DT
) || (cm
->cm_totype
> CHET_DT
))
583 if ((cm
->cm_fromunit
> (sc
->sc_counts
[cm
->cm_fromtype
] - 1)) ||
584 (cm
->cm_tounit
> (sc
->sc_counts
[cm
->cm_totype
] - 1)))
588 * Check the request against the changer's capabilities.
590 if ((sc
->sc_movemask
[cm
->cm_fromtype
] & (1 << cm
->cm_totype
)) == 0)
594 * Calculate the source and destination elements.
596 fromelem
= sc
->sc_firsts
[cm
->cm_fromtype
] + cm
->cm_fromunit
;
597 toelem
= sc
->sc_firsts
[cm
->cm_totype
] + cm
->cm_tounit
;
600 * Build the SCSI command.
602 memset(&cmd
, 0, sizeof(cmd
));
603 cmd
.opcode
= MOVE_MEDIUM
;
604 _lto2b(sc
->sc_picker
, cmd
.tea
);
605 _lto2b(fromelem
, cmd
.src
);
606 _lto2b(toelem
, cmd
.dst
);
607 if (cm
->cm_flags
& CM_INVERT
)
608 cmd
.flags
|= MOVE_MEDIUM_INVERT
;
611 * Send command to changer.
613 return (scsipi_command(sc
->sc_periph
, (void *)&cmd
, sizeof(cmd
), 0, 0,
614 CHRETRIES
, 100000, NULL
, 0));
618 ch_exchange(struct ch_softc
*sc
, struct changer_exchange_request
*ce
)
620 struct scsi_exchange_medium cmd
;
621 u_int16_t src
, dst1
, dst2
;
626 if ((ce
->ce_srctype
> CHET_DT
) || (ce
->ce_fdsttype
> CHET_DT
) ||
627 (ce
->ce_sdsttype
> CHET_DT
))
629 if ((ce
->ce_srcunit
> (sc
->sc_counts
[ce
->ce_srctype
] - 1)) ||
630 (ce
->ce_fdstunit
> (sc
->sc_counts
[ce
->ce_fdsttype
] - 1)) ||
631 (ce
->ce_sdstunit
> (sc
->sc_counts
[ce
->ce_sdsttype
] - 1)))
635 * Check the request against the changer's capabilities.
637 if (((sc
->sc_exchangemask
[ce
->ce_srctype
] &
638 (1 << ce
->ce_fdsttype
)) == 0) ||
639 ((sc
->sc_exchangemask
[ce
->ce_fdsttype
] &
640 (1 << ce
->ce_sdsttype
)) == 0))
644 * Calculate the source and destination elements.
646 src
= sc
->sc_firsts
[ce
->ce_srctype
] + ce
->ce_srcunit
;
647 dst1
= sc
->sc_firsts
[ce
->ce_fdsttype
] + ce
->ce_fdstunit
;
648 dst2
= sc
->sc_firsts
[ce
->ce_sdsttype
] + ce
->ce_sdstunit
;
651 * Build the SCSI command.
653 memset(&cmd
, 0, sizeof(cmd
));
654 cmd
.opcode
= EXCHANGE_MEDIUM
;
655 _lto2b(sc
->sc_picker
, cmd
.tea
);
656 _lto2b(src
, cmd
.src
);
657 _lto2b(dst1
, cmd
.fdst
);
658 _lto2b(dst2
, cmd
.sdst
);
659 if (ce
->ce_flags
& CE_INVERT1
)
660 cmd
.flags
|= EXCHANGE_MEDIUM_INV1
;
661 if (ce
->ce_flags
& CE_INVERT2
)
662 cmd
.flags
|= EXCHANGE_MEDIUM_INV2
;
665 * Send command to changer.
667 return (scsipi_command(sc
->sc_periph
, (void *)&cmd
, sizeof(cmd
), 0, 0,
668 CHRETRIES
, 100000, NULL
, 0));
672 ch_position(struct ch_softc
*sc
, struct changer_position_request
*cp
)
674 struct scsi_position_to_element cmd
;
680 if (cp
->cp_type
> CHET_DT
)
682 if (cp
->cp_unit
> (sc
->sc_counts
[cp
->cp_type
] - 1))
686 * Calculate the destination element.
688 dst
= sc
->sc_firsts
[cp
->cp_type
] + cp
->cp_unit
;
691 * Build the SCSI command.
693 memset(&cmd
, 0, sizeof(cmd
));
694 cmd
.opcode
= POSITION_TO_ELEMENT
;
695 _lto2b(sc
->sc_picker
, cmd
.tea
);
696 _lto2b(dst
, cmd
.dst
);
697 if (cp
->cp_flags
& CP_INVERT
)
698 cmd
.flags
|= POSITION_TO_ELEMENT_INVERT
;
701 * Send command to changer.
703 return (scsipi_command(sc
->sc_periph
, (void *)&cmd
, sizeof(cmd
), 0, 0,
704 CHRETRIES
, 100000, NULL
, 0));
708 * Perform a READ ELEMENT STATUS on behalf of the user, and return to
709 * the user only the data the user is interested in. This returns the
713 ch_ousergetelemstatus(struct ch_softc
*sc
, int chet
, u_int8_t
*uptr
)
715 struct read_element_status_header
*st_hdrp
, st_hdr
;
716 struct read_element_status_page_header
*pg_hdrp
;
717 struct read_element_status_descriptor
*desc
;
718 size_t size
, desclen
;
720 int avail
, i
, error
= 0;
724 * If there are no elements of the requested type in the changer,
725 * the request is invalid.
727 if (sc
->sc_counts
[chet
] == 0)
731 * Do the request the user wants, but only read the status header.
732 * This will tell us the amount of storage we must allocate in
733 * order to read all data.
735 error
= ch_getelemstatus(sc
, sc
->sc_firsts
[chet
],
736 sc
->sc_counts
[chet
], &st_hdr
, sizeof(st_hdr
), 0, 0);
740 size
= sizeof(struct read_element_status_header
) +
741 _3btol(st_hdr
.nbytes
);
744 * We must have at least room for the status header and
745 * one page header (since we only ask for one element type
748 if (size
< (sizeof(struct read_element_status_header
) +
749 sizeof(struct read_element_status_page_header
)))
753 * Allocate the storage and do the request again.
755 data
= malloc(size
, M_DEVBUF
, M_WAITOK
);
756 error
= ch_getelemstatus(sc
, sc
->sc_firsts
[chet
],
757 sc
->sc_counts
[chet
], data
, size
, 0, 0);
761 st_hdrp
= (struct read_element_status_header
*)data
;
762 pg_hdrp
= (struct read_element_status_page_header
*)((u_long
)st_hdrp
+
763 sizeof(struct read_element_status_header
));
764 desclen
= _2btol(pg_hdrp
->edl
);
767 * Fill in the user status array.
769 avail
= _2btol(st_hdrp
->count
);
771 if (avail
!= sc
->sc_counts
[chet
])
772 printf("%s: warning, READ ELEMENT STATUS avail != count\n",
773 device_xname(&sc
->sc_dev
));
775 desc
= (struct read_element_status_descriptor
*)((u_long
)data
+
776 sizeof(struct read_element_status_header
) +
777 sizeof(struct read_element_status_page_header
));
778 for (i
= 0; i
< avail
; ++i
) {
779 user_data
= desc
->flags1
;
780 error
= copyout(&user_data
, &uptr
[i
], avail
);
783 desc
= (struct read_element_status_descriptor
*)((u_long
)desc
789 free(data
, M_DEVBUF
);
794 * Perform a READ ELEMENT STATUS on behalf of the user. This returns
795 * the new (more complete) data format.
798 ch_usergetelemstatus(struct ch_softc
*sc
,
799 struct changer_element_status_request
*cesr
)
801 struct scsipi_channel
*chan
= sc
->sc_periph
->periph_channel
;
802 struct scsipi_periph
*dtperiph
;
803 struct read_element_status_header
*st_hdrp
, st_hdr
;
804 struct read_element_status_page_header
*pg_hdrp
;
805 struct read_element_status_descriptor
*desc
;
806 struct changer_volume_tag
*avol
, *pvol
;
807 size_t size
, desclen
, stddesclen
, offset
;
808 int first
, avail
, i
, error
= 0;
811 struct changer_element_status ces
;
816 if (cesr
->cesr_type
> CHET_DT
)
818 if (sc
->sc_counts
[cesr
->cesr_type
] == 0)
820 if (cesr
->cesr_unit
> (sc
->sc_counts
[cesr
->cesr_type
] - 1))
822 if (cesr
->cesr_count
>
823 (sc
->sc_counts
[cesr
->cesr_type
] + cesr
->cesr_unit
))
827 * Do the request the user wants, but only read the status header.
828 * This will tell us the amount of storage we must allocate
829 * in order to read all the data.
831 error
= ch_getelemstatus(sc
, sc
->sc_firsts
[cesr
->cesr_type
] +
832 cesr
->cesr_unit
, cesr
->cesr_count
, &st_hdr
, sizeof(st_hdr
), 0,
837 size
= sizeof(struct read_element_status_header
) +
838 _3btol(st_hdr
.nbytes
);
841 * We must have at least room for the status header and
842 * one page header (since we only ask for oen element type
845 if (size
< (sizeof(struct read_element_status_header
) +
846 sizeof(struct read_element_status_page_header
)))
850 * Allocate the storage and do the request again.
852 data
= malloc(size
, M_DEVBUF
, M_WAITOK
);
853 error
= ch_getelemstatus(sc
, sc
->sc_firsts
[cesr
->cesr_type
] +
854 cesr
->cesr_unit
, cesr
->cesr_count
, data
, size
, 0,
859 st_hdrp
= (struct read_element_status_header
*)data
;
860 pg_hdrp
= (struct read_element_status_page_header
*)((u_long
)st_hdrp
+
861 sizeof(struct read_element_status_header
));
862 desclen
= _2btol(pg_hdrp
->edl
);
865 * Fill in the user status array.
867 first
= _2btol(st_hdrp
->fear
);
868 if (first
< (sc
->sc_firsts
[cesr
->cesr_type
] + cesr
->cesr_unit
) ||
869 first
>= (sc
->sc_firsts
[cesr
->cesr_type
] + cesr
->cesr_unit
+
874 first
-= sc
->sc_firsts
[cesr
->cesr_type
] + cesr
->cesr_unit
;
876 avail
= _2btol(st_hdrp
->count
);
877 if (avail
<= 0 || avail
> cesr
->cesr_count
) {
882 offset
= sizeof(struct read_element_status_header
) +
883 sizeof(struct read_element_status_page_header
);
885 for (i
= 0; i
< cesr
->cesr_count
; i
++) {
886 memset(&ces
, 0, sizeof(ces
));
887 if (i
< first
|| i
>= (first
+ avail
)) {
888 error
= copyout(&ces
, &cesr
->cesr_data
[i
],
894 desc
= (struct read_element_status_descriptor
*)
895 ((char *)data
+ offset
);
896 stddesclen
= sizeof(struct read_element_status_descriptor
);
899 ces
.ces_flags
= CESTATUS_STATUS_VALID
;
902 * The SCSI flags conveniently map directly to the
905 ces
.ces_flags
|= (desc
->flags1
& 0x3f);
907 ces
.ces_asc
= desc
->sense_code
;
908 ces
.ces_ascq
= desc
->sense_qual
;
911 * For Data Transport elemenets, get the SCSI ID and LUN,
912 * and attempt to map them to a device name if they're
913 * on the same SCSI bus.
915 if (desc
->dt_scsi_flags
& READ_ELEMENT_STATUS_DT_IDVALID
) {
916 ces
.ces_target
= desc
->dt_scsi_addr
;
917 ces
.ces_flags
|= CESTATUS_TARGET_VALID
;
919 if (desc
->dt_scsi_flags
& READ_ELEMENT_STATUS_DT_LUVALID
) {
920 ces
.ces_lun
= desc
->dt_scsi_flags
&
921 READ_ELEMENT_STATUS_DT_LUNMASK
;
922 ces
.ces_flags
|= CESTATUS_LUN_VALID
;
924 if (desc
->dt_scsi_flags
& READ_ELEMENT_STATUS_DT_NOTBUS
)
925 ces
.ces_flags
|= CESTATUS_NOTBUS
;
926 else if ((ces
.ces_flags
&
927 (CESTATUS_TARGET_VALID
|CESTATUS_LUN_VALID
)) ==
928 (CESTATUS_TARGET_VALID
|CESTATUS_LUN_VALID
)) {
929 if (ces
.ces_target
< chan
->chan_ntargets
&&
930 ces
.ces_lun
< chan
->chan_nluns
&&
931 (dtperiph
= scsipi_lookup_periph(chan
,
932 ces
.ces_target
, ces
.ces_lun
)) != NULL
&&
933 dtperiph
->periph_dev
!= NULL
) {
934 strlcpy(ces
.ces_xname
,
935 device_xname(dtperiph
->periph_dev
),
936 sizeof(ces
.ces_xname
));
937 ces
.ces_flags
|= CESTATUS_XNAME_VALID
;
941 if (desc
->flags2
& READ_ELEMENT_STATUS_INVERT
)
942 ces
.ces_flags
|= CESTATUS_INVERTED
;
944 if (desc
->flags2
& READ_ELEMENT_STATUS_SVALID
) {
945 if (ch_map_element(sc
, _2btol(desc
->ssea
),
946 &ces
.ces_from_type
, &ces
.ces_from_unit
))
947 ces
.ces_flags
|= CESTATUS_FROM_VALID
;
951 * Extract volume tag information.
953 switch (pg_hdrp
->flags
&
954 (READ_ELEMENT_STATUS_PVOLTAG
|READ_ELEMENT_STATUS_AVOLTAG
)) {
955 case (READ_ELEMENT_STATUS_PVOLTAG
|READ_ELEMENT_STATUS_AVOLTAG
):
956 pvol
= (struct changer_volume_tag
*)(desc
+ 1);
960 case READ_ELEMENT_STATUS_PVOLTAG
:
961 pvol
= (struct changer_volume_tag
*)(desc
+ 1);
965 case READ_ELEMENT_STATUS_AVOLTAG
:
967 avol
= (struct changer_volume_tag
*)(desc
+ 1);
976 ch_voltag_convert_in(pvol
, &ces
.ces_pvoltag
);
977 ces
.ces_flags
|= CESTATUS_PVOL_VALID
;
978 stddesclen
+= sizeof(struct changer_volume_tag
);
981 ch_voltag_convert_in(avol
, &ces
.ces_avoltag
);
982 ces
.ces_flags
|= CESTATUS_AVOL_VALID
;
983 stddesclen
+= sizeof(struct changer_volume_tag
);
987 * Compute vendor-specific length. Note the 4 reserved
988 * bytes between the volume tags and the vendor-specific
989 * data. Copy it out of the user wants it.
992 if (desclen
> stddesclen
)
993 ces
.ces_vendor_len
= desclen
- stddesclen
;
995 if (ces
.ces_vendor_len
!= 0 && cesr
->cesr_vendor_data
!= NULL
) {
996 error
= copyin(&cesr
->cesr_vendor_data
[i
], &uvendptr
,
1000 error
= copyout((void *)((u_long
)desc
+ stddesclen
),
1001 uvendptr
, ces
.ces_vendor_len
);
1007 * Now copy out the status descriptor we've constructed.
1009 error
= copyout(&ces
, &cesr
->cesr_data
[i
], sizeof(ces
));
1016 free(data
, M_DEVBUF
);
1021 ch_getelemstatus(struct ch_softc
*sc
, int first
, int count
, void *data
,
1022 size_t datalen
, int scsiflags
, int flags
)
1024 struct scsi_read_element_status cmd
;
1027 * Build SCSI command.
1029 memset(&cmd
, 0, sizeof(cmd
));
1030 cmd
.opcode
= READ_ELEMENT_STATUS
;
1031 cmd
.byte2
= ELEMENT_TYPE_ALL
;
1032 if (flags
& CESR_VOLTAGS
)
1033 cmd
.byte2
|= READ_ELEMENT_STATUS_VOLTAG
;
1034 _lto2b(first
, cmd
.sea
);
1035 _lto2b(count
, cmd
.count
);
1036 _lto3b(datalen
, cmd
.len
);
1039 * Send command to changer.
1041 return (scsipi_command(sc
->sc_periph
, (void *)&cmd
, sizeof(cmd
),
1042 (void *)data
, datalen
,
1043 CHRETRIES
, 100000, NULL
, scsiflags
| XS_CTL_DATA_IN
));
1047 ch_setvoltag(struct ch_softc
*sc
, struct changer_set_voltag_request
*csvr
)
1049 struct scsi_send_volume_tag cmd
;
1050 struct changer_volume_tag voltag
;
1059 if (csvr
->csvr_type
> CHET_DT
)
1061 if (csvr
->csvr_unit
> (sc
->sc_counts
[csvr
->csvr_type
] - 1))
1064 dst
= sc
->sc_firsts
[csvr
->csvr_type
] + csvr
->csvr_unit
;
1067 * Build the SCSI command.
1069 memset(&cmd
, 0, sizeof(cmd
));
1070 cmd
.opcode
= SEND_VOLUME_TAG
;
1071 _lto2b(dst
, cmd
.eaddr
);
1073 #define ALTERNATE (csvr->csvr_flags & CSVR_ALTERNATE)
1075 switch (csvr
->csvr_flags
& CSVR_MODE_MASK
) {
1077 cmd
.sac
= ALTERNATE
? SAC_ASSERT_ALT
: SAC_ASSERT_PRIMARY
;
1080 case CSVR_MODE_REPLACE
:
1081 cmd
.sac
= ALTERNATE
? SAC_REPLACE_ALT
: SAC_REPLACE_PRIMARY
;
1084 case CSVR_MODE_CLEAR
:
1085 cmd
.sac
= ALTERNATE
? SAC_UNDEFINED_ALT
: SAC_UNDEFINED_PRIMARY
;
1094 if (cmd
.sac
< SAC_UNDEFINED_PRIMARY
) {
1095 error
= ch_voltag_convert_out(&csvr
->csvr_voltag
, &voltag
);
1099 datalen
= sizeof(voltag
);
1100 _lto2b(datalen
, cmd
.length
);
1104 * Send command to changer.
1106 return (scsipi_command(sc
->sc_periph
, (void *)&cmd
, sizeof(cmd
),
1107 (void *)data
, datalen
, CHRETRIES
, 100000, NULL
,
1108 datalen
? XS_CTL_DATA_OUT
: 0));
1112 ch_ielem(struct ch_softc
*sc
)
1115 struct scsi_initialize_element_status cmd
;
1118 * Build SCSI command.
1120 memset(&cmd
, 0, sizeof(cmd
));
1121 cmd
.opcode
= INITIALIZE_ELEMENT_STATUS
;
1124 * Send command to changer.
1126 * The problem is, how long to allow for the command?
1127 * It can take a *really* long time, and also depends
1128 * on unknowable factors such as whether there are
1129 * *almost* readable labels on tapes that a barcode
1130 * reader is trying to decipher.
1132 * I'm going to make this long enough to allow 5 minutes
1133 * per element plus an initial 10 minute wait.
1135 tmo
= sc
->sc_counts
[CHET_MT
] +
1136 sc
->sc_counts
[CHET_ST
] +
1137 sc
->sc_counts
[CHET_IE
] +
1138 sc
->sc_counts
[CHET_DT
];
1139 tmo
*= 5 * 60 * 1000;
1140 tmo
+= (10 * 60 * 1000);
1142 return (scsipi_command(sc
->sc_periph
, (void *)&cmd
, sizeof(cmd
), 0, 0,
1143 CHRETRIES
, tmo
, NULL
, XS_CTL_IGNORE_ILLEGAL_REQUEST
));
1147 * Ask the device about itself and fill in the parameters in our
1151 ch_get_params(struct ch_softc
*sc
, int scsiflags
)
1153 struct scsi_mode_sense_data
{
1154 struct scsi_mode_parameter_header_6 header
;
1156 struct page_element_address_assignment ea
;
1157 struct page_transport_geometry_parameters tg
;
1158 struct page_device_capabilities cap
;
1162 u_int8_t
*moves
, *exchanges
;
1165 * Grab info from the element address assignment page.
1167 memset(&sense_data
, 0, sizeof(sense_data
));
1168 error
= scsipi_mode_sense(sc
->sc_periph
, SMS_DBD
, 0x1d,
1169 &sense_data
.header
, sizeof(sense_data
),
1170 scsiflags
, CHRETRIES
, 6000);
1172 aprint_error_dev(&sc
->sc_dev
, "could not sense element address page\n");
1176 sc
->sc_firsts
[CHET_MT
] = _2btol(sense_data
.pages
.ea
.mtea
);
1177 sc
->sc_counts
[CHET_MT
] = _2btol(sense_data
.pages
.ea
.nmte
);
1178 sc
->sc_firsts
[CHET_ST
] = _2btol(sense_data
.pages
.ea
.fsea
);
1179 sc
->sc_counts
[CHET_ST
] = _2btol(sense_data
.pages
.ea
.nse
);
1180 sc
->sc_firsts
[CHET_IE
] = _2btol(sense_data
.pages
.ea
.fieea
);
1181 sc
->sc_counts
[CHET_IE
] = _2btol(sense_data
.pages
.ea
.niee
);
1182 sc
->sc_firsts
[CHET_DT
] = _2btol(sense_data
.pages
.ea
.fdtea
);
1183 sc
->sc_counts
[CHET_DT
] = _2btol(sense_data
.pages
.ea
.ndte
);
1185 /* XXX ask for transport geometry page XXX */
1188 * Grab info from the capabilities page.
1190 memset(&sense_data
, 0, sizeof(sense_data
));
1192 * XXX: Note: not all changers can deal with disabled block descriptors
1194 error
= scsipi_mode_sense(sc
->sc_periph
, SMS_DBD
, 0x1f,
1195 &sense_data
.header
, sizeof(sense_data
),
1196 scsiflags
, CHRETRIES
, 6000);
1198 aprint_error_dev(&sc
->sc_dev
, "could not sense capabilities page\n");
1202 memset(sc
->sc_movemask
, 0, sizeof(sc
->sc_movemask
));
1203 memset(sc
->sc_exchangemask
, 0, sizeof(sc
->sc_exchangemask
));
1204 moves
= &sense_data
.pages
.cap
.move_from_mt
;
1205 exchanges
= &sense_data
.pages
.cap
.exchange_with_mt
;
1206 for (from
= CHET_MT
; from
<= CHET_DT
; ++from
) {
1207 sc
->sc_movemask
[from
] = moves
[from
];
1208 sc
->sc_exchangemask
[from
] = exchanges
[from
];
1211 #ifdef CH_AUTOMATIC_IELEM_POLICY
1213 * If we need to do an Init-Element-Status,
1214 * do that now that we know what's in the changer.
1216 if ((scsiflags
& XS_CTL_IGNORE_MEDIA_CHANGE
) == 0) {
1217 if ((sc
->sc_periph
->periph_flags
& PERIPH_MEDIA_LOADED
) == 0)
1218 error
= ch_ielem(sc
);
1220 sc
->sc_periph
->periph_flags
|= PERIPH_MEDIA_LOADED
;
1222 sc
->sc_periph
->periph_flags
&= ~PERIPH_MEDIA_LOADED
;
1229 ch_get_quirks(struct ch_softc
*sc
, struct scsipi_inquiry_pattern
*inqbuf
)
1231 const struct chquirk
*match
;
1234 sc
->sc_settledelay
= 0;
1236 match
= scsipi_inqmatch(inqbuf
, chquirks
,
1237 sizeof(chquirks
) / sizeof(chquirks
[0]),
1238 sizeof(chquirks
[0]), &priority
);
1240 sc
->sc_settledelay
= match
->cq_settledelay
;
1244 ch_map_element(struct ch_softc
*sc
, u_int16_t elem
, int *typep
, int *unitp
)
1248 for (chet
= CHET_MT
; chet
<= CHET_DT
; chet
++) {
1249 if (elem
>= sc
->sc_firsts
[chet
] &&
1250 elem
< (sc
->sc_firsts
[chet
] + sc
->sc_counts
[chet
])) {
1252 *unitp
= elem
- sc
->sc_firsts
[chet
];
1260 ch_voltag_convert_in(const struct changer_volume_tag
*sv
,
1261 struct changer_voltag
*cv
)
1265 memset(cv
, 0, sizeof(struct changer_voltag
));
1268 * Copy the volume tag string from the SCSI representation.
1269 * Per the SCSI-2 spec, we stop at the first blank character.
1271 for (i
= 0; i
< sizeof(sv
->volid
); i
++) {
1272 if (sv
->volid
[i
] == ' ')
1274 cv
->cv_tag
[i
] = sv
->volid
[i
];
1276 cv
->cv_tag
[i
] = '\0';
1278 cv
->cv_serial
= _2btol(sv
->volseq
);
1282 ch_voltag_convert_out(const struct changer_voltag
*cv
,
1283 struct changer_volume_tag
*sv
)
1287 memset(sv
, ' ', sizeof(struct changer_volume_tag
));
1289 for (i
= 0; i
< sizeof(sv
->volid
); i
++) {
1290 if (cv
->cv_tag
[i
] == '\0')
1293 * Limit the character set to what is suggested in
1296 if ((cv
->cv_tag
[i
] < '0' || cv
->cv_tag
[i
] > '9') &&
1297 (cv
->cv_tag
[i
] < 'A' || cv
->cv_tag
[i
] > 'Z') &&
1298 (cv
->cv_tag
[i
] != '_'))
1300 sv
->volid
[i
] = cv
->cv_tag
[i
];
1303 _lto2b(cv
->cv_serial
, sv
->volseq
);