scsi_targ_bh.c revision 63172
142650Sgibbs/* 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 * 2850477Speter * $FreeBSD: head/sys/cam/scsi/scsi_targ_bh.c 63172 2000-07-14 19:41:43Z mjacob $ 2942650Sgibbs */ 3042650Sgibbs#include <stddef.h> /* For offsetof */ 3142650Sgibbs 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_extend.h> 4642650Sgibbs#include <cam/cam_periph.h> 4742650Sgibbs#include <cam/cam_queue.h> 4842650Sgibbs#include <cam/cam_xpt_periph.h> 4942650Sgibbs#include <cam/cam_debug.h> 5042650Sgibbs 5142650Sgibbs#include <cam/scsi/scsi_all.h> 5242650Sgibbs#include <cam/scsi/scsi_message.h> 5342650Sgibbs 5442650Sgibbstypedef enum { 5542650Sgibbs TARGBH_STATE_NORMAL, 5642650Sgibbs TARGBH_STATE_EXCEPTION, 5742650Sgibbs TARGBH_STATE_TEARDOWN 5842650Sgibbs} targbh_state; 5942650Sgibbs 6042650Sgibbstypedef enum { 6142650Sgibbs TARGBH_FLAG_NONE = 0x00, 6242650Sgibbs TARGBH_FLAG_LUN_ENABLED = 0x01 6342650Sgibbs} targbh_flags; 6442650Sgibbs 6542650Sgibbstypedef enum { 6642650Sgibbs TARGBH_CCB_WORKQ, 6742650Sgibbs TARGBH_CCB_WAITING 6842650Sgibbs} targbh_ccb_types; 6942650Sgibbs 7044503Sgibbs#define MAX_ACCEPT 8 7142650Sgibbs#define MAX_IMMEDIATE 16 7242650Sgibbs#define MAX_BUF_SIZE 256 /* Max inquiry/sense/mode page transfer */ 7342650Sgibbs 7442650Sgibbs#define MIN(a, b) ((a > b) ? b : a) 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 11542650Sgibbsstatic struct scsi_sense_data no_lun_sense_data = 11642650Sgibbs{ 11742650Sgibbs SSD_CURRENT_ERROR|SSD_ERRCODE_VALID, 11842650Sgibbs 0, 11942650Sgibbs SSD_KEY_NOT_READY, 12044503Sgibbs { 0, 0, 0, 0 }, 12142650Sgibbs /*extra_len*/offsetof(struct scsi_sense_data, fru) 12242650Sgibbs - offsetof(struct scsi_sense_data, extra_len), 12344503Sgibbs { 0, 0, 0, 0 }, 12442650Sgibbs /* Logical Unit Not Supported */ 12542650Sgibbs /*ASC*/0x25, /*ASCQ*/0 12642650Sgibbs}; 12742650Sgibbs 12842650Sgibbsstatic const int request_sense_size = offsetof(struct scsi_sense_data, 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 15342650SgibbsDATA_SET(periphdriver_set, targbhdriver); 15442650Sgibbs 15542650Sgibbsstatic void 15642650Sgibbstargbhinit(void) 15742650Sgibbs{ 15842650Sgibbs cam_status status; 15942650Sgibbs struct cam_path *path; 16042650Sgibbs 16142650Sgibbs /* 16242650Sgibbs * Install a global async callback. This callback will 16342650Sgibbs * receive async callbacks like "new path registered". 16442650Sgibbs */ 16542650Sgibbs status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 16642650Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 16742650Sgibbs 16842650Sgibbs if (status == CAM_REQ_CMP) { 16942650Sgibbs struct ccb_setasync csa; 17042650Sgibbs 17142650Sgibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 17242650Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 17342650Sgibbs csa.event_enable = AC_PATH_REGISTERED; 17442650Sgibbs csa.callback = targbhasync; 17542650Sgibbs csa.callback_arg = NULL; 17642650Sgibbs xpt_action((union ccb *)&csa); 17742650Sgibbs status = csa.ccb_h.status; 17842650Sgibbs xpt_free_path(path); 17942650Sgibbs } 18042650Sgibbs 18142650Sgibbs if (status != CAM_REQ_CMP) { 18242650Sgibbs printf("targbh: Failed to attach master async callback " 18342650Sgibbs "due to status 0x%x!\n", status); 18442650Sgibbs } 18542650Sgibbs} 18642650Sgibbs 18742650Sgibbsstatic void 18842650Sgibbstargbhasync(void *callback_arg, u_int32_t code, 18942650Sgibbs struct cam_path *path, void *arg) 19042650Sgibbs{ 19142650Sgibbs struct cam_periph *periph; 19242650Sgibbs 19342650Sgibbs periph = (struct cam_periph *)callback_arg; 19442650Sgibbs switch (code) { 19542650Sgibbs case AC_PATH_REGISTERED: 19642650Sgibbs { 19742650Sgibbs struct ccb_pathinq *cpi; 19842650Sgibbs struct cam_path *new_path; 19942650Sgibbs cam_status status; 20042650Sgibbs 20142650Sgibbs cpi = (struct ccb_pathinq *)arg; 20242650Sgibbs 20342650Sgibbs /* Only attach to controllers that support target mode */ 20442650Sgibbs if ((cpi->target_sprt & PIT_PROCESSOR) == 0) 20542650Sgibbs break; 20642650Sgibbs 20742650Sgibbs /* 20842650Sgibbs * Allocate a peripheral instance for 20942650Sgibbs * this target instance. 21042650Sgibbs */ 21142650Sgibbs status = xpt_create_path(&new_path, NULL, 21242650Sgibbs xpt_path_path_id(path), 21342650Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 21442650Sgibbs if (status != CAM_REQ_CMP) { 21542650Sgibbs printf("targbhasync: Unable to create path " 21642650Sgibbs "due to status 0x%x\n", status); 21742650Sgibbs break; 21842650Sgibbs } 21942650Sgibbs status = cam_periph_alloc(targbhctor, NULL, targbhdtor, 22042650Sgibbs targbhstart, 22142650Sgibbs "targbh", CAM_PERIPH_BIO, 22242650Sgibbs new_path, targbhasync, 22342650Sgibbs AC_PATH_REGISTERED, 22442650Sgibbs cpi); 22542650Sgibbs xpt_free_path(new_path); 22642650Sgibbs if (status != CAM_REQ_CMP 22742650Sgibbs && status != CAM_REQ_INPROG) 22842650Sgibbs printf("targbhasync: Unable to allocate new periph " 22942650Sgibbs "due to status 0x%x\n", status); 23042650Sgibbs break; 23142650Sgibbs } 23242650Sgibbs case AC_PATH_DEREGISTERED: 23342650Sgibbs { 23442650Sgibbs targbhdislun(periph); 23542650Sgibbs break; 23642650Sgibbs } 23742650Sgibbs default: 23842650Sgibbs break; 23942650Sgibbs } 24042650Sgibbs} 24142650Sgibbs 24242650Sgibbs/* Attempt to enable our lun */ 24342650Sgibbsstatic cam_status 24442650Sgibbstargbhenlun(struct cam_periph *periph) 24542650Sgibbs{ 24642650Sgibbs union ccb immed_ccb; 24742650Sgibbs struct targbh_softc *softc; 24842650Sgibbs cam_status status; 24942650Sgibbs int i; 25042650Sgibbs 25142650Sgibbs softc = (struct targbh_softc *)periph->softc; 25242650Sgibbs 25342650Sgibbs if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0) 25442650Sgibbs return (CAM_REQ_CMP); 25542650Sgibbs 25642650Sgibbs xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1); 25742650Sgibbs immed_ccb.ccb_h.func_code = XPT_EN_LUN; 25842650Sgibbs 25942650Sgibbs /* Don't need support for any vendor specific commands */ 26042650Sgibbs immed_ccb.cel.grp6_len = 0; 26142650Sgibbs immed_ccb.cel.grp7_len = 0; 26242650Sgibbs immed_ccb.cel.enable = 1; 26342650Sgibbs xpt_action(&immed_ccb); 26442650Sgibbs status = immed_ccb.ccb_h.status; 26542650Sgibbs if (status != CAM_REQ_CMP) { 26642650Sgibbs xpt_print_path(periph->path); 26742650Sgibbs printf("targbhenlun - Enable Lun Rejected for status 0x%x\n", 26842650Sgibbs status); 26942650Sgibbs return (status); 27042650Sgibbs } 27142650Sgibbs 27242650Sgibbs softc->flags |= TARGBH_FLAG_LUN_ENABLED; 27342650Sgibbs 27442650Sgibbs /* 27542650Sgibbs * Build up a buffer of accept target I/O 27642650Sgibbs * operations for incoming selections. 27742650Sgibbs */ 27842650Sgibbs for (i = 0; i < MAX_ACCEPT; i++) { 27942650Sgibbs struct ccb_accept_tio *atio; 28042650Sgibbs 28142650Sgibbs atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_DEVBUF, 28242650Sgibbs M_NOWAIT); 28342650Sgibbs if (atio == NULL) { 28442650Sgibbs status = CAM_RESRC_UNAVAIL; 28542650Sgibbs break; 28642650Sgibbs } 28742650Sgibbs 28842650Sgibbs atio->ccb_h.ccb_descr = targbhallocdescr(); 28942650Sgibbs 29042650Sgibbs if (atio->ccb_h.ccb_descr == NULL) { 29142650Sgibbs free(atio, M_DEVBUF); 29242650Sgibbs status = CAM_RESRC_UNAVAIL; 29342650Sgibbs break; 29442650Sgibbs } 29542650Sgibbs 29642650Sgibbs xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1); 29742650Sgibbs atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; 29842650Sgibbs atio->ccb_h.cbfcnp = targbhdone; 29942650Sgibbs xpt_action((union ccb *)atio); 30042650Sgibbs status = atio->ccb_h.status; 30142650Sgibbs if (status != CAM_REQ_INPROG) { 30242650Sgibbs targbhfreedescr(atio->ccb_h.ccb_descr); 30342650Sgibbs free(atio, M_DEVBUF); 30442650Sgibbs break; 30542650Sgibbs } 30642650Sgibbs ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link = 30742650Sgibbs softc->accept_tio_list; 30842650Sgibbs softc->accept_tio_list = atio; 30942650Sgibbs } 31042650Sgibbs 31142650Sgibbs if (i == 0) { 31242650Sgibbs xpt_print_path(periph->path); 31342650Sgibbs printf("targbhenlun - Could not allocate accept tio CCBs: " 31442650Sgibbs "status = 0x%x\n", status); 31542650Sgibbs targbhdislun(periph); 31642650Sgibbs return (CAM_REQ_CMP_ERR); 31742650Sgibbs } 31842650Sgibbs 31942650Sgibbs /* 32042650Sgibbs * Build up a buffer of immediate notify CCBs 32142650Sgibbs * so the SIM can tell us of asynchronous target mode events. 32242650Sgibbs */ 32342650Sgibbs for (i = 0; i < MAX_ACCEPT; i++) { 32442650Sgibbs struct ccb_immed_notify *inot; 32542650Sgibbs 32642650Sgibbs inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_DEVBUF, 32742650Sgibbs M_NOWAIT); 32842650Sgibbs 32942650Sgibbs if (inot == NULL) { 33042650Sgibbs status = CAM_RESRC_UNAVAIL; 33142650Sgibbs break; 33242650Sgibbs } 33342650Sgibbs 33442650Sgibbs xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1); 33542650Sgibbs inot->ccb_h.func_code = XPT_IMMED_NOTIFY; 33642650Sgibbs inot->ccb_h.cbfcnp = targbhdone; 33742650Sgibbs xpt_action((union ccb *)inot); 33842650Sgibbs status = inot->ccb_h.status; 33942650Sgibbs if (status != CAM_REQ_INPROG) { 34042650Sgibbs free(inot, M_DEVBUF); 34142650Sgibbs break; 34242650Sgibbs } 34342650Sgibbs SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h, 34442650Sgibbs periph_links.sle); 34542650Sgibbs } 34642650Sgibbs 34742650Sgibbs if (i == 0) { 34842650Sgibbs xpt_print_path(periph->path); 34942650Sgibbs printf("targbhenlun - Could not allocate immediate notify " 35042650Sgibbs "CCBs: status = 0x%x\n", status); 35142650Sgibbs targbhdislun(periph); 35242650Sgibbs return (CAM_REQ_CMP_ERR); 35342650Sgibbs } 35442650Sgibbs 35542650Sgibbs return (CAM_REQ_CMP); 35642650Sgibbs} 35742650Sgibbs 35842650Sgibbsstatic cam_status 35942650Sgibbstargbhdislun(struct cam_periph *periph) 36042650Sgibbs{ 36142650Sgibbs union ccb ccb; 36242650Sgibbs struct targbh_softc *softc; 36342650Sgibbs struct ccb_accept_tio* atio; 36442650Sgibbs struct ccb_hdr *ccb_h; 36542650Sgibbs 36642650Sgibbs softc = (struct targbh_softc *)periph->softc; 36742650Sgibbs if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0) 36842650Sgibbs return CAM_REQ_CMP; 36942650Sgibbs 37042650Sgibbs /* XXX Block for Continue I/O completion */ 37142650Sgibbs 37242650Sgibbs /* Kill off all ACCECPT and IMMEDIATE CCBs */ 37342650Sgibbs while ((atio = softc->accept_tio_list) != NULL) { 37442650Sgibbs 37542650Sgibbs softc->accept_tio_list = 37642650Sgibbs ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link; 37742650Sgibbs xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); 37842650Sgibbs ccb.cab.ccb_h.func_code = XPT_ABORT; 37942650Sgibbs ccb.cab.abort_ccb = (union ccb *)atio; 38042650Sgibbs xpt_action(&ccb); 38142650Sgibbs } 38242650Sgibbs 38342650Sgibbs while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) { 38442650Sgibbs SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle); 38542650Sgibbs xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); 38642650Sgibbs ccb.cab.ccb_h.func_code = XPT_ABORT; 38742650Sgibbs ccb.cab.abort_ccb = (union ccb *)ccb_h; 38842650Sgibbs xpt_action(&ccb); 38942650Sgibbs } 39042650Sgibbs 39142650Sgibbs /* 39242650Sgibbs * Dissable this lun. 39342650Sgibbs */ 39442650Sgibbs xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1); 39542650Sgibbs ccb.cel.ccb_h.func_code = XPT_EN_LUN; 39642650Sgibbs ccb.cel.enable = 0; 39742650Sgibbs xpt_action(&ccb); 39842650Sgibbs 39942650Sgibbs if (ccb.cel.ccb_h.status != CAM_REQ_CMP) 40042650Sgibbs printf("targbhdislun - Disabling lun on controller failed " 40142650Sgibbs "with status 0x%x\n", ccb.cel.ccb_h.status); 40242650Sgibbs else 40342650Sgibbs softc->flags &= ~TARGBH_FLAG_LUN_ENABLED; 40442650Sgibbs return (ccb.cel.ccb_h.status); 40542650Sgibbs} 40642650Sgibbs 40742650Sgibbsstatic cam_status 40842650Sgibbstargbhctor(struct cam_periph *periph, void *arg) 40942650Sgibbs{ 41042650Sgibbs struct ccb_pathinq *cpi; 41142650Sgibbs struct targbh_softc *softc; 41242650Sgibbs 41342650Sgibbs cpi = (struct ccb_pathinq *)arg; 41442650Sgibbs 41542650Sgibbs /* Allocate our per-instance private storage */ 41642650Sgibbs softc = (struct targbh_softc *)malloc(sizeof(*softc), 41742650Sgibbs M_DEVBUF, M_NOWAIT); 41842650Sgibbs if (softc == NULL) { 41942650Sgibbs printf("targctor: unable to malloc softc\n"); 42042650Sgibbs return (CAM_REQ_CMP_ERR); 42142650Sgibbs } 42242650Sgibbs 42363172Smjacob bzero(softc, sizeof(*softc)); 42442650Sgibbs TAILQ_INIT(&softc->pending_queue); 42542650Sgibbs TAILQ_INIT(&softc->work_queue); 42642650Sgibbs softc->accept_tio_list = NULL; 42742650Sgibbs SLIST_INIT(&softc->immed_notify_slist); 42842650Sgibbs softc->state = TARGBH_STATE_NORMAL; 42942650Sgibbs periph->softc = softc; 43042650Sgibbs softc->init_level++; 43142650Sgibbs 43242650Sgibbs return (targbhenlun(periph)); 43342650Sgibbs} 43442650Sgibbs 43542650Sgibbsstatic void 43642650Sgibbstargbhdtor(struct cam_periph *periph) 43742650Sgibbs{ 43842650Sgibbs struct targbh_softc *softc; 43942650Sgibbs 44042650Sgibbs softc = (struct targbh_softc *)periph->softc; 44142650Sgibbs 44242650Sgibbs softc->state = TARGBH_STATE_TEARDOWN; 44342650Sgibbs 44442650Sgibbs targbhdislun(periph); 44542650Sgibbs 44642650Sgibbs switch (softc->init_level) { 44742650Sgibbs default: 44842650Sgibbs /* FALLTHROUGH */ 44942650Sgibbs case 1: 45042650Sgibbs free(softc, M_DEVBUF); 45142650Sgibbs break; 45242650Sgibbs case 0: 45342650Sgibbs panic("targdtor - impossible init level");; 45442650Sgibbs } 45542650Sgibbs} 45642650Sgibbs 45742650Sgibbsstatic void 45842650Sgibbstargbhstart(struct cam_periph *periph, union ccb *start_ccb) 45942650Sgibbs{ 46042650Sgibbs struct targbh_softc *softc; 46142650Sgibbs struct ccb_hdr *ccbh; 46242650Sgibbs struct ccb_accept_tio *atio; 46342650Sgibbs struct targbh_cmd_desc *desc; 46442650Sgibbs struct ccb_scsiio *csio; 46542650Sgibbs ccb_flags flags; 46642650Sgibbs int s; 46742650Sgibbs 46842650Sgibbs softc = (struct targbh_softc *)periph->softc; 46942650Sgibbs 47042650Sgibbs s = splbio(); 47142650Sgibbs ccbh = TAILQ_FIRST(&softc->work_queue); 47242650Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 47342650Sgibbs start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING; 47442650Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 47542650Sgibbs periph_links.sle); 47642650Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 47742650Sgibbs splx(s); 47842650Sgibbs wakeup(&periph->ccb_list); 47942650Sgibbs } else if (ccbh == NULL) { 48042650Sgibbs splx(s); 48142650Sgibbs xpt_release_ccb(start_ccb); 48242650Sgibbs } else { 48342650Sgibbs TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe); 48442650Sgibbs TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh, 48542650Sgibbs periph_links.tqe); 48642650Sgibbs splx(s); 48742650Sgibbs atio = (struct ccb_accept_tio*)ccbh; 48842650Sgibbs desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; 48942650Sgibbs 49042650Sgibbs /* Is this a tagged request? */ 49142650Sgibbs flags = atio->ccb_h.flags & (CAM_TAG_ACTION_VALID|CAM_DIR_MASK); 49242650Sgibbs 49356594Smjacob csio = &start_ccb->csio; 49442650Sgibbs /* 49542650Sgibbs * If we are done with the transaction, tell the 49642650Sgibbs * controller to send status and perform a CMD_CMPLT. 49756594Smjacob * If we have associated sense data, see if we can 49856594Smjacob * send that too. 49942650Sgibbs */ 50056594Smjacob if (desc->data_resid == desc->data_increment) { 50142650Sgibbs flags |= CAM_SEND_STATUS; 50256594Smjacob if (atio->sense_len) { 50356594Smjacob csio->sense_len = atio->sense_len; 50456594Smjacob csio->sense_data = atio->sense_data; 50556594Smjacob flags |= CAM_SEND_SENSE; 50656594Smjacob } 50742650Sgibbs 50856594Smjacob } 50956594Smjacob 51042650Sgibbs cam_fill_ctio(csio, 51142650Sgibbs /*retries*/2, 51242650Sgibbs targbhdone, 51342650Sgibbs flags, 51442650Sgibbs /*tag_action*/MSG_SIMPLE_Q_TAG, 51542650Sgibbs atio->tag_id, 51642650Sgibbs atio->init_id, 51742650Sgibbs desc->status, 51842650Sgibbs /*data_ptr*/desc->data_increment == 0 51942650Sgibbs ? NULL : desc->data, 52042650Sgibbs /*dxfer_len*/desc->data_increment, 52142650Sgibbs /*timeout*/desc->timeout); 52242650Sgibbs 52342650Sgibbs /* Override our wildcard attachment */ 52442650Sgibbs start_ccb->ccb_h.target_id = atio->ccb_h.target_id; 52542650Sgibbs start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun; 52642650Sgibbs 52742650Sgibbs start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ; 52842650Sgibbs start_ccb->ccb_h.ccb_atio = atio; 52942650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 53042650Sgibbs ("Sending a CTIO\n")); 53142650Sgibbs xpt_action(start_ccb); 53242650Sgibbs s = splbio(); 53342650Sgibbs ccbh = TAILQ_FIRST(&softc->work_queue); 53442650Sgibbs splx(s); 53542650Sgibbs } 53642650Sgibbs if (ccbh != NULL) 53742650Sgibbs xpt_schedule(periph, /*priority*/1); 53842650Sgibbs} 53942650Sgibbs 54042650Sgibbsstatic void 54142650Sgibbstargbhdone(struct cam_periph *periph, union ccb *done_ccb) 54242650Sgibbs{ 54342650Sgibbs struct targbh_softc *softc; 54442650Sgibbs 54542650Sgibbs softc = (struct targbh_softc *)periph->softc; 54642650Sgibbs 54742650Sgibbs if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) { 54842650Sgibbs /* Caller will release the CCB */ 54942650Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 55042650Sgibbs return; 55142650Sgibbs } 55242650Sgibbs 55342650Sgibbs switch (done_ccb->ccb_h.func_code) { 55442650Sgibbs case XPT_ACCEPT_TARGET_IO: 55542650Sgibbs { 55642650Sgibbs struct ccb_accept_tio *atio; 55742650Sgibbs struct targbh_cmd_desc *descr; 55842650Sgibbs u_int8_t *cdb; 55942650Sgibbs 56042650Sgibbs atio = &done_ccb->atio; 56142650Sgibbs descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr; 56242650Sgibbs cdb = atio->cdb_io.cdb_bytes; 56342650Sgibbs if (softc->state == TARGBH_STATE_TEARDOWN 56442650Sgibbs || atio->ccb_h.status == CAM_REQ_ABORTED) { 56542650Sgibbs targbhfreedescr(descr); 56642650Sgibbs free(done_ccb, M_DEVBUF); 56742650Sgibbs return; 56842650Sgibbs } 56942650Sgibbs 57042650Sgibbs /* 57142650Sgibbs * Determine the type of incoming command and 57242650Sgibbs * setup our buffer for a response. 57342650Sgibbs */ 57442650Sgibbs switch (cdb[0]) { 57542650Sgibbs case INQUIRY: 57642650Sgibbs { 57742650Sgibbs struct scsi_inquiry *inq; 57842650Sgibbs 57942650Sgibbs inq = (struct scsi_inquiry *)cdb; 58042650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 58142650Sgibbs ("Saw an inquiry!\n")); 58242650Sgibbs /* 58342650Sgibbs * Validate the command. We don't 58442650Sgibbs * support any VPD pages, so complain 58542650Sgibbs * if EVPD is set. 58642650Sgibbs */ 58742650Sgibbs if ((inq->byte2 & SI_EVPD) != 0 58842650Sgibbs || inq->page_code != 0) { 58942650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 59042650Sgibbs atio->ccb_h.flags |= CAM_DIR_NONE; 59156594Smjacob /* 59256594Smjacob * This needs to have other than a 59356594Smjacob * no_lun_sense_data response. 59456594Smjacob */ 59556594Smjacob atio->sense_data = no_lun_sense_data; 59663172Smjacob atio->sense_len = sizeof(no_lun_sense_data); 59742650Sgibbs descr->data_resid = 0; 59842650Sgibbs descr->data_increment = 0; 59942650Sgibbs descr->status = SCSI_STATUS_CHECK_COND; 60042650Sgibbs break; 60142650Sgibbs } 60242650Sgibbs /* 60342650Sgibbs * Direction is always relative 60442650Sgibbs * to the initator. 60542650Sgibbs */ 60642650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 60742650Sgibbs atio->ccb_h.flags |= CAM_DIR_IN; 60842650Sgibbs descr->data = &no_lun_inq_data; 60942650Sgibbs descr->data_resid = MIN(sizeof(no_lun_inq_data), 61063172Smjacob SCSI_CDB6_LEN(inq->length)); 61142650Sgibbs descr->data_increment = descr->data_resid; 61242650Sgibbs descr->timeout = 5 * 1000; 61342650Sgibbs descr->status = SCSI_STATUS_OK; 61442650Sgibbs break; 61542650Sgibbs } 61642650Sgibbs case REQUEST_SENSE: 61742650Sgibbs { 61842650Sgibbs struct scsi_request_sense *rsense; 61942650Sgibbs 62042650Sgibbs rsense = (struct scsi_request_sense *)cdb; 62142650Sgibbs /* Refer to static sense data */ 62242650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 62342650Sgibbs atio->ccb_h.flags |= CAM_DIR_IN; 62442650Sgibbs descr->data = &no_lun_sense_data; 62542650Sgibbs descr->data_resid = request_sense_size; 62642650Sgibbs descr->data_resid = MIN(descr->data_resid, 62763172Smjacob SCSI_CDB6_LEN(rsense->length)); 62842650Sgibbs descr->data_increment = descr->data_resid; 62942650Sgibbs descr->timeout = 5 * 1000; 63042650Sgibbs descr->status = SCSI_STATUS_OK; 63142650Sgibbs break; 63242650Sgibbs } 63342650Sgibbs default: 63442650Sgibbs /* Constant CA, tell initiator */ 63542650Sgibbs /* Direction is always relative to the initator */ 63642650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 63742650Sgibbs atio->ccb_h.flags |= CAM_DIR_NONE; 63856594Smjacob atio->sense_data = no_lun_sense_data; 63956594Smjacob atio->sense_len = sizeof (no_lun_sense_data); 64042650Sgibbs descr->data_resid = 0; 64142650Sgibbs descr->data_increment = 0; 64242650Sgibbs descr->timeout = 5 * 1000; 64342650Sgibbs descr->status = SCSI_STATUS_CHECK_COND; 64442650Sgibbs break; 64542650Sgibbs } 64642650Sgibbs 64742650Sgibbs /* Queue us up to receive a Continue Target I/O ccb. */ 64842650Sgibbs TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h, 64942650Sgibbs periph_links.tqe); 65042650Sgibbs xpt_schedule(periph, /*priority*/1); 65142650Sgibbs break; 65242650Sgibbs } 65342650Sgibbs case XPT_CONT_TARGET_IO: 65442650Sgibbs { 65542650Sgibbs struct ccb_accept_tio *atio; 65642650Sgibbs struct targbh_cmd_desc *desc; 65742650Sgibbs 65842650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 65942650Sgibbs ("Received completed CTIO\n")); 66042650Sgibbs atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio; 66142650Sgibbs desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; 66242650Sgibbs 66342650Sgibbs TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h, 66442650Sgibbs periph_links.tqe); 66542650Sgibbs 66656594Smjacob /* 66756594Smjacob * We could check for CAM_SENT_SENSE bein set here, 66856594Smjacob * but since we're not maintaining any CA/UA state, 66956594Smjacob * there's no point. 67056594Smjacob */ 67156594Smjacob atio->sense_len = 0; 67256594Smjacob done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 67356594Smjacob done_ccb->ccb_h.status &= ~CAM_SENT_SENSE; 67456594Smjacob 67542650Sgibbs /* XXX Check for errors */ 67642650Sgibbs desc->data_resid -= desc->data_increment; 67742650Sgibbs xpt_release_ccb(done_ccb); 67842650Sgibbs if (softc->state != TARGBH_STATE_TEARDOWN) { 67942650Sgibbs 68042650Sgibbs /* 68142650Sgibbs * Send the original accept TIO back to the 68242650Sgibbs * controller to handle more work. 68342650Sgibbs */ 68442650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 68542650Sgibbs ("Returning ATIO to target\n")); 68642650Sgibbs /* Restore wildcards */ 68742650Sgibbs atio->ccb_h.target_id = CAM_TARGET_WILDCARD; 68842650Sgibbs atio->ccb_h.target_lun = CAM_LUN_WILDCARD; 68942650Sgibbs xpt_action((union ccb *)atio); 69042650Sgibbs break; 69142650Sgibbs } else { 69242650Sgibbs targbhfreedescr(desc); 69342650Sgibbs free(atio, M_DEVBUF); 69442650Sgibbs } 69542650Sgibbs break; 69642650Sgibbs } 69742650Sgibbs case XPT_IMMED_NOTIFY: 69842650Sgibbs { 69942650Sgibbs if (softc->state == TARGBH_STATE_TEARDOWN 70042650Sgibbs || done_ccb->ccb_h.status == CAM_REQ_ABORTED) { 70142650Sgibbs printf("Freed an immediate notify\n"); 70242650Sgibbs free(done_ccb, M_DEVBUF); 70342650Sgibbs } 70442650Sgibbs break; 70542650Sgibbs } 70644503Sgibbs default: 70744503Sgibbs panic("targbhdone: Unexpected ccb opcode"); 70844503Sgibbs break; 70942650Sgibbs } 71042650Sgibbs} 71142650Sgibbs 71244503Sgibbs#ifdef NOTYET 71342650Sgibbsstatic int 71442650Sgibbstargbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 71542650Sgibbs{ 71642650Sgibbs return 0; 71742650Sgibbs} 71844503Sgibbs#endif 71942650Sgibbs 72042650Sgibbsstatic struct targbh_cmd_desc* 72142650Sgibbstargbhallocdescr() 72242650Sgibbs{ 72342650Sgibbs struct targbh_cmd_desc* descr; 72442650Sgibbs 72542650Sgibbs /* Allocate the targbh_descr structure */ 72642650Sgibbs descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr), 72742650Sgibbs M_DEVBUF, M_NOWAIT); 72842650Sgibbs if (descr == NULL) 72942650Sgibbs return (NULL); 73042650Sgibbs 73142650Sgibbs bzero(descr, sizeof(*descr)); 73242650Sgibbs 73342650Sgibbs /* Allocate buffer backing store */ 73442650Sgibbs descr->backing_store = malloc(MAX_BUF_SIZE, M_DEVBUF, M_NOWAIT); 73542650Sgibbs if (descr->backing_store == NULL) { 73642650Sgibbs free(descr, M_DEVBUF); 73742650Sgibbs return (NULL); 73842650Sgibbs } 73942650Sgibbs descr->max_size = MAX_BUF_SIZE; 74042650Sgibbs return (descr); 74142650Sgibbs} 74242650Sgibbs 74342650Sgibbsstatic void 74442650Sgibbstargbhfreedescr(struct targbh_cmd_desc *descr) 74542650Sgibbs{ 74642650Sgibbs free(descr->backing_store, M_DEVBUF); 74742650Sgibbs free(descr, M_DEVBUF); 74842650Sgibbs} 749