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