scsi_pass.c revision 46581
1195534Sscottl/* 2195534Sscottl * Copyright (c) 1997, 1998 Justin T. Gibbs. 3195534Sscottl * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 4195534Sscottl * All rights reserved. 5195534Sscottl * 6195534Sscottl * Redistribution and use in source and binary forms, with or without 7195534Sscottl * modification, are permitted provided that the following conditions 8195534Sscottl * are met: 9195534Sscottl * 1. Redistributions of source code must retain the above copyright 10195534Sscottl * notice, this list of conditions, and the following disclaimer, 11195534Sscottl * without modification, immediately at the beginning of the file. 12195534Sscottl * 2. The name of the author may not be used to endorse or promote products 13195534Sscottl * derived from this software without specific prior written permission. 14195534Sscottl * 15195534Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16195534Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17195534Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18195534Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19195534Sscottl * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20195534Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21195534Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22195534Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23195534Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24195534Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25195534Sscottl * SUCH DAMAGE. 26195534Sscottl * 27195534Sscottl * $Id: scsi_pass.c,v 1.6 1999/02/10 00:03:15 ken Exp $ 28195534Sscottl */ 29195534Sscottl 30195534Sscottl#include <sys/param.h> 31195534Sscottl#include <sys/queue.h> 32195534Sscottl#include <sys/systm.h> 33195534Sscottl#include <sys/kernel.h> 34195534Sscottl#include <sys/types.h> 35195534Sscottl#include <sys/buf.h> 36195534Sscottl#include <sys/dkbad.h> 37195534Sscottl#include <sys/disklabel.h> 38195534Sscottl#include <sys/diskslice.h> 39195534Sscottl#include <sys/malloc.h> 40195534Sscottl#include <sys/fcntl.h> 41195534Sscottl#include <sys/stat.h> 42195534Sscottl#include <sys/conf.h> 43195534Sscottl#include <sys/buf.h> 44195534Sscottl#include <sys/proc.h> 45195534Sscottl#include <sys/errno.h> 46195534Sscottl#include <sys/devicestat.h> 47195534Sscottl 48195534Sscottl#include <cam/cam.h> 49195534Sscottl#include <cam/cam_ccb.h> 50195534Sscottl#include <cam/cam_extend.h> 51195534Sscottl#include <cam/cam_periph.h> 52195534Sscottl#include <cam/cam_xpt_periph.h> 53195534Sscottl#include <cam/cam_debug.h> 54195534Sscottl 55195534Sscottl#include <cam/scsi/scsi_all.h> 56195534Sscottl#include <cam/scsi/scsi_message.h> 57195534Sscottl#include <cam/scsi/scsi_da.h> 58195534Sscottl#include <cam/scsi/scsi_pass.h> 59195534Sscottl 60195534Sscottltypedef enum { 61195534Sscottl PASS_FLAG_OPEN = 0x01, 62195534Sscottl PASS_FLAG_LOCKED = 0x02, 63195534Sscottl PASS_FLAG_INVALID = 0x04 64195534Sscottl} pass_flags; 65195534Sscottl 66195534Sscottltypedef enum { 67195534Sscottl PASS_STATE_NORMAL 68195534Sscottl} pass_state; 69195534Sscottl 70195534Sscottltypedef enum { 71198849Smav PASS_CCB_BUFFER_IO, 72198849Smav PASS_CCB_WAITING 73198849Smav} pass_ccb_types; 74198849Smav 75198849Smav#define ccb_type ppriv_field0 76198849Smav#define ccb_bp ppriv_ptr1 77198849Smav 78198849Smavstruct pass_softc { 79198849Smav pass_state state; 80198849Smav pass_flags flags; 81198849Smav u_int8_t pd_type; 82198849Smav struct buf_queue_head buf_queue; 83198849Smav union ccb saved_ccb; 84198849Smav struct devstat device_stats; 85198849Smav#ifdef DEVFS 86198849Smav void *pass_devfs_token; 87198849Smav void *ctl_devfs_token; 88198849Smav#endif 89198849Smav}; 90198849Smav 91198849Smav#ifndef MIN 92198849Smav#define MIN(x,y) ((x<y) ? x : y) 93198849Smav#endif 94198849Smav 95198849Smav#define PASS_CDEV_MAJOR 31 96198849Smav 97198849Smavstatic d_open_t passopen; 98198849Smavstatic d_read_t passread; 99198849Smavstatic d_write_t passwrite; 100198849Smavstatic d_close_t passclose; 101198849Smavstatic d_ioctl_t passioctl; 102198849Smavstatic d_strategy_t passstrategy; 103198849Smav 104198849Smavstatic periph_init_t passinit; 105198849Smavstatic periph_ctor_t passregister; 106198849Smavstatic periph_oninv_t passoninvalidate; 107198849Smavstatic periph_dtor_t passcleanup; 108198849Smavstatic periph_start_t passstart; 109198849Smavstatic void passasync(void *callback_arg, u_int32_t code, 110198849Smav struct cam_path *path, void *arg); 111198849Smavstatic void passdone(struct cam_periph *periph, 112198849Smav union ccb *done_ccb); 113198849Smavstatic int passerror(union ccb *ccb, u_int32_t cam_flags, 114198849Smav u_int32_t sense_flags); 115198849Smavstatic int passsendccb(struct cam_periph *periph, union ccb *ccb, 116198849Smav union ccb *inccb); 117198849Smav 118198849Smavstatic struct periph_driver passdriver = 119198849Smav{ 120198849Smav passinit, "pass", 121198849Smav TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0 122198849Smav}; 123198849Smav 124198849SmavDATA_SET(periphdriver_set, passdriver); 125198849Smav 126198849Smavstatic struct cdevsw pass_cdevsw = 127198849Smav{ 128198849Smav /*d_open*/ passopen, 129198849Smav /*d_close*/ passclose, 130198849Smav /*d_read*/ passread, 131198849Smav /*d_write*/ passwrite, 132198849Smav /*d_ioctl*/ passioctl, 133198849Smav /*d_stop*/ nostop, 134198849Smav /*d_reset*/ noreset, 135198849Smav /*d_devtotty*/ nodevtotty, 136198849Smav /*d_poll*/ seltrue, 137198849Smav /*d_mmap*/ nommap, 138198849Smav /*d_strategy*/ passstrategy, 139198849Smav /*d_name*/ "pass", 140198849Smav /*d_spare*/ NULL, 141198849Smav /*d_maj*/ -1, 142198849Smav /*d_dump*/ nodump, 143198849Smav /*d_psize*/ nopsize, 144198849Smav /*d_flags*/ 0, 145198849Smav /*d_maxio*/ 0, 146198849Smav /*b_maj*/ -1 147198849Smav}; 148198849Smav 149198849Smavstatic struct extend_array *passperiphs; 150198849Smav 151198849Smavstatic void 152198849Smavpassinit(void) 153198849Smav{ 154198849Smav cam_status status; 155198849Smav struct cam_path *path; 156198849Smav 157198849Smav /* 158198849Smav * Create our extend array for storing the devices we attach to. 159198849Smav */ 160198849Smav passperiphs = cam_extend_new(); 161198849Smav if (passperiphs == NULL) { 162198849Smav printf("passm: Failed to alloc extend array!\n"); 163198849Smav return; 164198849Smav } 165198849Smav 166198849Smav /* 167198849Smav * Install a global async callback. This callback will 168198849Smav * receive async callbacks like "new device found". 169198849Smav */ 170198849Smav status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 171198849Smav CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 172198849Smav 173198849Smav if (status == CAM_REQ_CMP) { 174198849Smav struct ccb_setasync csa; 175198849Smav 176198849Smav xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 177198849Smav csa.ccb_h.func_code = XPT_SASYNC_CB; 178198849Smav csa.event_enable = AC_FOUND_DEVICE; 179198849Smav csa.callback = passasync; 180198849Smav csa.callback_arg = NULL; 181198849Smav xpt_action((union ccb *)&csa); 182198849Smav status = csa.ccb_h.status; 183198849Smav xpt_free_path(path); 184198849Smav } 185198849Smav 186198849Smav if (status != CAM_REQ_CMP) { 187198849Smav printf("pass: Failed to attach master async callback " 188198849Smav "due to status 0x%x!\n", status); 189198849Smav } else { 190198849Smav dev_t dev; 191198849Smav 192198849Smav /* If we were successfull, register our devsw */ 193198849Smav dev = makedev(PASS_CDEV_MAJOR, 0); 194198849Smav cdevsw_add(&dev, &pass_cdevsw, NULL); 195198849Smav } 196198849Smav 197198849Smav} 198198849Smav 199198849Smavstatic void 200198849Smavpassoninvalidate(struct cam_periph *periph) 201198849Smav{ 202198849Smav int s; 203198849Smav struct pass_softc *softc; 204198849Smav struct buf *q_bp; 205198849Smav struct ccb_setasync csa; 206198849Smav 207198849Smav softc = (struct pass_softc *)periph->softc; 208198849Smav 209198849Smav /* 210198849Smav * De-register any async callbacks. 211198849Smav */ 212198849Smav xpt_setup_ccb(&csa.ccb_h, periph->path, 213198849Smav /* priority */ 5); 214198849Smav csa.ccb_h.func_code = XPT_SASYNC_CB; 215198849Smav csa.event_enable = 0; 216198849Smav csa.callback = passasync; 217198849Smav csa.callback_arg = periph; 218198849Smav xpt_action((union ccb *)&csa); 219198849Smav 220198849Smav softc->flags |= PASS_FLAG_INVALID; 221198849Smav 222198849Smav /* 223198849Smav * Although the oninvalidate() routines are always called at 224198849Smav * splsoftcam, we need to be at splbio() here to keep the buffer 225198849Smav * queue from being modified while we traverse it. 226198849Smav */ 227198849Smav s = splbio(); 228198849Smav 229198849Smav /* 230198849Smav * Return all queued I/O with ENXIO. 231198849Smav * XXX Handle any transactions queued to the card 232198849Smav * with XPT_ABORT_CCB. 233198849Smav */ 234198849Smav while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ 235198849Smav bufq_remove(&softc->buf_queue, q_bp); 236198849Smav q_bp->b_resid = q_bp->b_bcount; 237198849Smav q_bp->b_error = ENXIO; 238198849Smav q_bp->b_flags |= B_ERROR; 239198849Smav biodone(q_bp); 240198849Smav } 241198849Smav splx(s); 242198849Smav 243198849Smav if (bootverbose) { 244198849Smav xpt_print_path(periph->path); 245198849Smav printf("lost device\n"); 246198849Smav } 247198849Smav 248198849Smav} 249198849Smav 250195534Sscottlstatic void 251195534Sscottlpasscleanup(struct cam_periph *periph) 252195534Sscottl{ 253195534Sscottl struct pass_softc *softc; 254195534Sscottl 255195534Sscottl softc = (struct pass_softc *)periph->softc; 256195534Sscottl 257195534Sscottl devstat_remove_entry(&softc->device_stats); 258195534Sscottl 259195534Sscottl cam_extend_release(passperiphs, periph->unit_number); 260195534Sscottl 261195534Sscottl if (bootverbose) { 262197541Smav xpt_print_path(periph->path); 263197541Smav printf("removing device entry\n"); 264197541Smav } 265195534Sscottl free(softc, M_DEVBUF); 266195534Sscottl} 267195534Sscottl 268195534Sscottlstatic void 269195534Sscottlpassasync(void *callback_arg, u_int32_t code, 270195534Sscottl struct cam_path *path, void *arg) 271195534Sscottl{ 272195534Sscottl struct cam_periph *periph; 273195534Sscottl 274198897Smav periph = (struct cam_periph *)callback_arg; 275198897Smav 276198897Smav switch (code) { 277198897Smav case AC_FOUND_DEVICE: 278198897Smav { 279198897Smav struct ccb_getdev *cgd; 280198897Smav cam_status status; 281198897Smav 282198897Smav cgd = (struct ccb_getdev *)arg; 283198897Smav 284198897Smav /* 285198897Smav * Allocate a peripheral instance for 286198897Smav * this device and start the probe 287198897Smav * process. 288198897Smav */ 289198897Smav status = cam_periph_alloc(passregister, passoninvalidate, 290198897Smav passcleanup, passstart, "pass", 291198897Smav CAM_PERIPH_BIO, cgd->ccb_h.path, 292198897Smav passasync, AC_FOUND_DEVICE, cgd); 293198897Smav 294198897Smav if (status != CAM_REQ_CMP 295198897Smav && status != CAM_REQ_INPROG) 296198897Smav printf("passasync: Unable to attach new device " 297198897Smav "due to status 0x%x\n", status); 298198897Smav 299198897Smav break; 300198897Smav } 301198897Smav case AC_LOST_DEVICE: 302198897Smav cam_periph_invalidate(periph); 303198897Smav break; 304198897Smav case AC_TRANSFER_NEG: 305198897Smav case AC_SENT_BDR: 306195534Sscottl case AC_SCSI_AEN: 307196659Smav case AC_UNSOL_RESEL: 308195534Sscottl case AC_BUS_RESET: 309195534Sscottl default: 310195534Sscottl break; 311195534Sscottl } 312195534Sscottl} 313195534Sscottl 314195534Sscottlstatic cam_status 315195534Sscottlpassregister(struct cam_periph *periph, void *arg) 316195534Sscottl{ 317195534Sscottl struct pass_softc *softc; 318195534Sscottl struct ccb_setasync csa; 319195534Sscottl struct ccb_getdev *cgd; 320195534Sscottl 321195534Sscottl cgd = (struct ccb_getdev *)arg; 322195534Sscottl if (periph == NULL) { 323195534Sscottl printf("passregister: periph was NULL!!\n"); 324195534Sscottl return(CAM_REQ_CMP_ERR); 325195534Sscottl } 326195534Sscottl 327195534Sscottl if (cgd == NULL) { 328195534Sscottl printf("passregister: no getdev CCB, can't register device\n"); 329195534Sscottl return(CAM_REQ_CMP_ERR); 330195534Sscottl } 331195534Sscottl 332195534Sscottl softc = (struct pass_softc *)malloc(sizeof(*softc), 333195534Sscottl M_DEVBUF, M_NOWAIT); 334195534Sscottl 335195534Sscottl if (softc == NULL) { 336195534Sscottl printf("passregister: Unable to probe new device. " 337195534Sscottl "Unable to allocate softc\n"); 338195534Sscottl return(CAM_REQ_CMP_ERR); 339195534Sscottl } 340195534Sscottl 341195534Sscottl bzero(softc, sizeof(*softc)); 342195534Sscottl softc->state = PASS_STATE_NORMAL; 343195534Sscottl softc->pd_type = cgd->pd_type; 344195534Sscottl bufq_init(&softc->buf_queue); 345195534Sscottl 346195534Sscottl periph->softc = softc; 347195534Sscottl 348195534Sscottl cam_extend_set(passperiphs, periph->unit_number, periph); 349195534Sscottl /* 350195534Sscottl * We pass in 0 for a blocksize, since we don't 351195534Sscottl * know what the blocksize of this device is, if 352195534Sscottl * it even has a blocksize. 353195534Sscottl */ 354195534Sscottl devstat_add_entry(&softc->device_stats, "pass", periph->unit_number, 355195534Sscottl 0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS, 356195534Sscottl cgd->pd_type | 357195534Sscottl DEVSTAT_TYPE_IF_SCSI | 358195534Sscottl DEVSTAT_TYPE_PASS, 359195534Sscottl DEVSTAT_PRIORITY_PASS); 360195534Sscottl /* 361195534Sscottl * Add an async callback so that we get 362195534Sscottl * notified if this device goes away. 363195534Sscottl */ 364195534Sscottl xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); 365195534Sscottl csa.ccb_h.func_code = XPT_SASYNC_CB; 366195534Sscottl csa.event_enable = AC_LOST_DEVICE; 367195534Sscottl csa.callback = passasync; 368195534Sscottl csa.callback_arg = periph; 369195534Sscottl xpt_action((union ccb *)&csa); 370195534Sscottl 371195534Sscottl if (bootverbose) 372195534Sscottl xpt_announce_periph(periph, NULL); 373195534Sscottl 374195534Sscottl return(CAM_REQ_CMP); 375195534Sscottl} 376195534Sscottl 377195534Sscottlstatic int 378195534Sscottlpassopen(dev_t dev, int flags, int fmt, struct proc *p) 379195534Sscottl{ 380195534Sscottl struct cam_periph *periph; 381195534Sscottl struct pass_softc *softc; 382195534Sscottl int unit, error; 383195534Sscottl int s; 384195534Sscottl 385195534Sscottl error = 0; /* default to no error */ 386195534Sscottl 387195534Sscottl /* unit = dkunit(dev); */ 388195534Sscottl /* XXX KDM fix this */ 389195534Sscottl unit = minor(dev) & 0xff; 390195534Sscottl 391195534Sscottl periph = cam_extend_get(passperiphs, unit); 392195534Sscottl 393195534Sscottl if (periph == NULL) 394195534Sscottl return (ENXIO); 395195534Sscottl 396195534Sscottl softc = (struct pass_softc *)periph->softc; 397195534Sscottl 398195534Sscottl s = splsoftcam(); 399195534Sscottl if (softc->flags & PASS_FLAG_INVALID) { 400195534Sscottl splx(s); 401195534Sscottl return(ENXIO); 402195534Sscottl } 403195534Sscottl 404195534Sscottl /* 405195534Sscottl * Don't allow access when we're running at a high securelvel. 406195534Sscottl */ 407195534Sscottl if (securelevel > 1) { 408195534Sscottl splx(s); 409195534Sscottl return(EPERM); 410195534Sscottl } 411195534Sscottl 412195534Sscottl /* 413195534Sscottl * Only allow read-write access. 414195534Sscottl */ 415195534Sscottl if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) { 416195534Sscottl splx(s); 417195534Sscottl return(EPERM); 418195534Sscottl } 419195534Sscottl 420195534Sscottl /* 421195534Sscottl * We don't allow nonblocking access. 422195534Sscottl */ 423195534Sscottl if ((flags & O_NONBLOCK) != 0) { 424195534Sscottl xpt_print_path(periph->path); 425195534Sscottl printf("can't do nonblocking accesss\n"); 426195534Sscottl splx(s); 427195534Sscottl return(EINVAL); 428195534Sscottl } 429195534Sscottl 430195534Sscottl if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { 431195534Sscottl splx(s); 432195534Sscottl return (error); 433195534Sscottl } 434195534Sscottl 435195534Sscottl splx(s); 436195534Sscottl 437195534Sscottl if ((softc->flags & PASS_FLAG_OPEN) == 0) { 438195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) 439195534Sscottl return(ENXIO); 440195534Sscottl softc->flags |= PASS_FLAG_OPEN; 441195534Sscottl } 442195534Sscottl 443195534Sscottl cam_periph_unlock(periph); 444195534Sscottl 445195534Sscottl return (error); 446195534Sscottl} 447195534Sscottl 448195534Sscottlstatic int 449195534Sscottlpassclose(dev_t dev, int flag, int fmt, struct proc *p) 450195534Sscottl{ 451195534Sscottl struct cam_periph *periph; 452195534Sscottl struct pass_softc *softc; 453195534Sscottl int unit, error; 454195534Sscottl 455195534Sscottl /* unit = dkunit(dev); */ 456195534Sscottl /* XXX KDM fix this */ 457195534Sscottl unit = minor(dev) & 0xff; 458195534Sscottl 459195534Sscottl periph = cam_extend_get(passperiphs, unit); 460195534Sscottl if (periph == NULL) 461195534Sscottl return (ENXIO); 462195534Sscottl 463195534Sscottl softc = (struct pass_softc *)periph->softc; 464195534Sscottl 465195534Sscottl if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 466195534Sscottl return (error); 467195534Sscottl 468195534Sscottl softc->flags &= ~PASS_FLAG_OPEN; 469195534Sscottl 470195534Sscottl cam_periph_unlock(periph); 471195534Sscottl cam_periph_release(periph); 472195534Sscottl 473195534Sscottl return (0); 474195534Sscottl} 475195534Sscottl 476195534Sscottlstatic int 477195534Sscottlpassread(dev_t dev, struct uio *uio, int ioflag) 478195534Sscottl{ 479195534Sscottl return(physio(passstrategy, NULL, dev, 1, minphys, uio)); 480195534Sscottl} 481195534Sscottl 482195534Sscottlstatic int 483195534Sscottlpasswrite(dev_t dev, struct uio *uio, int ioflag) 484195534Sscottl{ 485195534Sscottl return(physio(passstrategy, NULL, dev, 0, minphys, uio)); 486195534Sscottl} 487195534Sscottl 488195534Sscottl/* 489195534Sscottl * Actually translate the requested transfer into one the physical driver 490195534Sscottl * can understand. The transfer is described by a buf and will include 491195534Sscottl * only one physical transfer. 492195534Sscottl */ 493195534Sscottlstatic void 494195534Sscottlpassstrategy(struct buf *bp) 495195534Sscottl{ 496195534Sscottl struct cam_periph *periph; 497195534Sscottl struct pass_softc *softc; 498195534Sscottl u_int unit; 499195534Sscottl int s; 500195534Sscottl 501195534Sscottl /* 502195534Sscottl * The read/write interface for the passthrough driver doesn't 503195534Sscottl * really work right now. So, we just pass back EINVAL to tell the 504195534Sscottl * user to go away. 505195534Sscottl */ 506195534Sscottl bp->b_error = EINVAL; 507195534Sscottl goto bad; 508195534Sscottl 509195534Sscottl /* unit = dkunit(bp->b_dev); */ 510195534Sscottl /* XXX KDM fix this */ 511195534Sscottl unit = minor(bp->b_dev) & 0xff; 512195534Sscottl 513195534Sscottl periph = cam_extend_get(passperiphs, unit); 514195534Sscottl if (periph == NULL) { 515195534Sscottl bp->b_error = ENXIO; 516195534Sscottl goto bad; 517195534Sscottl } 518 softc = (struct pass_softc *)periph->softc; 519 520 /* 521 * Odd number of bytes or negative offset 522 */ 523 /* valid request? */ 524 if (bp->b_blkno < 0) { 525 bp->b_error = EINVAL; 526 goto bad; 527 } 528 529 /* 530 * Mask interrupts so that the pack cannot be invalidated until 531 * after we are in the queue. Otherwise, we might not properly 532 * clean up one of the buffers. 533 */ 534 s = splbio(); 535 536 bufq_insert_tail(&softc->buf_queue, bp); 537 538 splx(s); 539 540 /* 541 * Schedule ourselves for performing the work. 542 */ 543 xpt_schedule(periph, /* XXX priority */1); 544 545 return; 546bad: 547 bp->b_flags |= B_ERROR; 548 549 /* 550 * Correctly set the buf to indicate a completed xfer 551 */ 552 bp->b_resid = bp->b_bcount; 553 biodone(bp); 554 return; 555} 556 557static void 558passstart(struct cam_periph *periph, union ccb *start_ccb) 559{ 560 struct pass_softc *softc; 561 int s; 562 563 softc = (struct pass_softc *)periph->softc; 564 565 switch (softc->state) { 566 case PASS_STATE_NORMAL: 567 { 568 struct buf *bp; 569 570 s = splbio(); 571 bp = bufq_first(&softc->buf_queue); 572 if (periph->immediate_priority <= periph->pinfo.priority) { 573 start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; 574 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 575 periph_links.sle); 576 periph->immediate_priority = CAM_PRIORITY_NONE; 577 splx(s); 578 wakeup(&periph->ccb_list); 579 } else if (bp == NULL) { 580 splx(s); 581 xpt_release_ccb(start_ccb); 582 } else { 583 584 bufq_remove(&softc->buf_queue, bp); 585 586 devstat_start_transaction(&softc->device_stats); 587 588 /* 589 * XXX JGibbs - 590 * Interpret the contents of the bp as a CCB 591 * and pass it to a routine shared by our ioctl 592 * code and passtart. 593 * For now, just biodone it with EIO so we don't 594 * hang. 595 */ 596 bp->b_error = EIO; 597 bp->b_flags |= B_ERROR; 598 bp->b_resid = bp->b_bcount; 599 biodone(bp); 600 bp = bufq_first(&softc->buf_queue); 601 splx(s); 602 603 xpt_action(start_ccb); 604 605 } 606 if (bp != NULL) { 607 /* Have more work to do, so ensure we stay scheduled */ 608 xpt_schedule(periph, /* XXX priority */1); 609 } 610 break; 611 } 612 } 613} 614static void 615passdone(struct cam_periph *periph, union ccb *done_ccb) 616{ 617 struct pass_softc *softc; 618 struct ccb_scsiio *csio; 619 620 softc = (struct pass_softc *)periph->softc; 621 csio = &done_ccb->csio; 622 switch (csio->ccb_h.ccb_type) { 623 case PASS_CCB_BUFFER_IO: 624 { 625 struct buf *bp; 626 cam_status status; 627 u_int8_t scsi_status; 628 devstat_trans_flags ds_flags; 629 630 status = done_ccb->ccb_h.status; 631 scsi_status = done_ccb->csio.scsi_status; 632 bp = (struct buf *)done_ccb->ccb_h.ccb_bp; 633 /* XXX handle errors */ 634 if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP) 635 && (scsi_status == SCSI_STATUS_OK))) { 636 int error; 637 638 if ((error = passerror(done_ccb, 0, 0)) == ERESTART) { 639 /* 640 * A retry was scheuled, so 641 * just return. 642 */ 643 return; 644 } 645 646 /* 647 * XXX unfreeze the queue after we complete 648 * the abort process 649 */ 650 bp->b_error = error; 651 bp->b_flags |= B_ERROR; 652 } 653 654 if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 655 ds_flags = DEVSTAT_READ; 656 else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 657 ds_flags = DEVSTAT_WRITE; 658 else 659 ds_flags = DEVSTAT_NO_DATA; 660 661 devstat_end_transaction(&softc->device_stats, bp->b_bcount, 662 done_ccb->csio.tag_action & 0xf, 663 ds_flags); 664 665 biodone(bp); 666 break; 667 } 668 case PASS_CCB_WAITING: 669 { 670 /* Caller will release the CCB */ 671 wakeup(&done_ccb->ccb_h.cbfcnp); 672 return; 673 } 674 } 675 xpt_release_ccb(done_ccb); 676} 677 678static int 679passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 680{ 681 struct cam_periph *periph; 682 struct pass_softc *softc; 683 u_int8_t unit; 684 int error; 685 686 687 /* unit = dkunit(dev); */ 688 /* XXX KDM fix this */ 689 unit = minor(dev) & 0xff; 690 691 periph = cam_extend_get(passperiphs, unit); 692 693 if (periph == NULL) 694 return(ENXIO); 695 696 softc = (struct pass_softc *)periph->softc; 697 698 error = 0; 699 700 switch (cmd) { 701 702 case CAMIOCOMMAND: 703 { 704 union ccb *inccb; 705 union ccb *ccb; 706 int ccb_malloced; 707 708 inccb = (union ccb *)addr; 709 710 /* 711 * Some CCB types, like scan bus and scan lun can only go 712 * through the transport layer device. 713 */ 714 if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { 715 xpt_print_path(periph->path); 716 printf("CCB function code %#x is restricted to the " 717 "XPT device\n", inccb->ccb_h.func_code); 718 error = ENODEV; 719 break; 720 } 721 722 /* 723 * Non-immediate CCBs need a CCB from the per-device pool 724 * of CCBs, which is scheduled by the transport layer. 725 * Immediate CCBs and user-supplied CCBs should just be 726 * malloced. 727 */ 728 if ((inccb->ccb_h.func_code & XPT_FC_QUEUED) 729 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) { 730 ccb = cam_periph_getccb(periph, 731 inccb->ccb_h.pinfo.priority); 732 ccb_malloced = 0; 733 } else { 734 ccb = xpt_alloc_ccb(); 735 736 if (ccb != NULL) 737 xpt_setup_ccb(&ccb->ccb_h, periph->path, 738 inccb->ccb_h.pinfo.priority); 739 ccb_malloced = 1; 740 } 741 742 if (ccb == NULL) { 743 xpt_print_path(periph->path); 744 printf("unable to allocate CCB\n"); 745 error = ENOMEM; 746 break; 747 } 748 749 error = passsendccb(periph, ccb, inccb); 750 751 if (ccb_malloced) 752 xpt_free_ccb(ccb); 753 else 754 xpt_release_ccb(ccb); 755 756 break; 757 } 758 default: 759 error = cam_periph_ioctl(periph, cmd, addr, passerror); 760 break; 761 } 762 763 return(error); 764} 765 766/* 767 * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" 768 * should be the CCB that is copied in from the user. 769 */ 770static int 771passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) 772{ 773 struct pass_softc *softc; 774 struct cam_periph_map_info mapinfo; 775 int error, need_unmap; 776 777 softc = (struct pass_softc *)periph->softc; 778 779 need_unmap = 0; 780 781 /* 782 * There are some fields in the CCB header that need to be 783 * preserved, the rest we get from the user. 784 */ 785 xpt_merge_ccb(ccb, inccb); 786 787 /* 788 * There's no way for the user to have a completion 789 * function, so we put our own completion function in here. 790 */ 791 ccb->ccb_h.cbfcnp = passdone; 792 793 /* 794 * We only attempt to map the user memory into kernel space 795 * if they haven't passed in a physical memory pointer, 796 * and if there is actually an I/O operation to perform. 797 * Right now cam_periph_mapmem() only supports SCSI and device 798 * match CCBs. For the SCSI CCBs, we only pass the CCB in if 799 * there's actually data to map. cam_periph_mapmem() will do the 800 * right thing, even if there isn't data to map, but since CCBs 801 * without data are a reasonably common occurance (e.g. test unit 802 * ready), it will save a few cycles if we check for it here. 803 */ 804 if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) 805 && (((ccb->ccb_h.func_code == XPT_SCSI_IO) 806 && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)) 807 || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) { 808 809 bzero(&mapinfo, sizeof(mapinfo)); 810 811 error = cam_periph_mapmem(ccb, &mapinfo); 812 813 /* 814 * cam_periph_mapmem returned an error, we can't continue. 815 * Return the error to the user. 816 */ 817 if (error) 818 return(error); 819 820 /* 821 * We successfully mapped the memory in, so we need to 822 * unmap it when the transaction is done. 823 */ 824 need_unmap = 1; 825 } 826 827 /* 828 * If the user wants us to perform any error recovery, then honor 829 * that request. Otherwise, it's up to the user to perform any 830 * error recovery. 831 */ 832 error = cam_periph_runccb(ccb, 833 (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? 834 passerror : NULL, 835 /* cam_flags */ 0, 836 /* sense_flags */SF_RETRY_UA, 837 &softc->device_stats); 838 839 if (need_unmap != 0) 840 cam_periph_unmapmem(ccb, &mapinfo); 841 842 ccb->ccb_h.cbfcnp = NULL; 843 ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; 844 bcopy(ccb, inccb, sizeof(union ccb)); 845 846 return(error); 847} 848 849static int 850passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 851{ 852 struct cam_periph *periph; 853 struct pass_softc *softc; 854 855 periph = xpt_path_periph(ccb->ccb_h.path); 856 softc = (struct pass_softc *)periph->softc; 857 858 return(cam_periph_error(ccb, cam_flags, sense_flags, 859 &softc->saved_ccb)); 860} 861