1171568Sscottl/*- 2211095Sdes * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il> 3171568Sscottl * All rights reserved. 4171568Sscottl * 5171568Sscottl * Redistribution and use in source and binary forms, with or without 6171568Sscottl * modification, are permitted provided that the following conditions 7171568Sscottl * are met: 8171568Sscottl * 1. Redistributions of source code must retain the above copyright 9171568Sscottl * notice, this list of conditions and the following disclaimer. 10171568Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11171568Sscottl * notice, this list of conditions and the following disclaimer in the 12171568Sscottl * documentation and/or other materials provided with the distribution. 13171568Sscottl * 14171568Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15171568Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16171568Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17171568Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18171568Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19171568Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20171568Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21171568Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22171568Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23171568Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24171568Sscottl * SUCH DAMAGE. 25171568Sscottl * 26171568Sscottl */ 27211095Sdes/* 28211095Sdes | $Id: isc_cam.c 998 2009-12-20 10:32:45Z danny $ 29211095Sdes */ 30171568Sscottl#include <sys/cdefs.h> 31171568Sscottl__FBSDID("$FreeBSD: releng/11.0/sys/dev/iscsi_initiator/isc_cam.c 298955 2016-05-03 03:41:25Z pfg $"); 32171568Sscottl 33171568Sscottl#include "opt_iscsi_initiator.h" 34171568Sscottl 35171568Sscottl#include <sys/param.h> 36171568Sscottl#include <sys/kernel.h> 37171568Sscottl#include <sys/callout.h> 38171568Sscottl#if __FreeBSD_version >= 700000 39171568Sscottl#include <sys/lock.h> 40171568Sscottl#include <sys/mutex.h> 41171568Sscottl#endif 42171568Sscottl#include <sys/conf.h> 43171568Sscottl#include <sys/systm.h> 44171568Sscottl#include <sys/malloc.h> 45171568Sscottl#include <sys/mbuf.h> 46171568Sscottl#include <sys/uio.h> 47171568Sscottl#include <sys/sysctl.h> 48211095Sdes#include <sys/sx.h> 49295126Sglebius#include <vm/uma.h> 50171568Sscottl 51171568Sscottl#include <cam/cam.h> 52171568Sscottl#include <cam/cam_ccb.h> 53171568Sscottl#include <cam/cam_sim.h> 54171568Sscottl#include <cam/cam_xpt_sim.h> 55171568Sscottl#include <cam/cam_periph.h> 56171568Sscottl 57254657Strasz#include <dev/iscsi_initiator/iscsi.h> 58254657Strasz#include <dev/iscsi_initiator/iscsivar.h> 59171568Sscottl 60211095Sdesstatic void 61211095Sdes_inq(struct cam_sim *sim, union ccb *ccb) 62171568Sscottl{ 63211095Sdes struct ccb_pathinq *cpi = &ccb->cpi; 64211095Sdes isc_session_t *sp = cam_sim_softc(sim); 65211095Sdes 66171568Sscottl debug_called(8); 67257381Snwhitehorn debug(3, "sid=%d target=%d lun=%jx", sp->sid, ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun); 68211095Sdes 69211095Sdes cpi->version_num = 1; /* XXX??? */ 70211095Sdes cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_32; 71211095Sdes cpi->target_sprt = 0; 72211095Sdes cpi->hba_misc = 0; 73211095Sdes cpi->hba_eng_cnt = 0; 74211095Sdes cpi->max_target = 0; //ISCSI_MAX_TARGETS - 1; 75211095Sdes cpi->initiator_id = ISCSI_MAX_TARGETS; 76211095Sdes cpi->max_lun = sp->opt.maxluns - 1; 77211095Sdes cpi->bus_id = cam_sim_bus(sim); 78211095Sdes cpi->base_transfer_speed = 3300; // 40000; // XXX: 79211095Sdes strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 80211095Sdes strncpy(cpi->hba_vid, "iSCSI", HBA_IDLEN); 81211095Sdes strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 82211095Sdes cpi->unit_number = cam_sim_unit(sim); 83211095Sdes cpi->ccb_h.status = CAM_REQ_CMP; 84211095Sdes#if defined(KNOB_VALID_ADDRESS) 85211095Sdes cpi->transport = XPORT_ISCSI; 86211095Sdes cpi->transport_version = 0; 87171568Sscottl#endif 88171568Sscottl} 89171568Sscottl 90211095Sdesstatic __inline int 91211095Sdes_scsi_encap(struct cam_sim *sim, union ccb *ccb) 92171568Sscottl{ 93211095Sdes int ret; 94211095Sdes 95211095Sdes#if __FreeBSD_version < 700000 96211095Sdes ret = scsi_encap(sim, ccb); 97211095Sdes#else 98211095Sdes isc_session_t *sp = cam_sim_softc(sim); 99211095Sdes 100211095Sdes mtx_unlock(&sp->cam_mtx); 101211095Sdes ret = scsi_encap(sim, ccb); 102211095Sdes mtx_lock(&sp->cam_mtx); 103171568Sscottl#endif 104211095Sdes return ret; 105171568Sscottl} 106171568Sscottl 107171568Sscottlvoid 108171568Sscottlic_lost_target(isc_session_t *sp, int target) 109171568Sscottl{ 110211095Sdes debug_called(8); 111211095Sdes sdebug(2, "lost target=%d", target); 112171568Sscottl 113171568Sscottl if(sp->cam_path != NULL) { 114211095Sdes mtx_lock(&sp->cam_mtx); 115171568Sscottl xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL); 116171568Sscottl xpt_free_path(sp->cam_path); 117211095Sdes mtx_unlock(&sp->cam_mtx); 118171568Sscottl sp->cam_path = 0; // XXX 119171568Sscottl } 120171568Sscottl} 121171568Sscottl 122171568Sscottlstatic void 123211095Sdesscan_callback(struct cam_periph *periph, union ccb *ccb) 124171568Sscottl{ 125171568Sscottl isc_session_t *sp = (isc_session_t *)ccb->ccb_h.spriv_ptr0; 126171568Sscottl 127171568Sscottl debug_called(8); 128171568Sscottl 129272308Smav xpt_free_ccb(ccb); 130171568Sscottl 131211095Sdes if(sp->flags & ISC_SCANWAIT) { 132211095Sdes sp->flags &= ~ISC_SCANWAIT; 133171568Sscottl wakeup(sp); 134171568Sscottl } 135171568Sscottl} 136171568Sscottl 137211095Sdesstatic int 138211095Sdesic_scan(isc_session_t *sp) 139171568Sscottl{ 140211095Sdes union ccb *ccb; 141171568Sscottl 142171568Sscottl debug_called(8); 143211095Sdes sdebug(2, "scanning sid=%d", sp->sid); 144171568Sscottl 145211095Sdes sp->flags &= ~ISC_CAMDEVS; 146211095Sdes sp->flags |= ISC_SCANWAIT; 147211095Sdes 148272308Smav ccb = xpt_alloc_ccb(); 149272308Smav ccb->ccb_h.path = sp->cam_path; 150211095Sdes ccb->ccb_h.cbfcnp = scan_callback; 151171568Sscottl ccb->ccb_h.spriv_ptr0 = sp; 152171568Sscottl 153272308Smav xpt_rescan(ccb); 154171568Sscottl 155211095Sdes while(sp->flags & ISC_SCANWAIT) 156171568Sscottl tsleep(sp, PRIBIO, "ffp", 5*hz); // the timeout time should 157171568Sscottl // be configurable 158211095Sdes sdebug(2, "# of luns=%d", sp->target_nluns); 159211095Sdes 160171568Sscottl if(sp->target_nluns > 0) { 161211095Sdes sp->flags |= ISC_CAMDEVS; 162171568Sscottl return 0; 163171568Sscottl } 164171568Sscottl 165171568Sscottl return ENODEV; 166171568Sscottl} 167171568Sscottl 168171568Sscottlstatic void 169171568Sscottlic_action(struct cam_sim *sim, union ccb *ccb) 170171568Sscottl{ 171211095Sdes isc_session_t *sp = cam_sim_softc(sim); 172171568Sscottl struct ccb_hdr *ccb_h = &ccb->ccb_h; 173171568Sscottl 174171568Sscottl debug_called(8); 175171568Sscottl 176171568Sscottl ccb_h->spriv_ptr0 = sp; 177257381Snwhitehorn sdebug(4, "func_code=0x%x flags=0x%x status=0x%x target=%d lun=%jx retry_count=%d timeout=%d", 178171568Sscottl ccb_h->func_code, ccb->ccb_h.flags, ccb->ccb_h.status, 179257381Snwhitehorn ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun, 180171568Sscottl ccb->ccb_h.retry_count, ccb_h->timeout); 181211095Sdes if(sp == NULL) { 182211095Sdes xdebug("sp == NULL! cannot happen"); 183211095Sdes return; 184211095Sdes } 185171568Sscottl switch(ccb_h->func_code) { 186171568Sscottl case XPT_PATH_INQ: 187211095Sdes _inq(sim, ccb); 188171568Sscottl break; 189171568Sscottl 190171568Sscottl case XPT_RESET_BUS: // (can just be a stub that does nothing and completes) 191171568Sscottl { 192171568Sscottl struct ccb_pathinq *cpi = &ccb->cpi; 193171568Sscottl 194171568Sscottl debug(3, "XPT_RESET_BUS"); 195171568Sscottl cpi->ccb_h.status = CAM_REQ_CMP; 196171568Sscottl break; 197171568Sscottl } 198171568Sscottl 199171568Sscottl case XPT_SCSI_IO: 200171568Sscottl { 201171568Sscottl struct ccb_scsiio* csio = &ccb->csio; 202171568Sscottl 203171568Sscottl debug(4, "XPT_SCSI_IO cmd=0x%x", csio->cdb_io.cdb_bytes[0]); 204171568Sscottl if(sp == NULL) { 205171568Sscottl ccb_h->status = CAM_REQ_INVALID; //CAM_NO_NEXUS; 206171568Sscottl debug(4, "xpt_done.status=%d", ccb_h->status); 207171568Sscottl break; 208171568Sscottl } 209171568Sscottl if(ccb_h->target_lun == CAM_LUN_WILDCARD) { 210171568Sscottl debug(3, "target=%d: bad lun (-1)", ccb_h->target_id); 211171568Sscottl ccb_h->status = CAM_LUN_INVALID; 212171568Sscottl break; 213171568Sscottl } 214185289Sscottl if(_scsi_encap(sim, ccb) != 0) 215171568Sscottl return; 216171568Sscottl break; 217171568Sscottl } 218171568Sscottl 219171568Sscottl case XPT_CALC_GEOMETRY: 220171568Sscottl { 221171568Sscottl struct ccb_calc_geometry *ccg; 222171568Sscottl 223171568Sscottl ccg = &ccb->ccg; 224257381Snwhitehorn debug(4, "sid=%d target=%d lun=%jx XPT_CALC_GEOMETRY vsize=%jd bsize=%d", 225257381Snwhitehorn sp->sid, ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun, 226211095Sdes ccg->volume_size, ccg->block_size); 227171568Sscottl if(ccg->block_size == 0 || 228171568Sscottl (ccg->volume_size < ccg->block_size)) { 229171568Sscottl // print error message ... 230298955Spfg /* XXX: what error is appropriate? */ 231171568Sscottl break; 232211095Sdes } 233211095Sdes else { 234211095Sdes int lun, *off, boff; 235211095Sdes 236211095Sdes lun = ccb->ccb_h.target_lun; 237211095Sdes if(lun > ISCSI_MAX_LUNS) { 238211095Sdes // XXX: 239211095Sdes xdebug("lun %d > ISCSI_MAX_LUNS!\n", lun); 240211095Sdes lun %= ISCSI_MAX_LUNS; 241211095Sdes } 242211095Sdes off = &sp->target_lun[lun / (sizeof(int)*8)]; 243211095Sdes boff = BIT(lun % (sizeof(int)*8)); 244211095Sdes debug(4, "sp->target_nluns=%d *off=%x boff=%x", 245211095Sdes sp->target_nluns, *off, boff); 246211095Sdes 247211095Sdes if((*off & boff) == 0) { 248211095Sdes sp->target_nluns++; 249211095Sdes *off |= boff; 250211095Sdes } 251171568Sscottl cam_calc_geometry(ccg, /*extended*/1); 252211095Sdes } 253171568Sscottl break; 254171568Sscottl } 255171568Sscottl 256171568Sscottl case XPT_GET_TRAN_SETTINGS: 257171568Sscottl default: 258171568Sscottl ccb_h->status = CAM_REQ_INVALID; 259171568Sscottl break; 260171568Sscottl } 261171568Sscottl#if __FreeBSD_version < 700000 262211095Sdes XPT_DONE(sp, ccb); 263171568Sscottl#else 264171568Sscottl xpt_done(ccb); 265171568Sscottl#endif 266171568Sscottl return; 267171568Sscottl} 268171568Sscottl 269171568Sscottlstatic void 270171568Sscottlic_poll(struct cam_sim *sim) 271171568Sscottl{ 272211095Sdes debug_called(4); 273171568Sscottl 274171568Sscottl} 275171568Sscottl 276171568Sscottlint 277171568Sscottlic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp) 278171568Sscottl{ 279171568Sscottl debug_called(8); 280171568Sscottl 281211095Sdes if(sp && sp->cam_sim) { 282211095Sdes cp->path_id = cam_sim_path(sp->cam_sim); 283211095Sdes cp->target_id = 0; 284211095Sdes cp->target_nluns = ISCSI_MAX_LUNS; // XXX: -1? 285171568Sscottl return 0; 286171568Sscottl } 287171568Sscottl return ENXIO; 288171568Sscottl} 289171568Sscottl 290171568Sscottlvoid 291211095Sdesic_destroy(isc_session_t *sp ) 292171568Sscottl{ 293171568Sscottl debug_called(8); 294171568Sscottl 295211095Sdes if(sp->cam_path != NULL) { 296211095Sdes sdebug(2, "name=%s unit=%d", 297211095Sdes cam_sim_name(sp->cam_sim), cam_sim_unit(sp->cam_sim)); 298211095Sdes CAM_LOCK(sp); 299211095Sdes#if 0 300211095Sdes xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL); 301211095Sdes#else 302211095Sdes xpt_async(XPT_RESET_BUS, sp->cam_path, NULL); 303211095Sdes#endif 304211095Sdes xpt_free_path(sp->cam_path); 305211095Sdes xpt_bus_deregister(cam_sim_path(sp->cam_sim)); 306211095Sdes cam_sim_free(sp->cam_sim, TRUE /*free_devq*/); 307171568Sscottl 308211095Sdes CAM_UNLOCK(sp); 309211095Sdes sdebug(2, "done"); 310211095Sdes } 311171568Sscottl} 312171568Sscottl 313171568Sscottlint 314211095Sdesic_init(isc_session_t *sp) 315171568Sscottl{ 316171568Sscottl struct cam_sim *sim; 317171568Sscottl struct cam_devq *devq; 318171568Sscottl 319211095Sdes debug_called(8); 320211095Sdes 321171568Sscottl if((devq = cam_simq_alloc(256)) == NULL) 322171568Sscottl return ENOMEM; 323171568Sscottl 324171568Sscottl#if __FreeBSD_version >= 700000 325211095Sdes mtx_init(&sp->cam_mtx, "isc-cam", NULL, MTX_DEF); 326171568Sscottl#else 327171568Sscottl isp->cam_mtx = Giant; 328171568Sscottl#endif 329211095Sdes sim = cam_sim_alloc(ic_action, 330211095Sdes ic_poll, 331211095Sdes "iscsi", 332211095Sdes sp, 333211095Sdes sp->sid, // unit 334171568Sscottl#if __FreeBSD_version >= 700000 335211095Sdes &sp->cam_mtx, 336171568Sscottl#endif 337211095Sdes 1, // max_dev_transactions 338211095Sdes 0, // max_tagged_dev_transactions 339171568Sscottl devq); 340171568Sscottl if(sim == NULL) { 341171568Sscottl cam_simq_free(devq); 342171568Sscottl#if __FreeBSD_version >= 700000 343211095Sdes mtx_destroy(&sp->cam_mtx); 344171568Sscottl#endif 345171568Sscottl return ENXIO; 346171568Sscottl } 347211095Sdes 348211095Sdes CAM_LOCK(sp); 349185289Sscottl if(xpt_bus_register(sim, 350185289Sscottl#if __FreeBSD_version >= 700000 351185289Sscottl NULL, 352185289Sscottl#endif 353211095Sdes 0/*bus_number*/) != CAM_SUCCESS) { 354171568Sscottl 355211095Sdes cam_sim_free(sim, /*free_devq*/TRUE); 356211095Sdes CAM_UNLOCK(sp); 357211095Sdes#if __FreeBSD_version >= 700000 358211095Sdes mtx_destroy(&sp->cam_mtx); 359211095Sdes#endif 360211095Sdes return ENXIO; 361171568Sscottl } 362211095Sdes sp->cam_sim = sim; 363272308Smav if(xpt_create_path(&sp->cam_path, NULL, cam_sim_path(sp->cam_sim), 364272308Smav CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 365272308Smav xpt_bus_deregister(cam_sim_path(sp->cam_sim)); 366272308Smav cam_sim_free(sim, /*free_devq*/TRUE); 367272308Smav CAM_UNLOCK(sp); 368272308Smav#if __FreeBSD_version >= 700000 369272308Smav mtx_destroy(&sp->cam_mtx); 370272308Smav#endif 371272308Smav return ENXIO; 372272308Smav } 373211095Sdes CAM_UNLOCK(sp); 374171568Sscottl 375211095Sdes sdebug(1, "cam subsystem initialized"); 376171568Sscottl 377211095Sdes ic_scan(sp); 378171568Sscottl 379171568Sscottl return 0; 380171568Sscottl} 381