scsi_targ_bh.c revision 60041
1139826Simp/* 253541Sshin * Implementation of the Target Mode 'Black Hole device' for CAM. 353541Sshin * 453541Sshin * Copyright (c) 1999 Justin T. Gibbs. 553541Sshin * All rights reserved. 653541Sshin * 753541Sshin * Redistribution and use in source and binary forms, with or without 853541Sshin * modification, are permitted provided that the following conditions 953541Sshin * are met: 1053541Sshin * 1. Redistributions of source code must retain the above copyright 1153541Sshin * notice, this list of conditions, and the following disclaimer, 1253541Sshin * without modification, immediately at the beginning of the file. 1353541Sshin * 2. The name of the author may not be used to endorse or promote products 1453541Sshin * derived from this software without specific prior written permission. 1553541Sshin * 1653541Sshin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1753541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1853541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1953541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2053541Sshin * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2153541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2253541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2353541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2453541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2553541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2653541Sshin * SUCH DAMAGE. 2753541Sshin * 28174510Sobrien * $FreeBSD: head/sys/cam/scsi/scsi_targ_bh.c 60041 2000-05-05 09:59:14Z phk $ 29174510Sobrien */ 3053541Sshin#include <stddef.h> /* For offsetof */ 3153541Sshin 32139826Simp#include <sys/param.h> 3353541Sshin#include <sys/queue.h> 3453541Sshin#include <sys/systm.h> 3553541Sshin#include <sys/kernel.h> 3653541Sshin#include <sys/types.h> 3753541Sshin#include <sys/bio.h> 3853541Sshin#include <sys/conf.h> 3953541Sshin#include <sys/devicestat.h> 4053541Sshin#include <sys/malloc.h> 4153541Sshin#include <sys/uio.h> 4253541Sshin 4353541Sshin#include <cam/cam.h> 4453541Sshin#include <cam/cam_ccb.h> 4553541Sshin#include <cam/cam_extend.h> 4653541Sshin#include <cam/cam_periph.h> 4753541Sshin#include <cam/cam_queue.h> 4853541Sshin#include <cam/cam_xpt_periph.h> 4953541Sshin#include <cam/cam_debug.h> 5053541Sshin 5153541Sshin#include <cam/scsi/scsi_all.h> 5253541Sshin#include <cam/scsi/scsi_message.h> 5353541Sshin 5453541Sshintypedef enum { 5553541Sshin TARGBH_STATE_NORMAL, 5653541Sshin TARGBH_STATE_EXCEPTION, 5753541Sshin TARGBH_STATE_TEARDOWN 5853541Sshin} targbh_state; 5953541Sshin 6053541Sshintypedef enum { 6153541Sshin TARGBH_FLAG_NONE = 0x00, 6253541Sshin TARGBH_FLAG_LUN_ENABLED = 0x01 63174510Sobrien} targbh_flags; 64174510Sobrien 65174510Sobrientypedef enum { 6662587Sitojun TARGBH_CCB_WORKQ, 6762587Sitojun TARGBH_CCB_WAITING 6855009Sshin} targbh_ccb_types; 6953541Sshin 7053541Sshin#define MAX_ACCEPT 8 7195759Stanimura#define MAX_IMMEDIATE 16 72193066Sjamie#define MAX_BUF_SIZE 256 /* Max inquiry/sense/mode page transfer */ 7395759Stanimura 7495759Stanimura#define MIN(a, b) ((a > b) ? b : a) 7578064Sume 7653541Sshin/* Offsets into our private CCB area for storing accept information */ 77196019Srwatson#define ccb_type ppriv_field0 7853541Sshin#define ccb_descr ppriv_ptr1 7995759Stanimura 8053541Sshin/* We stick a pointer to the originating accept TIO in each continue I/O CCB */ 8153541Sshin#define ccb_atio ppriv_ptr1 8295759Stanimura 8395759StanimuraTAILQ_HEAD(ccb_queue, ccb_hdr); 8495759Stanimura 8553541Sshinstruct targbh_softc { 8653541Sshin struct ccb_queue pending_queue; 8753541Sshin struct ccb_queue work_queue; 8853541Sshin struct ccb_queue unknown_atio_queue; 89186119Sqingli struct devstat device_stats; 9053541Sshin targbh_state state; 9195759Stanimura targbh_flags flags; 92185571Sbz u_int init_level; 9353541Sshin u_int inq_data_len; 9453541Sshin struct ccb_accept_tio *accept_tio_list; 9595759Stanimura struct ccb_hdr_slist immed_notify_slist; 9653541Sshin}; 9762587Sitojun 9895759Stanimurastruct targbh_cmd_desc { 99122922Sandre struct ccb_accept_tio* atio_link; 100185571Sbz u_int data_resid; /* How much left to transfer */ 10195759Stanimura u_int data_increment;/* Amount to send before next disconnect */ 10295759Stanimura void* data; /* The data. Can be from backing_store or not */ 10395759Stanimura void* backing_store;/* Backing store allocated for this descriptor*/ 10453541Sshin u_int max_size; /* Size of backing_store */ 105148385Sume u_int32_t timeout; 10653541Sshin u_int8_t status; /* Status to return to initiator */ 10753541Sshin}; 10853541Sshin 109171167Sgnnstatic struct scsi_inquiry_data no_lun_inq_data = 110105199Ssam{ 111105199Ssam T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0, 112105199Ssam /* version */2, /* format version */2 113105199Ssam}; 11462587Sitojun 115185348Szecstatic struct scsi_sense_data no_lun_sense_data = 116195699Srwatson{ 117195699Srwatson SSD_CURRENT_ERROR|SSD_ERRCODE_VALID, 118195699Srwatson 0, 119195699Srwatson SSD_KEY_NOT_READY, 12053541Sshin { 0, 0, 0, 0 }, 121195727Srwatson /*extra_len*/offsetof(struct scsi_sense_data, fru) 122195727Srwatson - offsetof(struct scsi_sense_data, extra_len), 123195727Srwatson { 0, 0, 0, 0 }, 124195727Srwatson /* Logical Unit Not Supported */ 125185088Szec /*ASC*/0x25, /*ASCQ*/0 126195699Srwatson}; 127195699Srwatson 128195699Srwatsonstatic const int request_sense_size = offsetof(struct scsi_sense_data, fru); 129195699Srwatson 130195727Srwatsonstatic periph_init_t targbhinit; 131195727Srwatsonstatic void targbhasync(void *callback_arg, u_int32_t code, 132195699Srwatson struct cam_path *path, void *arg); 133175162Sobrienstatic cam_status targbhenlun(struct cam_periph *periph); 134175162Sobrienstatic cam_status targbhdislun(struct cam_periph *periph); 135175162Sobrienstatic periph_ctor_t targbhctor; 13662587Sitojunstatic periph_dtor_t targbhdtor; 13762587Sitojunstatic periph_start_t targbhstart; 138175162Sobrienstatic void targbhdone(struct cam_periph *periph, 139175162Sobrien union ccb *done_ccb); 140175162Sobrien#ifdef NOTYET 14162587Sitojunstatic int targbherror(union ccb *ccb, u_int32_t cam_flags, 142148892Sume u_int32_t sense_flags); 14362587Sitojun#endif 14462587Sitojunstatic struct targbh_cmd_desc* targbhallocdescr(void); 145175162Sobrienstatic void targbhfreedescr(struct targbh_cmd_desc *buf); 14653541Sshin 14753541Sshinstatic struct periph_driver targbhdriver = 14853541Sshin{ 149171259Sdelphij targbhinit, "targbh", 15053541Sshin TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0 151171259Sdelphij}; 152185088Szec 15353541SshinDATA_SET(periphdriver_set, targbhdriver); 15453541Sshin 155196039Srwatsonstatic void 156196039Srwatsontargbhinit(void) 157196039Srwatson{ 158196039Srwatson cam_status status; 159196039Srwatson struct cam_path *path; 160196039Srwatson 161196039Srwatson /* 162196039Srwatson * Install a global async callback. This callback will 163196039Srwatson * receive async callbacks like "new path registered". 164196039Srwatson */ 165196039Srwatson status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 166196039Srwatson CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 167196039Srwatson 168196039Srwatson if (status == CAM_REQ_CMP) { 16962587Sitojun struct ccb_setasync csa; 170171259Sdelphij 17162587Sitojun xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 17278064Sume csa.ccb_h.func_code = XPT_SASYNC_CB; 17362587Sitojun csa.event_enable = AC_PATH_REGISTERED; 17462587Sitojun csa.callback = targbhasync; 17562587Sitojun csa.callback_arg = NULL; 17662587Sitojun xpt_action((union ccb *)&csa); 17762587Sitojun status = csa.ccb_h.status; 17862587Sitojun xpt_free_path(path); 17962587Sitojun } 18062587Sitojun 18162587Sitojun if (status != CAM_REQ_CMP) { 18262587Sitojun printf("targbh: Failed to attach master async callback " 18362587Sitojun "due to status 0x%x!\n", status); 18462587Sitojun } 18562587Sitojun} 18662587Sitojun 18762587Sitojunstatic void 18862587Sitojuntargbhasync(void *callback_arg, u_int32_t code, 18962587Sitojun struct cam_path *path, void *arg) 19062587Sitojun{ 19162587Sitojun struct cam_periph *periph; 19262587Sitojun 19362587Sitojun periph = (struct cam_periph *)callback_arg; 19462587Sitojun switch (code) { 19562587Sitojun case AC_PATH_REGISTERED: 19678064Sume { 19762587Sitojun struct ccb_pathinq *cpi; 19862587Sitojun struct cam_path *new_path; 19962587Sitojun cam_status status; 20062587Sitojun 20162587Sitojun cpi = (struct ccb_pathinq *)arg; 20262587Sitojun 20362587Sitojun /* Only attach to controllers that support target mode */ 20462587Sitojun if ((cpi->target_sprt & PIT_PROCESSOR) == 0) 20562587Sitojun break; 20678064Sume 20762587Sitojun /* 20862587Sitojun * Allocate a peripheral instance for 20962587Sitojun * this target instance. 21062587Sitojun */ 21162587Sitojun status = xpt_create_path(&new_path, NULL, 21262587Sitojun xpt_path_path_id(path), 21362587Sitojun CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 21462587Sitojun if (status != CAM_REQ_CMP) { 21562587Sitojun printf("targbhasync: Unable to create path " 21662587Sitojun "due to status 0x%x\n", status); 21762587Sitojun break; 21862587Sitojun } 21962587Sitojun status = cam_periph_alloc(targbhctor, NULL, targbhdtor, 22062587Sitojun targbhstart, 22162587Sitojun "targbh", CAM_PERIPH_BIO, 22262587Sitojun new_path, targbhasync, 22362587Sitojun AC_PATH_REGISTERED, 22462587Sitojun cpi); 22553541Sshin xpt_free_path(new_path); 226148385Sume if (status != CAM_REQ_CMP 227148385Sume && status != CAM_REQ_INPROG) 228148385Sume printf("targbhasync: Unable to allocate new periph " 229148385Sume "due to status 0x%x\n", status); 230171259Sdelphij break; 231171259Sdelphij } 232148385Sume case AC_PATH_DEREGISTERED: 233148385Sume { 234148385Sume targbhdislun(periph); 235148385Sume break; 236148385Sume } 237148385Sume default: 238148385Sume break; 239148385Sume } 240148385Sume} 241148385Sume 242148385Sume/* Attempt to enable our lun */ 243148385Sumestatic cam_status 244148385Sumetargbhenlun(struct cam_periph *periph) 245148385Sume{ 246148385Sume union ccb immed_ccb; 247148385Sume struct targbh_softc *softc; 248148385Sume cam_status status; 249148385Sume int i; 250148385Sume 251148385Sume softc = (struct targbh_softc *)periph->softc; 252148385Sume 253148385Sume if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0) 254148385Sume return (CAM_REQ_CMP); 255148385Sume 256148385Sume xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1); 257148385Sume immed_ccb.ccb_h.func_code = XPT_EN_LUN; 258148385Sume 25953541Sshin /* Don't need support for any vendor specific commands */ 26053541Sshin immed_ccb.cel.grp6_len = 0; 26153541Sshin immed_ccb.cel.grp7_len = 0; 262171259Sdelphij immed_ccb.cel.enable = 1; 26353541Sshin xpt_action(&immed_ccb); 26453541Sshin status = immed_ccb.ccb_h.status; 26553541Sshin if (status != CAM_REQ_CMP) { 26662587Sitojun xpt_print_path(periph->path); 26753541Sshin printf("targbhenlun - Enable Lun Rejected for status 0x%x\n", 26862587Sitojun status); 26953541Sshin return (status); 270190964Srwatson } 27153541Sshin 27262587Sitojun softc->flags |= TARGBH_FLAG_LUN_ENABLED; 273181803Sbz 27462587Sitojun /* 27562587Sitojun * Build up a buffer of accept target I/O 27662587Sitojun * operations for incoming selections. 277190964Srwatson */ 27853541Sshin for (i = 0; i < MAX_ACCEPT; i++) { 27962587Sitojun struct ccb_accept_tio *atio; 28062587Sitojun 28153541Sshin atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_DEVBUF, 28262587Sitojun M_NOWAIT); 28362587Sitojun if (atio == NULL) { 28462587Sitojun status = CAM_RESRC_UNAVAIL; 28562587Sitojun break; 28662587Sitojun } 28762587Sitojun 28862587Sitojun atio->ccb_h.ccb_descr = targbhallocdescr(); 28962587Sitojun 29062587Sitojun if (atio->ccb_h.ccb_descr == NULL) { 29153541Sshin free(atio, M_DEVBUF); 29253541Sshin status = CAM_RESRC_UNAVAIL; 29353541Sshin break; 294121472Sume } 295121472Sume 296121472Sume xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1); 297121472Sume atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; 298121472Sume atio->ccb_h.cbfcnp = targbhdone; 299201688Sbz xpt_action((union ccb *)atio); 300121472Sume status = atio->ccb_h.status; 301121472Sume if (status != CAM_REQ_INPROG) { 302121472Sume targbhfreedescr(atio->ccb_h.ccb_descr); 30353541Sshin free(atio, M_DEVBUF); 30453541Sshin break; 30553541Sshin } 30653541Sshin ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link = 30753541Sshin softc->accept_tio_list; 30853541Sshin softc->accept_tio_list = atio; 30953541Sshin } 31053541Sshin 311121472Sume if (i == 0) { 312121472Sume xpt_print_path(periph->path); 313121472Sume printf("targbhenlun - Could not allocate accept tio CCBs: " 314121472Sume "status = 0x%x\n", status); 31553541Sshin targbhdislun(periph); 31653541Sshin return (CAM_REQ_CMP_ERR); 31753541Sshin } 31853541Sshin 31953541Sshin /* 32062587Sitojun * Build up a buffer of immediate notify CCBs 32162587Sitojun * so the SIM can tell us of asynchronous target mode events. 32253541Sshin */ 32362587Sitojun for (i = 0; i < MAX_ACCEPT; i++) { 32462587Sitojun struct ccb_immed_notify *inot; 32562587Sitojun 32653541Sshin inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_DEVBUF, 32753541Sshin M_NOWAIT); 32862587Sitojun 32962587Sitojun if (inot == NULL) { 33062587Sitojun status = CAM_RESRC_UNAVAIL; 33162587Sitojun break; 33262587Sitojun } 33362587Sitojun 33462587Sitojun xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1); 335190964Srwatson inot->ccb_h.func_code = XPT_IMMED_NOTIFY; 33662587Sitojun inot->ccb_h.cbfcnp = targbhdone; 33762587Sitojun xpt_action((union ccb *)inot); 33862587Sitojun status = inot->ccb_h.status; 33962587Sitojun if (status != CAM_REQ_INPROG) { 34062587Sitojun free(inot, M_DEVBUF); 34153541Sshin break; 34262587Sitojun } 34362587Sitojun SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h, 34462587Sitojun periph_links.sle); 34553541Sshin } 346190964Srwatson 34762587Sitojun if (i == 0) { 34862587Sitojun xpt_print_path(periph->path); 34962587Sitojun printf("targbhenlun - Could not allocate immediate notify " 35053541Sshin "CCBs: status = 0x%x\n", status); 35162587Sitojun targbhdislun(periph); 35262587Sitojun return (CAM_REQ_CMP_ERR); 35353541Sshin } 35453541Sshin 35553541Sshin return (CAM_REQ_CMP); 35653541Sshin} 35753541Sshin 35853541Sshinstatic cam_status 359190964Srwatsontargbhdislun(struct cam_periph *periph) 36053541Sshin{ 36153541Sshin union ccb ccb; 36253541Sshin struct targbh_softc *softc; 36353541Sshin struct ccb_accept_tio* atio; 36453541Sshin struct ccb_hdr *ccb_h; 36553541Sshin 36653541Sshin softc = (struct targbh_softc *)periph->softc; 36753541Sshin if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0) 36853541Sshin return CAM_REQ_CMP; 36953541Sshin 37062587Sitojun /* XXX Block for Continue I/O completion */ 371111119Simp 37262587Sitojun /* Kill off all ACCECPT and IMMEDIATE CCBs */ 37362587Sitojun while ((atio = softc->accept_tio_list) != NULL) { 37453541Sshin 37578064Sume softc->accept_tio_list = 37653541Sshin ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link; 37753541Sshin xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); 37853541Sshin ccb.cab.ccb_h.func_code = XPT_ABORT; 37953541Sshin ccb.cab.abort_ccb = (union ccb *)atio; 38053541Sshin xpt_action(&ccb); 38153541Sshin } 38253541Sshin 383121315Sume while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) { 384121315Sume SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle); 38553541Sshin xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); 38653541Sshin ccb.cab.ccb_h.func_code = XPT_ABORT; 38753541Sshin ccb.cab.abort_ccb = (union ccb *)ccb_h; 38853541Sshin xpt_action(&ccb); 38953541Sshin } 39053541Sshin 39178064Sume /* 39278064Sume * Dissable this lun. 393148987Sume */ 39478064Sume xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1); 39578064Sume ccb.cel.ccb_h.func_code = XPT_EN_LUN; 39678064Sume ccb.cel.enable = 0; 39778064Sume xpt_action(&ccb); 39878064Sume 39978064Sume if (ccb.cel.ccb_h.status != CAM_REQ_CMP) 400190964Srwatson printf("targbhdislun - Disabling lun on controller failed " 40195023Ssuz "with status 0x%x\n", ccb.cel.ccb_h.status); 40262587Sitojun else 40362587Sitojun softc->flags &= ~TARGBH_FLAG_LUN_ENABLED; 40462587Sitojun return (ccb.cel.ccb_h.status); 40562587Sitojun} 40662587Sitojun 407148987Sumestatic cam_status 40862587Sitojuntargbhctor(struct cam_periph *periph, void *arg) 40962587Sitojun{ 41053541Sshin struct ccb_pathinq *cpi; 41153541Sshin struct targbh_softc *softc; 41253541Sshin 41353541Sshin cpi = (struct ccb_pathinq *)arg; 41453541Sshin 41553541Sshin /* Allocate our per-instance private storage */ 416171259Sdelphij softc = (struct targbh_softc *)malloc(sizeof(*softc), 41753541Sshin M_DEVBUF, M_NOWAIT); 41853541Sshin if (softc == NULL) { 419192923Sbms printf("targctor: unable to malloc softc\n"); 42053541Sshin return (CAM_REQ_CMP_ERR); 42153541Sshin } 42253541Sshin 42353541Sshin bzero(softc, sizeof(softc)); 42453541Sshin TAILQ_INIT(&softc->pending_queue); 425165118Sbz TAILQ_INIT(&softc->work_queue); 42653541Sshin softc->accept_tio_list = NULL; 427192923Sbms SLIST_INIT(&softc->immed_notify_slist); 428192923Sbms softc->state = TARGBH_STATE_NORMAL; 42962587Sitojun periph->softc = softc; 43053541Sshin softc->init_level++; 43195023Ssuz 43262587Sitojun return (targbhenlun(periph)); 43353541Sshin} 43453541Sshin 43553541Sshinstatic void 43653541Sshintargbhdtor(struct cam_periph *periph) 43753541Sshin{ 43853541Sshin struct targbh_softc *softc; 43953541Sshin 44053541Sshin softc = (struct targbh_softc *)periph->softc; 441190964Srwatson 44253541Sshin softc->state = TARGBH_STATE_TEARDOWN; 44353541Sshin 44453541Sshin targbhdislun(periph); 44553541Sshin 446191672Sbms switch (softc->init_level) { 447191672Sbms default: 448191672Sbms /* FALLTHROUGH */ 449191672Sbms case 1: 450192923Sbms free(softc, M_DEVBUF); 451191672Sbms break; 452191672Sbms case 0: 453191672Sbms panic("targdtor - impossible init level");; 454191672Sbms } 455191672Sbms} 456191672Sbms 457191672Sbmsstatic void 458191672Sbmstargbhstart(struct cam_periph *periph, union ccb *start_ccb) 459191672Sbms{ 460191672Sbms struct targbh_softc *softc; 46153541Sshin struct ccb_hdr *ccbh; 46253541Sshin struct ccb_accept_tio *atio; 46362587Sitojun struct targbh_cmd_desc *desc; 46453541Sshin struct ccb_scsiio *csio; 46562587Sitojun ccb_flags flags; 46662587Sitojun int s; 46762587Sitojun 468190964Srwatson softc = (struct targbh_softc *)periph->softc; 46962587Sitojun 47062587Sitojun s = splbio(); 47162587Sitojun ccbh = TAILQ_FIRST(&softc->work_queue); 47253541Sshin if (periph->immediate_priority <= periph->pinfo.priority) { 47353541Sshin start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING; 47453541Sshin SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 47578064Sume periph_links.sle); 47653541Sshin periph->immediate_priority = CAM_PRIORITY_NONE; 477165118Sbz splx(s); 478165118Sbz wakeup(&periph->ccb_list); 479190964Srwatson } else if (ccbh == NULL) { 48053541Sshin splx(s); 48153541Sshin xpt_release_ccb(start_ccb); 48253541Sshin } else { 48383934Sbrooks TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe); 48453541Sshin TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh, 48553541Sshin periph_links.tqe); 486148987Sume splx(s); 48753541Sshin atio = (struct ccb_accept_tio*)ccbh; 48853541Sshin desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; 48953541Sshin 49053541Sshin /* Is this a tagged request? */ 49153541Sshin flags = atio->ccb_h.flags & (CAM_TAG_ACTION_VALID|CAM_DIR_MASK); 49253541Sshin 49353541Sshin csio = &start_ccb->csio; 49453541Sshin /* 49553541Sshin * If we are done with the transaction, tell the 49653541Sshin * controller to send status and perform a CMD_CMPLT. 49753541Sshin * If we have associated sense data, see if we can 49853541Sshin * send that too. 499190964Srwatson */ 500192923Sbms if (desc->data_resid == desc->data_increment) { 50153541Sshin flags |= CAM_SEND_STATUS; 502192923Sbms if (atio->sense_len) { 50353541Sshin csio->sense_len = atio->sense_len; 50453541Sshin csio->sense_data = atio->sense_data; 50553541Sshin flags |= CAM_SEND_SENSE; 506192923Sbms } 50753541Sshin 50853541Sshin } 50953541Sshin 51053541Sshin cam_fill_ctio(csio, 51153541Sshin /*retries*/2, 512192923Sbms targbhdone, 51362587Sitojun flags, 51462587Sitojun /*tag_action*/MSG_SIMPLE_Q_TAG, 51553541Sshin atio->tag_id, 51662587Sitojun atio->init_id, 51753541Sshin desc->status, 51862587Sitojun /*data_ptr*/desc->data_increment == 0 51962587Sitojun ? NULL : desc->data, 52062587Sitojun /*dxfer_len*/desc->data_increment, 52162587Sitojun /*timeout*/desc->timeout); 52253541Sshin 52353541Sshin /* Override our wildcard attachment */ 52453541Sshin start_ccb->ccb_h.target_id = atio->ccb_h.target_id; 52553541Sshin start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun; 52653541Sshin 52753541Sshin start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ; 52853541Sshin start_ccb->ccb_h.ccb_atio = atio; 52953541Sshin CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 53053541Sshin ("Sending a CTIO\n")); 53153541Sshin xpt_action(start_ccb); 532192923Sbms s = splbio(); 53353541Sshin ccbh = TAILQ_FIRST(&softc->work_queue); 534126194Sume splx(s); 535126194Sume } 53653541Sshin if (ccbh != NULL) 53753541Sshin xpt_schedule(periph, /*priority*/1); 53862587Sitojun} 53962587Sitojun 54062587Sitojunstatic void 54162587Sitojuntargbhdone(struct cam_periph *periph, union ccb *done_ccb) 54253541Sshin{ 54353541Sshin struct targbh_softc *softc; 54453541Sshin 54553541Sshin softc = (struct targbh_softc *)periph->softc; 546192923Sbms 54753541Sshin if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) { 54853541Sshin /* Caller will release the CCB */ 549151465Ssuz wakeup(&done_ccb->ccb_h.cbfcnp); 550151465Ssuz return; 55153541Sshin } 552151465Ssuz 55353541Sshin switch (done_ccb->ccb_h.func_code) { 55453541Sshin case XPT_ACCEPT_TARGET_IO: 55553541Sshin { 55653541Sshin struct ccb_accept_tio *atio; 55753541Sshin struct targbh_cmd_desc *descr; 55853541Sshin u_int8_t *cdb; 55953541Sshin 56053541Sshin atio = &done_ccb->atio; 561192923Sbms descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr; 56253541Sshin cdb = atio->cdb_io.cdb_bytes; 56353541Sshin if (softc->state == TARGBH_STATE_TEARDOWN 56453541Sshin || atio->ccb_h.status == CAM_REQ_ABORTED) { 56553541Sshin targbhfreedescr(descr); 56653541Sshin free(done_ccb, M_DEVBUF); 56753541Sshin return; 56853541Sshin } 56953541Sshin 57053541Sshin /* 57153541Sshin * Determine the type of incoming command and 57253541Sshin * setup our buffer for a response. 57353541Sshin */ 57453541Sshin switch (cdb[0]) { 57553541Sshin case INQUIRY: 57653541Sshin { 577192923Sbms struct scsi_inquiry *inq; 57853541Sshin 57953541Sshin inq = (struct scsi_inquiry *)cdb; 58053541Sshin CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 58153541Sshin ("Saw an inquiry!\n")); 58253541Sshin /* 58353541Sshin * Validate the command. We don't 58462587Sitojun * support any VPD pages, so complain 58562587Sitojun * if EVPD is set. 58653541Sshin */ 58762587Sitojun if ((inq->byte2 & SI_EVPD) != 0 588108741Ssam || inq->page_code != 0) { 58953541Sshin atio->ccb_h.flags &= ~CAM_DIR_MASK; 590111119Simp atio->ccb_h.flags |= CAM_DIR_NONE; 591111070Ssam /* 592111070Ssam * This needs to have other than a 593111070Ssam * no_lun_sense_data response. 59462587Sitojun */ 595111119Simp atio->sense_data = no_lun_sense_data; 59662587Sitojun atio->sense_len = sizeof (no_lun_sense_data); 59762587Sitojun descr->data_resid = 0; 59862587Sitojun descr->data_increment = 0; 59962587Sitojun descr->status = SCSI_STATUS_CHECK_COND; 60062587Sitojun break; 60153541Sshin } 60253541Sshin /* 60353541Sshin * Direction is always relative 60453541Sshin * to the initator. 60553541Sshin */ 60653541Sshin atio->ccb_h.flags &= ~CAM_DIR_MASK; 60753541Sshin atio->ccb_h.flags |= CAM_DIR_IN; 60853541Sshin descr->data = &no_lun_inq_data; 60953541Sshin descr->data_resid = MIN(sizeof(no_lun_inq_data), 61053541Sshin inq->length); 61153541Sshin descr->data_increment = descr->data_resid; 61253541Sshin descr->timeout = 5 * 1000; 61362587Sitojun descr->status = SCSI_STATUS_OK; 614108741Ssam break; 615108741Ssam } 61653541Sshin case REQUEST_SENSE: 617120891Sume { 61862587Sitojun struct scsi_request_sense *rsense; 61953541Sshin 62062587Sitojun rsense = (struct scsi_request_sense *)cdb; 621108741Ssam /* Refer to static sense data */ 622108741Ssam atio->ccb_h.flags &= ~CAM_DIR_MASK; 62362587Sitojun atio->ccb_h.flags |= CAM_DIR_IN; 62453541Sshin descr->data = &no_lun_sense_data; 62553541Sshin descr->data_resid = request_sense_size; 626166046Sume descr->data_resid = MIN(descr->data_resid, 627166046Sume rsense->length); 62853541Sshin descr->data_increment = descr->data_resid; 62953541Sshin descr->timeout = 5 * 1000; 63053541Sshin descr->status = SCSI_STATUS_OK; 63153541Sshin break; 63253541Sshin } 633190964Srwatson default: 634190964Srwatson /* Constant CA, tell initiator */ 63553541Sshin /* Direction is always relative to the initator */ 63653541Sshin atio->ccb_h.flags &= ~CAM_DIR_MASK; 63753541Sshin atio->ccb_h.flags |= CAM_DIR_NONE; 63853541Sshin atio->sense_data = no_lun_sense_data; 63953541Sshin atio->sense_len = sizeof (no_lun_sense_data); 640192923Sbms descr->data_resid = 0; 64153541Sshin descr->data_increment = 0; 64253541Sshin descr->timeout = 5 * 1000; 64353541Sshin descr->status = SCSI_STATUS_CHECK_COND; 64453541Sshin break; 64596116Sume } 64696116Sume 647191672Sbms /* Queue us up to receive a Continue Target I/O ccb. */ 648191672Sbms TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h, 649191672Sbms periph_links.tqe); 650192923Sbms xpt_schedule(periph, /*priority*/1); 651192923Sbms break; 652192923Sbms } 653192923Sbms case XPT_CONT_TARGET_IO: 654192923Sbms { 655191672Sbms struct ccb_accept_tio *atio; 656191672Sbms struct targbh_cmd_desc *desc; 657191672Sbms 658192923Sbms CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 65962587Sitojun ("Received completed CTIO\n")); 660191672Sbms atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio; 661191672Sbms desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; 66253541Sshin 66353541Sshin TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h, 66453541Sshin periph_links.tqe); 66553541Sshin 66653541Sshin /* 66753541Sshin * We could check for CAM_SENT_SENSE bein set here, 66853541Sshin * but since we're not maintaining any CA/UA state, 669181803Sbz * there's no point. 67062587Sitojun */ 67162587Sitojun atio->sense_len = 0; 67253541Sshin done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 67353541Sshin done_ccb->ccb_h.status &= ~CAM_SENT_SENSE; 67462587Sitojun 67553541Sshin /* XXX Check for errors */ 67653541Sshin desc->data_resid -= desc->data_increment; 67753541Sshin xpt_release_ccb(done_ccb); 67853541Sshin if (softc->state != TARGBH_STATE_TEARDOWN) { 67953541Sshin 68062587Sitojun /* 68153541Sshin * Send the original accept TIO back to the 682120891Sume * controller to handle more work. 68362587Sitojun */ 68462587Sitojun CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 68562587Sitojun ("Returning ATIO to target\n")); 68662587Sitojun /* Restore wildcards */ 68762587Sitojun atio->ccb_h.target_id = CAM_TARGET_WILDCARD; 68853541Sshin atio->ccb_h.target_lun = CAM_LUN_WILDCARD; 68953541Sshin xpt_action((union ccb *)atio); 690193066Sjamie break; 69153541Sshin } else { 692193066Sjamie targbhfreedescr(desc); 69353541Sshin free(atio, M_DEVBUF); 694169664Sjinmei } 695169664Sjinmei break; 696169664Sjinmei } 697169664Sjinmei case XPT_IMMED_NOTIFY: 698181803Sbz { 69978064Sume if (softc->state == TARGBH_STATE_TEARDOWN 70078064Sume || done_ccb->ccb_h.status == CAM_REQ_ABORTED) { 70162587Sitojun printf("Freed an immediate notify\n"); 70262587Sitojun free(done_ccb, M_DEVBUF); 70362587Sitojun } 70462587Sitojun break; 70562587Sitojun } 70662587Sitojun default: 70762587Sitojun panic("targbhdone: Unexpected ccb opcode"); 708111119Simp break; 70962587Sitojun } 710111119Simp} 71162587Sitojun 71262587Sitojun#ifdef NOTYET 71362587Sitojunstatic int 71462587Sitojuntargbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 71562587Sitojun{ 716166619Sbms return 0; 717108466Ssam} 718108466Ssam#endif 719108466Ssam 720108466Ssamstatic struct targbh_cmd_desc* 721108466Ssamtargbhallocdescr() 722108466Ssam{ 723108466Ssam struct targbh_cmd_desc* descr; 724108466Ssam 725108466Ssam /* Allocate the targbh_descr structure */ 726108466Ssam descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr), 72753541Sshin M_DEVBUF, M_NOWAIT); 72853541Sshin if (descr == NULL) 72953541Sshin return (NULL); 73053541Sshin 73178064Sume bzero(descr, sizeof(*descr)); 73262587Sitojun 73362587Sitojun /* Allocate buffer backing store */ 734193066Sjamie descr->backing_store = malloc(MAX_BUF_SIZE, M_DEVBUF, M_NOWAIT); 735193066Sjamie if (descr->backing_store == NULL) { 736194118Sjamie free(descr, M_DEVBUF); 737193066Sjamie return (NULL); 738193066Sjamie } 73953541Sshin descr->max_size = MAX_BUF_SIZE; 74053541Sshin return (descr); 74153541Sshin} 74253541Sshin 74353541Sshinstatic void 74453541Sshintargbhfreedescr(struct targbh_cmd_desc *descr) 74553541Sshin{ 74653541Sshin free(descr->backing_store, M_DEVBUF); 74753541Sshin free(descr, M_DEVBUF); 748194118Sjamie} 749194118Sjamie