1/*- 2 * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27/* 28 | $Id: isc_cam.c 998 2009-12-20 10:32:45Z danny $ 29 */ 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: releng/11.0/sys/dev/iscsi_initiator/isc_cam.c 298955 2016-05-03 03:41:25Z pfg $"); 32 33#include "opt_iscsi_initiator.h" 34 35#include <sys/param.h> 36#include <sys/kernel.h> 37#include <sys/callout.h> 38#if __FreeBSD_version >= 700000 39#include <sys/lock.h> 40#include <sys/mutex.h> 41#endif 42#include <sys/conf.h> 43#include <sys/systm.h> 44#include <sys/malloc.h> 45#include <sys/mbuf.h> 46#include <sys/uio.h> 47#include <sys/sysctl.h> 48#include <sys/sx.h> 49#include <vm/uma.h> 50 51#include <cam/cam.h> 52#include <cam/cam_ccb.h> 53#include <cam/cam_sim.h> 54#include <cam/cam_xpt_sim.h> 55#include <cam/cam_periph.h> 56 57#include <dev/iscsi_initiator/iscsi.h> 58#include <dev/iscsi_initiator/iscsivar.h> 59 60static void 61_inq(struct cam_sim *sim, union ccb *ccb) 62{ 63 struct ccb_pathinq *cpi = &ccb->cpi; 64 isc_session_t *sp = cam_sim_softc(sim); 65 66 debug_called(8); 67 debug(3, "sid=%d target=%d lun=%jx", sp->sid, ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun); 68 69 cpi->version_num = 1; /* XXX??? */ 70 cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_32; 71 cpi->target_sprt = 0; 72 cpi->hba_misc = 0; 73 cpi->hba_eng_cnt = 0; 74 cpi->max_target = 0; //ISCSI_MAX_TARGETS - 1; 75 cpi->initiator_id = ISCSI_MAX_TARGETS; 76 cpi->max_lun = sp->opt.maxluns - 1; 77 cpi->bus_id = cam_sim_bus(sim); 78 cpi->base_transfer_speed = 3300; // 40000; // XXX: 79 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 80 strncpy(cpi->hba_vid, "iSCSI", HBA_IDLEN); 81 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 82 cpi->unit_number = cam_sim_unit(sim); 83 cpi->ccb_h.status = CAM_REQ_CMP; 84#if defined(KNOB_VALID_ADDRESS) 85 cpi->transport = XPORT_ISCSI; 86 cpi->transport_version = 0; 87#endif 88} 89 90static __inline int 91_scsi_encap(struct cam_sim *sim, union ccb *ccb) 92{ 93 int ret; 94 95#if __FreeBSD_version < 700000 96 ret = scsi_encap(sim, ccb); 97#else 98 isc_session_t *sp = cam_sim_softc(sim); 99 100 mtx_unlock(&sp->cam_mtx); 101 ret = scsi_encap(sim, ccb); 102 mtx_lock(&sp->cam_mtx); 103#endif 104 return ret; 105} 106 107void 108ic_lost_target(isc_session_t *sp, int target) 109{ 110 debug_called(8); 111 sdebug(2, "lost target=%d", target); 112 113 if(sp->cam_path != NULL) { 114 mtx_lock(&sp->cam_mtx); 115 xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL); 116 xpt_free_path(sp->cam_path); 117 mtx_unlock(&sp->cam_mtx); 118 sp->cam_path = 0; // XXX 119 } 120} 121 122static void 123scan_callback(struct cam_periph *periph, union ccb *ccb) 124{ 125 isc_session_t *sp = (isc_session_t *)ccb->ccb_h.spriv_ptr0; 126 127 debug_called(8); 128 129 xpt_free_ccb(ccb); 130 131 if(sp->flags & ISC_SCANWAIT) { 132 sp->flags &= ~ISC_SCANWAIT; 133 wakeup(sp); 134 } 135} 136 137static int 138ic_scan(isc_session_t *sp) 139{ 140 union ccb *ccb; 141 142 debug_called(8); 143 sdebug(2, "scanning sid=%d", sp->sid); 144 145 sp->flags &= ~ISC_CAMDEVS; 146 sp->flags |= ISC_SCANWAIT; 147 148 ccb = xpt_alloc_ccb(); 149 ccb->ccb_h.path = sp->cam_path; 150 ccb->ccb_h.cbfcnp = scan_callback; 151 ccb->ccb_h.spriv_ptr0 = sp; 152 153 xpt_rescan(ccb); 154 155 while(sp->flags & ISC_SCANWAIT) 156 tsleep(sp, PRIBIO, "ffp", 5*hz); // the timeout time should 157 // be configurable 158 sdebug(2, "# of luns=%d", sp->target_nluns); 159 160 if(sp->target_nluns > 0) { 161 sp->flags |= ISC_CAMDEVS; 162 return 0; 163 } 164 165 return ENODEV; 166} 167 168static void 169ic_action(struct cam_sim *sim, union ccb *ccb) 170{ 171 isc_session_t *sp = cam_sim_softc(sim); 172 struct ccb_hdr *ccb_h = &ccb->ccb_h; 173 174 debug_called(8); 175 176 ccb_h->spriv_ptr0 = sp; 177 sdebug(4, "func_code=0x%x flags=0x%x status=0x%x target=%d lun=%jx retry_count=%d timeout=%d", 178 ccb_h->func_code, ccb->ccb_h.flags, ccb->ccb_h.status, 179 ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun, 180 ccb->ccb_h.retry_count, ccb_h->timeout); 181 if(sp == NULL) { 182 xdebug("sp == NULL! cannot happen"); 183 return; 184 } 185 switch(ccb_h->func_code) { 186 case XPT_PATH_INQ: 187 _inq(sim, ccb); 188 break; 189 190 case XPT_RESET_BUS: // (can just be a stub that does nothing and completes) 191 { 192 struct ccb_pathinq *cpi = &ccb->cpi; 193 194 debug(3, "XPT_RESET_BUS"); 195 cpi->ccb_h.status = CAM_REQ_CMP; 196 break; 197 } 198 199 case XPT_SCSI_IO: 200 { 201 struct ccb_scsiio* csio = &ccb->csio; 202 203 debug(4, "XPT_SCSI_IO cmd=0x%x", csio->cdb_io.cdb_bytes[0]); 204 if(sp == NULL) { 205 ccb_h->status = CAM_REQ_INVALID; //CAM_NO_NEXUS; 206 debug(4, "xpt_done.status=%d", ccb_h->status); 207 break; 208 } 209 if(ccb_h->target_lun == CAM_LUN_WILDCARD) { 210 debug(3, "target=%d: bad lun (-1)", ccb_h->target_id); 211 ccb_h->status = CAM_LUN_INVALID; 212 break; 213 } 214 if(_scsi_encap(sim, ccb) != 0) 215 return; 216 break; 217 } 218 219 case XPT_CALC_GEOMETRY: 220 { 221 struct ccb_calc_geometry *ccg; 222 223 ccg = &ccb->ccg; 224 debug(4, "sid=%d target=%d lun=%jx XPT_CALC_GEOMETRY vsize=%jd bsize=%d", 225 sp->sid, ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun, 226 ccg->volume_size, ccg->block_size); 227 if(ccg->block_size == 0 || 228 (ccg->volume_size < ccg->block_size)) { 229 // print error message ... 230 /* XXX: what error is appropriate? */ 231 break; 232 } 233 else { 234 int lun, *off, boff; 235 236 lun = ccb->ccb_h.target_lun; 237 if(lun > ISCSI_MAX_LUNS) { 238 // XXX: 239 xdebug("lun %d > ISCSI_MAX_LUNS!\n", lun); 240 lun %= ISCSI_MAX_LUNS; 241 } 242 off = &sp->target_lun[lun / (sizeof(int)*8)]; 243 boff = BIT(lun % (sizeof(int)*8)); 244 debug(4, "sp->target_nluns=%d *off=%x boff=%x", 245 sp->target_nluns, *off, boff); 246 247 if((*off & boff) == 0) { 248 sp->target_nluns++; 249 *off |= boff; 250 } 251 cam_calc_geometry(ccg, /*extended*/1); 252 } 253 break; 254 } 255 256 case XPT_GET_TRAN_SETTINGS: 257 default: 258 ccb_h->status = CAM_REQ_INVALID; 259 break; 260 } 261#if __FreeBSD_version < 700000 262 XPT_DONE(sp, ccb); 263#else 264 xpt_done(ccb); 265#endif 266 return; 267} 268 269static void 270ic_poll(struct cam_sim *sim) 271{ 272 debug_called(4); 273 274} 275 276int 277ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp) 278{ 279 debug_called(8); 280 281 if(sp && sp->cam_sim) { 282 cp->path_id = cam_sim_path(sp->cam_sim); 283 cp->target_id = 0; 284 cp->target_nluns = ISCSI_MAX_LUNS; // XXX: -1? 285 return 0; 286 } 287 return ENXIO; 288} 289 290void 291ic_destroy(isc_session_t *sp ) 292{ 293 debug_called(8); 294 295 if(sp->cam_path != NULL) { 296 sdebug(2, "name=%s unit=%d", 297 cam_sim_name(sp->cam_sim), cam_sim_unit(sp->cam_sim)); 298 CAM_LOCK(sp); 299#if 0 300 xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL); 301#else 302 xpt_async(XPT_RESET_BUS, sp->cam_path, NULL); 303#endif 304 xpt_free_path(sp->cam_path); 305 xpt_bus_deregister(cam_sim_path(sp->cam_sim)); 306 cam_sim_free(sp->cam_sim, TRUE /*free_devq*/); 307 308 CAM_UNLOCK(sp); 309 sdebug(2, "done"); 310 } 311} 312 313int 314ic_init(isc_session_t *sp) 315{ 316 struct cam_sim *sim; 317 struct cam_devq *devq; 318 319 debug_called(8); 320 321 if((devq = cam_simq_alloc(256)) == NULL) 322 return ENOMEM; 323 324#if __FreeBSD_version >= 700000 325 mtx_init(&sp->cam_mtx, "isc-cam", NULL, MTX_DEF); 326#else 327 isp->cam_mtx = Giant; 328#endif 329 sim = cam_sim_alloc(ic_action, 330 ic_poll, 331 "iscsi", 332 sp, 333 sp->sid, // unit 334#if __FreeBSD_version >= 700000 335 &sp->cam_mtx, 336#endif 337 1, // max_dev_transactions 338 0, // max_tagged_dev_transactions 339 devq); 340 if(sim == NULL) { 341 cam_simq_free(devq); 342#if __FreeBSD_version >= 700000 343 mtx_destroy(&sp->cam_mtx); 344#endif 345 return ENXIO; 346 } 347 348 CAM_LOCK(sp); 349 if(xpt_bus_register(sim, 350#if __FreeBSD_version >= 700000 351 NULL, 352#endif 353 0/*bus_number*/) != CAM_SUCCESS) { 354 355 cam_sim_free(sim, /*free_devq*/TRUE); 356 CAM_UNLOCK(sp); 357#if __FreeBSD_version >= 700000 358 mtx_destroy(&sp->cam_mtx); 359#endif 360 return ENXIO; 361 } 362 sp->cam_sim = sim; 363 if(xpt_create_path(&sp->cam_path, NULL, cam_sim_path(sp->cam_sim), 364 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 365 xpt_bus_deregister(cam_sim_path(sp->cam_sim)); 366 cam_sim_free(sim, /*free_devq*/TRUE); 367 CAM_UNLOCK(sp); 368#if __FreeBSD_version >= 700000 369 mtx_destroy(&sp->cam_mtx); 370#endif 371 return ENXIO; 372 } 373 CAM_UNLOCK(sp); 374 375 sdebug(1, "cam subsystem initialized"); 376 377 ic_scan(sp); 378 379 return 0; 380} 381