diff options
Diffstat (limited to 'sys/cam/scsi/scsi_targ_bh.c')
| -rw-r--r-- | sys/cam/scsi/scsi_targ_bh.c | 715 |
1 files changed, 0 insertions, 715 deletions
diff --git a/sys/cam/scsi/scsi_targ_bh.c b/sys/cam/scsi/scsi_targ_bh.c deleted file mode 100644 index ceddcbe65c60e..0000000000000 --- a/sys/cam/scsi/scsi_targ_bh.c +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Implementation of the Target Mode 'Black Hole device' for CAM. - * - * Copyright (c) 1999 Justin T. Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - */ -#include <stddef.h> /* For offsetof */ - -#include <sys/param.h> -#include <sys/queue.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/types.h> -#include <sys/buf.h> -#include <sys/conf.h> -#include <sys/devicestat.h> -#include <sys/malloc.h> -#include <sys/uio.h> - -#include <cam/cam.h> -#include <cam/cam_ccb.h> -#include <cam/cam_extend.h> -#include <cam/cam_periph.h> -#include <cam/cam_queue.h> -#include <cam/cam_xpt_periph.h> -#include <cam/cam_debug.h> - -#include <cam/scsi/scsi_all.h> -#include <cam/scsi/scsi_message.h> - -typedef enum { - TARGBH_STATE_NORMAL, - TARGBH_STATE_EXCEPTION, - TARGBH_STATE_TEARDOWN -} targbh_state; - -typedef enum { - TARGBH_FLAG_NONE = 0x00, - TARGBH_FLAG_LUN_ENABLED = 0x01 -} targbh_flags; - -typedef enum { - TARGBH_CCB_WORKQ, - TARGBH_CCB_WAITING -} targbh_ccb_types; - -#define MAX_ACCEPT 16 -#define MAX_IMMEDIATE 16 -#define MAX_BUF_SIZE 256 /* Max inquiry/sense/mode page transfer */ - -#define MIN(a, b) ((a > b) ? b : a) - -/* Offsets into our private CCB area for storing accept information */ -#define ccb_type ppriv_field0 -#define ccb_descr ppriv_ptr1 - -/* We stick a pointer to the originating accept TIO in each continue I/O CCB */ -#define ccb_atio ppriv_ptr1 - -TAILQ_HEAD(ccb_queue, ccb_hdr); - -struct targbh_softc { - struct ccb_queue pending_queue; - struct ccb_queue work_queue; - struct ccb_queue unknown_atio_queue; - struct devstat device_stats; - targbh_state state; - targbh_flags flags; - u_int init_level; - u_int inq_data_len; - struct ccb_accept_tio *accept_tio_list; - struct ccb_hdr_slist immed_notify_slist; -}; - -struct targbh_cmd_desc { - struct ccb_accept_tio* atio_link; - u_int data_resid; /* How much left to transfer */ - u_int data_increment;/* Amount to send before next disconnect */ - void* data; /* The data. Can be from backing_store or not */ - void* backing_store;/* Backing store allocated for this descriptor*/ - u_int max_size; /* Size of backing_store */ - u_int32_t timeout; - u_int8_t status; /* Status to return to initiator */ -}; - -static struct scsi_inquiry_data no_lun_inq_data = -{ - T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0, - /* version */2, /* format version */2 -}; - -static struct scsi_sense_data no_lun_sense_data = -{ - SSD_CURRENT_ERROR|SSD_ERRCODE_VALID, - 0, - SSD_KEY_NOT_READY, - 0, 0, 0, 0, - /*extra_len*/offsetof(struct scsi_sense_data, fru) - - offsetof(struct scsi_sense_data, extra_len), - 0, 0, 0, 0, - /* Logical Unit Not Supported */ - /*ASC*/0x25, /*ASCQ*/0 -}; - -static const int request_sense_size = offsetof(struct scsi_sense_data, fru); - -static periph_init_t targbhinit; -static void targbhasync(void *callback_arg, u_int32_t code, - struct cam_path *path, void *arg); -static cam_status targbhenlun(struct cam_periph *periph); -static cam_status targbhdislun(struct cam_periph *periph); -static periph_ctor_t targbhctor; -static periph_dtor_t targbhdtor; -static periph_start_t targbhstart; -static void targbhdone(struct cam_periph *periph, - union ccb *done_ccb); -static int targbherror(union ccb *ccb, u_int32_t cam_flags, - u_int32_t sense_flags); -static struct targbh_cmd_desc* targbhallocdescr(void); -static void targbhfreedescr(struct targbh_cmd_desc *buf); - -static struct periph_driver targbhdriver = -{ - targbhinit, "targbh", - TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0 -}; - -DATA_SET(periphdriver_set, targbhdriver); - -static void -targbhinit(void) -{ - cam_status status; - struct cam_path *path; - - /* - * Install a global async callback. This callback will - * receive async callbacks like "new path registered". - */ - status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - - if (status == CAM_REQ_CMP) { - struct ccb_setasync csa; - - xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_PATH_REGISTERED; - csa.callback = targbhasync; - csa.callback_arg = NULL; - xpt_action((union ccb *)&csa); - status = csa.ccb_h.status; - xpt_free_path(path); - } - - if (status != CAM_REQ_CMP) { - printf("targbh: Failed to attach master async callback " - "due to status 0x%x!\n", status); - } -} - -static void -targbhasync(void *callback_arg, u_int32_t code, - struct cam_path *path, void *arg) -{ - struct cam_periph *periph; - - periph = (struct cam_periph *)callback_arg; - switch (code) { - case AC_PATH_REGISTERED: - { - struct ccb_pathinq *cpi; - struct cam_path *new_path; - cam_status status; - - cpi = (struct ccb_pathinq *)arg; - - /* Only attach to controllers that support target mode */ - if ((cpi->target_sprt & PIT_PROCESSOR) == 0) - break; - - /* - * Allocate a peripheral instance for - * this target instance. - */ - status = xpt_create_path(&new_path, NULL, - xpt_path_path_id(path), - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - if (status != CAM_REQ_CMP) { - printf("targbhasync: Unable to create path " - "due to status 0x%x\n", status); - break; - } - status = cam_periph_alloc(targbhctor, NULL, targbhdtor, - targbhstart, - "targbh", CAM_PERIPH_BIO, - new_path, targbhasync, - AC_PATH_REGISTERED, - cpi); - xpt_free_path(new_path); - if (status != CAM_REQ_CMP - && status != CAM_REQ_INPROG) - printf("targbhasync: Unable to allocate new periph " - "due to status 0x%x\n", status); - break; - } - case AC_PATH_DEREGISTERED: - { - targbhdislun(periph); - break; - } - default: - break; - } -} - -/* Attempt to enable our lun */ -static cam_status -targbhenlun(struct cam_periph *periph) -{ - union ccb immed_ccb; - struct targbh_softc *softc; - cam_status status; - int i; - - softc = (struct targbh_softc *)periph->softc; - - if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0) - return (CAM_REQ_CMP); - - xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1); - immed_ccb.ccb_h.func_code = XPT_EN_LUN; - - /* Don't need support for any vendor specific commands */ - immed_ccb.cel.grp6_len = 0; - immed_ccb.cel.grp7_len = 0; - immed_ccb.cel.enable = 1; - xpt_action(&immed_ccb); - status = immed_ccb.ccb_h.status; - if (status != CAM_REQ_CMP) { - xpt_print_path(periph->path); - printf("targbhenlun - Enable Lun Rejected for status 0x%x\n", - status); - return (status); - } - - softc->flags |= TARGBH_FLAG_LUN_ENABLED; - - /* - * Build up a buffer of accept target I/O - * operations for incoming selections. - */ - for (i = 0; i < MAX_ACCEPT; i++) { - struct ccb_accept_tio *atio; - - atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_DEVBUF, - M_NOWAIT); - if (atio == NULL) { - status = CAM_RESRC_UNAVAIL; - break; - } - - atio->ccb_h.ccb_descr = targbhallocdescr(); - - if (atio->ccb_h.ccb_descr == NULL) { - free(atio, M_DEVBUF); - status = CAM_RESRC_UNAVAIL; - break; - } - - xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1); - atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; - atio->ccb_h.cbfcnp = targbhdone; - xpt_action((union ccb *)atio); - status = atio->ccb_h.status; - if (status != CAM_REQ_INPROG) { - targbhfreedescr(atio->ccb_h.ccb_descr); - free(atio, M_DEVBUF); - break; - } - ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link = - softc->accept_tio_list; - softc->accept_tio_list = atio; - } - - if (i == 0) { - xpt_print_path(periph->path); - printf("targbhenlun - Could not allocate accept tio CCBs: " - "status = 0x%x\n", status); - targbhdislun(periph); - return (CAM_REQ_CMP_ERR); - } - - /* - * Build up a buffer of immediate notify CCBs - * so the SIM can tell us of asynchronous target mode events. - */ - for (i = 0; i < MAX_ACCEPT; i++) { - struct ccb_immed_notify *inot; - - inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_DEVBUF, - M_NOWAIT); - - if (inot == NULL) { - status = CAM_RESRC_UNAVAIL; - break; - } - - xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1); - inot->ccb_h.func_code = XPT_IMMED_NOTIFY; - inot->ccb_h.cbfcnp = targbhdone; - xpt_action((union ccb *)inot); - status = inot->ccb_h.status; - if (status != CAM_REQ_INPROG) { - free(inot, M_DEVBUF); - break; - } - SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h, - periph_links.sle); - } - - if (i == 0) { - xpt_print_path(periph->path); - printf("targbhenlun - Could not allocate immediate notify " - "CCBs: status = 0x%x\n", status); - targbhdislun(periph); - return (CAM_REQ_CMP_ERR); - } - - return (CAM_REQ_CMP); -} - -static cam_status -targbhdislun(struct cam_periph *periph) -{ - union ccb ccb; - struct targbh_softc *softc; - struct ccb_accept_tio* atio; - struct ccb_hdr *ccb_h; - - softc = (struct targbh_softc *)periph->softc; - if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0) - return CAM_REQ_CMP; - - /* XXX Block for Continue I/O completion */ - - /* Kill off all ACCECPT and IMMEDIATE CCBs */ - while ((atio = softc->accept_tio_list) != NULL) { - - softc->accept_tio_list = - ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link; - xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); - ccb.cab.ccb_h.func_code = XPT_ABORT; - ccb.cab.abort_ccb = (union ccb *)atio; - xpt_action(&ccb); - } - - while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) { - SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle); - xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); - ccb.cab.ccb_h.func_code = XPT_ABORT; - ccb.cab.abort_ccb = (union ccb *)ccb_h; - xpt_action(&ccb); - } - - /* - * Dissable this lun. - */ - xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1); - ccb.cel.ccb_h.func_code = XPT_EN_LUN; - ccb.cel.enable = 0; - xpt_action(&ccb); - - if (ccb.cel.ccb_h.status != CAM_REQ_CMP) - printf("targbhdislun - Disabling lun on controller failed " - "with status 0x%x\n", ccb.cel.ccb_h.status); - else - softc->flags &= ~TARGBH_FLAG_LUN_ENABLED; - return (ccb.cel.ccb_h.status); -} - -static cam_status -targbhctor(struct cam_periph *periph, void *arg) -{ - struct ccb_pathinq *cpi; - struct targbh_softc *softc; - - cpi = (struct ccb_pathinq *)arg; - - /* Allocate our per-instance private storage */ - softc = (struct targbh_softc *)malloc(sizeof(*softc), - M_DEVBUF, M_NOWAIT); - if (softc == NULL) { - printf("targctor: unable to malloc softc\n"); - return (CAM_REQ_CMP_ERR); - } - - bzero(softc, sizeof(softc)); - TAILQ_INIT(&softc->pending_queue); - TAILQ_INIT(&softc->work_queue); - softc->accept_tio_list = NULL; - SLIST_INIT(&softc->immed_notify_slist); - softc->state = TARGBH_STATE_NORMAL; - periph->softc = softc; - softc->init_level++; - - return (targbhenlun(periph)); -} - -static void -targbhdtor(struct cam_periph *periph) -{ - struct targbh_softc *softc; - - softc = (struct targbh_softc *)periph->softc; - - softc->state = TARGBH_STATE_TEARDOWN; - - targbhdislun(periph); - - switch (softc->init_level) { - default: - /* FALLTHROUGH */ - case 1: - free(softc, M_DEVBUF); - break; - case 0: - panic("targdtor - impossible init level");; - } -} - -static void -targbhstart(struct cam_periph *periph, union ccb *start_ccb) -{ - struct targbh_softc *softc; - struct ccb_hdr *ccbh; - struct ccb_accept_tio *atio; - struct targbh_cmd_desc *desc; - struct ccb_scsiio *csio; - ccb_flags flags; - int s; - - softc = (struct targbh_softc *)periph->softc; - - s = splbio(); - ccbh = TAILQ_FIRST(&softc->work_queue); - if (periph->immediate_priority <= periph->pinfo.priority) { - start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING; - SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, - periph_links.sle); - periph->immediate_priority = CAM_PRIORITY_NONE; - splx(s); - wakeup(&periph->ccb_list); - } else if (ccbh == NULL) { - splx(s); - xpt_release_ccb(start_ccb); - } else { - TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe); - TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh, - periph_links.tqe); - splx(s); - atio = (struct ccb_accept_tio*)ccbh; - desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; - - /* Is this a tagged request? */ - flags = atio->ccb_h.flags & (CAM_TAG_ACTION_VALID|CAM_DIR_MASK); - - /* - * If we are done with the transaction, tell the - * controller to send status and perform a CMD_CMPLT. - */ - if (desc->data_resid == desc->data_increment) - flags |= CAM_SEND_STATUS; - - csio = &start_ccb->csio; - cam_fill_ctio(csio, - /*retries*/2, - targbhdone, - flags, - /*tag_action*/MSG_SIMPLE_Q_TAG, - atio->tag_id, - atio->init_id, - desc->status, - /*data_ptr*/desc->data_increment == 0 - ? NULL : desc->data, - /*dxfer_len*/desc->data_increment, - /*timeout*/desc->timeout); - - /* Override our wildcard attachment */ - start_ccb->ccb_h.target_id = atio->ccb_h.target_id; - start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun; - - start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ; - start_ccb->ccb_h.ccb_atio = atio; - CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, - ("Sending a CTIO\n")); - xpt_action(start_ccb); - s = splbio(); - ccbh = TAILQ_FIRST(&softc->work_queue); - splx(s); - } - if (ccbh != NULL) - xpt_schedule(periph, /*priority*/1); -} - -static void -targbhdone(struct cam_periph *periph, union ccb *done_ccb) -{ - struct targbh_softc *softc; - - softc = (struct targbh_softc *)periph->softc; - - if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) { - /* Caller will release the CCB */ - wakeup(&done_ccb->ccb_h.cbfcnp); - return; - } - - switch (done_ccb->ccb_h.func_code) { - case XPT_ACCEPT_TARGET_IO: - { - struct ccb_accept_tio *atio; - struct targbh_cmd_desc *descr; - u_int8_t *cdb; - - atio = &done_ccb->atio; - descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr; - cdb = atio->cdb_io.cdb_bytes; - if (softc->state == TARGBH_STATE_TEARDOWN - || atio->ccb_h.status == CAM_REQ_ABORTED) { - targbhfreedescr(descr); - free(done_ccb, M_DEVBUF); - return; - } - - /* - * Determine the type of incoming command and - * setup our buffer for a response. - */ - switch (cdb[0]) { - case INQUIRY: - { - struct scsi_inquiry *inq; - - inq = (struct scsi_inquiry *)cdb; - CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, - ("Saw an inquiry!\n")); - /* - * Validate the command. We don't - * support any VPD pages, so complain - * if EVPD is set. - */ - if ((inq->byte2 & SI_EVPD) != 0 - || inq->page_code != 0) { - atio->ccb_h.flags &= ~CAM_DIR_MASK; - atio->ccb_h.flags |= CAM_DIR_NONE; - descr->data_resid = 0; - descr->data_increment = 0; - descr->status = SCSI_STATUS_CHECK_COND; - break; - } - /* - * Direction is always relative - * to the initator. - */ - atio->ccb_h.flags &= ~CAM_DIR_MASK; - atio->ccb_h.flags |= CAM_DIR_IN; - descr->data = &no_lun_inq_data; - descr->data_resid = MIN(sizeof(no_lun_inq_data), - inq->length); - descr->data_increment = descr->data_resid; - descr->timeout = 5 * 1000; - descr->status = SCSI_STATUS_OK; - break; - } - case REQUEST_SENSE: - { - struct scsi_request_sense *rsense; - - rsense = (struct scsi_request_sense *)cdb; - /* Refer to static sense data */ - atio->ccb_h.flags &= ~CAM_DIR_MASK; - atio->ccb_h.flags |= CAM_DIR_IN; - descr->data = &no_lun_sense_data; - descr->data_resid = request_sense_size; - descr->data_resid = MIN(descr->data_resid, - rsense->length); - descr->data_increment = descr->data_resid; - descr->timeout = 5 * 1000; - descr->status = SCSI_STATUS_OK; - break; - } - default: - /* Constant CA, tell initiator */ - /* Direction is always relative to the initator */ - atio->ccb_h.flags &= ~CAM_DIR_MASK; - atio->ccb_h.flags |= CAM_DIR_NONE; - descr->data_resid = 0; - descr->data_increment = 0; - descr->timeout = 5 * 1000; - descr->status = SCSI_STATUS_CHECK_COND; - break; - } - - /* Queue us up to receive a Continue Target I/O ccb. */ - TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h, - periph_links.tqe); - xpt_schedule(periph, /*priority*/1); - break; - } - case XPT_CONT_TARGET_IO: - { - struct ccb_accept_tio *atio; - struct targbh_cmd_desc *desc; - - CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, - ("Received completed CTIO\n")); - atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio; - desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; - - TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h, - periph_links.tqe); - - /* XXX Check for errors */ - desc->data_resid -= desc->data_increment; - xpt_release_ccb(done_ccb); - if (softc->state != TARGBH_STATE_TEARDOWN) { - - /* - * Send the original accept TIO back to the - * controller to handle more work. - */ - CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, - ("Returning ATIO to target\n")); - /* Restore wildcards */ - atio->ccb_h.target_id = CAM_TARGET_WILDCARD; - atio->ccb_h.target_lun = CAM_LUN_WILDCARD; - xpt_action((union ccb *)atio); - break; - } else { - targbhfreedescr(desc); - free(atio, M_DEVBUF); - } - break; - } - case XPT_IMMED_NOTIFY: - { - if (softc->state == TARGBH_STATE_TEARDOWN - || done_ccb->ccb_h.status == CAM_REQ_ABORTED) { - printf("Freed an immediate notify\n"); - free(done_ccb, M_DEVBUF); - } - break; - } - } -} - -static int -targbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) -{ - return 0; -} - -static struct targbh_cmd_desc* -targbhallocdescr() -{ - struct targbh_cmd_desc* descr; - - /* Allocate the targbh_descr structure */ - descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr), - M_DEVBUF, M_NOWAIT); - if (descr == NULL) - return (NULL); - - bzero(descr, sizeof(*descr)); - - /* Allocate buffer backing store */ - descr->backing_store = malloc(MAX_BUF_SIZE, M_DEVBUF, M_NOWAIT); - if (descr->backing_store == NULL) { - free(descr, M_DEVBUF); - return (NULL); - } - descr->max_size = MAX_BUF_SIZE; - return (descr); -} - -static void -targbhfreedescr(struct targbh_cmd_desc *descr) -{ - free(descr->backing_store, M_DEVBUF); - free(descr, M_DEVBUF); -} |
