1139743Simp/*- 239213Sgibbs * Copyright (c) 1997 Justin T. Gibbs. 343819Sken * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 439213Sgibbs * All rights reserved. 539213Sgibbs * 639213Sgibbs * Redistribution and use in source and binary forms, with or without 739213Sgibbs * modification, are permitted provided that the following conditions 839213Sgibbs * are met: 939213Sgibbs * 1. Redistributions of source code must retain the above copyright 1039213Sgibbs * notice, this list of conditions, and the following disclaimer, 1139213Sgibbs * without modification, immediately at the beginning of the file. 1239213Sgibbs * 2. The name of the author may not be used to endorse or promote products 1339213Sgibbs * derived from this software without specific prior written permission. 1439213Sgibbs * 1539213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1639213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1739213Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1839213Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 1939213Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2039213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2139213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2239213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2339213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2439213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2539213Sgibbs * SUCH DAMAGE. 2639213Sgibbs */ 27116162Sobrien 2839213Sgibbs/* 2939213Sgibbs * Derived from the NetBSD SCSI changer driver. 3039213Sgibbs * 3139213Sgibbs * $NetBSD: ch.c,v 1.32 1998/01/12 09:49:12 thorpej Exp $ 3239213Sgibbs * 3339213Sgibbs */ 34139743Simp/*- 3539213Sgibbs * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej@and.com> 3639213Sgibbs * All rights reserved. 3739213Sgibbs * 3839213Sgibbs * Partially based on an autochanger driver written by Stefan Grefen 3939213Sgibbs * and on an autochanger driver written by the Systems Programming Group 4039213Sgibbs * at the University of Utah Computer Science Department. 4139213Sgibbs * 4239213Sgibbs * Redistribution and use in source and binary forms, with or without 4339213Sgibbs * modification, are permitted provided that the following conditions 4439213Sgibbs * are met: 4539213Sgibbs * 1. Redistributions of source code must retain the above copyright 4639213Sgibbs * notice, this list of conditions and the following disclaimer. 4739213Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 4839213Sgibbs * notice, this list of conditions and the following disclaimer in the 4939213Sgibbs * documentation and/or other materials provided with the distribution. 5039213Sgibbs * 3. All advertising materials mentioning features or use of this software 5139213Sgibbs * must display the following acknowledgements: 5239213Sgibbs * This product includes software developed by Jason R. Thorpe 5339213Sgibbs * for And Communications, http://www.and.com/ 5439213Sgibbs * 4. The name of the author may not be used to endorse or promote products 5539213Sgibbs * derived from this software without specific prior written permission. 5639213Sgibbs * 5739213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 5839213Sgibbs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 5939213Sgibbs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 6039213Sgibbs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 6139213Sgibbs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 6239213Sgibbs * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 6339213Sgibbs * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 6439213Sgibbs * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 6539213Sgibbs * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6639213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6739213Sgibbs * SUCH DAMAGE. 6839213Sgibbs */ 6939213Sgibbs 70116162Sobrien#include <sys/cdefs.h> 71116162Sobrien__FBSDID("$FreeBSD$"); 72116162Sobrien 7339213Sgibbs#include <sys/param.h> 7439213Sgibbs#include <sys/queue.h> 7539213Sgibbs#include <sys/systm.h> 7639213Sgibbs#include <sys/kernel.h> 7739213Sgibbs#include <sys/types.h> 7839213Sgibbs#include <sys/malloc.h> 7939213Sgibbs#include <sys/fcntl.h> 8039213Sgibbs#include <sys/conf.h> 8139213Sgibbs#include <sys/chio.h> 8239213Sgibbs#include <sys/errno.h> 8339213Sgibbs#include <sys/devicestat.h> 8439213Sgibbs 8539213Sgibbs#include <cam/cam.h> 8639213Sgibbs#include <cam/cam_ccb.h> 8739213Sgibbs#include <cam/cam_periph.h> 8839213Sgibbs#include <cam/cam_xpt_periph.h> 8939213Sgibbs#include <cam/cam_debug.h> 9039213Sgibbs 9139213Sgibbs#include <cam/scsi/scsi_all.h> 9239213Sgibbs#include <cam/scsi/scsi_message.h> 9339213Sgibbs#include <cam/scsi/scsi_ch.h> 9439213Sgibbs 9539213Sgibbs/* 9639213Sgibbs * Timeout definitions for various changer related commands. They may 9739213Sgibbs * be too short for some devices (especially the timeout for INITIALIZE 9839213Sgibbs * ELEMENT STATUS). 9939213Sgibbs */ 10039213Sgibbs 10142017Seivindstatic const u_int32_t CH_TIMEOUT_MODE_SENSE = 6000; 102255043Skenstatic const u_int32_t CH_TIMEOUT_MOVE_MEDIUM = 15 * 60 * 1000; 103255043Skenstatic const u_int32_t CH_TIMEOUT_EXCHANGE_MEDIUM = 15 * 60 * 1000; 104255043Skenstatic const u_int32_t CH_TIMEOUT_POSITION_TO_ELEMENT = 15 * 60 * 1000; 105255043Skenstatic const u_int32_t CH_TIMEOUT_READ_ELEMENT_STATUS = 5 * 60 * 1000; 10642017Seivindstatic const u_int32_t CH_TIMEOUT_SEND_VOLTAG = 10000; 10742017Seivindstatic const u_int32_t CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS = 500000; 10839213Sgibbs 10939213Sgibbstypedef enum { 110236138Sken CH_FLAG_INVALID = 0x001 11139213Sgibbs} ch_flags; 11239213Sgibbs 11339213Sgibbstypedef enum { 11439213Sgibbs CH_STATE_PROBE, 11539213Sgibbs CH_STATE_NORMAL 11639213Sgibbs} ch_state; 11739213Sgibbs 11839213Sgibbstypedef enum { 11939213Sgibbs CH_CCB_PROBE, 12039213Sgibbs CH_CCB_WAITING 12139213Sgibbs} ch_ccb_types; 12239213Sgibbs 12339885Skentypedef enum { 12439885Sken CH_Q_NONE = 0x00, 125253274Sken CH_Q_NO_DBD = 0x01, 126253274Sken CH_Q_NO_DVCID = 0x02 12739885Sken} ch_quirks; 12839885Sken 129250792Ssmh#define CH_Q_BIT_STRING \ 130250792Ssmh "\020" \ 131253274Sken "\001NO_DBD" \ 132253274Sken "\002NO_DVCID" 133250792Ssmh 13439213Sgibbs#define ccb_state ppriv_field0 13539213Sgibbs#define ccb_bp ppriv_ptr1 13639213Sgibbs 13739213Sgibbsstruct scsi_mode_sense_data { 13839213Sgibbs struct scsi_mode_header_6 header; 13939885Sken struct scsi_mode_blk_desc blk_desc; 14039213Sgibbs union { 14139213Sgibbs struct page_element_address_assignment ea; 14239213Sgibbs struct page_transport_geometry_parameters tg; 14339213Sgibbs struct page_device_capabilities cap; 14439213Sgibbs } pages; 14539213Sgibbs}; 14639213Sgibbs 14739213Sgibbsstruct ch_softc { 14839213Sgibbs ch_flags flags; 14939213Sgibbs ch_state state; 15039885Sken ch_quirks quirks; 15139213Sgibbs union ccb saved_ccb; 152112006Sphk struct devstat *device_stats; 153244014Sken struct cdev *dev; 154244014Sken int open_count; 15539213Sgibbs 15639213Sgibbs int sc_picker; /* current picker */ 15739213Sgibbs 15839213Sgibbs /* 15939213Sgibbs * The following information is obtained from the 16039213Sgibbs * element address assignment page. 16139213Sgibbs */ 162115464Sphk int sc_firsts[CHET_MAX + 1]; /* firsts */ 163115464Sphk int sc_counts[CHET_MAX + 1]; /* counts */ 16439213Sgibbs 16539213Sgibbs /* 16639213Sgibbs * The following mask defines the legal combinations 16739213Sgibbs * of elements for the MOVE MEDIUM command. 16839213Sgibbs */ 169115464Sphk u_int8_t sc_movemask[CHET_MAX + 1]; 17039213Sgibbs 17139213Sgibbs /* 17239213Sgibbs * As above, but for EXCHANGE MEDIUM. 17339213Sgibbs */ 174115464Sphk u_int8_t sc_exchangemask[CHET_MAX + 1]; 17539213Sgibbs 17639213Sgibbs /* 17739213Sgibbs * Quirks; see below. XXX KDM not implemented yet 17839213Sgibbs */ 17939213Sgibbs int sc_settledelay; /* delay for settle */ 18039213Sgibbs}; 18139213Sgibbs 18239213Sgibbsstatic d_open_t chopen; 18339213Sgibbsstatic d_close_t chclose; 18439213Sgibbsstatic d_ioctl_t chioctl; 18539213Sgibbsstatic periph_init_t chinit; 18639213Sgibbsstatic periph_ctor_t chregister; 18740603Skenstatic periph_oninv_t choninvalidate; 18839213Sgibbsstatic periph_dtor_t chcleanup; 18939213Sgibbsstatic periph_start_t chstart; 19039213Sgibbsstatic void chasync(void *callback_arg, u_int32_t code, 19139213Sgibbs struct cam_path *path, void *arg); 19239213Sgibbsstatic void chdone(struct cam_periph *periph, 19339213Sgibbs union ccb *done_ccb); 19439213Sgibbsstatic int cherror(union ccb *ccb, u_int32_t cam_flags, 19539213Sgibbs u_int32_t sense_flags); 19639213Sgibbsstatic int chmove(struct cam_periph *periph, 19739213Sgibbs struct changer_move *cm); 19839213Sgibbsstatic int chexchange(struct cam_periph *periph, 19939213Sgibbs struct changer_exchange *ce); 20039213Sgibbsstatic int chposition(struct cam_periph *periph, 20139213Sgibbs struct changer_position *cp); 20239213Sgibbsstatic int chgetelemstatus(struct cam_periph *periph, 203249658Sken int scsi_version, u_long cmd, 20439213Sgibbs struct changer_element_status_request *csr); 20539213Sgibbsstatic int chsetvoltag(struct cam_periph *periph, 20639213Sgibbs struct changer_set_voltag_request *csvr); 20739213Sgibbsstatic int chielem(struct cam_periph *periph, 20839213Sgibbs unsigned int timeout); 20939213Sgibbsstatic int chgetparams(struct cam_periph *periph); 210249658Skenstatic int chscsiversion(struct cam_periph *periph); 21139213Sgibbs 21239213Sgibbsstatic struct periph_driver chdriver = 21339213Sgibbs{ 21439213Sgibbs chinit, "ch", 21539213Sgibbs TAILQ_HEAD_INITIALIZER(chdriver.units), /* generation */ 0 21639213Sgibbs}; 21739213Sgibbs 21872119SpeterPERIPHDRIVER_DECLARE(ch, chdriver); 21939213Sgibbs 22047625Sphkstatic struct cdevsw ch_cdevsw = { 221126080Sphk .d_version = D_VERSION, 222236138Sken .d_flags = D_TRACKCLOSE, 223111815Sphk .d_open = chopen, 224111815Sphk .d_close = chclose, 225111815Sphk .d_ioctl = chioctl, 226111815Sphk .d_name = "ch", 22739213Sgibbs}; 22839213Sgibbs 229227293Sedstatic MALLOC_DEFINE(M_SCSICH, "scsi_ch", "scsi_ch buffers"); 230169562Sscottl 231104094Sphkstatic void 23239213Sgibbschinit(void) 23339213Sgibbs{ 23439213Sgibbs cam_status status; 23539213Sgibbs 23639213Sgibbs /* 23739213Sgibbs * Install a global async callback. This callback will 23839213Sgibbs * receive async callbacks like "new device found". 23939213Sgibbs */ 240169605Sscottl status = xpt_register_async(AC_FOUND_DEVICE, chasync, NULL, NULL); 24139213Sgibbs 24239213Sgibbs if (status != CAM_REQ_CMP) { 24339213Sgibbs printf("ch: Failed to attach master async callback " 24439213Sgibbs "due to status 0x%x!\n", status); 24539213Sgibbs } 24639213Sgibbs} 24739213Sgibbs 24839213Sgibbsstatic void 249244014Skenchdevgonecb(void *arg) 250244014Sken{ 251244014Sken struct cam_sim *sim; 252244014Sken struct ch_softc *softc; 253244014Sken struct cam_periph *periph; 254244014Sken int i; 255244014Sken 256244014Sken periph = (struct cam_periph *)arg; 257244014Sken sim = periph->sim; 258244014Sken softc = (struct ch_softc *)periph->softc; 259244014Sken 260244014Sken KASSERT(softc->open_count >= 0, ("Negative open count %d", 261244014Sken softc->open_count)); 262244014Sken 263244014Sken mtx_lock(sim->mtx); 264244014Sken 265244014Sken /* 266244014Sken * When we get this callback, we will get no more close calls from 267244014Sken * devfs. So if we have any dangling opens, we need to release the 268244014Sken * reference held for that particular context. 269244014Sken */ 270244014Sken for (i = 0; i < softc->open_count; i++) 271244014Sken cam_periph_release_locked(periph); 272244014Sken 273244014Sken softc->open_count = 0; 274244014Sken 275244014Sken /* 276244014Sken * Release the reference held for the device node, it is gone now. 277244014Sken */ 278244014Sken cam_periph_release_locked(periph); 279244014Sken 280244014Sken /* 281244014Sken * We reference the SIM lock directly here, instead of using 282244014Sken * cam_periph_unlock(). The reason is that the final call to 283244014Sken * cam_periph_release_locked() above could result in the periph 284244014Sken * getting freed. If that is the case, dereferencing the periph 285244014Sken * with a cam_periph_unlock() call would cause a page fault. 286244014Sken */ 287244014Sken mtx_unlock(sim->mtx); 288244014Sken} 289244014Sken 290244014Skenstatic void 29140603Skenchoninvalidate(struct cam_periph *periph) 29240603Sken{ 29340603Sken struct ch_softc *softc; 29440603Sken 29540603Sken softc = (struct ch_softc *)periph->softc; 29640603Sken 29740603Sken /* 29840603Sken * De-register any async callbacks. 29940603Sken */ 300169605Sscottl xpt_register_async(0, chasync, periph, periph->path); 30140603Sken 30240603Sken softc->flags |= CH_FLAG_INVALID; 30340603Sken 304244014Sken /* 305244014Sken * Tell devfs this device has gone away, and ask for a callback 306244014Sken * when it has cleaned up its state. 307244014Sken */ 308244014Sken destroy_dev_sched_cb(softc->dev, chdevgonecb, periph); 30940603Sken} 31040603Sken 31140603Skenstatic void 31239213Sgibbschcleanup(struct cam_periph *periph) 31339213Sgibbs{ 31440603Sken struct ch_softc *softc; 31539213Sgibbs 31640603Sken softc = (struct ch_softc *)periph->softc; 31740603Sken 318112006Sphk devstat_remove_entry(softc->device_stats); 319244014Sken 32040603Sken free(softc, M_DEVBUF); 32139213Sgibbs} 32239213Sgibbs 32339213Sgibbsstatic void 32439213Sgibbschasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 32539213Sgibbs{ 32639213Sgibbs struct cam_periph *periph; 32739213Sgibbs 32839213Sgibbs periph = (struct cam_periph *)callback_arg; 32939213Sgibbs 33039213Sgibbs switch(code) { 33139213Sgibbs case AC_FOUND_DEVICE: 33239213Sgibbs { 33339213Sgibbs struct ccb_getdev *cgd; 33439213Sgibbs cam_status status; 33539213Sgibbs 33639213Sgibbs cgd = (struct ccb_getdev *)arg; 33779177Smjacob if (cgd == NULL) 33879177Smjacob break; 33939213Sgibbs 340195534Sscottl if (cgd->protocol != PROTO_SCSI) 341195534Sscottl break; 342195534Sscottl 34356148Smjacob if (SID_TYPE(&cgd->inq_data)!= T_CHANGER) 34439213Sgibbs break; 34539213Sgibbs 34639213Sgibbs /* 34739213Sgibbs * Allocate a peripheral instance for 34839213Sgibbs * this device and start the probe 34939213Sgibbs * process. 35039213Sgibbs */ 35140603Sken status = cam_periph_alloc(chregister, choninvalidate, 35240603Sken chcleanup, chstart, "ch", 35340603Sken CAM_PERIPH_BIO, cgd->ccb_h.path, 35439213Sgibbs chasync, AC_FOUND_DEVICE, cgd); 35539213Sgibbs 35639213Sgibbs if (status != CAM_REQ_CMP 35739213Sgibbs && status != CAM_REQ_INPROG) 35839213Sgibbs printf("chasync: Unable to probe new device " 35939213Sgibbs "due to status 0x%x\n", status); 36039213Sgibbs 36139213Sgibbs break; 36239213Sgibbs 36339213Sgibbs } 36439213Sgibbs default: 36547413Sgibbs cam_periph_async(periph, code, path, arg); 36639213Sgibbs break; 36739213Sgibbs } 36839213Sgibbs} 36939213Sgibbs 37039213Sgibbsstatic cam_status 37139213Sgibbschregister(struct cam_periph *periph, void *arg) 37239213Sgibbs{ 37339213Sgibbs struct ch_softc *softc; 37439213Sgibbs struct ccb_getdev *cgd; 375220644Smav struct ccb_pathinq cpi; 37639213Sgibbs 37739213Sgibbs cgd = (struct ccb_getdev *)arg; 37839213Sgibbs if (cgd == NULL) { 37939213Sgibbs printf("chregister: no getdev CCB, can't register device\n"); 38039213Sgibbs return(CAM_REQ_CMP_ERR); 38139213Sgibbs } 38239213Sgibbs 38339213Sgibbs softc = (struct ch_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 38439213Sgibbs 38539213Sgibbs if (softc == NULL) { 38639213Sgibbs printf("chregister: Unable to probe new device. " 38739213Sgibbs "Unable to allocate softc\n"); 38839213Sgibbs return(CAM_REQ_CMP_ERR); 38939213Sgibbs } 39039213Sgibbs 39139213Sgibbs bzero(softc, sizeof(*softc)); 39239213Sgibbs softc->state = CH_STATE_PROBE; 39339213Sgibbs periph->softc = softc; 39439885Sken softc->quirks = CH_Q_NONE; 39539213Sgibbs 396253274Sken /* 397253274Sken * The DVCID and CURDATA bits were not introduced until the SMC 398253274Sken * spec. If this device claims SCSI-2 or earlier support, then it 399253274Sken * very likely does not support these bits. 400253274Sken */ 401253274Sken if (cgd->inq_data.version <= SCSI_REV_2) 402253274Sken softc->quirks |= CH_Q_NO_DVCID; 403253274Sken 404220644Smav bzero(&cpi, sizeof(cpi)); 405220644Smav xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 406220644Smav cpi.ccb_h.func_code = XPT_PATH_INQ; 407220644Smav xpt_action((union ccb *)&cpi); 408220644Smav 40939213Sgibbs /* 41039213Sgibbs * Changers don't have a blocksize, and obviously don't support 41139213Sgibbs * tagged queueing. 41239213Sgibbs */ 413169605Sscottl cam_periph_unlock(periph); 414112006Sphk softc->device_stats = devstat_new_entry("ch", 41539213Sgibbs periph->unit_number, 0, 41639213Sgibbs DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS, 417220644Smav SID_TYPE(&cgd->inq_data) | 418220644Smav XPORT_DEVSTAT_TYPE(cpi.transport), 41943819Sken DEVSTAT_PRIORITY_OTHER); 42039213Sgibbs 421244014Sken /* 422244014Sken * Acquire a reference to the periph before we create the devfs 423244014Sken * instance for it. We'll release this reference once the devfs 424244014Sken * instance has been freed. 425244014Sken */ 426244014Sken if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 427244014Sken xpt_print(periph->path, "%s: lost periph during " 428244014Sken "registration!\n", __func__); 429244014Sken cam_periph_lock(periph); 430244014Sken return (CAM_REQ_CMP_ERR); 431244014Sken } 432244014Sken 433244014Sken 43453520Smjacob /* Register the device */ 43553520Smjacob softc->dev = make_dev(&ch_cdevsw, periph->unit_number, UID_ROOT, 43653520Smjacob GID_OPERATOR, 0600, "%s%d", periph->periph_name, 43753520Smjacob periph->unit_number); 438168752Sscottl cam_periph_lock(periph); 439101940Snjl softc->dev->si_drv1 = periph; 44053520Smjacob 44139213Sgibbs /* 44239213Sgibbs * Add an async callback so that we get 44339213Sgibbs * notified if this device goes away. 44439213Sgibbs */ 445169605Sscottl xpt_register_async(AC_LOST_DEVICE, chasync, periph, periph->path); 44639213Sgibbs 44739213Sgibbs /* 448168752Sscottl * Lock this periph until we are setup. 44939213Sgibbs * This first call can't block 45039213Sgibbs */ 451168752Sscottl (void)cam_periph_hold(periph, PRIBIO); 452203108Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 45339213Sgibbs 45439213Sgibbs return(CAM_REQ_CMP); 45539213Sgibbs} 45639213Sgibbs 45739213Sgibbsstatic int 458130585Sphkchopen(struct cdev *dev, int flags, int fmt, struct thread *td) 45939213Sgibbs{ 46039213Sgibbs struct cam_periph *periph; 46139213Sgibbs struct ch_softc *softc; 462101940Snjl int error; 46339213Sgibbs 464101940Snjl periph = (struct cam_periph *)dev->si_drv1; 465168752Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) 466168752Sscottl return (ENXIO); 46739213Sgibbs 46839213Sgibbs softc = (struct ch_softc *)periph->softc; 46939213Sgibbs 470168752Sscottl cam_periph_lock(periph); 471168752Sscottl 47240603Sken if (softc->flags & CH_FLAG_INVALID) { 473236138Sken cam_periph_release_locked(periph); 474168752Sscottl cam_periph_unlock(periph); 47539213Sgibbs return(ENXIO); 47640603Sken } 47739213Sgibbs 478168752Sscottl if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) { 479168752Sscottl cam_periph_unlock(periph); 480168752Sscottl cam_periph_release(periph); 48139213Sgibbs return (error); 48241297Sken } 48341297Sken 48439213Sgibbs /* 48539213Sgibbs * Load information about this changer device into the softc. 48639213Sgibbs */ 48739213Sgibbs if ((error = chgetparams(periph)) != 0) { 488249658Sken cam_periph_unhold(periph); 489236138Sken cam_periph_release_locked(periph); 49039213Sgibbs cam_periph_unlock(periph); 49139213Sgibbs return(error); 49239213Sgibbs } 49339213Sgibbs 494168752Sscottl cam_periph_unhold(periph); 495244014Sken 496244014Sken softc->open_count++; 497244014Sken 49839213Sgibbs cam_periph_unlock(periph); 49939213Sgibbs 50039213Sgibbs return(error); 50139213Sgibbs} 50239213Sgibbs 50339213Sgibbsstatic int 504130585Sphkchclose(struct cdev *dev, int flag, int fmt, struct thread *td) 50539213Sgibbs{ 506244014Sken struct cam_sim *sim; 50739213Sgibbs struct cam_periph *periph; 508244014Sken struct ch_softc *softc; 50939213Sgibbs 510101940Snjl periph = (struct cam_periph *)dev->si_drv1; 51139213Sgibbs if (periph == NULL) 51239213Sgibbs return(ENXIO); 51339213Sgibbs 514244014Sken sim = periph->sim; 515244014Sken softc = (struct ch_softc *)periph->softc; 51639213Sgibbs 517244014Sken mtx_lock(sim->mtx); 518244014Sken 519244014Sken softc->open_count--; 520244014Sken 521244014Sken cam_periph_release_locked(periph); 522244014Sken 523244014Sken /* 524244014Sken * We reference the SIM lock directly here, instead of using 525244014Sken * cam_periph_unlock(). The reason is that the call to 526244014Sken * cam_periph_release_locked() above could result in the periph 527244014Sken * getting freed. If that is the case, dereferencing the periph 528244014Sken * with a cam_periph_unlock() call would cause a page fault. 529244014Sken * 530244014Sken * cam_periph_release() avoids this problem using the same method, 531244014Sken * but we're manually acquiring and dropping the lock here to 532244014Sken * protect the open count and avoid another lock acquisition and 533244014Sken * release. 534244014Sken */ 535244014Sken mtx_unlock(sim->mtx); 536244014Sken 53739213Sgibbs return(0); 53839213Sgibbs} 53939213Sgibbs 54039213Sgibbsstatic void 54139213Sgibbschstart(struct cam_periph *periph, union ccb *start_ccb) 54239213Sgibbs{ 54339213Sgibbs struct ch_softc *softc; 54439213Sgibbs 54539213Sgibbs softc = (struct ch_softc *)periph->softc; 54639213Sgibbs 54739213Sgibbs switch (softc->state) { 54839213Sgibbs case CH_STATE_NORMAL: 54939213Sgibbs { 55039213Sgibbs if (periph->immediate_priority <= periph->pinfo.priority){ 55139213Sgibbs start_ccb->ccb_h.ccb_state = CH_CCB_WAITING; 55239213Sgibbs 55339213Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 55439213Sgibbs periph_links.sle); 55539213Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 55639213Sgibbs wakeup(&periph->ccb_list); 557168752Sscottl } 55839213Sgibbs break; 55939213Sgibbs } 56039213Sgibbs case CH_STATE_PROBE: 56139213Sgibbs { 56239885Sken int mode_buffer_len; 56339885Sken void *mode_buffer; 56439213Sgibbs 56539885Sken /* 56639885Sken * Include the block descriptor when calculating the mode 56739885Sken * buffer length, 56839885Sken */ 56939885Sken mode_buffer_len = sizeof(struct scsi_mode_header_6) + 57039885Sken sizeof(struct scsi_mode_blk_desc) + 57139885Sken sizeof(struct page_element_address_assignment); 57239213Sgibbs 573169562Sscottl mode_buffer = malloc(mode_buffer_len, M_SCSICH, M_NOWAIT); 57439885Sken 57539885Sken if (mode_buffer == NULL) { 57639213Sgibbs printf("chstart: couldn't malloc mode sense data\n"); 57739213Sgibbs break; 57839213Sgibbs } 57939885Sken bzero(mode_buffer, mode_buffer_len); 58039213Sgibbs 58139213Sgibbs /* 58239213Sgibbs * Get the element address assignment page. 58339213Sgibbs */ 58439213Sgibbs scsi_mode_sense(&start_ccb->csio, 58539213Sgibbs /* retries */ 1, 58639213Sgibbs /* cbfcnp */ chdone, 58739213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 58839885Sken /* dbd */ (softc->quirks & CH_Q_NO_DBD) ? 58939885Sken FALSE : TRUE, 59039213Sgibbs /* page_code */ SMS_PAGE_CTRL_CURRENT, 59139213Sgibbs /* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE, 59239885Sken /* param_buf */ (u_int8_t *)mode_buffer, 59339885Sken /* param_len */ mode_buffer_len, 59439213Sgibbs /* sense_len */ SSD_FULL_SIZE, 59539213Sgibbs /* timeout */ CH_TIMEOUT_MODE_SENSE); 59639213Sgibbs 59739213Sgibbs start_ccb->ccb_h.ccb_bp = NULL; 59839213Sgibbs start_ccb->ccb_h.ccb_state = CH_CCB_PROBE; 59939213Sgibbs xpt_action(start_ccb); 60039213Sgibbs break; 60139213Sgibbs } 60239213Sgibbs } 60339213Sgibbs} 60439213Sgibbs 60539213Sgibbsstatic void 60639213Sgibbschdone(struct cam_periph *periph, union ccb *done_ccb) 60739213Sgibbs{ 60839213Sgibbs struct ch_softc *softc; 60939213Sgibbs struct ccb_scsiio *csio; 61039213Sgibbs 61139213Sgibbs softc = (struct ch_softc *)periph->softc; 61239213Sgibbs csio = &done_ccb->csio; 61339213Sgibbs 61439213Sgibbs switch(done_ccb->ccb_h.ccb_state) { 61539213Sgibbs case CH_CCB_PROBE: 61639213Sgibbs { 61739885Sken struct scsi_mode_header_6 *mode_header; 61839885Sken struct page_element_address_assignment *ea; 61939213Sgibbs char announce_buf[80]; 62039213Sgibbs 62139213Sgibbs 62239885Sken mode_header = (struct scsi_mode_header_6 *)csio->data_ptr; 62339885Sken 62439885Sken ea = (struct page_element_address_assignment *) 62539885Sken find_mode_page_6(mode_header); 62639885Sken 62739213Sgibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP){ 62839213Sgibbs 62939885Sken softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea); 63039885Sken softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte); 63139885Sken softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea); 63239885Sken softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse); 63339885Sken softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea); 63439885Sken softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee); 63539885Sken softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea); 63639885Sken softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte); 63739213Sgibbs softc->sc_picker = softc->sc_firsts[CHET_MT]; 63839213Sgibbs 63939213Sgibbs#define PLURAL(c) (c) == 1 ? "" : "s" 64041514Sarchie snprintf(announce_buf, sizeof(announce_buf), 64141514Sarchie "%d slot%s, %d drive%s, " 64239213Sgibbs "%d picker%s, %d portal%s", 64339213Sgibbs softc->sc_counts[CHET_ST], 64439213Sgibbs PLURAL(softc->sc_counts[CHET_ST]), 64539213Sgibbs softc->sc_counts[CHET_DT], 64639213Sgibbs PLURAL(softc->sc_counts[CHET_DT]), 64739213Sgibbs softc->sc_counts[CHET_MT], 64839213Sgibbs PLURAL(softc->sc_counts[CHET_MT]), 64939213Sgibbs softc->sc_counts[CHET_IE], 65039213Sgibbs PLURAL(softc->sc_counts[CHET_IE])); 65139213Sgibbs#undef PLURAL 65239213Sgibbs } else { 65339213Sgibbs int error; 65439213Sgibbs 65574840Sken error = cherror(done_ccb, CAM_RETRY_SELTO, 65674840Sken SF_RETRY_UA | SF_NO_PRINT); 65739213Sgibbs /* 65839213Sgibbs * Retry any UNIT ATTENTION type errors. They 65939213Sgibbs * are expected at boot. 66039213Sgibbs */ 66139213Sgibbs if (error == ERESTART) { 66239213Sgibbs /* 66339213Sgibbs * A retry was scheuled, so 66439213Sgibbs * just return. 66539213Sgibbs */ 66639213Sgibbs return; 66739213Sgibbs } else if (error != 0) { 66839885Sken int retry_scheduled; 66939885Sken struct scsi_mode_sense_6 *sms; 67039885Sken 67139885Sken sms = (struct scsi_mode_sense_6 *) 67239885Sken done_ccb->csio.cdb_io.cdb_bytes; 67339885Sken 67439885Sken /* 67539885Sken * Check to see if block descriptors were 67639885Sken * disabled. Some devices don't like that. 67739885Sken * We're taking advantage of the fact that 67839885Sken * the first few bytes of the 6 and 10 byte 67939885Sken * mode sense commands are the same. If 68039885Sken * block descriptors were disabled, enable 68139885Sken * them and re-send the command. 68239885Sken */ 68339885Sken if (sms->byte2 & SMS_DBD) { 68439885Sken sms->byte2 &= ~SMS_DBD; 68539885Sken xpt_action(done_ccb); 68639885Sken softc->quirks |= CH_Q_NO_DBD; 68739885Sken retry_scheduled = 1; 68839885Sken } else 68939885Sken retry_scheduled = 0; 69039885Sken 69139213Sgibbs /* Don't wedge this device's queue */ 692199279Smav if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 693199279Smav cam_release_devq(done_ccb->ccb_h.path, 69439213Sgibbs /*relsim_flags*/0, 69539213Sgibbs /*reduction*/0, 69639213Sgibbs /*timeout*/0, 69739213Sgibbs /*getcount_only*/0); 69839885Sken 69939885Sken if (retry_scheduled) 70039885Sken return; 70139885Sken 70239885Sken if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) 70339885Sken == CAM_SCSI_STATUS_ERROR) 70439885Sken scsi_sense_print(&done_ccb->csio); 70539885Sken else { 706164906Smjacob xpt_print(periph->path, 707164906Smjacob "got CAM status %#x\n", 708164906Smjacob done_ccb->ccb_h.status); 70939885Sken } 710164906Smjacob xpt_print(periph->path, "fatal error, failed " 711164906Smjacob "to attach to device\n"); 71239885Sken 71339885Sken cam_periph_invalidate(periph); 71439885Sken 71539885Sken announce_buf[0] = '\0'; 71639213Sgibbs } 71739213Sgibbs } 718250792Ssmh if (announce_buf[0] != '\0') { 71939885Sken xpt_announce_periph(periph, announce_buf); 720250792Ssmh xpt_announce_quirks(periph, softc->quirks, 721250792Ssmh CH_Q_BIT_STRING); 722250792Ssmh } 72339213Sgibbs softc->state = CH_STATE_NORMAL; 724169562Sscottl free(mode_header, M_SCSICH); 72558921Sken /* 72658921Sken * Since our peripheral may be invalidated by an error 72758921Sken * above or an external event, we must release our CCB 72858921Sken * before releasing the probe lock on the peripheral. 72958921Sken * The peripheral will only go away once the last lock 73058921Sken * is removed, and we need it around for the CCB release 73158921Sken * operation. 73258921Sken */ 73358921Sken xpt_release_ccb(done_ccb); 734168752Sscottl cam_periph_unhold(periph); 73558921Sken return; 73639213Sgibbs } 73739213Sgibbs case CH_CCB_WAITING: 73839213Sgibbs { 73939213Sgibbs /* Caller will release the CCB */ 74039213Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 74139213Sgibbs return; 74239213Sgibbs } 74358921Sken default: 74458921Sken break; 74539213Sgibbs } 74639213Sgibbs xpt_release_ccb(done_ccb); 74739213Sgibbs} 74839213Sgibbs 74939213Sgibbsstatic int 75039213Sgibbscherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 75139213Sgibbs{ 75239213Sgibbs struct ch_softc *softc; 75339213Sgibbs struct cam_periph *periph; 75439213Sgibbs 75539213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 75639213Sgibbs softc = (struct ch_softc *)periph->softc; 75739213Sgibbs 75839213Sgibbs return (cam_periph_error(ccb, cam_flags, sense_flags, 75939213Sgibbs &softc->saved_ccb)); 76039213Sgibbs} 76139213Sgibbs 76239213Sgibbsstatic int 763130585Sphkchioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 76439213Sgibbs{ 76539213Sgibbs struct cam_periph *periph; 76639213Sgibbs struct ch_softc *softc; 76739213Sgibbs int error; 76839213Sgibbs 769101940Snjl periph = (struct cam_periph *)dev->si_drv1; 77039213Sgibbs if (periph == NULL) 77139213Sgibbs return(ENXIO); 77239213Sgibbs 773168752Sscottl cam_periph_lock(periph); 77439213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering chioctl\n")); 77539213Sgibbs 77639213Sgibbs softc = (struct ch_softc *)periph->softc; 77739213Sgibbs 77839213Sgibbs error = 0; 77939213Sgibbs 78039213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 78139904Sken ("trying to do ioctl %#lx\n", cmd)); 78239213Sgibbs 78339213Sgibbs /* 78439213Sgibbs * If this command can change the device's state, we must 78539213Sgibbs * have the device open for writing. 78639213Sgibbs */ 78739213Sgibbs switch (cmd) { 78839213Sgibbs case CHIOGPICKER: 78939213Sgibbs case CHIOGPARAMS: 790249658Sken case OCHIOGSTATUS: 79139213Sgibbs case CHIOGSTATUS: 79239213Sgibbs break; 79339213Sgibbs 79439213Sgibbs default: 795168752Sscottl if ((flag & FWRITE) == 0) { 796168752Sscottl cam_periph_unlock(periph); 79739213Sgibbs return (EBADF); 798168752Sscottl } 79939213Sgibbs } 80039213Sgibbs 80139213Sgibbs switch (cmd) { 80239213Sgibbs case CHIOMOVE: 80339213Sgibbs error = chmove(periph, (struct changer_move *)addr); 80439213Sgibbs break; 80539213Sgibbs 80639213Sgibbs case CHIOEXCHANGE: 80739213Sgibbs error = chexchange(periph, (struct changer_exchange *)addr); 80839213Sgibbs break; 80939213Sgibbs 81039213Sgibbs case CHIOPOSITION: 81139213Sgibbs error = chposition(periph, (struct changer_position *)addr); 81239213Sgibbs break; 81339213Sgibbs 81439213Sgibbs case CHIOGPICKER: 81539213Sgibbs *(int *)addr = softc->sc_picker - softc->sc_firsts[CHET_MT]; 81639213Sgibbs break; 81739213Sgibbs 81839213Sgibbs case CHIOSPICKER: 81939213Sgibbs { 82039213Sgibbs int new_picker = *(int *)addr; 82139213Sgibbs 822168752Sscottl if (new_picker > (softc->sc_counts[CHET_MT] - 1)) { 823168752Sscottl error = EINVAL; 824168752Sscottl break; 825168752Sscottl } 82639213Sgibbs softc->sc_picker = softc->sc_firsts[CHET_MT] + new_picker; 82739213Sgibbs break; 82839213Sgibbs } 82939213Sgibbs case CHIOGPARAMS: 83039213Sgibbs { 83139213Sgibbs struct changer_params *cp = (struct changer_params *)addr; 83239213Sgibbs 83339213Sgibbs cp->cp_npickers = softc->sc_counts[CHET_MT]; 83439213Sgibbs cp->cp_nslots = softc->sc_counts[CHET_ST]; 83539213Sgibbs cp->cp_nportals = softc->sc_counts[CHET_IE]; 83639213Sgibbs cp->cp_ndrives = softc->sc_counts[CHET_DT]; 83739213Sgibbs break; 83839213Sgibbs } 83939213Sgibbs case CHIOIELEM: 84039213Sgibbs error = chielem(periph, *(unsigned int *)addr); 84139213Sgibbs break; 84239213Sgibbs 843249658Sken case OCHIOGSTATUS: 844249658Sken { 845249658Sken error = chgetelemstatus(periph, SCSI_REV_2, cmd, 846249658Sken (struct changer_element_status_request *)addr); 847249658Sken break; 848249658Sken } 849249658Sken 85039213Sgibbs case CHIOGSTATUS: 85139213Sgibbs { 852249658Sken int scsi_version; 853249658Sken 854249658Sken scsi_version = chscsiversion(periph); 855249658Sken if (scsi_version >= SCSI_REV_0) { 856249658Sken error = chgetelemstatus(periph, scsi_version, cmd, 857249658Sken (struct changer_element_status_request *)addr); 858249658Sken } 859249658Sken else { /* unable to determine the SCSI version */ 860249658Sken cam_periph_unlock(periph); 861249658Sken return (ENXIO); 862249658Sken } 86339213Sgibbs break; 86439213Sgibbs } 86539213Sgibbs 86639213Sgibbs case CHIOSETVOLTAG: 86739213Sgibbs { 86839213Sgibbs error = chsetvoltag(periph, 86939213Sgibbs (struct changer_set_voltag_request *) addr); 87039213Sgibbs break; 87139213Sgibbs } 87239213Sgibbs 87339213Sgibbs /* Implement prevent/allow? */ 87439213Sgibbs 87539213Sgibbs default: 87639213Sgibbs error = cam_periph_ioctl(periph, cmd, addr, cherror); 87739213Sgibbs break; 87839213Sgibbs } 87939213Sgibbs 880168752Sscottl cam_periph_unlock(periph); 88139213Sgibbs return (error); 88239213Sgibbs} 88339213Sgibbs 88439213Sgibbsstatic int 88539213Sgibbschmove(struct cam_periph *periph, struct changer_move *cm) 88639213Sgibbs{ 88739213Sgibbs struct ch_softc *softc; 88839213Sgibbs u_int16_t fromelem, toelem; 88939213Sgibbs union ccb *ccb; 89039213Sgibbs int error; 89139213Sgibbs 89239213Sgibbs error = 0; 89339213Sgibbs softc = (struct ch_softc *)periph->softc; 89439213Sgibbs 89539213Sgibbs /* 89639213Sgibbs * Check arguments. 89739213Sgibbs */ 89839213Sgibbs if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT)) 89939213Sgibbs return (EINVAL); 90039213Sgibbs if ((cm->cm_fromunit > (softc->sc_counts[cm->cm_fromtype] - 1)) || 90139213Sgibbs (cm->cm_tounit > (softc->sc_counts[cm->cm_totype] - 1))) 90239213Sgibbs return (ENODEV); 90339213Sgibbs 90439213Sgibbs /* 90539213Sgibbs * Check the request against the changer's capabilities. 90639213Sgibbs */ 90739213Sgibbs if ((softc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0) 90841708Sgibbs return (ENODEV); 90939213Sgibbs 91039213Sgibbs /* 91139213Sgibbs * Calculate the source and destination elements. 91239213Sgibbs */ 91339213Sgibbs fromelem = softc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit; 91439213Sgibbs toelem = softc->sc_firsts[cm->cm_totype] + cm->cm_tounit; 91539213Sgibbs 916198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 91739213Sgibbs 91839213Sgibbs scsi_move_medium(&ccb->csio, 91939213Sgibbs /* retries */ 1, 92039213Sgibbs /* cbfcnp */ chdone, 92139213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 92239213Sgibbs /* tea */ softc->sc_picker, 92339213Sgibbs /* src */ fromelem, 92439213Sgibbs /* dst */ toelem, 92539213Sgibbs /* invert */ (cm->cm_flags & CM_INVERT) ? TRUE : FALSE, 92639213Sgibbs /* sense_len */ SSD_FULL_SIZE, 92739213Sgibbs /* timeout */ CH_TIMEOUT_MOVE_MEDIUM); 92839213Sgibbs 92974840Sken error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO, 93074840Sken /*sense_flags*/ SF_RETRY_UA, 931112006Sphk softc->device_stats); 93239213Sgibbs 93339213Sgibbs xpt_release_ccb(ccb); 93439213Sgibbs 93539213Sgibbs return(error); 93639213Sgibbs} 93739213Sgibbs 93839213Sgibbsstatic int 93939213Sgibbschexchange(struct cam_periph *periph, struct changer_exchange *ce) 94039213Sgibbs{ 94139213Sgibbs struct ch_softc *softc; 94239213Sgibbs u_int16_t src, dst1, dst2; 94339213Sgibbs union ccb *ccb; 94439213Sgibbs int error; 94539213Sgibbs 94639213Sgibbs error = 0; 94739213Sgibbs softc = (struct ch_softc *)periph->softc; 94839213Sgibbs /* 94939213Sgibbs * Check arguments. 95039213Sgibbs */ 95139213Sgibbs if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) || 95239213Sgibbs (ce->ce_sdsttype > CHET_DT)) 95339213Sgibbs return (EINVAL); 95439213Sgibbs if ((ce->ce_srcunit > (softc->sc_counts[ce->ce_srctype] - 1)) || 95539213Sgibbs (ce->ce_fdstunit > (softc->sc_counts[ce->ce_fdsttype] - 1)) || 95639213Sgibbs (ce->ce_sdstunit > (softc->sc_counts[ce->ce_sdsttype] - 1))) 95739213Sgibbs return (ENODEV); 95839213Sgibbs 95939213Sgibbs /* 96039213Sgibbs * Check the request against the changer's capabilities. 96139213Sgibbs */ 96239213Sgibbs if (((softc->sc_exchangemask[ce->ce_srctype] & 96339213Sgibbs (1 << ce->ce_fdsttype)) == 0) || 96439213Sgibbs ((softc->sc_exchangemask[ce->ce_fdsttype] & 96539213Sgibbs (1 << ce->ce_sdsttype)) == 0)) 96641708Sgibbs return (ENODEV); 96739213Sgibbs 96839213Sgibbs /* 96939213Sgibbs * Calculate the source and destination elements. 97039213Sgibbs */ 97139213Sgibbs src = softc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit; 97239213Sgibbs dst1 = softc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit; 97339213Sgibbs dst2 = softc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit; 97439213Sgibbs 975198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 97639213Sgibbs 97739213Sgibbs scsi_exchange_medium(&ccb->csio, 97839213Sgibbs /* retries */ 1, 97939213Sgibbs /* cbfcnp */ chdone, 98039213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 98139213Sgibbs /* tea */ softc->sc_picker, 98239213Sgibbs /* src */ src, 98339213Sgibbs /* dst1 */ dst1, 98439213Sgibbs /* dst2 */ dst2, 98539213Sgibbs /* invert1 */ (ce->ce_flags & CE_INVERT1) ? 98639213Sgibbs TRUE : FALSE, 98739213Sgibbs /* invert2 */ (ce->ce_flags & CE_INVERT2) ? 98839213Sgibbs TRUE : FALSE, 98939213Sgibbs /* sense_len */ SSD_FULL_SIZE, 99039213Sgibbs /* timeout */ CH_TIMEOUT_EXCHANGE_MEDIUM); 99139213Sgibbs 99274840Sken error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO, 99374840Sken /*sense_flags*/ SF_RETRY_UA, 994112006Sphk softc->device_stats); 99539213Sgibbs 99639213Sgibbs xpt_release_ccb(ccb); 99739213Sgibbs 99839213Sgibbs return(error); 99939213Sgibbs} 100039213Sgibbs 100139213Sgibbsstatic int 100239213Sgibbschposition(struct cam_periph *periph, struct changer_position *cp) 100339213Sgibbs{ 100439213Sgibbs struct ch_softc *softc; 100539213Sgibbs u_int16_t dst; 100639213Sgibbs union ccb *ccb; 100739213Sgibbs int error; 100839213Sgibbs 100939213Sgibbs error = 0; 101039213Sgibbs softc = (struct ch_softc *)periph->softc; 101139213Sgibbs 101239213Sgibbs /* 101339213Sgibbs * Check arguments. 101439213Sgibbs */ 101539213Sgibbs if (cp->cp_type > CHET_DT) 101639213Sgibbs return (EINVAL); 101739213Sgibbs if (cp->cp_unit > (softc->sc_counts[cp->cp_type] - 1)) 101839213Sgibbs return (ENODEV); 101939213Sgibbs 102039213Sgibbs /* 102139213Sgibbs * Calculate the destination element. 102239213Sgibbs */ 102339213Sgibbs dst = softc->sc_firsts[cp->cp_type] + cp->cp_unit; 102439213Sgibbs 1025198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 102639213Sgibbs 102739213Sgibbs scsi_position_to_element(&ccb->csio, 102839213Sgibbs /* retries */ 1, 102939213Sgibbs /* cbfcnp */ chdone, 103039213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 103139213Sgibbs /* tea */ softc->sc_picker, 103239213Sgibbs /* dst */ dst, 103339213Sgibbs /* invert */ (cp->cp_flags & CP_INVERT) ? 103439213Sgibbs TRUE : FALSE, 103539213Sgibbs /* sense_len */ SSD_FULL_SIZE, 103639213Sgibbs /* timeout */ CH_TIMEOUT_POSITION_TO_ELEMENT); 103739213Sgibbs 103874840Sken error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 103974840Sken /*sense_flags*/ SF_RETRY_UA, 1040112006Sphk softc->device_stats); 104139213Sgibbs 104239213Sgibbs xpt_release_ccb(ccb); 104339213Sgibbs 104439213Sgibbs return(error); 104539213Sgibbs} 104639213Sgibbs 104739213Sgibbs/* 104839213Sgibbs * Copy a volume tag to a volume_tag struct, converting SCSI byte order 104939213Sgibbs * to host native byte order in the volume serial number. The volume 105039213Sgibbs * label as returned by the changer is transferred to user mode as 105139213Sgibbs * nul-terminated string. Volume labels are truncated at the first 105239213Sgibbs * space, as suggested by SCSI-2. 105339213Sgibbs */ 105439213Sgibbsstatic void 105539213Sgibbscopy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag) 105639213Sgibbs{ 105739213Sgibbs int i; 105839213Sgibbs for (i=0; i<CH_VOLTAG_MAXLEN; i++) { 105939213Sgibbs char c = voltag->vif[i]; 106039213Sgibbs if (c && c != ' ') 106139213Sgibbs uvoltag->cv_volid[i] = c; 106239213Sgibbs else 106339213Sgibbs break; 106439213Sgibbs } 106539213Sgibbs uvoltag->cv_serial = scsi_2btoul(voltag->vsn); 106639213Sgibbs} 106739213Sgibbs 106839213Sgibbs/* 1069249658Sken * Copy an element status descriptor to a user-mode 107039213Sgibbs * changer_element_status structure. 107139213Sgibbs */ 1072249658Skenstatic void 107339213Sgibbscopy_element_status(struct ch_softc *softc, 107439213Sgibbs u_int16_t flags, 107539213Sgibbs struct read_element_status_descriptor *desc, 1076249658Sken struct changer_element_status *ces, 1077249658Sken int scsi_version) 107839213Sgibbs{ 107939213Sgibbs u_int16_t eaddr = scsi_2btoul(desc->eaddr); 108039213Sgibbs u_int16_t et; 1081249658Sken struct volume_tag *pvol_tag = NULL, *avol_tag = NULL; 1082249658Sken struct read_element_status_device_id *devid = NULL; 108339213Sgibbs 108439213Sgibbs ces->ces_int_addr = eaddr; 108539213Sgibbs /* set up logical address in element status */ 108639213Sgibbs for (et = CHET_MT; et <= CHET_DT; et++) { 108739213Sgibbs if ((softc->sc_firsts[et] <= eaddr) 108839213Sgibbs && ((softc->sc_firsts[et] + softc->sc_counts[et]) 108939213Sgibbs > eaddr)) { 109039213Sgibbs ces->ces_addr = eaddr - softc->sc_firsts[et]; 109139213Sgibbs ces->ces_type = et; 109239213Sgibbs break; 109339213Sgibbs } 109439213Sgibbs } 109539213Sgibbs 109639213Sgibbs ces->ces_flags = desc->flags1; 109739213Sgibbs 109839213Sgibbs ces->ces_sensecode = desc->sense_code; 109939213Sgibbs ces->ces_sensequal = desc->sense_qual; 110039213Sgibbs 110139213Sgibbs if (desc->flags2 & READ_ELEMENT_STATUS_INVERT) 110239213Sgibbs ces->ces_flags |= CES_INVERT; 110339213Sgibbs 110439213Sgibbs if (desc->flags2 & READ_ELEMENT_STATUS_SVALID) { 110539213Sgibbs 110639213Sgibbs eaddr = scsi_2btoul(desc->ssea); 110739213Sgibbs 110839213Sgibbs /* convert source address to logical format */ 110939213Sgibbs for (et = CHET_MT; et <= CHET_DT; et++) { 111039213Sgibbs if ((softc->sc_firsts[et] <= eaddr) 111139213Sgibbs && ((softc->sc_firsts[et] + softc->sc_counts[et]) 111239213Sgibbs > eaddr)) { 1113249658Sken ces->ces_source_addr = 111439213Sgibbs eaddr - softc->sc_firsts[et]; 111539213Sgibbs ces->ces_source_type = et; 111639213Sgibbs ces->ces_flags |= CES_SOURCE_VALID; 111739213Sgibbs break; 111839213Sgibbs } 111939213Sgibbs } 112039213Sgibbs 112139213Sgibbs if (!(ces->ces_flags & CES_SOURCE_VALID)) 112239213Sgibbs printf("ch: warning: could not map element source " 112358921Sken "address %ud to a valid element type\n", 112439213Sgibbs eaddr); 112539213Sgibbs } 112639213Sgibbs 1127249658Sken /* 1128249658Sken * pvoltag and avoltag are common between SCSI-2 and later versions 1129249658Sken */ 113039213Sgibbs if (flags & READ_ELEMENT_STATUS_PVOLTAG) 1131249658Sken pvol_tag = &desc->voltag_devid.pvoltag; 113239213Sgibbs if (flags & READ_ELEMENT_STATUS_AVOLTAG) 1133249658Sken avol_tag = (flags & READ_ELEMENT_STATUS_PVOLTAG) ? 1134249658Sken &desc->voltag_devid.voltag[1] :&desc->voltag_devid.pvoltag; 1135249658Sken /* 1136249658Sken * For SCSI-3 and later, element status can carry designator and 1137249658Sken * other information. 1138249658Sken */ 1139249658Sken if (scsi_version >= SCSI_REV_SPC) { 1140249658Sken if ((flags & READ_ELEMENT_STATUS_PVOLTAG) ^ 1141249658Sken (flags & READ_ELEMENT_STATUS_AVOLTAG)) 1142249658Sken devid = &desc->voltag_devid.pvol_and_devid.devid; 1143249658Sken else if (!(flags & READ_ELEMENT_STATUS_PVOLTAG) && 1144249658Sken !(flags & READ_ELEMENT_STATUS_AVOLTAG)) 1145249658Sken devid = &desc->voltag_devid.devid; 1146249658Sken else /* Have both PVOLTAG and AVOLTAG */ 1147249658Sken devid = &desc->voltag_devid.vol_tags_and_devid.devid; 1148249658Sken } 114939213Sgibbs 1150249658Sken if (pvol_tag) 1151249658Sken copy_voltag(&(ces->ces_pvoltag), pvol_tag); 1152249658Sken if (avol_tag) 1153249658Sken copy_voltag(&(ces->ces_pvoltag), avol_tag); 1154249658Sken if (devid != NULL) { 1155249658Sken if (devid->designator_length > 0) { 1156249658Sken bcopy((void *)devid->designator, 1157249658Sken (void *)ces->ces_designator, 1158249658Sken devid->designator_length); 1159249658Sken ces->ces_designator_length = devid->designator_length; 1160249658Sken /* 1161249658Sken * Make sure we are always NUL terminated. The 1162249701Sken * This won't matter for the binary code set, 1163249701Sken * since the user will only pay attention to the 1164249701Sken * length field. 1165249658Sken */ 1166249701Sken ces->ces_designator[devid->designator_length]= '\0'; 1167249658Sken } 1168249658Sken if (devid->piv_assoc_designator_type & 1169249658Sken READ_ELEMENT_STATUS_PIV_SET) { 1170249658Sken ces->ces_flags |= CES_PIV; 1171249658Sken ces->ces_protocol_id = 1172249658Sken READ_ELEMENT_STATUS_PROTOCOL_ID( 1173249658Sken devid->prot_code_set); 1174249658Sken } 1175249658Sken ces->ces_code_set = 1176249658Sken READ_ELEMENT_STATUS_CODE_SET(devid->prot_code_set); 1177249658Sken ces->ces_assoc = READ_ELEMENT_STATUS_ASSOCIATION( 1178249658Sken devid->piv_assoc_designator_type); 1179249658Sken ces->ces_designator_type = READ_ELEMENT_STATUS_DESIGNATOR_TYPE( 1180249658Sken devid->piv_assoc_designator_type); 1181249658Sken } else if (scsi_version > SCSI_REV_2) { 1182249658Sken /* SCSI-SPC and No devid, no designator */ 1183249658Sken ces->ces_designator_length = 0; 1184249658Sken ces->ces_designator[0] = '\0'; 1185249658Sken ces->ces_protocol_id = CES_PROTOCOL_ID_FCP_4; 118639213Sgibbs } 118739213Sgibbs 1188249658Sken if (scsi_version <= SCSI_REV_2) { 1189249658Sken if (desc->dt_or_obsolete.scsi_2.dt_scsi_flags & 1190249658Sken READ_ELEMENT_STATUS_DT_IDVALID) { 1191249658Sken ces->ces_flags |= CES_SCSIID_VALID; 1192249658Sken ces->ces_scsi_id = 1193249658Sken desc->dt_or_obsolete.scsi_2.dt_scsi_addr; 1194249658Sken } 1195249658Sken 1196249658Sken if (desc->dt_or_obsolete.scsi_2.dt_scsi_addr & 1197249658Sken READ_ELEMENT_STATUS_DT_LUVALID) { 1198249658Sken ces->ces_flags |= CES_LUN_VALID; 1199249658Sken ces->ces_scsi_lun = 1200249658Sken desc->dt_or_obsolete.scsi_2.dt_scsi_flags & 1201249658Sken READ_ELEMENT_STATUS_DT_LUNMASK; 1202249658Sken } 120339213Sgibbs } 120439213Sgibbs} 120539213Sgibbs 120639213Sgibbsstatic int 1207249658Skenchgetelemstatus(struct cam_periph *periph, int scsi_version, u_long cmd, 120839213Sgibbs struct changer_element_status_request *cesr) 120939213Sgibbs{ 121039213Sgibbs struct read_element_status_header *st_hdr; 121139213Sgibbs struct read_element_status_page_header *pg_hdr; 121239213Sgibbs struct read_element_status_descriptor *desc; 121339213Sgibbs caddr_t data = NULL; 121439213Sgibbs size_t size, desclen; 121539213Sgibbs int avail, i, error = 0; 1216253274Sken int curdata, dvcid, sense_flags; 1217253274Sken int try_no_dvcid = 0; 121839213Sgibbs struct changer_element_status *user_data = NULL; 121939213Sgibbs struct ch_softc *softc; 122039213Sgibbs union ccb *ccb; 122139213Sgibbs int chet = cesr->cesr_element_type; 122239213Sgibbs int want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0; 122339213Sgibbs 122439213Sgibbs softc = (struct ch_softc *)periph->softc; 122539213Sgibbs 122639213Sgibbs /* perform argument checking */ 122739213Sgibbs 122839213Sgibbs /* 122939213Sgibbs * Perform a range check on the cesr_element_{base,count} 123039213Sgibbs * request argument fields. 123139213Sgibbs */ 123239213Sgibbs if ((softc->sc_counts[chet] - cesr->cesr_element_base) <= 0 123339213Sgibbs || (cesr->cesr_element_base + cesr->cesr_element_count) 123439213Sgibbs > softc->sc_counts[chet]) 123539213Sgibbs return (EINVAL); 123639213Sgibbs 123739213Sgibbs /* 123839213Sgibbs * Request one descriptor for the given element type. This 123939213Sgibbs * is used to determine the size of the descriptor so that 124039213Sgibbs * we can allocate enough storage for all of them. We assume 124139213Sgibbs * that the first one can fit into 1k. 124239213Sgibbs */ 1243168752Sscottl cam_periph_unlock(periph); 1244111119Simp data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK); 124539213Sgibbs 1246168752Sscottl cam_periph_lock(periph); 1247198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 124839213Sgibbs 1249253274Sken sense_flags = SF_RETRY_UA; 1250253274Sken if (softc->quirks & CH_Q_NO_DVCID) { 1251253274Sken dvcid = 0; 1252253274Sken curdata = 0; 1253253274Sken } else { 1254253274Sken dvcid = 1; 1255253274Sken curdata = 1; 1256253274Sken /* 1257253274Sken * Don't print anything for an Illegal Request, because 1258253274Sken * these flags can cause some changers to complain. We'll 1259253274Sken * retry without them if we get an error. 1260253274Sken */ 1261253274Sken sense_flags |= SF_QUIET_IR; 1262253274Sken } 1263253274Sken 1264253274Skenretry_einval: 1265253274Sken 126639213Sgibbs scsi_read_element_status(&ccb->csio, 126739213Sgibbs /* retries */ 1, 126839213Sgibbs /* cbfcnp */ chdone, 126939213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 127039213Sgibbs /* voltag */ want_voltags, 127139213Sgibbs /* sea */ softc->sc_firsts[chet], 1272253368Sken /* curdata */ curdata, 1273253274Sken /* dvcid */ dvcid, 127439213Sgibbs /* count */ 1, 127539213Sgibbs /* data_ptr */ data, 127639213Sgibbs /* dxfer_len */ 1024, 127739213Sgibbs /* sense_len */ SSD_FULL_SIZE, 127839213Sgibbs /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS); 127939213Sgibbs 128074840Sken error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 1281253274Sken /*sense_flags*/ sense_flags, 1282112006Sphk softc->device_stats); 128339213Sgibbs 1284253274Sken /* 1285253274Sken * An Illegal Request sense key (only used if there is no asc/ascq) 1286253274Sken * or 0x24,0x00 for an ASC/ASCQ both map to EINVAL. If dvcid or 1287253274Sken * curdata are set (we set both or neither), try turning them off 1288253274Sken * and see if the command is successful. 1289253274Sken */ 1290253274Sken if ((error == EINVAL) 1291253274Sken && (dvcid || curdata)) { 1292253274Sken dvcid = 0; 1293253274Sken curdata = 0; 1294253274Sken error = 0; 1295253274Sken /* At this point we want to report any Illegal Request */ 1296253274Sken sense_flags &= ~SF_QUIET_IR; 1297253274Sken try_no_dvcid = 1; 1298253274Sken goto retry_einval; 1299253274Sken } 1300253274Sken 1301253274Sken /* 1302253274Sken * In this case, we tried a read element status with dvcid and 1303253274Sken * curdata set, and it failed. We retried without those bits, and 1304253274Sken * it succeeded. Suggest to the user that he set a quirk, so we 1305253274Sken * don't go through the retry process the first time in the future. 1306253274Sken * This should only happen on changers that claim SCSI-3 or higher, 1307253274Sken * but don't support these bits. 1308253274Sken */ 1309253274Sken if ((try_no_dvcid != 0) 1310253274Sken && (error == 0)) 1311253274Sken softc->quirks |= CH_Q_NO_DVCID; 1312253274Sken 131339213Sgibbs if (error) 131439213Sgibbs goto done; 1315168752Sscottl cam_periph_unlock(periph); 131639213Sgibbs 131739213Sgibbs st_hdr = (struct read_element_status_header *)data; 131850270Sbde pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr + 131939213Sgibbs sizeof(struct read_element_status_header)); 132039213Sgibbs desclen = scsi_2btoul(pg_hdr->edl); 132139213Sgibbs 132239213Sgibbs size = sizeof(struct read_element_status_header) + 132339213Sgibbs sizeof(struct read_element_status_page_header) + 132439213Sgibbs (desclen * cesr->cesr_element_count); 132539213Sgibbs /* 132639213Sgibbs * Reallocate storage for descriptors and get them from the 132739213Sgibbs * device. 132839213Sgibbs */ 132939213Sgibbs free(data, M_DEVBUF); 1330111119Simp data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK); 133139213Sgibbs 1332168752Sscottl cam_periph_lock(periph); 133339213Sgibbs scsi_read_element_status(&ccb->csio, 133439213Sgibbs /* retries */ 1, 133539213Sgibbs /* cbfcnp */ chdone, 133639213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 133739213Sgibbs /* voltag */ want_voltags, 133839213Sgibbs /* sea */ softc->sc_firsts[chet] 133939213Sgibbs + cesr->cesr_element_base, 1340253368Sken /* curdata */ curdata, 1341253274Sken /* dvcid */ dvcid, 134239213Sgibbs /* count */ cesr->cesr_element_count, 134339213Sgibbs /* data_ptr */ data, 134439213Sgibbs /* dxfer_len */ size, 134539213Sgibbs /* sense_len */ SSD_FULL_SIZE, 134639213Sgibbs /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS); 1347249658Sken 134874840Sken error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 134974840Sken /*sense_flags*/ SF_RETRY_UA, 1350112006Sphk softc->device_stats); 135139213Sgibbs 135239213Sgibbs if (error) 135339213Sgibbs goto done; 1354168752Sscottl cam_periph_unlock(periph); 135539213Sgibbs 135639213Sgibbs /* 135739213Sgibbs * Fill in the user status array. 135839213Sgibbs */ 135939213Sgibbs st_hdr = (struct read_element_status_header *)data; 1360144132Sken pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr + 1361144132Sken sizeof(struct read_element_status_header)); 136239213Sgibbs avail = scsi_2btoul(st_hdr->count); 136339213Sgibbs 136439213Sgibbs if (avail != cesr->cesr_element_count) { 1365164906Smjacob xpt_print(periph->path, 1366164906Smjacob "warning, READ ELEMENT STATUS avail != count\n"); 136739213Sgibbs } 136839213Sgibbs 136939213Sgibbs user_data = (struct changer_element_status *) 137039213Sgibbs malloc(avail * sizeof(struct changer_element_status), 1371111119Simp M_DEVBUF, M_WAITOK | M_ZERO); 137239213Sgibbs 137350270Sbde desc = (struct read_element_status_descriptor *)((uintptr_t)data + 137439213Sgibbs sizeof(struct read_element_status_header) + 137539213Sgibbs sizeof(struct read_element_status_page_header)); 137639213Sgibbs /* 137739213Sgibbs * Set up the individual element status structures 137839213Sgibbs */ 137939213Sgibbs for (i = 0; i < avail; ++i) { 1380249658Sken struct changer_element_status *ces; 138139213Sgibbs 1382249658Sken /* 1383249658Sken * In the changer_element_status structure, fields from 1384249658Sken * the beginning to the field of ces_scsi_lun are common 1385249658Sken * between SCSI-2 and SCSI-3, while all the rest are new 1386249658Sken * from SCSI-3. In order to maintain backward compatibility 1387249658Sken * of the chio command, the ces pointer, below, is computed 1388249658Sken * such that it lines up with the structure boundary 1389249658Sken * corresponding to the SCSI version. 1390249658Sken */ 1391249658Sken ces = cmd == OCHIOGSTATUS ? 1392249658Sken (struct changer_element_status *) 1393249658Sken ((unsigned char *)user_data + i * 1394249658Sken (offsetof(struct changer_element_status,ces_scsi_lun)+1)): 1395249658Sken &user_data[i]; 139639213Sgibbs 1397249658Sken copy_element_status(softc, pg_hdr->flags, desc, 1398249658Sken ces, scsi_version); 1399249658Sken 140050270Sbde desc = (struct read_element_status_descriptor *) 1401249658Sken ((unsigned char *)desc + desclen); 140239213Sgibbs } 140339213Sgibbs 140439213Sgibbs /* Copy element status structures out to userspace. */ 1405249658Sken if (cmd == OCHIOGSTATUS) 1406249658Sken error = copyout(user_data, 1407249658Sken cesr->cesr_element_status, 1408249658Sken avail* (offsetof(struct changer_element_status, 1409249658Sken ces_scsi_lun) + 1)); 1410249658Sken else 1411249658Sken error = copyout(user_data, 1412249658Sken cesr->cesr_element_status, 1413249658Sken avail * sizeof(struct changer_element_status)); 1414249658Sken 1415168752Sscottl cam_periph_lock(periph); 141639213Sgibbs 141739213Sgibbs done: 141839213Sgibbs xpt_release_ccb(ccb); 141939213Sgibbs 142039213Sgibbs if (data != NULL) 142139213Sgibbs free(data, M_DEVBUF); 142239213Sgibbs if (user_data != NULL) 142339213Sgibbs free(user_data, M_DEVBUF); 142439213Sgibbs 142539213Sgibbs return (error); 142639213Sgibbs} 142739213Sgibbs 142839213Sgibbsstatic int 142939213Sgibbschielem(struct cam_periph *periph, 143039213Sgibbs unsigned int timeout) 143139213Sgibbs{ 143239213Sgibbs union ccb *ccb; 143339213Sgibbs struct ch_softc *softc; 143439213Sgibbs int error; 143539213Sgibbs 143639213Sgibbs if (!timeout) { 143739213Sgibbs timeout = CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS; 143839213Sgibbs } else { 143939213Sgibbs timeout *= 1000; 144039213Sgibbs } 144139213Sgibbs 144239213Sgibbs error = 0; 144339213Sgibbs softc = (struct ch_softc *)periph->softc; 144439213Sgibbs 1445198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 144639213Sgibbs 144739213Sgibbs scsi_initialize_element_status(&ccb->csio, 144839213Sgibbs /* retries */ 1, 144939213Sgibbs /* cbfcnp */ chdone, 145039213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 145139213Sgibbs /* sense_len */ SSD_FULL_SIZE, 145239213Sgibbs /* timeout */ timeout); 145339213Sgibbs 145474840Sken error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 145574840Sken /*sense_flags*/ SF_RETRY_UA, 1456112006Sphk softc->device_stats); 145739213Sgibbs 145839213Sgibbs xpt_release_ccb(ccb); 145939213Sgibbs 146039213Sgibbs return(error); 146139213Sgibbs} 146239213Sgibbs 146339213Sgibbsstatic int 146439213Sgibbschsetvoltag(struct cam_periph *periph, 146539213Sgibbs struct changer_set_voltag_request *csvr) 146639213Sgibbs{ 146739213Sgibbs union ccb *ccb; 146839213Sgibbs struct ch_softc *softc; 146939213Sgibbs u_int16_t ea; 147039213Sgibbs u_int8_t sac; 147139213Sgibbs struct scsi_send_volume_tag_parameters ssvtp; 147239213Sgibbs int error; 147339213Sgibbs int i; 147439213Sgibbs 147539213Sgibbs error = 0; 147639213Sgibbs softc = (struct ch_softc *)periph->softc; 147739213Sgibbs 147839213Sgibbs bzero(&ssvtp, sizeof(ssvtp)); 147939213Sgibbs for (i=0; i<sizeof(ssvtp.vitf); i++) { 148039213Sgibbs ssvtp.vitf[i] = ' '; 148139213Sgibbs } 148239213Sgibbs 148339213Sgibbs /* 148439213Sgibbs * Check arguments. 148539213Sgibbs */ 148639213Sgibbs if (csvr->csvr_type > CHET_DT) 148739213Sgibbs return EINVAL; 148839213Sgibbs if (csvr->csvr_addr > (softc->sc_counts[csvr->csvr_type] - 1)) 148939213Sgibbs return ENODEV; 149039213Sgibbs 149139213Sgibbs ea = softc->sc_firsts[csvr->csvr_type] + csvr->csvr_addr; 149239213Sgibbs 149339213Sgibbs if (csvr->csvr_flags & CSVR_ALTERNATE) { 149439213Sgibbs switch (csvr->csvr_flags & CSVR_MODE_MASK) { 149539213Sgibbs case CSVR_MODE_SET: 149639213Sgibbs sac = SEND_VOLUME_TAG_ASSERT_ALTERNATE; 149739213Sgibbs break; 149839213Sgibbs case CSVR_MODE_REPLACE: 149939213Sgibbs sac = SEND_VOLUME_TAG_REPLACE_ALTERNATE; 150039213Sgibbs break; 150139213Sgibbs case CSVR_MODE_CLEAR: 150239213Sgibbs sac = SEND_VOLUME_TAG_UNDEFINED_ALTERNATE; 150339213Sgibbs break; 150439213Sgibbs default: 150539213Sgibbs error = EINVAL; 150639213Sgibbs goto out; 150739213Sgibbs } 150839213Sgibbs } else { 150939213Sgibbs switch (csvr->csvr_flags & CSVR_MODE_MASK) { 151039213Sgibbs case CSVR_MODE_SET: 151139213Sgibbs sac = SEND_VOLUME_TAG_ASSERT_PRIMARY; 151239213Sgibbs break; 151339213Sgibbs case CSVR_MODE_REPLACE: 151439213Sgibbs sac = SEND_VOLUME_TAG_REPLACE_PRIMARY; 151539213Sgibbs break; 151639213Sgibbs case CSVR_MODE_CLEAR: 151739213Sgibbs sac = SEND_VOLUME_TAG_UNDEFINED_PRIMARY; 151839213Sgibbs break; 151939213Sgibbs default: 152039213Sgibbs error = EINVAL; 152139213Sgibbs goto out; 152239213Sgibbs } 152339213Sgibbs } 152439213Sgibbs 152539213Sgibbs memcpy(ssvtp.vitf, csvr->csvr_voltag.cv_volid, 152639213Sgibbs min(strlen(csvr->csvr_voltag.cv_volid), sizeof(ssvtp.vitf))); 152739213Sgibbs scsi_ulto2b(csvr->csvr_voltag.cv_serial, ssvtp.minvsn); 152839213Sgibbs 1529198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 153039213Sgibbs 153139213Sgibbs scsi_send_volume_tag(&ccb->csio, 153239213Sgibbs /* retries */ 1, 153339213Sgibbs /* cbfcnp */ chdone, 153439213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 153539213Sgibbs /* element_address */ ea, 153639213Sgibbs /* send_action_code */ sac, 153739213Sgibbs /* parameters */ &ssvtp, 153839213Sgibbs /* sense_len */ SSD_FULL_SIZE, 153939213Sgibbs /* timeout */ CH_TIMEOUT_SEND_VOLTAG); 154039213Sgibbs 154174840Sken error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 154274840Sken /*sense_flags*/ SF_RETRY_UA, 1543112006Sphk softc->device_stats); 154439213Sgibbs 154539213Sgibbs xpt_release_ccb(ccb); 154639213Sgibbs 154739213Sgibbs out: 154839213Sgibbs return error; 154939213Sgibbs} 155039213Sgibbs 155139213Sgibbsstatic int 155239213Sgibbschgetparams(struct cam_periph *periph) 155339213Sgibbs{ 155439213Sgibbs union ccb *ccb; 155539213Sgibbs struct ch_softc *softc; 155639885Sken void *mode_buffer; 155739885Sken int mode_buffer_len; 155839885Sken struct page_element_address_assignment *ea; 155939885Sken struct page_device_capabilities *cap; 156039885Sken int error, from, dbd; 156139213Sgibbs u_int8_t *moves, *exchanges; 156239213Sgibbs 156339213Sgibbs error = 0; 156439213Sgibbs 156539213Sgibbs softc = (struct ch_softc *)periph->softc; 156639213Sgibbs 1567198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 156839213Sgibbs 156939885Sken /* 157039885Sken * The scsi_mode_sense_data structure is just a convenience 157139885Sken * structure that allows us to easily calculate the worst-case 157239885Sken * storage size of the mode sense buffer. 157339885Sken */ 157439885Sken mode_buffer_len = sizeof(struct scsi_mode_sense_data); 157539885Sken 1576169562Sscottl mode_buffer = malloc(mode_buffer_len, M_SCSICH, M_NOWAIT); 157739885Sken 157839885Sken if (mode_buffer == NULL) { 157939213Sgibbs printf("chgetparams: couldn't malloc mode sense data\n"); 158039213Sgibbs return(ENOSPC); 158139213Sgibbs } 158239213Sgibbs 158339885Sken bzero(mode_buffer, mode_buffer_len); 158439213Sgibbs 158539885Sken if (softc->quirks & CH_Q_NO_DBD) 158639885Sken dbd = FALSE; 158739885Sken else 158839885Sken dbd = TRUE; 158939885Sken 159039213Sgibbs /* 159139213Sgibbs * Get the element address assignment page. 159239213Sgibbs */ 159339213Sgibbs scsi_mode_sense(&ccb->csio, 159439213Sgibbs /* retries */ 1, 159539213Sgibbs /* cbfcnp */ chdone, 159639213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 159739885Sken /* dbd */ dbd, 159839213Sgibbs /* page_code */ SMS_PAGE_CTRL_CURRENT, 159939213Sgibbs /* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE, 160039885Sken /* param_buf */ (u_int8_t *)mode_buffer, 160139885Sken /* param_len */ mode_buffer_len, 160239213Sgibbs /* sense_len */ SSD_FULL_SIZE, 160339213Sgibbs /* timeout */ CH_TIMEOUT_MODE_SENSE); 160439213Sgibbs 160574840Sken error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 160674840Sken /* sense_flags */ SF_RETRY_UA|SF_NO_PRINT, 1607112006Sphk softc->device_stats); 160839213Sgibbs 160939213Sgibbs if (error) { 161039885Sken if (dbd) { 161139885Sken struct scsi_mode_sense_6 *sms; 161239885Sken 161339885Sken sms = (struct scsi_mode_sense_6 *) 161439885Sken ccb->csio.cdb_io.cdb_bytes; 161539885Sken 161639885Sken sms->byte2 &= ~SMS_DBD; 161774840Sken error = cam_periph_runccb(ccb, cherror, 161874840Sken /*cam_flags*/ CAM_RETRY_SELTO, 161974840Sken /*sense_flags*/ SF_RETRY_UA, 1620112006Sphk softc->device_stats); 162139885Sken } else { 162239885Sken /* 162339885Sken * Since we disabled sense printing above, print 162439885Sken * out the sense here since we got an error. 162539885Sken */ 162639885Sken scsi_sense_print(&ccb->csio); 162739885Sken } 162839885Sken 162939885Sken if (error) { 1630164906Smjacob xpt_print(periph->path, 1631164906Smjacob "chgetparams: error getting element " 1632164906Smjacob "address page\n"); 163339885Sken xpt_release_ccb(ccb); 1634169562Sscottl free(mode_buffer, M_SCSICH); 163539885Sken return(error); 163639885Sken } 163739213Sgibbs } 163839213Sgibbs 163939885Sken ea = (struct page_element_address_assignment *) 164039885Sken find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer); 164139213Sgibbs 164239885Sken softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea); 164339885Sken softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte); 164439885Sken softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea); 164539885Sken softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse); 164639885Sken softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea); 164739885Sken softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee); 164839885Sken softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea); 164939885Sken softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte); 165039213Sgibbs 165139885Sken bzero(mode_buffer, mode_buffer_len); 165239885Sken 165339213Sgibbs /* 165439213Sgibbs * Now get the device capabilities page. 165539213Sgibbs */ 165639213Sgibbs scsi_mode_sense(&ccb->csio, 165739213Sgibbs /* retries */ 1, 165839213Sgibbs /* cbfcnp */ chdone, 165939213Sgibbs /* tag_action */ MSG_SIMPLE_Q_TAG, 166039885Sken /* dbd */ dbd, 166139213Sgibbs /* page_code */ SMS_PAGE_CTRL_CURRENT, 166239213Sgibbs /* page */ CH_DEVICE_CAP_PAGE, 166339885Sken /* param_buf */ (u_int8_t *)mode_buffer, 166439885Sken /* param_len */ mode_buffer_len, 166539213Sgibbs /* sense_len */ SSD_FULL_SIZE, 166639213Sgibbs /* timeout */ CH_TIMEOUT_MODE_SENSE); 166739213Sgibbs 166874840Sken error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 166974840Sken /* sense_flags */ SF_RETRY_UA | SF_NO_PRINT, 1670112006Sphk softc->device_stats); 167139213Sgibbs 167239885Sken if (error) { 167339885Sken if (dbd) { 167439885Sken struct scsi_mode_sense_6 *sms; 167539213Sgibbs 167639885Sken sms = (struct scsi_mode_sense_6 *) 167739885Sken ccb->csio.cdb_io.cdb_bytes; 167839885Sken 167939885Sken sms->byte2 &= ~SMS_DBD; 168074840Sken error = cam_periph_runccb(ccb, cherror, 168174840Sken /*cam_flags*/ CAM_RETRY_SELTO, 168274840Sken /*sense_flags*/ SF_RETRY_UA, 1683112006Sphk softc->device_stats); 168439885Sken } else { 168539885Sken /* 168639885Sken * Since we disabled sense printing above, print 168739885Sken * out the sense here since we got an error. 168839885Sken */ 168939885Sken scsi_sense_print(&ccb->csio); 169039885Sken } 169139885Sken 169239885Sken if (error) { 1693164906Smjacob xpt_print(periph->path, 1694164906Smjacob "chgetparams: error getting device " 1695164906Smjacob "capabilities page\n"); 169639885Sken xpt_release_ccb(ccb); 1697169562Sscottl free(mode_buffer, M_SCSICH); 169839885Sken return(error); 169939885Sken } 170039213Sgibbs } 170139213Sgibbs 170239885Sken xpt_release_ccb(ccb); 170339213Sgibbs 170439885Sken cap = (struct page_device_capabilities *) 170539885Sken find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer); 170639885Sken 170739213Sgibbs bzero(softc->sc_movemask, sizeof(softc->sc_movemask)); 170839213Sgibbs bzero(softc->sc_exchangemask, sizeof(softc->sc_exchangemask)); 1709115464Sphk moves = cap->move_from; 1710115464Sphk exchanges = cap->exchange_with; 1711115464Sphk for (from = CHET_MT; from <= CHET_MAX; ++from) { 171239213Sgibbs softc->sc_movemask[from] = moves[from]; 171339213Sgibbs softc->sc_exchangemask[from] = exchanges[from]; 171439213Sgibbs } 171539213Sgibbs 1716169562Sscottl free(mode_buffer, M_SCSICH); 171739885Sken 171839213Sgibbs return(error); 171939213Sgibbs} 172039213Sgibbs 1721249658Skenstatic int 1722249658Skenchscsiversion(struct cam_periph *periph) 1723249658Sken{ 1724249658Sken struct scsi_inquiry_data *inq_data; 1725249658Sken struct ccb_getdev *cgd; 1726249658Sken int dev_scsi_version; 1727249658Sken struct cam_sim *sim; 1728249658Sken 1729249658Sken sim = xpt_path_sim(periph->path); 1730249658Sken mtx_assert(sim->mtx, MA_OWNED); 1731249658Sken if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) == NULL) 1732249658Sken return (-1); 1733249658Sken /* 1734249658Sken * Get the device information. 1735249658Sken */ 1736249658Sken xpt_setup_ccb(&cgd->ccb_h, 1737249658Sken periph->path, 1738249658Sken CAM_PRIORITY_NORMAL); 1739249658Sken cgd->ccb_h.func_code = XPT_GDEV_TYPE; 1740249658Sken xpt_action((union ccb *)cgd); 1741249658Sken 1742249658Sken if (cgd->ccb_h.status != CAM_REQ_CMP) { 1743249658Sken xpt_free_ccb((union ccb *)cgd); 1744249658Sken return -1; 1745249658Sken } 1746249658Sken 1747249658Sken inq_data = &cgd->inq_data; 1748249658Sken dev_scsi_version = inq_data->version; 1749249658Sken xpt_free_ccb((union ccb *)cgd); 1750249658Sken 1751249658Sken return dev_scsi_version; 1752249658Sken} 1753249658Sken 175439213Sgibbsvoid 175539213Sgibbsscsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries, 175639213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 175739213Sgibbs u_int8_t tag_action, u_int32_t tea, u_int32_t src, 175839213Sgibbs u_int32_t dst, int invert, u_int8_t sense_len, 175939213Sgibbs u_int32_t timeout) 176039213Sgibbs{ 176139213Sgibbs struct scsi_move_medium *scsi_cmd; 176239213Sgibbs 176339213Sgibbs scsi_cmd = (struct scsi_move_medium *)&csio->cdb_io.cdb_bytes; 176439213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 176539213Sgibbs 176639213Sgibbs scsi_cmd->opcode = MOVE_MEDIUM; 176739213Sgibbs 176839213Sgibbs scsi_ulto2b(tea, scsi_cmd->tea); 176939213Sgibbs scsi_ulto2b(src, scsi_cmd->src); 177039213Sgibbs scsi_ulto2b(dst, scsi_cmd->dst); 177139213Sgibbs 177239213Sgibbs if (invert) 177339213Sgibbs scsi_cmd->invert |= MOVE_MEDIUM_INVERT; 177439213Sgibbs 177539213Sgibbs cam_fill_csio(csio, 177639213Sgibbs retries, 177739213Sgibbs cbfcnp, 177839213Sgibbs /*flags*/ CAM_DIR_NONE, 177939213Sgibbs tag_action, 178039213Sgibbs /*data_ptr*/ NULL, 178139213Sgibbs /*dxfer_len*/ 0, 178239213Sgibbs sense_len, 178339213Sgibbs sizeof(*scsi_cmd), 178439213Sgibbs timeout); 178539213Sgibbs} 178639213Sgibbs 178739213Sgibbsvoid 178839213Sgibbsscsi_exchange_medium(struct ccb_scsiio *csio, u_int32_t retries, 178939213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 179039213Sgibbs u_int8_t tag_action, u_int32_t tea, u_int32_t src, 179139213Sgibbs u_int32_t dst1, u_int32_t dst2, int invert1, 179239213Sgibbs int invert2, u_int8_t sense_len, u_int32_t timeout) 179339213Sgibbs{ 179439213Sgibbs struct scsi_exchange_medium *scsi_cmd; 179539213Sgibbs 179639213Sgibbs scsi_cmd = (struct scsi_exchange_medium *)&csio->cdb_io.cdb_bytes; 179739213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 179839213Sgibbs 179939213Sgibbs scsi_cmd->opcode = EXCHANGE_MEDIUM; 180039213Sgibbs 180139213Sgibbs scsi_ulto2b(tea, scsi_cmd->tea); 180239213Sgibbs scsi_ulto2b(src, scsi_cmd->src); 180339213Sgibbs scsi_ulto2b(dst1, scsi_cmd->fdst); 180439213Sgibbs scsi_ulto2b(dst2, scsi_cmd->sdst); 180539213Sgibbs 180639213Sgibbs if (invert1) 180739213Sgibbs scsi_cmd->invert |= EXCHANGE_MEDIUM_INV1; 180839213Sgibbs 180939213Sgibbs if (invert2) 181039213Sgibbs scsi_cmd->invert |= EXCHANGE_MEDIUM_INV2; 181139213Sgibbs 181239213Sgibbs cam_fill_csio(csio, 181339213Sgibbs retries, 181439213Sgibbs cbfcnp, 181539213Sgibbs /*flags*/ CAM_DIR_NONE, 181639213Sgibbs tag_action, 181739213Sgibbs /*data_ptr*/ NULL, 181839213Sgibbs /*dxfer_len*/ 0, 181939213Sgibbs sense_len, 182039213Sgibbs sizeof(*scsi_cmd), 182139213Sgibbs timeout); 182239213Sgibbs} 182339213Sgibbs 182439213Sgibbsvoid 182539213Sgibbsscsi_position_to_element(struct ccb_scsiio *csio, u_int32_t retries, 182639213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 182739213Sgibbs u_int8_t tag_action, u_int32_t tea, u_int32_t dst, 182839213Sgibbs int invert, u_int8_t sense_len, u_int32_t timeout) 182939213Sgibbs{ 183039213Sgibbs struct scsi_position_to_element *scsi_cmd; 183139213Sgibbs 183239213Sgibbs scsi_cmd = (struct scsi_position_to_element *)&csio->cdb_io.cdb_bytes; 183339213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 183439213Sgibbs 183539213Sgibbs scsi_cmd->opcode = POSITION_TO_ELEMENT; 183639213Sgibbs 183739213Sgibbs scsi_ulto2b(tea, scsi_cmd->tea); 183839213Sgibbs scsi_ulto2b(dst, scsi_cmd->dst); 183939213Sgibbs 184039213Sgibbs if (invert) 184139213Sgibbs scsi_cmd->invert |= POSITION_TO_ELEMENT_INVERT; 184239213Sgibbs 184339213Sgibbs cam_fill_csio(csio, 184439213Sgibbs retries, 184539213Sgibbs cbfcnp, 184639213Sgibbs /*flags*/ CAM_DIR_NONE, 184739213Sgibbs tag_action, 184839213Sgibbs /*data_ptr*/ NULL, 184939213Sgibbs /*dxfer_len*/ 0, 185039213Sgibbs sense_len, 185139213Sgibbs sizeof(*scsi_cmd), 185239213Sgibbs timeout); 185339213Sgibbs} 185439213Sgibbs 185539213Sgibbsvoid 185639213Sgibbsscsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries, 185739213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 185839213Sgibbs u_int8_t tag_action, int voltag, u_int32_t sea, 1859249658Sken int curdata, int dvcid, 186039213Sgibbs u_int32_t count, u_int8_t *data_ptr, 186139213Sgibbs u_int32_t dxfer_len, u_int8_t sense_len, 186239213Sgibbs u_int32_t timeout) 186339213Sgibbs{ 186439213Sgibbs struct scsi_read_element_status *scsi_cmd; 186539213Sgibbs 186639213Sgibbs scsi_cmd = (struct scsi_read_element_status *)&csio->cdb_io.cdb_bytes; 186739213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 186839213Sgibbs 186939213Sgibbs scsi_cmd->opcode = READ_ELEMENT_STATUS; 187039213Sgibbs 187139213Sgibbs scsi_ulto2b(sea, scsi_cmd->sea); 187239213Sgibbs scsi_ulto2b(count, scsi_cmd->count); 187339213Sgibbs scsi_ulto3b(dxfer_len, scsi_cmd->len); 1874249658Sken if (dvcid) 1875249658Sken scsi_cmd->flags |= READ_ELEMENT_STATUS_DVCID; 1876249658Sken if (curdata) 1877249658Sken scsi_cmd->flags |= READ_ELEMENT_STATUS_CURDATA; 187839213Sgibbs 187939213Sgibbs if (voltag) 188039213Sgibbs scsi_cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG; 188139213Sgibbs 188239213Sgibbs cam_fill_csio(csio, 188339213Sgibbs retries, 188439213Sgibbs cbfcnp, 188539213Sgibbs /*flags*/ CAM_DIR_IN, 188639213Sgibbs tag_action, 188739213Sgibbs data_ptr, 188839213Sgibbs dxfer_len, 188939213Sgibbs sense_len, 189039213Sgibbs sizeof(*scsi_cmd), 189139213Sgibbs timeout); 189239213Sgibbs} 189339213Sgibbs 189439213Sgibbsvoid 189539213Sgibbsscsi_initialize_element_status(struct ccb_scsiio *csio, u_int32_t retries, 189639213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 189739213Sgibbs u_int8_t tag_action, u_int8_t sense_len, 189839213Sgibbs u_int32_t timeout) 189939213Sgibbs{ 190039213Sgibbs struct scsi_initialize_element_status *scsi_cmd; 190139213Sgibbs 190239213Sgibbs scsi_cmd = (struct scsi_initialize_element_status *) 190339213Sgibbs &csio->cdb_io.cdb_bytes; 190439213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 190539213Sgibbs 190639213Sgibbs scsi_cmd->opcode = INITIALIZE_ELEMENT_STATUS; 190739213Sgibbs 190839213Sgibbs cam_fill_csio(csio, 190939213Sgibbs retries, 191039213Sgibbs cbfcnp, 191139213Sgibbs /*flags*/ CAM_DIR_NONE, 191239213Sgibbs tag_action, 191339213Sgibbs /* data_ptr */ NULL, 191439213Sgibbs /* dxfer_len */ 0, 191539213Sgibbs sense_len, 191639213Sgibbs sizeof(*scsi_cmd), 191739213Sgibbs timeout); 191839213Sgibbs} 191939213Sgibbs 192039213Sgibbsvoid 192139213Sgibbsscsi_send_volume_tag(struct ccb_scsiio *csio, u_int32_t retries, 192239213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 192339213Sgibbs u_int8_t tag_action, 192439213Sgibbs u_int16_t element_address, 192539213Sgibbs u_int8_t send_action_code, 192639213Sgibbs struct scsi_send_volume_tag_parameters *parameters, 192739213Sgibbs u_int8_t sense_len, u_int32_t timeout) 192839213Sgibbs{ 192939213Sgibbs struct scsi_send_volume_tag *scsi_cmd; 193039213Sgibbs 193139213Sgibbs scsi_cmd = (struct scsi_send_volume_tag *) &csio->cdb_io.cdb_bytes; 193239213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 193339213Sgibbs 193439213Sgibbs scsi_cmd->opcode = SEND_VOLUME_TAG; 193539213Sgibbs scsi_ulto2b(element_address, scsi_cmd->ea); 193639213Sgibbs scsi_cmd->sac = send_action_code; 193739213Sgibbs scsi_ulto2b(sizeof(*parameters), scsi_cmd->pll); 193839213Sgibbs 193939213Sgibbs cam_fill_csio(csio, 194039213Sgibbs retries, 194139213Sgibbs cbfcnp, 194239213Sgibbs /*flags*/ CAM_DIR_OUT, 194339213Sgibbs tag_action, 194439213Sgibbs /* data_ptr */ (u_int8_t *) parameters, 194539213Sgibbs sizeof(*parameters), 194639213Sgibbs sense_len, 194739213Sgibbs sizeof(*scsi_cmd), 194839213Sgibbs timeout); 194939213Sgibbs} 1950