1139743Simp/*- 242650Sgibbs * Implementation of the Target Mode 'Black Hole device' for CAM. 342650Sgibbs * 442650Sgibbs * Copyright (c) 1999 Justin T. Gibbs. 542650Sgibbs * All rights reserved. 642650Sgibbs * 742650Sgibbs * Redistribution and use in source and binary forms, with or without 842650Sgibbs * modification, are permitted provided that the following conditions 942650Sgibbs * are met: 1042650Sgibbs * 1. Redistributions of source code must retain the above copyright 1142650Sgibbs * notice, this list of conditions, and the following disclaimer, 1242650Sgibbs * without modification, immediately at the beginning of the file. 1342650Sgibbs * 2. The name of the author may not be used to endorse or promote products 1442650Sgibbs * derived from this software without specific prior written permission. 1542650Sgibbs * 1642650Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1742650Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1842650Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1942650Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2042650Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2142650Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2242650Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2342650Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2442650Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2542650Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2642650Sgibbs * SUCH DAMAGE. 2742650Sgibbs */ 2842650Sgibbs 29116162Sobrien#include <sys/cdefs.h> 30116162Sobrien__FBSDID("$FreeBSD$"); 31116162Sobrien 3242650Sgibbs#include <sys/param.h> 3342650Sgibbs#include <sys/queue.h> 3442650Sgibbs#include <sys/systm.h> 3542650Sgibbs#include <sys/kernel.h> 3642650Sgibbs#include <sys/types.h> 3760041Sphk#include <sys/bio.h> 3842650Sgibbs#include <sys/conf.h> 3942650Sgibbs#include <sys/devicestat.h> 4042650Sgibbs#include <sys/malloc.h> 4142650Sgibbs#include <sys/uio.h> 4242650Sgibbs 4342650Sgibbs#include <cam/cam.h> 4442650Sgibbs#include <cam/cam_ccb.h> 4542650Sgibbs#include <cam/cam_periph.h> 4642650Sgibbs#include <cam/cam_queue.h> 4742650Sgibbs#include <cam/cam_xpt_periph.h> 4842650Sgibbs#include <cam/cam_debug.h> 49168752Sscottl#include <cam/cam_sim.h> 5042650Sgibbs 5142650Sgibbs#include <cam/scsi/scsi_all.h> 5242650Sgibbs#include <cam/scsi/scsi_message.h> 5342650Sgibbs 54249132Smavstatic MALLOC_DEFINE(M_SCSIBH, "SCSI bh", "SCSI blackhole buffers"); 55147723Savatar 5642650Sgibbstypedef enum { 5742650Sgibbs TARGBH_STATE_NORMAL, 5842650Sgibbs TARGBH_STATE_EXCEPTION, 5942650Sgibbs TARGBH_STATE_TEARDOWN 6042650Sgibbs} targbh_state; 6142650Sgibbs 6242650Sgibbstypedef enum { 6342650Sgibbs TARGBH_FLAG_NONE = 0x00, 6442650Sgibbs TARGBH_FLAG_LUN_ENABLED = 0x01 6542650Sgibbs} targbh_flags; 6642650Sgibbs 6742650Sgibbstypedef enum { 6842650Sgibbs TARGBH_CCB_WORKQ, 6942650Sgibbs TARGBH_CCB_WAITING 7042650Sgibbs} targbh_ccb_types; 7142650Sgibbs 7244503Sgibbs#define MAX_ACCEPT 8 7342650Sgibbs#define MAX_IMMEDIATE 16 7442650Sgibbs#define MAX_BUF_SIZE 256 /* Max inquiry/sense/mode page transfer */ 7542650Sgibbs 7642650Sgibbs/* Offsets into our private CCB area for storing accept information */ 7742650Sgibbs#define ccb_type ppriv_field0 7842650Sgibbs#define ccb_descr ppriv_ptr1 7942650Sgibbs 8042650Sgibbs/* We stick a pointer to the originating accept TIO in each continue I/O CCB */ 8142650Sgibbs#define ccb_atio ppriv_ptr1 8242650Sgibbs 8360938SjakeTAILQ_HEAD(ccb_queue, ccb_hdr); 8442650Sgibbs 8542650Sgibbsstruct targbh_softc { 8642650Sgibbs struct ccb_queue pending_queue; 8742650Sgibbs struct ccb_queue work_queue; 8842650Sgibbs struct ccb_queue unknown_atio_queue; 8942650Sgibbs struct devstat device_stats; 9042650Sgibbs targbh_state state; 9142650Sgibbs targbh_flags flags; 9242650Sgibbs u_int init_level; 9342650Sgibbs u_int inq_data_len; 9442650Sgibbs struct ccb_accept_tio *accept_tio_list; 9542650Sgibbs struct ccb_hdr_slist immed_notify_slist; 9642650Sgibbs}; 9742650Sgibbs 9842650Sgibbsstruct targbh_cmd_desc { 9942650Sgibbs struct ccb_accept_tio* atio_link; 10042650Sgibbs u_int data_resid; /* How much left to transfer */ 10142650Sgibbs u_int data_increment;/* Amount to send before next disconnect */ 10242650Sgibbs void* data; /* The data. Can be from backing_store or not */ 10342650Sgibbs void* backing_store;/* Backing store allocated for this descriptor*/ 10442650Sgibbs u_int max_size; /* Size of backing_store */ 10542650Sgibbs u_int32_t timeout; 10642650Sgibbs u_int8_t status; /* Status to return to initiator */ 10742650Sgibbs}; 10842650Sgibbs 10942650Sgibbsstatic struct scsi_inquiry_data no_lun_inq_data = 11042650Sgibbs{ 11142650Sgibbs T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0, 11242650Sgibbs /* version */2, /* format version */2 11342650Sgibbs}; 11442650Sgibbs 115226067Skenstatic struct scsi_sense_data_fixed no_lun_sense_data = 11642650Sgibbs{ 11742650Sgibbs SSD_CURRENT_ERROR|SSD_ERRCODE_VALID, 11842650Sgibbs 0, 11942650Sgibbs SSD_KEY_NOT_READY, 12044503Sgibbs { 0, 0, 0, 0 }, 121226067Sken /*extra_len*/offsetof(struct scsi_sense_data_fixed, fru) 122226067Sken - offsetof(struct scsi_sense_data_fixed, extra_len), 12344503Sgibbs { 0, 0, 0, 0 }, 12442650Sgibbs /* Logical Unit Not Supported */ 12542650Sgibbs /*ASC*/0x25, /*ASCQ*/0 12642650Sgibbs}; 12742650Sgibbs 128226067Skenstatic const int request_sense_size = offsetof(struct scsi_sense_data_fixed, fru); 12942650Sgibbs 13042650Sgibbsstatic periph_init_t targbhinit; 13142650Sgibbsstatic void targbhasync(void *callback_arg, u_int32_t code, 13242650Sgibbs struct cam_path *path, void *arg); 13342650Sgibbsstatic cam_status targbhenlun(struct cam_periph *periph); 13442650Sgibbsstatic cam_status targbhdislun(struct cam_periph *periph); 13542650Sgibbsstatic periph_ctor_t targbhctor; 13642650Sgibbsstatic periph_dtor_t targbhdtor; 13742650Sgibbsstatic periph_start_t targbhstart; 13842650Sgibbsstatic void targbhdone(struct cam_periph *periph, 13942650Sgibbs union ccb *done_ccb); 14044503Sgibbs#ifdef NOTYET 14142650Sgibbsstatic int targbherror(union ccb *ccb, u_int32_t cam_flags, 14242650Sgibbs u_int32_t sense_flags); 14344503Sgibbs#endif 14442650Sgibbsstatic struct targbh_cmd_desc* targbhallocdescr(void); 14542650Sgibbsstatic void targbhfreedescr(struct targbh_cmd_desc *buf); 14642650Sgibbs 14742650Sgibbsstatic struct periph_driver targbhdriver = 14842650Sgibbs{ 14942650Sgibbs targbhinit, "targbh", 15042650Sgibbs TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0 15142650Sgibbs}; 15242650Sgibbs 15372119SpeterPERIPHDRIVER_DECLARE(targbh, targbhdriver); 15442650Sgibbs 15542650Sgibbsstatic void 15642650Sgibbstargbhinit(void) 15742650Sgibbs{ 15842650Sgibbs cam_status status; 15942650Sgibbs 16042650Sgibbs /* 16142650Sgibbs * Install a global async callback. This callback will 16242650Sgibbs * receive async callbacks like "new path registered". 16342650Sgibbs */ 164169605Sscottl status = xpt_register_async(AC_PATH_REGISTERED | AC_PATH_DEREGISTERED, 165169605Sscottl targbhasync, NULL, NULL); 16642650Sgibbs 16742650Sgibbs if (status != CAM_REQ_CMP) { 16842650Sgibbs printf("targbh: Failed to attach master async callback " 16942650Sgibbs "due to status 0x%x!\n", status); 17042650Sgibbs } 17142650Sgibbs} 17242650Sgibbs 17342650Sgibbsstatic void 17442650Sgibbstargbhasync(void *callback_arg, u_int32_t code, 17542650Sgibbs struct cam_path *path, void *arg) 17642650Sgibbs{ 177120426Ssimokawa struct cam_path *new_path; 178120601Ssimokawa struct ccb_pathinq *cpi; 179120601Ssimokawa path_id_t bus_path_id; 180120426Ssimokawa cam_status status; 18142650Sgibbs 182120601Ssimokawa cpi = (struct ccb_pathinq *)arg; 183120601Ssimokawa if (code == AC_PATH_REGISTERED) 184120601Ssimokawa bus_path_id = cpi->ccb_h.path_id; 185120601Ssimokawa else 186120601Ssimokawa bus_path_id = xpt_path_path_id(path); 187120426Ssimokawa /* 188120426Ssimokawa * Allocate a peripheral instance for 189120426Ssimokawa * this target instance. 190120426Ssimokawa */ 191120426Ssimokawa status = xpt_create_path(&new_path, NULL, 192120601Ssimokawa bus_path_id, 193120426Ssimokawa CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 194120426Ssimokawa if (status != CAM_REQ_CMP) { 195120426Ssimokawa printf("targbhasync: Unable to create path " 196120426Ssimokawa "due to status 0x%x\n", status); 197120426Ssimokawa return; 198120426Ssimokawa } 199120426Ssimokawa 20042650Sgibbs switch (code) { 20142650Sgibbs case AC_PATH_REGISTERED: 20242650Sgibbs { 20342650Sgibbs /* Only attach to controllers that support target mode */ 20442650Sgibbs if ((cpi->target_sprt & PIT_PROCESSOR) == 0) 20542650Sgibbs break; 20642650Sgibbs 20742650Sgibbs status = cam_periph_alloc(targbhctor, NULL, targbhdtor, 20842650Sgibbs targbhstart, 20942650Sgibbs "targbh", CAM_PERIPH_BIO, 21042650Sgibbs new_path, targbhasync, 21142650Sgibbs AC_PATH_REGISTERED, 21242650Sgibbs cpi); 21342650Sgibbs break; 21442650Sgibbs } 21542650Sgibbs case AC_PATH_DEREGISTERED: 21642650Sgibbs { 217120601Ssimokawa struct cam_periph *periph; 218120601Ssimokawa 219120601Ssimokawa if ((periph = cam_periph_find(new_path, "targbh")) != NULL) 220120601Ssimokawa cam_periph_invalidate(periph); 22142650Sgibbs break; 22242650Sgibbs } 22342650Sgibbs default: 22442650Sgibbs break; 22542650Sgibbs } 226120426Ssimokawa xpt_free_path(new_path); 22742650Sgibbs} 22842650Sgibbs 22942650Sgibbs/* Attempt to enable our lun */ 23042650Sgibbsstatic cam_status 23142650Sgibbstargbhenlun(struct cam_periph *periph) 23242650Sgibbs{ 23342650Sgibbs union ccb immed_ccb; 23442650Sgibbs struct targbh_softc *softc; 23542650Sgibbs cam_status status; 23642650Sgibbs int i; 23742650Sgibbs 23842650Sgibbs softc = (struct targbh_softc *)periph->softc; 23942650Sgibbs 24042650Sgibbs if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0) 24142650Sgibbs return (CAM_REQ_CMP); 24242650Sgibbs 243198382Smav xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 24442650Sgibbs immed_ccb.ccb_h.func_code = XPT_EN_LUN; 24542650Sgibbs 24642650Sgibbs /* Don't need support for any vendor specific commands */ 24742650Sgibbs immed_ccb.cel.grp6_len = 0; 24842650Sgibbs immed_ccb.cel.grp7_len = 0; 24942650Sgibbs immed_ccb.cel.enable = 1; 25042650Sgibbs xpt_action(&immed_ccb); 25142650Sgibbs status = immed_ccb.ccb_h.status; 25242650Sgibbs if (status != CAM_REQ_CMP) { 253164906Smjacob xpt_print(periph->path, 254164906Smjacob "targbhenlun - Enable Lun Rejected with status 0x%x\n", 255164906Smjacob status); 25642650Sgibbs return (status); 25742650Sgibbs } 25842650Sgibbs 25942650Sgibbs softc->flags |= TARGBH_FLAG_LUN_ENABLED; 26042650Sgibbs 26142650Sgibbs /* 26242650Sgibbs * Build up a buffer of accept target I/O 26342650Sgibbs * operations for incoming selections. 26442650Sgibbs */ 26542650Sgibbs for (i = 0; i < MAX_ACCEPT; i++) { 26642650Sgibbs struct ccb_accept_tio *atio; 26742650Sgibbs 268147723Savatar atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_SCSIBH, 26942650Sgibbs M_NOWAIT); 27042650Sgibbs if (atio == NULL) { 27142650Sgibbs status = CAM_RESRC_UNAVAIL; 27242650Sgibbs break; 27342650Sgibbs } 27442650Sgibbs 27542650Sgibbs atio->ccb_h.ccb_descr = targbhallocdescr(); 27642650Sgibbs 27742650Sgibbs if (atio->ccb_h.ccb_descr == NULL) { 278147723Savatar free(atio, M_SCSIBH); 27942650Sgibbs status = CAM_RESRC_UNAVAIL; 28042650Sgibbs break; 28142650Sgibbs } 28242650Sgibbs 283198382Smav xpt_setup_ccb(&atio->ccb_h, periph->path, CAM_PRIORITY_NORMAL); 28442650Sgibbs atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; 28542650Sgibbs atio->ccb_h.cbfcnp = targbhdone; 286255559Smav ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link = 287255559Smav softc->accept_tio_list; 288255559Smav softc->accept_tio_list = atio; 28942650Sgibbs xpt_action((union ccb *)atio); 29042650Sgibbs status = atio->ccb_h.status; 291255559Smav if (status != CAM_REQ_INPROG) 29242650Sgibbs break; 29342650Sgibbs } 29442650Sgibbs 29542650Sgibbs if (i == 0) { 296164906Smjacob xpt_print(periph->path, 297164906Smjacob "targbhenlun - Could not allocate accept tio CCBs: status " 298164906Smjacob "= 0x%x\n", status); 29942650Sgibbs targbhdislun(periph); 30042650Sgibbs return (CAM_REQ_CMP_ERR); 30142650Sgibbs } 30242650Sgibbs 30342650Sgibbs /* 30442650Sgibbs * Build up a buffer of immediate notify CCBs 30542650Sgibbs * so the SIM can tell us of asynchronous target mode events. 30642650Sgibbs */ 30742650Sgibbs for (i = 0; i < MAX_ACCEPT; i++) { 308255562Smav struct ccb_immediate_notify *inot; 30942650Sgibbs 310255562Smav inot = (struct ccb_immediate_notify*)malloc(sizeof(*inot), 311255562Smav M_SCSIBH, M_NOWAIT); 31242650Sgibbs 31342650Sgibbs if (inot == NULL) { 31442650Sgibbs status = CAM_RESRC_UNAVAIL; 31542650Sgibbs break; 31642650Sgibbs } 31742650Sgibbs 318198382Smav xpt_setup_ccb(&inot->ccb_h, periph->path, CAM_PRIORITY_NORMAL); 319255562Smav inot->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; 32042650Sgibbs inot->ccb_h.cbfcnp = targbhdone; 321255559Smav SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h, 322255559Smav periph_links.sle); 32342650Sgibbs xpt_action((union ccb *)inot); 32442650Sgibbs status = inot->ccb_h.status; 325255559Smav if (status != CAM_REQ_INPROG) 32642650Sgibbs break; 32742650Sgibbs } 32842650Sgibbs 32942650Sgibbs if (i == 0) { 330164906Smjacob xpt_print(periph->path, 331164906Smjacob "targbhenlun - Could not allocate immediate notify " 332164906Smjacob "CCBs: status = 0x%x\n", status); 33342650Sgibbs targbhdislun(periph); 33442650Sgibbs return (CAM_REQ_CMP_ERR); 33542650Sgibbs } 33642650Sgibbs 33742650Sgibbs return (CAM_REQ_CMP); 33842650Sgibbs} 33942650Sgibbs 34042650Sgibbsstatic cam_status 34142650Sgibbstargbhdislun(struct cam_periph *periph) 34242650Sgibbs{ 34342650Sgibbs union ccb ccb; 34442650Sgibbs struct targbh_softc *softc; 34542650Sgibbs struct ccb_accept_tio* atio; 34642650Sgibbs struct ccb_hdr *ccb_h; 34742650Sgibbs 34842650Sgibbs softc = (struct targbh_softc *)periph->softc; 34942650Sgibbs if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0) 35042650Sgibbs return CAM_REQ_CMP; 35142650Sgibbs 35242650Sgibbs /* XXX Block for Continue I/O completion */ 35342650Sgibbs 35442650Sgibbs /* Kill off all ACCECPT and IMMEDIATE CCBs */ 35542650Sgibbs while ((atio = softc->accept_tio_list) != NULL) { 35642650Sgibbs 35742650Sgibbs softc->accept_tio_list = 35842650Sgibbs ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link; 359198382Smav xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 36042650Sgibbs ccb.cab.ccb_h.func_code = XPT_ABORT; 36142650Sgibbs ccb.cab.abort_ccb = (union ccb *)atio; 36242650Sgibbs xpt_action(&ccb); 36342650Sgibbs } 36442650Sgibbs 36542650Sgibbs while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) { 36642650Sgibbs SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle); 367198382Smav xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 36842650Sgibbs ccb.cab.ccb_h.func_code = XPT_ABORT; 36942650Sgibbs ccb.cab.abort_ccb = (union ccb *)ccb_h; 37042650Sgibbs xpt_action(&ccb); 37142650Sgibbs } 37242650Sgibbs 37342650Sgibbs /* 37442650Sgibbs * Dissable this lun. 37542650Sgibbs */ 376198382Smav xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 37742650Sgibbs ccb.cel.ccb_h.func_code = XPT_EN_LUN; 37842650Sgibbs ccb.cel.enable = 0; 37942650Sgibbs xpt_action(&ccb); 38042650Sgibbs 38142650Sgibbs if (ccb.cel.ccb_h.status != CAM_REQ_CMP) 38242650Sgibbs printf("targbhdislun - Disabling lun on controller failed " 38342650Sgibbs "with status 0x%x\n", ccb.cel.ccb_h.status); 38442650Sgibbs else 38542650Sgibbs softc->flags &= ~TARGBH_FLAG_LUN_ENABLED; 38642650Sgibbs return (ccb.cel.ccb_h.status); 38742650Sgibbs} 38842650Sgibbs 38942650Sgibbsstatic cam_status 39042650Sgibbstargbhctor(struct cam_periph *periph, void *arg) 39142650Sgibbs{ 39242650Sgibbs struct targbh_softc *softc; 39342650Sgibbs 39442650Sgibbs /* Allocate our per-instance private storage */ 39542650Sgibbs softc = (struct targbh_softc *)malloc(sizeof(*softc), 396147723Savatar M_SCSIBH, M_NOWAIT); 39742650Sgibbs if (softc == NULL) { 39842650Sgibbs printf("targctor: unable to malloc softc\n"); 39942650Sgibbs return (CAM_REQ_CMP_ERR); 40042650Sgibbs } 40142650Sgibbs 40263172Smjacob bzero(softc, sizeof(*softc)); 40342650Sgibbs TAILQ_INIT(&softc->pending_queue); 40442650Sgibbs TAILQ_INIT(&softc->work_queue); 40542650Sgibbs softc->accept_tio_list = NULL; 40642650Sgibbs SLIST_INIT(&softc->immed_notify_slist); 40742650Sgibbs softc->state = TARGBH_STATE_NORMAL; 40842650Sgibbs periph->softc = softc; 40942650Sgibbs softc->init_level++; 41042650Sgibbs 411255559Smav if (targbhenlun(periph) != CAM_REQ_CMP) 412255559Smav cam_periph_invalidate(periph); 413255559Smav return (CAM_REQ_CMP); 41442650Sgibbs} 41542650Sgibbs 41642650Sgibbsstatic void 41742650Sgibbstargbhdtor(struct cam_periph *periph) 41842650Sgibbs{ 41942650Sgibbs struct targbh_softc *softc; 42042650Sgibbs 42142650Sgibbs softc = (struct targbh_softc *)periph->softc; 42242650Sgibbs 42342650Sgibbs softc->state = TARGBH_STATE_TEARDOWN; 42442650Sgibbs 42542650Sgibbs targbhdislun(periph); 42642650Sgibbs 42742650Sgibbs switch (softc->init_level) { 428115561Sphk case 0: 429201758Smbr panic("targdtor - impossible init level"); 430115561Sphk case 1: 431115561Sphk /* FALLTHROUGH */ 43242650Sgibbs default: 433120426Ssimokawa /* XXX Wait for callback of targbhdislun() */ 434168752Sscottl msleep(softc, periph->sim->mtx, PRIBIO, "targbh", hz/2); 435147723Savatar free(softc, M_SCSIBH); 43642650Sgibbs break; 43742650Sgibbs } 43842650Sgibbs} 43942650Sgibbs 44042650Sgibbsstatic void 44142650Sgibbstargbhstart(struct cam_periph *periph, union ccb *start_ccb) 44242650Sgibbs{ 44342650Sgibbs struct targbh_softc *softc; 44442650Sgibbs struct ccb_hdr *ccbh; 44542650Sgibbs struct ccb_accept_tio *atio; 44642650Sgibbs struct targbh_cmd_desc *desc; 44742650Sgibbs struct ccb_scsiio *csio; 44842650Sgibbs ccb_flags flags; 44942650Sgibbs 45042650Sgibbs softc = (struct targbh_softc *)periph->softc; 45142650Sgibbs 45242650Sgibbs ccbh = TAILQ_FIRST(&softc->work_queue); 45342650Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 45442650Sgibbs start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING; 45542650Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 45642650Sgibbs periph_links.sle); 45742650Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 45842650Sgibbs wakeup(&periph->ccb_list); 45942650Sgibbs } else if (ccbh == NULL) { 46042650Sgibbs xpt_release_ccb(start_ccb); 46142650Sgibbs } else { 46242650Sgibbs TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe); 46342650Sgibbs TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh, 46442650Sgibbs periph_links.tqe); 46542650Sgibbs atio = (struct ccb_accept_tio*)ccbh; 46642650Sgibbs desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; 46742650Sgibbs 46842650Sgibbs /* Is this a tagged request? */ 46980573Smjacob flags = atio->ccb_h.flags & 47080573Smjacob (CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK); 47142650Sgibbs 47256594Smjacob csio = &start_ccb->csio; 47342650Sgibbs /* 47442650Sgibbs * If we are done with the transaction, tell the 47542650Sgibbs * controller to send status and perform a CMD_CMPLT. 47656594Smjacob * If we have associated sense data, see if we can 47756594Smjacob * send that too. 47842650Sgibbs */ 47956594Smjacob if (desc->data_resid == desc->data_increment) { 48042650Sgibbs flags |= CAM_SEND_STATUS; 48156594Smjacob if (atio->sense_len) { 48256594Smjacob csio->sense_len = atio->sense_len; 48356594Smjacob csio->sense_data = atio->sense_data; 48456594Smjacob flags |= CAM_SEND_SENSE; 48556594Smjacob } 48642650Sgibbs 48756594Smjacob } 48856594Smjacob 48942650Sgibbs cam_fill_ctio(csio, 49042650Sgibbs /*retries*/2, 49142650Sgibbs targbhdone, 49242650Sgibbs flags, 49363190Smjacob (flags & CAM_TAG_ACTION_VALID)? 49463190Smjacob MSG_SIMPLE_Q_TAG : 0, 49542650Sgibbs atio->tag_id, 49642650Sgibbs atio->init_id, 49742650Sgibbs desc->status, 49842650Sgibbs /*data_ptr*/desc->data_increment == 0 49942650Sgibbs ? NULL : desc->data, 50042650Sgibbs /*dxfer_len*/desc->data_increment, 50142650Sgibbs /*timeout*/desc->timeout); 50242650Sgibbs 50342650Sgibbs /* Override our wildcard attachment */ 50442650Sgibbs start_ccb->ccb_h.target_id = atio->ccb_h.target_id; 50542650Sgibbs start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun; 50642650Sgibbs 50742650Sgibbs start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ; 50842650Sgibbs start_ccb->ccb_h.ccb_atio = atio; 50942650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 51042650Sgibbs ("Sending a CTIO\n")); 51142650Sgibbs xpt_action(start_ccb); 51280573Smjacob /* 51380573Smjacob * If the queue was frozen waiting for the response 51480573Smjacob * to this ATIO (for instance disconnection was disallowed), 51580573Smjacob * then release it now that our response has been queued. 51680573Smjacob */ 51780573Smjacob if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) { 51880573Smjacob cam_release_devq(periph->path, 51980573Smjacob /*relsim_flags*/0, 52080573Smjacob /*reduction*/0, 52180573Smjacob /*timeout*/0, 52280573Smjacob /*getcount_only*/0); 52380573Smjacob atio->ccb_h.status &= ~CAM_DEV_QFRZN; 52480573Smjacob } 52542650Sgibbs ccbh = TAILQ_FIRST(&softc->work_queue); 52642650Sgibbs } 52742650Sgibbs if (ccbh != NULL) 528198382Smav xpt_schedule(periph, CAM_PRIORITY_NORMAL); 52942650Sgibbs} 53042650Sgibbs 53142650Sgibbsstatic void 53242650Sgibbstargbhdone(struct cam_periph *periph, union ccb *done_ccb) 53342650Sgibbs{ 53442650Sgibbs struct targbh_softc *softc; 53542650Sgibbs 53642650Sgibbs softc = (struct targbh_softc *)periph->softc; 53742650Sgibbs 53842650Sgibbs if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) { 53942650Sgibbs /* Caller will release the CCB */ 54042650Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 54142650Sgibbs return; 54242650Sgibbs } 54342650Sgibbs 54442650Sgibbs switch (done_ccb->ccb_h.func_code) { 54542650Sgibbs case XPT_ACCEPT_TARGET_IO: 54642650Sgibbs { 54742650Sgibbs struct ccb_accept_tio *atio; 54842650Sgibbs struct targbh_cmd_desc *descr; 54942650Sgibbs u_int8_t *cdb; 55080573Smjacob int priority; 55142650Sgibbs 55242650Sgibbs atio = &done_ccb->atio; 55342650Sgibbs descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr; 55442650Sgibbs cdb = atio->cdb_io.cdb_bytes; 55542650Sgibbs if (softc->state == TARGBH_STATE_TEARDOWN 55642650Sgibbs || atio->ccb_h.status == CAM_REQ_ABORTED) { 55742650Sgibbs targbhfreedescr(descr); 558147723Savatar xpt_free_ccb(done_ccb); 55942650Sgibbs return; 56042650Sgibbs } 56142650Sgibbs 56242650Sgibbs /* 56342650Sgibbs * Determine the type of incoming command and 56442650Sgibbs * setup our buffer for a response. 56542650Sgibbs */ 56642650Sgibbs switch (cdb[0]) { 56742650Sgibbs case INQUIRY: 56842650Sgibbs { 56942650Sgibbs struct scsi_inquiry *inq; 57042650Sgibbs 57142650Sgibbs inq = (struct scsi_inquiry *)cdb; 57242650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 57342650Sgibbs ("Saw an inquiry!\n")); 57442650Sgibbs /* 57542650Sgibbs * Validate the command. We don't 57642650Sgibbs * support any VPD pages, so complain 57742650Sgibbs * if EVPD is set. 57842650Sgibbs */ 57942650Sgibbs if ((inq->byte2 & SI_EVPD) != 0 58042650Sgibbs || inq->page_code != 0) { 58142650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 58242650Sgibbs atio->ccb_h.flags |= CAM_DIR_NONE; 58356594Smjacob /* 58456594Smjacob * This needs to have other than a 58556594Smjacob * no_lun_sense_data response. 58656594Smjacob */ 587226067Sken bcopy(&no_lun_sense_data, &atio->sense_data, 588226067Sken min(sizeof(no_lun_sense_data), 589226067Sken sizeof(atio->sense_data))); 59063172Smjacob atio->sense_len = sizeof(no_lun_sense_data); 59142650Sgibbs descr->data_resid = 0; 59242650Sgibbs descr->data_increment = 0; 59342650Sgibbs descr->status = SCSI_STATUS_CHECK_COND; 59442650Sgibbs break; 59542650Sgibbs } 59642650Sgibbs /* 59742650Sgibbs * Direction is always relative 59842650Sgibbs * to the initator. 59942650Sgibbs */ 60042650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 60142650Sgibbs atio->ccb_h.flags |= CAM_DIR_IN; 60242650Sgibbs descr->data = &no_lun_inq_data; 60342650Sgibbs descr->data_resid = MIN(sizeof(no_lun_inq_data), 604231772Sken scsi_2btoul(inq->length)); 60542650Sgibbs descr->data_increment = descr->data_resid; 60642650Sgibbs descr->timeout = 5 * 1000; 60742650Sgibbs descr->status = SCSI_STATUS_OK; 60842650Sgibbs break; 60942650Sgibbs } 61042650Sgibbs case REQUEST_SENSE: 61142650Sgibbs { 61242650Sgibbs struct scsi_request_sense *rsense; 61342650Sgibbs 61442650Sgibbs rsense = (struct scsi_request_sense *)cdb; 61542650Sgibbs /* Refer to static sense data */ 61642650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 61742650Sgibbs atio->ccb_h.flags |= CAM_DIR_IN; 61842650Sgibbs descr->data = &no_lun_sense_data; 61942650Sgibbs descr->data_resid = request_sense_size; 62042650Sgibbs descr->data_resid = MIN(descr->data_resid, 62163172Smjacob SCSI_CDB6_LEN(rsense->length)); 62242650Sgibbs descr->data_increment = descr->data_resid; 62342650Sgibbs descr->timeout = 5 * 1000; 62442650Sgibbs descr->status = SCSI_STATUS_OK; 62542650Sgibbs break; 62642650Sgibbs } 62742650Sgibbs default: 62842650Sgibbs /* Constant CA, tell initiator */ 62942650Sgibbs /* Direction is always relative to the initator */ 63042650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 63142650Sgibbs atio->ccb_h.flags |= CAM_DIR_NONE; 632226067Sken bcopy(&no_lun_sense_data, &atio->sense_data, 633226067Sken min(sizeof(no_lun_sense_data), 634226067Sken sizeof(atio->sense_data))); 63556594Smjacob atio->sense_len = sizeof (no_lun_sense_data); 63642650Sgibbs descr->data_resid = 0; 63742650Sgibbs descr->data_increment = 0; 63842650Sgibbs descr->timeout = 5 * 1000; 63942650Sgibbs descr->status = SCSI_STATUS_CHECK_COND; 64042650Sgibbs break; 64142650Sgibbs } 64242650Sgibbs 64342650Sgibbs /* Queue us up to receive a Continue Target I/O ccb. */ 64480573Smjacob if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) { 64580573Smjacob TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h, 64680573Smjacob periph_links.tqe); 64780573Smjacob priority = 0; 64880573Smjacob } else { 64980573Smjacob TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h, 65080573Smjacob periph_links.tqe); 651198382Smav priority = CAM_PRIORITY_NORMAL; 65280573Smjacob } 65380573Smjacob xpt_schedule(periph, priority); 65442650Sgibbs break; 65542650Sgibbs } 65642650Sgibbs case XPT_CONT_TARGET_IO: 65742650Sgibbs { 65842650Sgibbs struct ccb_accept_tio *atio; 65942650Sgibbs struct targbh_cmd_desc *desc; 66042650Sgibbs 66142650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 66242650Sgibbs ("Received completed CTIO\n")); 66342650Sgibbs atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio; 66442650Sgibbs desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; 66542650Sgibbs 66642650Sgibbs TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h, 66742650Sgibbs periph_links.tqe); 66842650Sgibbs 66956594Smjacob /* 67056594Smjacob * We could check for CAM_SENT_SENSE bein set here, 67156594Smjacob * but since we're not maintaining any CA/UA state, 67256594Smjacob * there's no point. 67356594Smjacob */ 67456594Smjacob atio->sense_len = 0; 67556594Smjacob done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 67656594Smjacob done_ccb->ccb_h.status &= ~CAM_SENT_SENSE; 67756594Smjacob 67880573Smjacob /* 67980573Smjacob * Any errors will not change the data we return, 68080573Smjacob * so make sure the queue is not left frozen. 68180573Smjacob * XXX - At some point there may be errors that 68280573Smjacob * leave us in a connected state with the 68380573Smjacob * initiator... 68480573Smjacob */ 68580573Smjacob if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 68680573Smjacob printf("Releasing Queue\n"); 68780573Smjacob cam_release_devq(done_ccb->ccb_h.path, 68880573Smjacob /*relsim_flags*/0, 68980573Smjacob /*reduction*/0, 69080573Smjacob /*timeout*/0, 69180573Smjacob /*getcount_only*/0); 69280573Smjacob done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 69380573Smjacob } 69442650Sgibbs desc->data_resid -= desc->data_increment; 69542650Sgibbs xpt_release_ccb(done_ccb); 69642650Sgibbs if (softc->state != TARGBH_STATE_TEARDOWN) { 69742650Sgibbs 69842650Sgibbs /* 69942650Sgibbs * Send the original accept TIO back to the 70042650Sgibbs * controller to handle more work. 70142650Sgibbs */ 70242650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 70342650Sgibbs ("Returning ATIO to target\n")); 70442650Sgibbs /* Restore wildcards */ 70542650Sgibbs atio->ccb_h.target_id = CAM_TARGET_WILDCARD; 70642650Sgibbs atio->ccb_h.target_lun = CAM_LUN_WILDCARD; 70742650Sgibbs xpt_action((union ccb *)atio); 70842650Sgibbs break; 70942650Sgibbs } else { 71042650Sgibbs targbhfreedescr(desc); 711147723Savatar free(atio, M_SCSIBH); 71242650Sgibbs } 71342650Sgibbs break; 71442650Sgibbs } 715255562Smav case XPT_IMMEDIATE_NOTIFY: 71642650Sgibbs { 71780573Smjacob int frozen; 71880573Smjacob 71980573Smjacob frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0; 72042650Sgibbs if (softc->state == TARGBH_STATE_TEARDOWN 72142650Sgibbs || done_ccb->ccb_h.status == CAM_REQ_ABORTED) { 72242650Sgibbs printf("Freed an immediate notify\n"); 723147723Savatar xpt_free_ccb(done_ccb); 72480573Smjacob } else { 72580573Smjacob /* Requeue for another immediate event */ 72680573Smjacob xpt_action(done_ccb); 72742650Sgibbs } 72880573Smjacob if (frozen != 0) 72980573Smjacob cam_release_devq(periph->path, 73080573Smjacob /*relsim_flags*/0, 73180573Smjacob /*opening reduction*/0, 73280573Smjacob /*timeout*/0, 73380573Smjacob /*getcount_only*/0); 73442650Sgibbs break; 73542650Sgibbs } 73644503Sgibbs default: 73744503Sgibbs panic("targbhdone: Unexpected ccb opcode"); 73844503Sgibbs break; 73942650Sgibbs } 74042650Sgibbs} 74142650Sgibbs 74244503Sgibbs#ifdef NOTYET 74342650Sgibbsstatic int 74442650Sgibbstargbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 74542650Sgibbs{ 74642650Sgibbs return 0; 74742650Sgibbs} 74844503Sgibbs#endif 74942650Sgibbs 75042650Sgibbsstatic struct targbh_cmd_desc* 75142650Sgibbstargbhallocdescr() 75242650Sgibbs{ 75342650Sgibbs struct targbh_cmd_desc* descr; 75442650Sgibbs 75542650Sgibbs /* Allocate the targbh_descr structure */ 75642650Sgibbs descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr), 757147723Savatar M_SCSIBH, M_NOWAIT); 75842650Sgibbs if (descr == NULL) 75942650Sgibbs return (NULL); 76042650Sgibbs 76142650Sgibbs bzero(descr, sizeof(*descr)); 76242650Sgibbs 76342650Sgibbs /* Allocate buffer backing store */ 764147723Savatar descr->backing_store = malloc(MAX_BUF_SIZE, M_SCSIBH, M_NOWAIT); 76542650Sgibbs if (descr->backing_store == NULL) { 766147723Savatar free(descr, M_SCSIBH); 76742650Sgibbs return (NULL); 76842650Sgibbs } 76942650Sgibbs descr->max_size = MAX_BUF_SIZE; 77042650Sgibbs return (descr); 77142650Sgibbs} 77242650Sgibbs 77342650Sgibbsstatic void 77442650Sgibbstargbhfreedescr(struct targbh_cmd_desc *descr) 77542650Sgibbs{ 776147723Savatar free(descr->backing_store, M_SCSIBH); 777147723Savatar free(descr, M_SCSIBH); 77842650Sgibbs} 779