scsi_targ_bh.c revision 139743
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: head/sys/cam/scsi/scsi_targ_bh.c 139743 2005-01-05 22:34:37Z imp $"); 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> 4942650Sgibbs 5042650Sgibbs#include <cam/scsi/scsi_all.h> 5142650Sgibbs#include <cam/scsi/scsi_message.h> 5242650Sgibbs 5342650Sgibbstypedef enum { 5442650Sgibbs TARGBH_STATE_NORMAL, 5542650Sgibbs TARGBH_STATE_EXCEPTION, 5642650Sgibbs TARGBH_STATE_TEARDOWN 5742650Sgibbs} targbh_state; 5842650Sgibbs 5942650Sgibbstypedef enum { 6042650Sgibbs TARGBH_FLAG_NONE = 0x00, 6142650Sgibbs TARGBH_FLAG_LUN_ENABLED = 0x01 6242650Sgibbs} targbh_flags; 6342650Sgibbs 6442650Sgibbstypedef enum { 6542650Sgibbs TARGBH_CCB_WORKQ, 6642650Sgibbs TARGBH_CCB_WAITING 6742650Sgibbs} targbh_ccb_types; 6842650Sgibbs 6944503Sgibbs#define MAX_ACCEPT 8 7042650Sgibbs#define MAX_IMMEDIATE 16 7142650Sgibbs#define MAX_BUF_SIZE 256 /* Max inquiry/sense/mode page transfer */ 7242650Sgibbs 7342650Sgibbs/* Offsets into our private CCB area for storing accept information */ 7442650Sgibbs#define ccb_type ppriv_field0 7542650Sgibbs#define ccb_descr ppriv_ptr1 7642650Sgibbs 7742650Sgibbs/* We stick a pointer to the originating accept TIO in each continue I/O CCB */ 7842650Sgibbs#define ccb_atio ppriv_ptr1 7942650Sgibbs 8060938SjakeTAILQ_HEAD(ccb_queue, ccb_hdr); 8142650Sgibbs 8242650Sgibbsstruct targbh_softc { 8342650Sgibbs struct ccb_queue pending_queue; 8442650Sgibbs struct ccb_queue work_queue; 8542650Sgibbs struct ccb_queue unknown_atio_queue; 8642650Sgibbs struct devstat device_stats; 8742650Sgibbs targbh_state state; 8842650Sgibbs targbh_flags flags; 8942650Sgibbs u_int init_level; 9042650Sgibbs u_int inq_data_len; 9142650Sgibbs struct ccb_accept_tio *accept_tio_list; 9242650Sgibbs struct ccb_hdr_slist immed_notify_slist; 9342650Sgibbs}; 9442650Sgibbs 9542650Sgibbsstruct targbh_cmd_desc { 9642650Sgibbs struct ccb_accept_tio* atio_link; 9742650Sgibbs u_int data_resid; /* How much left to transfer */ 9842650Sgibbs u_int data_increment;/* Amount to send before next disconnect */ 9942650Sgibbs void* data; /* The data. Can be from backing_store or not */ 10042650Sgibbs void* backing_store;/* Backing store allocated for this descriptor*/ 10142650Sgibbs u_int max_size; /* Size of backing_store */ 10242650Sgibbs u_int32_t timeout; 10342650Sgibbs u_int8_t status; /* Status to return to initiator */ 10442650Sgibbs}; 10542650Sgibbs 10642650Sgibbsstatic struct scsi_inquiry_data no_lun_inq_data = 10742650Sgibbs{ 10842650Sgibbs T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0, 10942650Sgibbs /* version */2, /* format version */2 11042650Sgibbs}; 11142650Sgibbs 11242650Sgibbsstatic struct scsi_sense_data no_lun_sense_data = 11342650Sgibbs{ 11442650Sgibbs SSD_CURRENT_ERROR|SSD_ERRCODE_VALID, 11542650Sgibbs 0, 11642650Sgibbs SSD_KEY_NOT_READY, 11744503Sgibbs { 0, 0, 0, 0 }, 11842650Sgibbs /*extra_len*/offsetof(struct scsi_sense_data, fru) 11942650Sgibbs - offsetof(struct scsi_sense_data, extra_len), 12044503Sgibbs { 0, 0, 0, 0 }, 12142650Sgibbs /* Logical Unit Not Supported */ 12242650Sgibbs /*ASC*/0x25, /*ASCQ*/0 12342650Sgibbs}; 12442650Sgibbs 12542650Sgibbsstatic const int request_sense_size = offsetof(struct scsi_sense_data, fru); 12642650Sgibbs 12742650Sgibbsstatic periph_init_t targbhinit; 12842650Sgibbsstatic void targbhasync(void *callback_arg, u_int32_t code, 12942650Sgibbs struct cam_path *path, void *arg); 13042650Sgibbsstatic cam_status targbhenlun(struct cam_periph *periph); 13142650Sgibbsstatic cam_status targbhdislun(struct cam_periph *periph); 13242650Sgibbsstatic periph_ctor_t targbhctor; 13342650Sgibbsstatic periph_dtor_t targbhdtor; 13442650Sgibbsstatic periph_start_t targbhstart; 13542650Sgibbsstatic void targbhdone(struct cam_periph *periph, 13642650Sgibbs union ccb *done_ccb); 13744503Sgibbs#ifdef NOTYET 13842650Sgibbsstatic int targbherror(union ccb *ccb, u_int32_t cam_flags, 13942650Sgibbs u_int32_t sense_flags); 14044503Sgibbs#endif 14142650Sgibbsstatic struct targbh_cmd_desc* targbhallocdescr(void); 14242650Sgibbsstatic void targbhfreedescr(struct targbh_cmd_desc *buf); 14342650Sgibbs 14442650Sgibbsstatic struct periph_driver targbhdriver = 14542650Sgibbs{ 14642650Sgibbs targbhinit, "targbh", 14742650Sgibbs TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0 14842650Sgibbs}; 14942650Sgibbs 15072119SpeterPERIPHDRIVER_DECLARE(targbh, targbhdriver); 15142650Sgibbs 15242650Sgibbsstatic void 15342650Sgibbstargbhinit(void) 15442650Sgibbs{ 15542650Sgibbs cam_status status; 15642650Sgibbs struct cam_path *path; 15742650Sgibbs 15842650Sgibbs /* 15942650Sgibbs * Install a global async callback. This callback will 16042650Sgibbs * receive async callbacks like "new path registered". 16142650Sgibbs */ 16242650Sgibbs status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 16342650Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 16442650Sgibbs 16542650Sgibbs if (status == CAM_REQ_CMP) { 16642650Sgibbs struct ccb_setasync csa; 16742650Sgibbs 16842650Sgibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 16942650Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 170120426Ssimokawa csa.event_enable = AC_PATH_REGISTERED | AC_PATH_DEREGISTERED; 17142650Sgibbs csa.callback = targbhasync; 17242650Sgibbs csa.callback_arg = NULL; 17342650Sgibbs xpt_action((union ccb *)&csa); 17442650Sgibbs status = csa.ccb_h.status; 17542650Sgibbs xpt_free_path(path); 17642650Sgibbs } 17742650Sgibbs 17842650Sgibbs if (status != CAM_REQ_CMP) { 17942650Sgibbs printf("targbh: Failed to attach master async callback " 18042650Sgibbs "due to status 0x%x!\n", status); 18142650Sgibbs } 18242650Sgibbs} 18342650Sgibbs 18442650Sgibbsstatic void 18542650Sgibbstargbhasync(void *callback_arg, u_int32_t code, 18642650Sgibbs struct cam_path *path, void *arg) 18742650Sgibbs{ 188120426Ssimokawa struct cam_path *new_path; 189120601Ssimokawa struct ccb_pathinq *cpi; 190120601Ssimokawa path_id_t bus_path_id; 191120426Ssimokawa cam_status status; 19242650Sgibbs 193120601Ssimokawa cpi = (struct ccb_pathinq *)arg; 194120601Ssimokawa if (code == AC_PATH_REGISTERED) 195120601Ssimokawa bus_path_id = cpi->ccb_h.path_id; 196120601Ssimokawa else 197120601Ssimokawa bus_path_id = xpt_path_path_id(path); 198120426Ssimokawa /* 199120426Ssimokawa * Allocate a peripheral instance for 200120426Ssimokawa * this target instance. 201120426Ssimokawa */ 202120426Ssimokawa status = xpt_create_path(&new_path, NULL, 203120601Ssimokawa bus_path_id, 204120426Ssimokawa CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 205120426Ssimokawa if (status != CAM_REQ_CMP) { 206120426Ssimokawa printf("targbhasync: Unable to create path " 207120426Ssimokawa "due to status 0x%x\n", status); 208120426Ssimokawa return; 209120426Ssimokawa } 210120426Ssimokawa 21142650Sgibbs switch (code) { 21242650Sgibbs case AC_PATH_REGISTERED: 21342650Sgibbs { 21442650Sgibbs /* Only attach to controllers that support target mode */ 21542650Sgibbs if ((cpi->target_sprt & PIT_PROCESSOR) == 0) 21642650Sgibbs break; 21742650Sgibbs 21842650Sgibbs status = cam_periph_alloc(targbhctor, NULL, targbhdtor, 21942650Sgibbs targbhstart, 22042650Sgibbs "targbh", CAM_PERIPH_BIO, 22142650Sgibbs new_path, targbhasync, 22242650Sgibbs AC_PATH_REGISTERED, 22342650Sgibbs cpi); 22442650Sgibbs break; 22542650Sgibbs } 22642650Sgibbs case AC_PATH_DEREGISTERED: 22742650Sgibbs { 228120601Ssimokawa struct cam_periph *periph; 229120601Ssimokawa 230120601Ssimokawa if ((periph = cam_periph_find(new_path, "targbh")) != NULL) 231120601Ssimokawa cam_periph_invalidate(periph); 23242650Sgibbs break; 23342650Sgibbs } 23442650Sgibbs default: 23542650Sgibbs break; 23642650Sgibbs } 237120426Ssimokawa xpt_free_path(new_path); 23842650Sgibbs} 23942650Sgibbs 24042650Sgibbs/* Attempt to enable our lun */ 24142650Sgibbsstatic cam_status 24242650Sgibbstargbhenlun(struct cam_periph *periph) 24342650Sgibbs{ 24442650Sgibbs union ccb immed_ccb; 24542650Sgibbs struct targbh_softc *softc; 24642650Sgibbs cam_status status; 24742650Sgibbs int i; 24842650Sgibbs 24942650Sgibbs softc = (struct targbh_softc *)periph->softc; 25042650Sgibbs 25142650Sgibbs if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0) 25242650Sgibbs return (CAM_REQ_CMP); 25342650Sgibbs 25442650Sgibbs xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1); 25542650Sgibbs immed_ccb.ccb_h.func_code = XPT_EN_LUN; 25642650Sgibbs 25742650Sgibbs /* Don't need support for any vendor specific commands */ 25842650Sgibbs immed_ccb.cel.grp6_len = 0; 25942650Sgibbs immed_ccb.cel.grp7_len = 0; 26042650Sgibbs immed_ccb.cel.enable = 1; 26142650Sgibbs xpt_action(&immed_ccb); 26242650Sgibbs status = immed_ccb.ccb_h.status; 26342650Sgibbs if (status != CAM_REQ_CMP) { 26442650Sgibbs xpt_print_path(periph->path); 26571493Smjacob printf("targbhenlun - Enable Lun Rejected with status 0x%x\n", 26642650Sgibbs status); 26742650Sgibbs return (status); 26842650Sgibbs } 26942650Sgibbs 27042650Sgibbs softc->flags |= TARGBH_FLAG_LUN_ENABLED; 27142650Sgibbs 27242650Sgibbs /* 27342650Sgibbs * Build up a buffer of accept target I/O 27442650Sgibbs * operations for incoming selections. 27542650Sgibbs */ 27642650Sgibbs for (i = 0; i < MAX_ACCEPT; i++) { 27742650Sgibbs struct ccb_accept_tio *atio; 27842650Sgibbs 27942650Sgibbs atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_DEVBUF, 28042650Sgibbs M_NOWAIT); 28142650Sgibbs if (atio == NULL) { 28242650Sgibbs status = CAM_RESRC_UNAVAIL; 28342650Sgibbs break; 28442650Sgibbs } 28542650Sgibbs 28642650Sgibbs atio->ccb_h.ccb_descr = targbhallocdescr(); 28742650Sgibbs 28842650Sgibbs if (atio->ccb_h.ccb_descr == NULL) { 28942650Sgibbs free(atio, M_DEVBUF); 29042650Sgibbs status = CAM_RESRC_UNAVAIL; 29142650Sgibbs break; 29242650Sgibbs } 29342650Sgibbs 29442650Sgibbs xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1); 29542650Sgibbs atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; 29642650Sgibbs atio->ccb_h.cbfcnp = targbhdone; 29742650Sgibbs xpt_action((union ccb *)atio); 29842650Sgibbs status = atio->ccb_h.status; 29942650Sgibbs if (status != CAM_REQ_INPROG) { 30042650Sgibbs targbhfreedescr(atio->ccb_h.ccb_descr); 30142650Sgibbs free(atio, M_DEVBUF); 30242650Sgibbs break; 30342650Sgibbs } 30442650Sgibbs ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link = 30542650Sgibbs softc->accept_tio_list; 30642650Sgibbs softc->accept_tio_list = atio; 30742650Sgibbs } 30842650Sgibbs 30942650Sgibbs if (i == 0) { 31042650Sgibbs xpt_print_path(periph->path); 31142650Sgibbs printf("targbhenlun - Could not allocate accept tio CCBs: " 31242650Sgibbs "status = 0x%x\n", status); 31342650Sgibbs targbhdislun(periph); 31442650Sgibbs return (CAM_REQ_CMP_ERR); 31542650Sgibbs } 31642650Sgibbs 31742650Sgibbs /* 31842650Sgibbs * Build up a buffer of immediate notify CCBs 31942650Sgibbs * so the SIM can tell us of asynchronous target mode events. 32042650Sgibbs */ 32142650Sgibbs for (i = 0; i < MAX_ACCEPT; i++) { 32242650Sgibbs struct ccb_immed_notify *inot; 32342650Sgibbs 32442650Sgibbs inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_DEVBUF, 32542650Sgibbs M_NOWAIT); 32642650Sgibbs 32742650Sgibbs if (inot == NULL) { 32842650Sgibbs status = CAM_RESRC_UNAVAIL; 32942650Sgibbs break; 33042650Sgibbs } 33142650Sgibbs 33242650Sgibbs xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1); 33342650Sgibbs inot->ccb_h.func_code = XPT_IMMED_NOTIFY; 33442650Sgibbs inot->ccb_h.cbfcnp = targbhdone; 33542650Sgibbs xpt_action((union ccb *)inot); 33642650Sgibbs status = inot->ccb_h.status; 33742650Sgibbs if (status != CAM_REQ_INPROG) { 33842650Sgibbs free(inot, M_DEVBUF); 33942650Sgibbs break; 34042650Sgibbs } 34142650Sgibbs SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h, 34242650Sgibbs periph_links.sle); 34342650Sgibbs } 34442650Sgibbs 34542650Sgibbs if (i == 0) { 34642650Sgibbs xpt_print_path(periph->path); 34742650Sgibbs printf("targbhenlun - Could not allocate immediate notify " 34842650Sgibbs "CCBs: status = 0x%x\n", status); 34942650Sgibbs targbhdislun(periph); 35042650Sgibbs return (CAM_REQ_CMP_ERR); 35142650Sgibbs } 35242650Sgibbs 35342650Sgibbs return (CAM_REQ_CMP); 35442650Sgibbs} 35542650Sgibbs 35642650Sgibbsstatic cam_status 35742650Sgibbstargbhdislun(struct cam_periph *periph) 35842650Sgibbs{ 35942650Sgibbs union ccb ccb; 36042650Sgibbs struct targbh_softc *softc; 36142650Sgibbs struct ccb_accept_tio* atio; 36242650Sgibbs struct ccb_hdr *ccb_h; 36342650Sgibbs 36442650Sgibbs softc = (struct targbh_softc *)periph->softc; 36542650Sgibbs if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0) 36642650Sgibbs return CAM_REQ_CMP; 36742650Sgibbs 36842650Sgibbs /* XXX Block for Continue I/O completion */ 36942650Sgibbs 37042650Sgibbs /* Kill off all ACCECPT and IMMEDIATE CCBs */ 37142650Sgibbs while ((atio = softc->accept_tio_list) != NULL) { 37242650Sgibbs 37342650Sgibbs softc->accept_tio_list = 37442650Sgibbs ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link; 37542650Sgibbs xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); 37642650Sgibbs ccb.cab.ccb_h.func_code = XPT_ABORT; 37742650Sgibbs ccb.cab.abort_ccb = (union ccb *)atio; 37842650Sgibbs xpt_action(&ccb); 37942650Sgibbs } 38042650Sgibbs 38142650Sgibbs while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) { 38242650Sgibbs SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle); 38342650Sgibbs xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); 38442650Sgibbs ccb.cab.ccb_h.func_code = XPT_ABORT; 38542650Sgibbs ccb.cab.abort_ccb = (union ccb *)ccb_h; 38642650Sgibbs xpt_action(&ccb); 38742650Sgibbs } 38842650Sgibbs 38942650Sgibbs /* 39042650Sgibbs * Dissable this lun. 39142650Sgibbs */ 39242650Sgibbs xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1); 39342650Sgibbs ccb.cel.ccb_h.func_code = XPT_EN_LUN; 39442650Sgibbs ccb.cel.enable = 0; 39542650Sgibbs xpt_action(&ccb); 39642650Sgibbs 39742650Sgibbs if (ccb.cel.ccb_h.status != CAM_REQ_CMP) 39842650Sgibbs printf("targbhdislun - Disabling lun on controller failed " 39942650Sgibbs "with status 0x%x\n", ccb.cel.ccb_h.status); 40042650Sgibbs else 40142650Sgibbs softc->flags &= ~TARGBH_FLAG_LUN_ENABLED; 40242650Sgibbs return (ccb.cel.ccb_h.status); 40342650Sgibbs} 40442650Sgibbs 40542650Sgibbsstatic cam_status 40642650Sgibbstargbhctor(struct cam_periph *periph, void *arg) 40742650Sgibbs{ 40842650Sgibbs struct targbh_softc *softc; 40942650Sgibbs 41042650Sgibbs /* Allocate our per-instance private storage */ 41142650Sgibbs softc = (struct targbh_softc *)malloc(sizeof(*softc), 41242650Sgibbs M_DEVBUF, M_NOWAIT); 41342650Sgibbs if (softc == NULL) { 41442650Sgibbs printf("targctor: unable to malloc softc\n"); 41542650Sgibbs return (CAM_REQ_CMP_ERR); 41642650Sgibbs } 41742650Sgibbs 41863172Smjacob bzero(softc, sizeof(*softc)); 41942650Sgibbs TAILQ_INIT(&softc->pending_queue); 42042650Sgibbs TAILQ_INIT(&softc->work_queue); 42142650Sgibbs softc->accept_tio_list = NULL; 42242650Sgibbs SLIST_INIT(&softc->immed_notify_slist); 42342650Sgibbs softc->state = TARGBH_STATE_NORMAL; 42442650Sgibbs periph->softc = softc; 42542650Sgibbs softc->init_level++; 42642650Sgibbs 42742650Sgibbs return (targbhenlun(periph)); 42842650Sgibbs} 42942650Sgibbs 43042650Sgibbsstatic void 43142650Sgibbstargbhdtor(struct cam_periph *periph) 43242650Sgibbs{ 43342650Sgibbs struct targbh_softc *softc; 43442650Sgibbs 43542650Sgibbs softc = (struct targbh_softc *)periph->softc; 43642650Sgibbs 43742650Sgibbs softc->state = TARGBH_STATE_TEARDOWN; 43842650Sgibbs 43942650Sgibbs targbhdislun(periph); 44042650Sgibbs 44142650Sgibbs switch (softc->init_level) { 442115561Sphk case 0: 443115561Sphk panic("targdtor - impossible init level");; 444115561Sphk case 1: 445115561Sphk /* FALLTHROUGH */ 44642650Sgibbs default: 447120426Ssimokawa /* XXX Wait for callback of targbhdislun() */ 448120426Ssimokawa tsleep(softc, PRIBIO, "targbh", hz/2); 44942650Sgibbs free(softc, M_DEVBUF); 45042650Sgibbs break; 45142650Sgibbs } 45242650Sgibbs} 45342650Sgibbs 45442650Sgibbsstatic void 45542650Sgibbstargbhstart(struct cam_periph *periph, union ccb *start_ccb) 45642650Sgibbs{ 45742650Sgibbs struct targbh_softc *softc; 45842650Sgibbs struct ccb_hdr *ccbh; 45942650Sgibbs struct ccb_accept_tio *atio; 46042650Sgibbs struct targbh_cmd_desc *desc; 46142650Sgibbs struct ccb_scsiio *csio; 46242650Sgibbs ccb_flags flags; 46342650Sgibbs int s; 46442650Sgibbs 46542650Sgibbs softc = (struct targbh_softc *)periph->softc; 46642650Sgibbs 46742650Sgibbs s = splbio(); 46842650Sgibbs ccbh = TAILQ_FIRST(&softc->work_queue); 46942650Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 47042650Sgibbs start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING; 47142650Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 47242650Sgibbs periph_links.sle); 47342650Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 47442650Sgibbs splx(s); 47542650Sgibbs wakeup(&periph->ccb_list); 47642650Sgibbs } else if (ccbh == NULL) { 47742650Sgibbs splx(s); 47842650Sgibbs xpt_release_ccb(start_ccb); 47942650Sgibbs } else { 48042650Sgibbs TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe); 48142650Sgibbs TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh, 48242650Sgibbs periph_links.tqe); 48342650Sgibbs splx(s); 48442650Sgibbs atio = (struct ccb_accept_tio*)ccbh; 48542650Sgibbs desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; 48642650Sgibbs 48742650Sgibbs /* Is this a tagged request? */ 48880573Smjacob flags = atio->ccb_h.flags & 48980573Smjacob (CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK); 49042650Sgibbs 49156594Smjacob csio = &start_ccb->csio; 49242650Sgibbs /* 49342650Sgibbs * If we are done with the transaction, tell the 49442650Sgibbs * controller to send status and perform a CMD_CMPLT. 49556594Smjacob * If we have associated sense data, see if we can 49656594Smjacob * send that too. 49742650Sgibbs */ 49856594Smjacob if (desc->data_resid == desc->data_increment) { 49942650Sgibbs flags |= CAM_SEND_STATUS; 50056594Smjacob if (atio->sense_len) { 50156594Smjacob csio->sense_len = atio->sense_len; 50256594Smjacob csio->sense_data = atio->sense_data; 50356594Smjacob flags |= CAM_SEND_SENSE; 50456594Smjacob } 50542650Sgibbs 50656594Smjacob } 50756594Smjacob 50842650Sgibbs cam_fill_ctio(csio, 50942650Sgibbs /*retries*/2, 51042650Sgibbs targbhdone, 51142650Sgibbs flags, 51263190Smjacob (flags & CAM_TAG_ACTION_VALID)? 51363190Smjacob MSG_SIMPLE_Q_TAG : 0, 51442650Sgibbs atio->tag_id, 51542650Sgibbs atio->init_id, 51642650Sgibbs desc->status, 51742650Sgibbs /*data_ptr*/desc->data_increment == 0 51842650Sgibbs ? NULL : desc->data, 51942650Sgibbs /*dxfer_len*/desc->data_increment, 52042650Sgibbs /*timeout*/desc->timeout); 52142650Sgibbs 52242650Sgibbs /* Override our wildcard attachment */ 52342650Sgibbs start_ccb->ccb_h.target_id = atio->ccb_h.target_id; 52442650Sgibbs start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun; 52542650Sgibbs 52642650Sgibbs start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ; 52742650Sgibbs start_ccb->ccb_h.ccb_atio = atio; 52842650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 52942650Sgibbs ("Sending a CTIO\n")); 53042650Sgibbs xpt_action(start_ccb); 53180573Smjacob /* 53280573Smjacob * If the queue was frozen waiting for the response 53380573Smjacob * to this ATIO (for instance disconnection was disallowed), 53480573Smjacob * then release it now that our response has been queued. 53580573Smjacob */ 53680573Smjacob if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) { 53780573Smjacob cam_release_devq(periph->path, 53880573Smjacob /*relsim_flags*/0, 53980573Smjacob /*reduction*/0, 54080573Smjacob /*timeout*/0, 54180573Smjacob /*getcount_only*/0); 54280573Smjacob atio->ccb_h.status &= ~CAM_DEV_QFRZN; 54380573Smjacob } 54442650Sgibbs s = splbio(); 54542650Sgibbs ccbh = TAILQ_FIRST(&softc->work_queue); 54642650Sgibbs splx(s); 54742650Sgibbs } 54842650Sgibbs if (ccbh != NULL) 54942650Sgibbs xpt_schedule(periph, /*priority*/1); 55042650Sgibbs} 55142650Sgibbs 55242650Sgibbsstatic void 55342650Sgibbstargbhdone(struct cam_periph *periph, union ccb *done_ccb) 55442650Sgibbs{ 55542650Sgibbs struct targbh_softc *softc; 55642650Sgibbs 55742650Sgibbs softc = (struct targbh_softc *)periph->softc; 55842650Sgibbs 55942650Sgibbs if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) { 56042650Sgibbs /* Caller will release the CCB */ 56142650Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 56242650Sgibbs return; 56342650Sgibbs } 56442650Sgibbs 56542650Sgibbs switch (done_ccb->ccb_h.func_code) { 56642650Sgibbs case XPT_ACCEPT_TARGET_IO: 56742650Sgibbs { 56842650Sgibbs struct ccb_accept_tio *atio; 56942650Sgibbs struct targbh_cmd_desc *descr; 57042650Sgibbs u_int8_t *cdb; 57180573Smjacob int priority; 57242650Sgibbs 57342650Sgibbs atio = &done_ccb->atio; 57442650Sgibbs descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr; 57542650Sgibbs cdb = atio->cdb_io.cdb_bytes; 57642650Sgibbs if (softc->state == TARGBH_STATE_TEARDOWN 57742650Sgibbs || atio->ccb_h.status == CAM_REQ_ABORTED) { 57842650Sgibbs targbhfreedescr(descr); 57942650Sgibbs free(done_ccb, M_DEVBUF); 58042650Sgibbs return; 58142650Sgibbs } 58242650Sgibbs 58342650Sgibbs /* 58442650Sgibbs * Determine the type of incoming command and 58542650Sgibbs * setup our buffer for a response. 58642650Sgibbs */ 58742650Sgibbs switch (cdb[0]) { 58842650Sgibbs case INQUIRY: 58942650Sgibbs { 59042650Sgibbs struct scsi_inquiry *inq; 59142650Sgibbs 59242650Sgibbs inq = (struct scsi_inquiry *)cdb; 59342650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 59442650Sgibbs ("Saw an inquiry!\n")); 59542650Sgibbs /* 59642650Sgibbs * Validate the command. We don't 59742650Sgibbs * support any VPD pages, so complain 59842650Sgibbs * if EVPD is set. 59942650Sgibbs */ 60042650Sgibbs if ((inq->byte2 & SI_EVPD) != 0 60142650Sgibbs || inq->page_code != 0) { 60242650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 60342650Sgibbs atio->ccb_h.flags |= CAM_DIR_NONE; 60456594Smjacob /* 60556594Smjacob * This needs to have other than a 60656594Smjacob * no_lun_sense_data response. 60756594Smjacob */ 60856594Smjacob atio->sense_data = no_lun_sense_data; 60963172Smjacob atio->sense_len = sizeof(no_lun_sense_data); 61042650Sgibbs descr->data_resid = 0; 61142650Sgibbs descr->data_increment = 0; 61242650Sgibbs descr->status = SCSI_STATUS_CHECK_COND; 61342650Sgibbs break; 61442650Sgibbs } 61542650Sgibbs /* 61642650Sgibbs * Direction is always relative 61742650Sgibbs * to the initator. 61842650Sgibbs */ 61942650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 62042650Sgibbs atio->ccb_h.flags |= CAM_DIR_IN; 62142650Sgibbs descr->data = &no_lun_inq_data; 62242650Sgibbs descr->data_resid = MIN(sizeof(no_lun_inq_data), 62363172Smjacob SCSI_CDB6_LEN(inq->length)); 62442650Sgibbs descr->data_increment = descr->data_resid; 62542650Sgibbs descr->timeout = 5 * 1000; 62642650Sgibbs descr->status = SCSI_STATUS_OK; 62742650Sgibbs break; 62842650Sgibbs } 62942650Sgibbs case REQUEST_SENSE: 63042650Sgibbs { 63142650Sgibbs struct scsi_request_sense *rsense; 63242650Sgibbs 63342650Sgibbs rsense = (struct scsi_request_sense *)cdb; 63442650Sgibbs /* Refer to static sense data */ 63542650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 63642650Sgibbs atio->ccb_h.flags |= CAM_DIR_IN; 63742650Sgibbs descr->data = &no_lun_sense_data; 63842650Sgibbs descr->data_resid = request_sense_size; 63942650Sgibbs descr->data_resid = MIN(descr->data_resid, 64063172Smjacob SCSI_CDB6_LEN(rsense->length)); 64142650Sgibbs descr->data_increment = descr->data_resid; 64242650Sgibbs descr->timeout = 5 * 1000; 64342650Sgibbs descr->status = SCSI_STATUS_OK; 64442650Sgibbs break; 64542650Sgibbs } 64642650Sgibbs default: 64742650Sgibbs /* Constant CA, tell initiator */ 64842650Sgibbs /* Direction is always relative to the initator */ 64942650Sgibbs atio->ccb_h.flags &= ~CAM_DIR_MASK; 65042650Sgibbs atio->ccb_h.flags |= CAM_DIR_NONE; 65156594Smjacob atio->sense_data = no_lun_sense_data; 65256594Smjacob atio->sense_len = sizeof (no_lun_sense_data); 65342650Sgibbs descr->data_resid = 0; 65442650Sgibbs descr->data_increment = 0; 65542650Sgibbs descr->timeout = 5 * 1000; 65642650Sgibbs descr->status = SCSI_STATUS_CHECK_COND; 65742650Sgibbs break; 65842650Sgibbs } 65942650Sgibbs 66042650Sgibbs /* Queue us up to receive a Continue Target I/O ccb. */ 66180573Smjacob if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) { 66280573Smjacob TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h, 66380573Smjacob periph_links.tqe); 66480573Smjacob priority = 0; 66580573Smjacob } else { 66680573Smjacob TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h, 66780573Smjacob periph_links.tqe); 66880573Smjacob priority = 1; 66980573Smjacob } 67080573Smjacob xpt_schedule(periph, priority); 67142650Sgibbs break; 67242650Sgibbs } 67342650Sgibbs case XPT_CONT_TARGET_IO: 67442650Sgibbs { 67542650Sgibbs struct ccb_accept_tio *atio; 67642650Sgibbs struct targbh_cmd_desc *desc; 67742650Sgibbs 67842650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 67942650Sgibbs ("Received completed CTIO\n")); 68042650Sgibbs atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio; 68142650Sgibbs desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; 68242650Sgibbs 68342650Sgibbs TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h, 68442650Sgibbs periph_links.tqe); 68542650Sgibbs 68656594Smjacob /* 68756594Smjacob * We could check for CAM_SENT_SENSE bein set here, 68856594Smjacob * but since we're not maintaining any CA/UA state, 68956594Smjacob * there's no point. 69056594Smjacob */ 69156594Smjacob atio->sense_len = 0; 69256594Smjacob done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 69356594Smjacob done_ccb->ccb_h.status &= ~CAM_SENT_SENSE; 69456594Smjacob 69580573Smjacob /* 69680573Smjacob * Any errors will not change the data we return, 69780573Smjacob * so make sure the queue is not left frozen. 69880573Smjacob * XXX - At some point there may be errors that 69980573Smjacob * leave us in a connected state with the 70080573Smjacob * initiator... 70180573Smjacob */ 70280573Smjacob if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 70380573Smjacob printf("Releasing Queue\n"); 70480573Smjacob cam_release_devq(done_ccb->ccb_h.path, 70580573Smjacob /*relsim_flags*/0, 70680573Smjacob /*reduction*/0, 70780573Smjacob /*timeout*/0, 70880573Smjacob /*getcount_only*/0); 70980573Smjacob done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 71080573Smjacob } 71142650Sgibbs desc->data_resid -= desc->data_increment; 71242650Sgibbs xpt_release_ccb(done_ccb); 71342650Sgibbs if (softc->state != TARGBH_STATE_TEARDOWN) { 71442650Sgibbs 71542650Sgibbs /* 71642650Sgibbs * Send the original accept TIO back to the 71742650Sgibbs * controller to handle more work. 71842650Sgibbs */ 71942650Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 72042650Sgibbs ("Returning ATIO to target\n")); 72142650Sgibbs /* Restore wildcards */ 72242650Sgibbs atio->ccb_h.target_id = CAM_TARGET_WILDCARD; 72342650Sgibbs atio->ccb_h.target_lun = CAM_LUN_WILDCARD; 72442650Sgibbs xpt_action((union ccb *)atio); 72542650Sgibbs break; 72642650Sgibbs } else { 72742650Sgibbs targbhfreedescr(desc); 72842650Sgibbs free(atio, M_DEVBUF); 72942650Sgibbs } 73042650Sgibbs break; 73142650Sgibbs } 73242650Sgibbs case XPT_IMMED_NOTIFY: 73342650Sgibbs { 73480573Smjacob int frozen; 73580573Smjacob 73680573Smjacob frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0; 73742650Sgibbs if (softc->state == TARGBH_STATE_TEARDOWN 73842650Sgibbs || done_ccb->ccb_h.status == CAM_REQ_ABORTED) { 73942650Sgibbs printf("Freed an immediate notify\n"); 74042650Sgibbs free(done_ccb, M_DEVBUF); 74180573Smjacob } else { 74280573Smjacob /* Requeue for another immediate event */ 74380573Smjacob xpt_action(done_ccb); 74442650Sgibbs } 74580573Smjacob if (frozen != 0) 74680573Smjacob cam_release_devq(periph->path, 74780573Smjacob /*relsim_flags*/0, 74880573Smjacob /*opening reduction*/0, 74980573Smjacob /*timeout*/0, 75080573Smjacob /*getcount_only*/0); 75142650Sgibbs break; 75242650Sgibbs } 75344503Sgibbs default: 75444503Sgibbs panic("targbhdone: Unexpected ccb opcode"); 75544503Sgibbs break; 75642650Sgibbs } 75742650Sgibbs} 75842650Sgibbs 75944503Sgibbs#ifdef NOTYET 76042650Sgibbsstatic int 76142650Sgibbstargbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 76242650Sgibbs{ 76342650Sgibbs return 0; 76442650Sgibbs} 76544503Sgibbs#endif 76642650Sgibbs 76742650Sgibbsstatic struct targbh_cmd_desc* 76842650Sgibbstargbhallocdescr() 76942650Sgibbs{ 77042650Sgibbs struct targbh_cmd_desc* descr; 77142650Sgibbs 77242650Sgibbs /* Allocate the targbh_descr structure */ 77342650Sgibbs descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr), 77442650Sgibbs M_DEVBUF, M_NOWAIT); 77542650Sgibbs if (descr == NULL) 77642650Sgibbs return (NULL); 77742650Sgibbs 77842650Sgibbs bzero(descr, sizeof(*descr)); 77942650Sgibbs 78042650Sgibbs /* Allocate buffer backing store */ 78142650Sgibbs descr->backing_store = malloc(MAX_BUF_SIZE, M_DEVBUF, M_NOWAIT); 78242650Sgibbs if (descr->backing_store == NULL) { 78342650Sgibbs free(descr, M_DEVBUF); 78442650Sgibbs return (NULL); 78542650Sgibbs } 78642650Sgibbs descr->max_size = MAX_BUF_SIZE; 78742650Sgibbs return (descr); 78842650Sgibbs} 78942650Sgibbs 79042650Sgibbsstatic void 79142650Sgibbstargbhfreedescr(struct targbh_cmd_desc *descr) 79242650Sgibbs{ 79342650Sgibbs free(descr->backing_store, M_DEVBUF); 79442650Sgibbs free(descr, M_DEVBUF); 79542650Sgibbs} 796