scsi_sg.c revision 268255
1145132Sanholt/*- 2145132Sanholt * Copyright (c) 2007 Scott Long 3145132Sanholt * All rights reserved. 4145132Sanholt * 5145132Sanholt * Redistribution and use in source and binary forms, with or without 6145132Sanholt * modification, are permitted provided that the following conditions 7145132Sanholt * are met: 8145132Sanholt * 1. Redistributions of source code must retain the above copyright 9145132Sanholt * notice, this list of conditions, and the following disclaimer, 10145132Sanholt * without modification, immediately at the beginning of the file. 11145132Sanholt * 2. The name of the author may not be used to endorse or promote products 12145132Sanholt * derived from this software without specific prior written permission. 13145132Sanholt * 14145132Sanholt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15145132Sanholt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16145132Sanholt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17145132Sanholt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 18145132Sanholt * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19145132Sanholt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20145132Sanholt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21145132Sanholt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22145132Sanholt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23145132Sanholt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24145132Sanholt * SUCH DAMAGE. 25145132Sanholt */ 26145132Sanholt 27145132Sanholt/* 28145132Sanholt * scsi_sg peripheral driver. This driver is meant to implement the Linux 29145132Sanholt * SG passthrough interface for SCSI. 30145132Sanholt */ 31152909Sanholt 32152909Sanholt#include <sys/cdefs.h> 33152909Sanholt__FBSDID("$FreeBSD: stable/10/sys/cam/scsi/scsi_sg.c 268255 2014-07-04 15:09:56Z mav $"); 34182080Srnoland 35182080Srnoland#include <sys/param.h> 36182080Srnoland#include <sys/systm.h> 37182080Srnoland#include <sys/kernel.h> 38182080Srnoland#include <sys/types.h> 39182080Srnoland#include <sys/bio.h> 40182080Srnoland#include <sys/malloc.h> 41145132Sanholt#include <sys/fcntl.h> 42145132Sanholt#include <sys/ioccom.h> 43152909Sanholt#include <sys/conf.h> 44145132Sanholt#include <sys/errno.h> 45153013Sanholt#include <sys/devicestat.h> 46153013Sanholt#include <sys/proc.h> 47153013Sanholt#include <sys/uio.h> 48145132Sanholt 49153013Sanholt#include <cam/cam.h> 50145132Sanholt#include <cam/cam_ccb.h> 51182080Srnoland#include <cam/cam_periph.h> 52182080Srnoland#include <cam/cam_queue.h> 53152909Sanholt#include <cam/cam_xpt_periph.h> 54152909Sanholt#include <cam/cam_debug.h> 55145132Sanholt#include <cam/cam_sim.h> 56145132Sanholt 57145132Sanholt#include <cam/scsi/scsi_all.h> 58145132Sanholt#include <cam/scsi/scsi_message.h> 59145132Sanholt#include <cam/scsi/scsi_sg.h> 60145132Sanholt 61145132Sanholt#include <compat/linux/linux_ioctl.h> 62182080Srnoland 63182080Srnolandtypedef enum { 64182080Srnoland SG_FLAG_LOCKED = 0x01, 65182080Srnoland SG_FLAG_INVALID = 0x02 66182080Srnoland} sg_flags; 67182080Srnoland 68182080Srnolandtypedef enum { 69182080Srnoland SG_STATE_NORMAL 70145132Sanholt} sg_state; 71182080Srnoland 72182080Srnolandtypedef enum { 73182080Srnoland SG_RDWR_FREE, 74182080Srnoland SG_RDWR_INPROG, 75145132Sanholt SG_RDWR_DONE 76182080Srnoland} sg_rdwr_state; 77182080Srnoland 78145132Sanholttypedef enum { 79182080Srnoland SG_CCB_RDWR_IO 80182080Srnoland} sg_ccb_types; 81145132Sanholt 82189099Srnoland#define ccb_type ppriv_field0 83182080Srnoland#define ccb_rdwr ppriv_ptr1 84182080Srnoland 85182080Srnolandstruct sg_rdwr { 86182080Srnoland TAILQ_ENTRY(sg_rdwr) rdwr_link; 87182080Srnoland int tag; 88182080Srnoland int state; 89145132Sanholt int buf_len; 90182080Srnoland char *buf; 91182080Srnoland union ccb *ccb; 92145132Sanholt union { 93182080Srnoland struct sg_header hdr; 94182080Srnoland struct sg_io_hdr io_hdr; 95189099Srnoland } hdr; 96182080Srnoland}; 97145132Sanholt 98189099Srnolandstruct sg_softc { 99189099Srnoland sg_state state; 100182080Srnoland sg_flags flags; 101182080Srnoland int open_count; 102182080Srnoland struct devstat *device_stats; 103182080Srnoland TAILQ_HEAD(, sg_rdwr) rdwr_done; 104145132Sanholt struct cdev *dev; 105182080Srnoland int sg_timeout; 106145132Sanholt int sg_user_timeout; 107182080Srnoland uint8_t pd_type; 108182080Srnoland union ccb saved_ccb; 109182080Srnoland}; 110182080Srnoland 111182080Srnolandstatic d_open_t sgopen; 112182080Srnolandstatic d_close_t sgclose; 113182080Srnolandstatic d_ioctl_t sgioctl; 114182080Srnolandstatic d_write_t sgwrite; 115145132Sanholtstatic d_read_t sgread; 116182080Srnoland 117182080Srnolandstatic periph_init_t sginit; 118182080Srnolandstatic periph_ctor_t sgregister; 119182080Srnolandstatic periph_oninv_t sgoninvalidate; 120182080Srnolandstatic periph_dtor_t sgcleanup; 121145132Sanholtstatic void sgasync(void *callback_arg, uint32_t code, 122145132Sanholt struct cam_path *path, void *arg); 123145132Sanholtstatic void sgdone(struct cam_periph *periph, union ccb *done_ccb); 124145132Sanholtstatic int sgsendccb(struct cam_periph *periph, union ccb *ccb); 125145132Sanholtstatic int sgsendrdwr(struct cam_periph *periph, union ccb *ccb); 126145132Sanholtstatic int sgerror(union ccb *ccb, uint32_t cam_flags, 127145132Sanholt uint32_t sense_flags); 128145132Sanholtstatic void sg_scsiio_status(struct ccb_scsiio *csio, 129145132Sanholt u_short *hoststat, u_short *drvstat); 130145132Sanholt 131189053Srnolandstatic int scsi_group_len(u_char cmd); 132145132Sanholt 133145132Sanholtstatic struct periph_driver sgdriver = 134191274Srnoland{ 135189128Srnoland sginit, "sg", 136196466Srnoland TAILQ_HEAD_INITIALIZER(sgdriver.units), /* gen */ 0 137196466Srnoland}; 138196466SrnolandPERIPHDRIVER_DECLARE(sg, sgdriver); 139189128Srnoland 140189052Srnolandstatic struct cdevsw sg_cdevsw = { 141189052Srnoland .d_version = D_VERSION, 142189052Srnoland .d_flags = D_NEEDGIANT | D_TRACKCLOSE, 143189052Srnoland .d_open = sgopen, 144189052Srnoland .d_close = sgclose, 145189052Srnoland .d_ioctl = sgioctl, 146189052Srnoland .d_write = sgwrite, 147189052Srnoland .d_read = sgread, 148189052Srnoland .d_name = "sg", 149189052Srnoland}; 150189052Srnoland 151189052Srnolandstatic int sg_version = 30125; 152189052Srnoland 153189052Srnolandstatic void 154189052Srnolandsginit(void) 155189052Srnoland{ 156189052Srnoland cam_status status; 157189052Srnoland 158189052Srnoland /* 159189052Srnoland * Install a global async callback. This callback will receive aync 160189052Srnoland * callbacks like "new device found". 161189563Srnoland */ 162145132Sanholt status = xpt_register_async(AC_FOUND_DEVICE, sgasync, NULL, NULL); 163152909Sanholt 164145132Sanholt if (status != CAM_REQ_CMP) { 165153579Sjhb printf("sg: Failed to attach master async callbac " 166153033Sanholt "due to status 0x%x!\n", status); 167145132Sanholt } 168189563Srnoland} 169189563Srnoland 170153033Sanholtstatic void 171189563Srnolandsgdevgonecb(void *arg) 172153033Sanholt{ 173153033Sanholt struct cam_periph *periph; 174153579Sjhb struct sg_softc *softc; 175189563Srnoland struct mtx *mtx; 176189563Srnoland int i; 177153579Sjhb 178145132Sanholt periph = (struct cam_periph *)arg; 179189563Srnoland mtx = cam_periph_mtx(periph); 180189563Srnoland mtx_lock(mtx); 181186299Srnoland 182186299Srnoland softc = (struct sg_softc *)periph->softc; 183152909Sanholt KASSERT(softc->open_count >= 0, ("Negative open count %d", 184152909Sanholt softc->open_count)); 185189915Srnoland 186189915Srnoland /* 187189915Srnoland * When we get this callback, we will get no more close calls from 188189915Srnoland * devfs. So if we have any dangling opens, we need to release the 189145132Sanholt * reference held for that particular context. 190145132Sanholt */ 191145132Sanholt for (i = 0; i < softc->open_count; i++) 192145132Sanholt cam_periph_release_locked(periph); 193145132Sanholt 194145132Sanholt softc->open_count = 0; 195189563Srnoland 196145132Sanholt /* 197182080Srnoland * Release the reference held for the device node, it is gone now. 198152909Sanholt */ 199189052Srnoland cam_periph_release_locked(periph); 200152909Sanholt 201189563Srnoland /* 202189563Srnoland * We reference the lock directly here, instead of using 203152909Sanholt * cam_periph_unlock(). The reason is that the final call to 204153579Sjhb * cam_periph_release_locked() above could result in the periph 205189563Srnoland * getting freed. If that is the case, dereferencing the periph 206189563Srnoland * with a cam_periph_unlock() call would cause a page fault. 207152909Sanholt */ 208189563Srnoland mtx_unlock(mtx); 209153579Sjhb} 210189563Srnoland 211153579Sjhb 212152909Sanholtstatic void 213196465Srnolandsgoninvalidate(struct cam_periph *periph) 214152909Sanholt{ 215152909Sanholt struct sg_softc *softc; 216152909Sanholt 217152909Sanholt softc = (struct sg_softc *)periph->softc; 218196465Srnoland 219183573Srnoland /* 220189052Srnoland * Deregister any async callbacks. 221189052Srnoland */ 222189052Srnoland xpt_register_async(0, sgasync, periph, periph->path); 223189052Srnoland 224189052Srnoland softc->flags |= SG_FLAG_INVALID; 225189052Srnoland 226189052Srnoland /* 227189052Srnoland * Tell devfs this device has gone away, and ask for a callback 228189052Srnoland * when it has cleaned up its state. 229189052Srnoland */ 230189052Srnoland destroy_dev_sched_cb(softc->dev, sgdevgonecb, periph); 231189052Srnoland 232191274Srnoland /* 233191274Srnoland * XXX Return all queued I/O with ENXIO. 234191274Srnoland * XXX Handle any transactions queued to the card 235191274Srnoland * with XPT_ABORT_CCB. 236191274Srnoland */ 237191274Srnoland 238191274Srnoland} 239189052Srnoland 240191274Srnolandstatic void 241191274Srnolandsgcleanup(struct cam_periph *periph) 242191274Srnoland{ 243191274Srnoland struct sg_softc *softc; 244191274Srnoland 245191274Srnoland softc = (struct sg_softc *)periph->softc; 246189052Srnoland 247189052Srnoland devstat_remove_entry(softc->device_stats); 248191274Srnoland 249191274Srnoland free(softc, M_DEVBUF); 250191274Srnoland} 251191274Srnoland 252191274Srnolandstatic void 253191274Srnolandsgasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 254191274Srnoland{ 255189052Srnoland struct cam_periph *periph; 256189052Srnoland 257182080Srnoland periph = (struct cam_periph *)callback_arg; 258182080Srnoland 259182080Srnoland switch (code) { 260182080Srnoland case AC_FOUND_DEVICE: 261152909Sanholt { 262189052Srnoland struct ccb_getdev *cgd; 263189052Srnoland cam_status status; 264152909Sanholt 265152909Sanholt cgd = (struct ccb_getdev *)arg; 266152909Sanholt if (cgd == NULL) 267145132Sanholt break; 268145132Sanholt 269189563Srnoland if (cgd->protocol != PROTO_SCSI) 270145132Sanholt break; 271189052Srnoland 272189052Srnoland /* 273189563Srnoland * Allocate a peripheral instance for this device and 274189052Srnoland * start the probe process. 275189052Srnoland */ 276189052Srnoland status = cam_periph_alloc(sgregister, sgoninvalidate, 277194749Srnoland sgcleanup, NULL, "sg", 278194749Srnoland CAM_PERIPH_BIO, path, 279194749Srnoland sgasync, AC_FOUND_DEVICE, cgd); 280189052Srnoland if ((status != CAM_REQ_CMP) && (status != CAM_REQ_INPROG)) { 281194749Srnoland const struct cam_status_entry *entry; 282194749Srnoland 283194749Srnoland entry = cam_fetch_status_entry(status); 284194749Srnoland printf("sgasync: Unable to attach new device " 285189052Srnoland "due to status %#x: %s\n", status, entry ? 286189052Srnoland entry->status_text : "Unknown"); 287145132Sanholt } 288145132Sanholt break; 289145132Sanholt } 290145132Sanholt default: 291145132Sanholt cam_periph_async(periph, code, path, arg); 292145132Sanholt break; 293145132Sanholt } 294145132Sanholt} 295145132Sanholt 296152909Sanholtstatic cam_status 297152909Sanholtsgregister(struct cam_periph *periph, void *arg) 298152909Sanholt{ 299145132Sanholt struct sg_softc *softc; 300145132Sanholt struct ccb_getdev *cgd; 301145132Sanholt struct ccb_pathinq cpi; 302145132Sanholt int no_tags; 303189915Srnoland 304189915Srnoland cgd = (struct ccb_getdev *)arg; 305152909Sanholt if (cgd == NULL) { 306145132Sanholt printf("sgregister: no getdev CCB, can't register device\n"); 307145132Sanholt return (CAM_REQ_CMP_ERR); 308145132Sanholt } 309145132Sanholt 310145132Sanholt softc = malloc(sizeof(*softc), M_DEVBUF, M_ZERO | M_NOWAIT); 311182080Srnoland if (softc == NULL) { 312145132Sanholt printf("sgregister: Unable to allocate softc\n"); 313152909Sanholt return (CAM_REQ_CMP_ERR); 314145132Sanholt } 315145132Sanholt 316145132Sanholt softc->state = SG_STATE_NORMAL; 317145132Sanholt softc->pd_type = SID_TYPE(&cgd->inq_data); 318152909Sanholt softc->sg_timeout = SG_DEFAULT_TIMEOUT / SG_DEFAULT_HZ * hz; 319152909Sanholt softc->sg_user_timeout = SG_DEFAULT_TIMEOUT; 320183573Srnoland TAILQ_INIT(&softc->rdwr_done); 321152909Sanholt periph->softc = softc; 322152909Sanholt 323145132Sanholt bzero(&cpi, sizeof(cpi)); 324183573Srnoland xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 325183573Srnoland cpi.ccb_h.func_code = XPT_PATH_INQ; 326152909Sanholt xpt_action((union ccb *)&cpi); 327145132Sanholt 328145132Sanholt /* 329183573Srnoland * We pass in 0 for all blocksize, since we don't know what the 330145132Sanholt * blocksize of the device is, if it even has a blocksize. 331145132Sanholt */ 332145132Sanholt cam_periph_unlock(periph); 333145132Sanholt no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0; 334145132Sanholt softc->device_stats = devstat_new_entry("sg", 335183573Srnoland periph->unit_number, 0, 336145132Sanholt DEVSTAT_NO_BLOCKSIZE 337145132Sanholt | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0), 338145132Sanholt softc->pd_type | 339145132Sanholt XPORT_DEVSTAT_TYPE(cpi.transport) | 340145132Sanholt DEVSTAT_TYPE_PASS, 341145132Sanholt DEVSTAT_PRIORITY_PASS); 342145132Sanholt 343145132Sanholt /* 344145132Sanholt * Acquire a reference to the periph before we create the devfs 345145132Sanholt * instance for it. We'll release this reference once the devfs 346145132Sanholt * instance has been freed. 347145132Sanholt */ 348183573Srnoland if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 349145132Sanholt xpt_print(periph->path, "%s: lost periph during " 350145132Sanholt "registration!\n", __func__); 351145132Sanholt cam_periph_lock(periph); 352145132Sanholt return (CAM_REQ_CMP_ERR); 353182080Srnoland } 354145132Sanholt 355145132Sanholt /* Register the device */ 356145132Sanholt softc->dev = make_dev(&sg_cdevsw, periph->unit_number, 357145132Sanholt UID_ROOT, GID_OPERATOR, 0600, "%s%d", 358145132Sanholt periph->periph_name, periph->unit_number); 359145132Sanholt if (periph->unit_number < 26) { 360145132Sanholt (void)make_dev_alias(softc->dev, "sg%c", 361183573Srnoland periph->unit_number + 'a'); 362145132Sanholt } else { 363183573Srnoland (void)make_dev_alias(softc->dev, "sg%c%c", 364183573Srnoland ((periph->unit_number / 26) - 1) + 'a', 365145132Sanholt (periph->unit_number % 26) + 'a'); 366145132Sanholt } 367145132Sanholt cam_periph_lock(periph); 368145132Sanholt softc->dev->si_drv1 = periph; 369183573Srnoland 370183833Srnoland /* 371145132Sanholt * Add as async callback so that we get 372145132Sanholt * notified if this device goes away. 373145132Sanholt */ 374183573Srnoland xpt_register_async(AC_LOST_DEVICE, sgasync, periph, periph->path); 375183573Srnoland 376183573Srnoland if (bootverbose) 377145132Sanholt xpt_announce_periph(periph, NULL); 378183833Srnoland 379145132Sanholt return (CAM_REQ_CMP); 380145132Sanholt} 381145132Sanholt 382145132Sanholtstatic void 383182467Srnolandsgdone(struct cam_periph *periph, union ccb *done_ccb) 384182080Srnoland{ 385182467Srnoland struct sg_softc *softc; 386182080Srnoland struct ccb_scsiio *csio; 387183573Srnoland 388183573Srnoland softc = (struct sg_softc *)periph->softc; 389145132Sanholt csio = &done_ccb->csio; 390145132Sanholt switch (csio->ccb_h.ccb_type) { 391145132Sanholt case SG_CCB_RDWR_IO: 392152909Sanholt { 393152909Sanholt struct sg_rdwr *rdwr; 394152909Sanholt int state; 395183573Srnoland 396145132Sanholt devstat_end_transaction(softc->device_stats, 397183573Srnoland csio->dxfer_len, 398145132Sanholt csio->tag_action & 0xf, 399145132Sanholt ((csio->ccb_h.flags & CAM_DIR_MASK) == 400183833Srnoland CAM_DIR_NONE) ? DEVSTAT_NO_DATA : 401145132Sanholt (csio->ccb_h.flags & CAM_DIR_OUT) ? 402145132Sanholt DEVSTAT_WRITE : DEVSTAT_READ, 403145132Sanholt NULL, NULL); 404145132Sanholt 405152909Sanholt rdwr = done_ccb->ccb_h.ccb_rdwr; 406145132Sanholt state = rdwr->state; 407145132Sanholt rdwr->state = SG_RDWR_DONE; 408145132Sanholt wakeup(rdwr); 409145132Sanholt break; 410145132Sanholt } 411145132Sanholt default: 412145132Sanholt panic("unknown sg CCB type"); 413145132Sanholt } 414145132Sanholt} 415145132Sanholt 416182080Srnolandstatic int 417182080Srnolandsgopen(struct cdev *dev, int flags, int fmt, struct thread *td) 418145132Sanholt{ 419145132Sanholt struct cam_periph *periph; 420145132Sanholt struct sg_softc *softc; 421183573Srnoland int error = 0; 422145132Sanholt 423182080Srnoland periph = (struct cam_periph *)dev->si_drv1; 424145132Sanholt if (periph == NULL) 425145132Sanholt return (ENXIO); 426145132Sanholt 427145132Sanholt if (cam_periph_acquire(periph) != CAM_REQ_CMP) 428145132Sanholt return (ENXIO); 429145132Sanholt 430182080Srnoland /* 431145132Sanholt * Don't allow access when we're running at a high securelevel. 432182080Srnoland */ 433152909Sanholt error = securelevel_gt(td->td_ucred, 1); 434183573Srnoland if (error) { 435145132Sanholt cam_periph_release(periph); 436145132Sanholt return (error); 437207066Srnoland } 438207066Srnoland 439207066Srnoland cam_periph_lock(periph); 440207066Srnoland 441207066Srnoland softc = (struct sg_softc *)periph->softc; 442145132Sanholt if (softc->flags & SG_FLAG_INVALID) { 443207066Srnoland cam_periph_release_locked(periph); 444145132Sanholt cam_periph_unlock(periph); 445145132Sanholt return (ENXIO); 446145132Sanholt } 447145132Sanholt 448182080Srnoland softc->open_count++; 449182080Srnoland 450182080Srnoland cam_periph_unlock(periph); 451182080Srnoland 452182080Srnoland return (error); 453182080Srnoland} 454182080Srnoland 455182080Srnolandstatic int 456183573Srnolandsgclose(struct cdev *dev, int flag, int fmt, struct thread *td) 457183573Srnoland{ 458182080Srnoland struct cam_periph *periph; 459183573Srnoland struct sg_softc *softc; 460152909Sanholt struct mtx *mtx; 461182080Srnoland 462183573Srnoland periph = (struct cam_periph *)dev->si_drv1; 463182080Srnoland if (periph == NULL) 464182080Srnoland return (ENXIO); 465182080Srnoland mtx = cam_periph_mtx(periph); 466152909Sanholt mtx_lock(mtx); 467145132Sanholt 468145132Sanholt softc = periph->softc; 469145132Sanholt softc->open_count--; 470145132Sanholt 471183573Srnoland cam_periph_release_locked(periph); 472145132Sanholt 473145132Sanholt /* 474183573Srnoland * We reference the lock directly here, instead of using 475183573Srnoland * cam_periph_unlock(). The reason is that the call to 476145132Sanholt * cam_periph_release_locked() above could result in the periph 477145132Sanholt * getting freed. If that is the case, dereferencing the periph 478182080Srnoland * with a cam_periph_unlock() call would cause a page fault. 479145132Sanholt * 480145132Sanholt * cam_periph_release() avoids this problem using the same method, 481215367Snwhitehorn * but we're manually acquiring and dropping the lock here to 482145132Sanholt * protect the open count and avoid another lock acquisition and 483145132Sanholt * release. 484145132Sanholt */ 485145132Sanholt mtx_unlock(mtx); 486145132Sanholt 487145132Sanholt return (0); 488145132Sanholt} 489145132Sanholt 490145132Sanholtstatic int 491145132Sanholtsgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 492145132Sanholt{ 493182080Srnoland union ccb *ccb; 494182080Srnoland struct ccb_scsiio *csio; 495182080Srnoland struct cam_periph *periph; 496182080Srnoland struct sg_softc *softc; 497182080Srnoland struct sg_io_hdr *req; 498182080Srnoland int dir, error; 499182080Srnoland 500152909Sanholt periph = (struct cam_periph *)dev->si_drv1; 501183573Srnoland if (periph == NULL) 502183573Srnoland return (ENXIO); 503183573Srnoland 504183573Srnoland cam_periph_lock(periph); 505183573Srnoland 506145132Sanholt softc = (struct sg_softc *)periph->softc; 507145132Sanholt error = 0; 508145132Sanholt 509145132Sanholt switch (cmd) { 510145132Sanholt case SG_GET_VERSION_NUM: 511145132Sanholt { 512152909Sanholt int *version = (int *)arg; 513145132Sanholt 514145132Sanholt *version = sg_version; 515183573Srnoland break; 516182080Srnoland } 517182080Srnoland case SG_SET_TIMEOUT: 518182080Srnoland { 519145132Sanholt u_int user_timeout = *(u_int *)arg; 520183573Srnoland 521145132Sanholt softc->sg_user_timeout = user_timeout; 522145132Sanholt softc->sg_timeout = user_timeout / SG_DEFAULT_HZ * hz; 523145132Sanholt break; 524182080Srnoland } 525145132Sanholt case SG_GET_TIMEOUT: 526152909Sanholt /* 527145132Sanholt * The value is returned directly to the syscall. 528183573Srnoland */ 529145132Sanholt td->td_retval[0] = softc->sg_user_timeout; 530145132Sanholt error = 0; 531145132Sanholt break; 532145132Sanholt case SG_IO: 533145132Sanholt req = (struct sg_io_hdr *)arg; 534145132Sanholt 535145132Sanholt if (req->cmd_len > IOCDBLEN) { 536145132Sanholt error = EINVAL; 537145132Sanholt break; 538152909Sanholt } 539145132Sanholt 540145132Sanholt if (req->iovec_count != 0) { 541145132Sanholt error = EOPNOTSUPP; 542145132Sanholt break; 543189130Srnoland } 544189130Srnoland 545145132Sanholt ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 546152909Sanholt csio = &ccb->csio; 547145132Sanholt 548145132Sanholt error = copyin(req->cmdp, &csio->cdb_io.cdb_bytes, 549152909Sanholt req->cmd_len); 550152909Sanholt if (error) { 551152909Sanholt xpt_release_ccb(ccb); 552152909Sanholt break; 553152909Sanholt } 554152909Sanholt 555152909Sanholt switch(req->dxfer_direction) { 556152909Sanholt case SG_DXFER_TO_DEV: 557152909Sanholt dir = CAM_DIR_OUT; 558152909Sanholt break; 559152909Sanholt case SG_DXFER_FROM_DEV: 560145132Sanholt dir = CAM_DIR_IN; 561145132Sanholt break; 562183573Srnoland case SG_DXFER_TO_FROM_DEV: 563183833Srnoland dir = CAM_DIR_IN | CAM_DIR_OUT; 564145132Sanholt break; 565145132Sanholt case SG_DXFER_NONE: 566145132Sanholt default: 567183573Srnoland dir = CAM_DIR_NONE; 568182468Srnoland break; 569183573Srnoland } 570182468Srnoland 571182468Srnoland cam_fill_csio(csio, 572145132Sanholt /*retries*/1, 573182080Srnoland sgdone, 574207066Srnoland dir|CAM_DEV_QFRZDIS, 575182080Srnoland MSG_SIMPLE_Q_TAG, 576145132Sanholt req->dxferp, 577182080Srnoland req->dxfer_len, 578182080Srnoland req->mx_sb_len, 579182080Srnoland req->cmd_len, 580182080Srnoland req->timeout); 581182080Srnoland 582182080Srnoland error = sgsendccb(periph, ccb); 583182080Srnoland if (error) { 584145132Sanholt req->host_status = DID_ERROR; 585145132Sanholt req->driver_status = DRIVER_INVALID; 586145132Sanholt xpt_release_ccb(ccb); 587182080Srnoland break; 588145132Sanholt } 589183573Srnoland 590145132Sanholt req->status = csio->scsi_status; 591145132Sanholt req->masked_status = (csio->scsi_status >> 1) & 0x7f; 592145132Sanholt sg_scsiio_status(csio, &req->host_status, &req->driver_status); 593145132Sanholt req->resid = csio->resid; 594145132Sanholt req->duration = csio->ccb_h.timeout; 595145132Sanholt req->info = 0; 596145132Sanholt 597145132Sanholt if ((csio->ccb_h.status & CAM_AUTOSNS_VALID) 598182080Srnoland && (req->sbp != NULL)) { 599145132Sanholt req->sb_len_wr = req->mx_sb_len - csio->sense_resid; 600145132Sanholt error = copyout(&csio->sense_data, req->sbp, 601183573Srnoland req->sb_len_wr); 602183573Srnoland } 603183573Srnoland 604145132Sanholt xpt_release_ccb(ccb); 605183573Srnoland break; 606183573Srnoland 607183573Srnoland case SG_GET_RESERVED_SIZE: 608145132Sanholt { 609145132Sanholt int *size = (int *)arg; 610145132Sanholt *size = DFLTPHYS; 611145132Sanholt break; 612145132Sanholt } 613145132Sanholt 614182080Srnoland case SG_GET_SCSI_ID: 615145132Sanholt { 616145132Sanholt struct sg_scsi_id *id = (struct sg_scsi_id *)arg; 617196465Srnoland 618145132Sanholt id->host_no = cam_sim_path(xpt_path_sim(periph->path)); 619183573Srnoland id->channel = xpt_path_path_id(periph->path); 620145132Sanholt id->scsi_id = xpt_path_target_id(periph->path); 621145132Sanholt id->lun = xpt_path_lun_id(periph->path); 622145132Sanholt id->scsi_type = softc->pd_type; 623183573Srnoland id->h_cmd_per_lun = 1; 624183573Srnoland id->d_queue_depth = 1; 625145132Sanholt id->unused[0] = 0; 626145132Sanholt id->unused[1] = 0; 627183573Srnoland break; 628152909Sanholt } 629145132Sanholt 630145132Sanholt case SG_GET_SG_TABLESIZE: 631145132Sanholt { 632145132Sanholt int *size = (int *)arg; 633145132Sanholt *size = 0; 634145132Sanholt break; 635183573Srnoland } 636145132Sanholt 637183573Srnoland case SG_EMULATED_HOST: 638183573Srnoland case SG_SET_TRANSFORM: 639145132Sanholt case SG_GET_TRANSFORM: 640182080Srnoland case SG_GET_NUM_WAITING: 641183573Srnoland case SG_SCSI_RESET: 642145132Sanholt case SG_GET_REQUEST_TABLE: 643145132Sanholt case SG_SET_KEEP_ORPHAN: 644145132Sanholt case SG_GET_KEEP_ORPHAN: 645183573Srnoland case SG_GET_ACCESS_COUNT: 646183573Srnoland case SG_SET_FORCE_LOW_DMA: 647145132Sanholt case SG_GET_LOW_DMA: 648145132Sanholt case SG_SET_FORCE_PACK_ID: 649145132Sanholt case SG_GET_PACK_ID: 650145132Sanholt case SG_SET_RESERVED_SIZE: 651145132Sanholt case SG_GET_COMMAND_Q: 652183573Srnoland case SG_SET_COMMAND_Q: 653183573Srnoland case SG_SET_DEBUG: 654145132Sanholt case SG_NEXT_CMD_LEN: 655145132Sanholt default: 656182080Srnoland#ifdef CAMDEBUG 657145132Sanholt printf("sgioctl: rejecting cmd 0x%lx\n", cmd); 658145132Sanholt#endif 659145132Sanholt error = ENODEV; 660183573Srnoland break; 661183573Srnoland } 662145132Sanholt 663183573Srnoland cam_periph_unlock(periph); 664145132Sanholt return (error); 665145132Sanholt} 666145132Sanholt 667145132Sanholtstatic int 668145132Sanholtsgwrite(struct cdev *dev, struct uio *uio, int ioflag) 669145132Sanholt{ 670183573Srnoland union ccb *ccb; 671152909Sanholt struct cam_periph *periph; 672145132Sanholt struct ccb_scsiio *csio; 673145132Sanholt struct sg_softc *sc; 674183573Srnoland struct sg_header *hdr; 675145132Sanholt struct sg_rdwr *rdwr; 676182080Srnoland u_char cdb_cmd; 677145132Sanholt char *buf; 678145132Sanholt int error = 0, cdb_len, buf_len, dir; 679183573Srnoland 680182080Srnoland periph = dev->si_drv1; 681145132Sanholt rdwr = malloc(sizeof(*rdwr), M_DEVBUF, M_WAITOK | M_ZERO); 682183573Srnoland hdr = &rdwr->hdr.hdr; 683145132Sanholt 684145132Sanholt /* Copy in the header block and sanity check it */ 685183573Srnoland if (uio->uio_resid < sizeof(*hdr)) { 686182080Srnoland error = EINVAL; 687189869Srnoland goto out_hdr; 688145132Sanholt } 689145132Sanholt error = uiomove(hdr, sizeof(*hdr), uio); 690145132Sanholt if (error) 691145132Sanholt goto out_hdr; 692183573Srnoland 693183573Srnoland /* XXX: We don't support SG 3.x read/write API. */ 694145132Sanholt if (hdr->reply_len < 0) { 695145132Sanholt error = ENODEV; 696145132Sanholt goto out_hdr; 697183573Srnoland } 698183573Srnoland 699182080Srnoland ccb = xpt_alloc_ccb(); 700145132Sanholt if (ccb == NULL) { 701145132Sanholt error = ENOMEM; 702145132Sanholt goto out_hdr; 703183573Srnoland } 704183573Srnoland csio = &ccb->csio; 705182080Srnoland 706183833Srnoland /* 707145132Sanholt * Copy in the CDB block. The designers of the interface didn't 708145132Sanholt * bother to provide a size for this in the header, so we have to 709145132Sanholt * figure it out ourselves. 710145132Sanholt */ 711145132Sanholt if (uio->uio_resid < 1) 712183573Srnoland goto out_ccb; 713145132Sanholt error = uiomove(&cdb_cmd, 1, uio); 714145132Sanholt if (error) 715152909Sanholt goto out_ccb; 716145132Sanholt if (hdr->twelve_byte) 717145132Sanholt cdb_len = 12; 718145132Sanholt else 719145132Sanholt cdb_len = scsi_group_len(cdb_cmd); 720145132Sanholt /* 721145132Sanholt * We've already read the first byte of the CDB and advanced the uio 722145132Sanholt * pointer. Just read the rest. 723145132Sanholt */ 724145132Sanholt csio->cdb_io.cdb_bytes[0] = cdb_cmd; 725145132Sanholt error = uiomove(&csio->cdb_io.cdb_bytes[1], cdb_len - 1, uio); 726182080Srnoland if (error) 727145132Sanholt goto out_ccb; 728145132Sanholt 729182080Srnoland /* 730145132Sanholt * Now set up the data block. Again, the designers didn't bother 731145132Sanholt * to make this reliable. 732183573Srnoland */ 733145132Sanholt buf_len = uio->uio_resid; 734183573Srnoland if (buf_len != 0) { 735183573Srnoland buf = malloc(buf_len, M_DEVBUF, M_WAITOK | M_ZERO); 736145132Sanholt error = uiomove(buf, buf_len, uio); 737145132Sanholt if (error) 738145132Sanholt goto out_buf; 739145132Sanholt dir = CAM_DIR_OUT; 740183573Srnoland } else if (hdr->reply_len != 0) { 741182080Srnoland buf = malloc(hdr->reply_len, M_DEVBUF, M_WAITOK | M_ZERO); 742145132Sanholt buf_len = hdr->reply_len; 743183573Srnoland dir = CAM_DIR_IN; 744182080Srnoland } else { 745183573Srnoland buf = NULL; 746145132Sanholt buf_len = 0; 747145132Sanholt dir = CAM_DIR_NONE; 748145132Sanholt } 749145132Sanholt 750145132Sanholt cam_periph_lock(periph); 751145132Sanholt sc = periph->softc; 752145132Sanholt xpt_setup_ccb(&ccb->ccb_h, periph->path, CAM_PRIORITY_NORMAL); 753145132Sanholt cam_fill_csio(csio, 754145132Sanholt /*retries*/1, 755145132Sanholt sgdone, 756145132Sanholt dir|CAM_DEV_QFRZDIS, 757145132Sanholt MSG_SIMPLE_Q_TAG, 758145132Sanholt buf, 759145132Sanholt buf_len, 760145132Sanholt SG_MAX_SENSE, 761145132Sanholt cdb_len, 762145132Sanholt sc->sg_timeout); 763145132Sanholt 764145132Sanholt /* 765145132Sanholt * Send off the command and hope that it works. This path does not 766145132Sanholt * go through sgstart because the I/O is supposed to be asynchronous. 767145132Sanholt */ 768145132Sanholt rdwr->buf = buf; 769145132Sanholt rdwr->buf_len = buf_len; 770183573Srnoland rdwr->tag = hdr->pack_id; 771145132Sanholt rdwr->ccb = ccb; 772183573Srnoland rdwr->state = SG_RDWR_INPROG; 773145132Sanholt ccb->ccb_h.ccb_rdwr = rdwr; 774145132Sanholt ccb->ccb_h.ccb_type = SG_CCB_RDWR_IO; 775183573Srnoland TAILQ_INSERT_TAIL(&sc->rdwr_done, rdwr, rdwr_link); 776145132Sanholt error = sgsendrdwr(periph, ccb); 777145132Sanholt cam_periph_unlock(periph); 778145132Sanholt return (error); 779145132Sanholt 780145132Sanholtout_buf: 781183573Srnoland free(buf, M_DEVBUF); 782145132Sanholtout_ccb: 783145132Sanholt xpt_free_ccb(ccb); 784182080Srnolandout_hdr: 785152909Sanholt free(rdwr, M_DEVBUF); 786182080Srnoland return (error); 787182080Srnoland} 788145132Sanholt 789145132Sanholtstatic int 790182080Srnolandsgread(struct cdev *dev, struct uio *uio, int ioflag) 791145132Sanholt{ 792182080Srnoland struct ccb_scsiio *csio; 793182080Srnoland struct cam_periph *periph; 794145132Sanholt struct sg_softc *sc; 795182080Srnoland struct sg_header *hdr; 796182080Srnoland struct sg_rdwr *rdwr; 797182080Srnoland u_short hstat, dstat; 798145132Sanholt int error, pack_len, reply_len, pack_id; 799145132Sanholt 800145132Sanholt periph = dev->si_drv1; 801145132Sanholt 802182080Srnoland /* XXX The pack len field needs to be updated and written out instead 803145132Sanholt * of discarded. Not sure how to do that. 804145132Sanholt */ 805182080Srnoland uio->uio_rw = UIO_WRITE; 806182080Srnoland if ((error = uiomove(&pack_len, 4, uio)) != 0) 807182080Srnoland return (error); 808145132Sanholt if ((error = uiomove(&reply_len, 4, uio)) != 0) 809182080Srnoland return (error); 810182080Srnoland if ((error = uiomove(&pack_id, 4, uio)) != 0) 811182080Srnoland return (error); 812182080Srnoland uio->uio_rw = UIO_READ; 813182080Srnoland 814182080Srnoland cam_periph_lock(periph); 815182080Srnoland sc = periph->softc; 816182080Srnolandsearch: 817182080Srnoland TAILQ_FOREACH(rdwr, &sc->rdwr_done, rdwr_link) { 818145132Sanholt if (rdwr->tag == pack_id) 819145132Sanholt break; 820145132Sanholt } 821145132Sanholt if ((rdwr == NULL) || (rdwr->state != SG_RDWR_DONE)) { 822145132Sanholt if (cam_periph_sleep(periph, rdwr, PCATCH, "sgread", 0) == ERESTART) 823145132Sanholt return (EAGAIN); 824145132Sanholt goto search; 825145132Sanholt } 826145132Sanholt TAILQ_REMOVE(&sc->rdwr_done, rdwr, rdwr_link); 827145132Sanholt cam_periph_unlock(periph); 828145132Sanholt 829145132Sanholt hdr = &rdwr->hdr.hdr; 830145132Sanholt csio = &rdwr->ccb->csio; 831145132Sanholt sg_scsiio_status(csio, &hstat, &dstat); 832145132Sanholt hdr->host_status = hstat; 833145132Sanholt hdr->driver_status = dstat; 834145132Sanholt hdr->target_status = csio->scsi_status >> 1; 835145132Sanholt 836145132Sanholt switch (hstat) { 837145132Sanholt case DID_OK: 838145132Sanholt case DID_PASSTHROUGH: 839145132Sanholt case DID_SOFT_ERROR: 840145132Sanholt hdr->result = 0; 841145132Sanholt break; 842145132Sanholt case DID_NO_CONNECT: 843145132Sanholt case DID_BUS_BUSY: 844145132Sanholt case DID_TIME_OUT: 845145132Sanholt hdr->result = EBUSY; 846145132Sanholt break; 847145132Sanholt case DID_BAD_TARGET: 848145132Sanholt case DID_ABORT: 849145132Sanholt case DID_PARITY: 850145132Sanholt case DID_RESET: 851145132Sanholt case DID_BAD_INTR: 852145132Sanholt case DID_ERROR: 853145132Sanholt default: 854145132Sanholt hdr->result = EIO; 855145132Sanholt break; 856145132Sanholt } 857 858 if (dstat == DRIVER_SENSE) { 859 bcopy(&csio->sense_data, hdr->sense_buffer, 860 min(csio->sense_len, SG_MAX_SENSE)); 861#ifdef CAMDEBUG 862 scsi_sense_print(csio); 863#endif 864 } 865 866 error = uiomove(&hdr->result, sizeof(*hdr) - 867 offsetof(struct sg_header, result), uio); 868 if ((error == 0) && (hdr->result == 0)) 869 error = uiomove(rdwr->buf, rdwr->buf_len, uio); 870 871 cam_periph_lock(periph); 872 xpt_free_ccb(rdwr->ccb); 873 cam_periph_unlock(periph); 874 free(rdwr->buf, M_DEVBUF); 875 free(rdwr, M_DEVBUF); 876 return (error); 877} 878 879static int 880sgsendccb(struct cam_periph *periph, union ccb *ccb) 881{ 882 struct sg_softc *softc; 883 struct cam_periph_map_info mapinfo; 884 int error; 885 886 softc = periph->softc; 887 bzero(&mapinfo, sizeof(mapinfo)); 888 889 /* 890 * cam_periph_mapmem calls into proc and vm functions that can 891 * sleep as well as trigger I/O, so we can't hold the lock. 892 * Dropping it here is reasonably safe. 893 * The only CCB opcode that is possible here is XPT_SCSI_IO, no 894 * need for additional checks. 895 */ 896 cam_periph_unlock(periph); 897 error = cam_periph_mapmem(ccb, &mapinfo); 898 cam_periph_lock(periph); 899 if (error) 900 return (error); 901 902 error = cam_periph_runccb(ccb, 903 sgerror, 904 CAM_RETRY_SELTO, 905 SF_RETRY_UA, 906 softc->device_stats); 907 908 cam_periph_unmapmem(ccb, &mapinfo); 909 910 return (error); 911} 912 913static int 914sgsendrdwr(struct cam_periph *periph, union ccb *ccb) 915{ 916 struct sg_softc *softc; 917 918 softc = periph->softc; 919 devstat_start_transaction(softc->device_stats, NULL); 920 xpt_action(ccb); 921 return (0); 922} 923 924static int 925sgerror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags) 926{ 927 struct cam_periph *periph; 928 struct sg_softc *softc; 929 930 periph = xpt_path_periph(ccb->ccb_h.path); 931 softc = (struct sg_softc *)periph->softc; 932 933 return (cam_periph_error(ccb, cam_flags, sense_flags, 934 &softc->saved_ccb)); 935} 936 937static void 938sg_scsiio_status(struct ccb_scsiio *csio, u_short *hoststat, u_short *drvstat) 939{ 940 int status; 941 942 status = csio->ccb_h.status; 943 944 switch (status & CAM_STATUS_MASK) { 945 case CAM_REQ_CMP: 946 *hoststat = DID_OK; 947 *drvstat = 0; 948 break; 949 case CAM_REQ_CMP_ERR: 950 *hoststat = DID_ERROR; 951 *drvstat = 0; 952 break; 953 case CAM_REQ_ABORTED: 954 *hoststat = DID_ABORT; 955 *drvstat = 0; 956 break; 957 case CAM_REQ_INVALID: 958 *hoststat = DID_ERROR; 959 *drvstat = DRIVER_INVALID; 960 break; 961 case CAM_DEV_NOT_THERE: 962 *hoststat = DID_BAD_TARGET; 963 *drvstat = 0; 964 break; 965 case CAM_SEL_TIMEOUT: 966 *hoststat = DID_NO_CONNECT; 967 *drvstat = 0; 968 break; 969 case CAM_CMD_TIMEOUT: 970 *hoststat = DID_TIME_OUT; 971 *drvstat = 0; 972 break; 973 case CAM_SCSI_STATUS_ERROR: 974 *hoststat = DID_ERROR; 975 *drvstat = 0; 976 break; 977 case CAM_SCSI_BUS_RESET: 978 *hoststat = DID_RESET; 979 *drvstat = 0; 980 break; 981 case CAM_UNCOR_PARITY: 982 *hoststat = DID_PARITY; 983 *drvstat = 0; 984 break; 985 case CAM_SCSI_BUSY: 986 *hoststat = DID_BUS_BUSY; 987 *drvstat = 0; 988 break; 989 default: 990 *hoststat = DID_ERROR; 991 *drvstat = DRIVER_ERROR; 992 } 993 994 if (status & CAM_AUTOSNS_VALID) 995 *drvstat = DRIVER_SENSE; 996} 997 998static int 999scsi_group_len(u_char cmd) 1000{ 1001 int len[] = {6, 10, 10, 12, 12, 12, 10, 10}; 1002 int group; 1003 1004 group = (cmd >> 5) & 0x7; 1005 return (len[group]); 1006} 1007 1008