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 */
27171568Sscottl/*
28211095Sdes | $Id: iscsi_subr.c 743 2009-08-08 10:54:53Z danny $
29171568Sscottl */
30171568Sscottl
31171568Sscottl#include <sys/cdefs.h>
32171568Sscottl__FBSDID("$FreeBSD$");
33171568Sscottl
34171568Sscottl#include "opt_iscsi_initiator.h"
35171568Sscottl
36171568Sscottl#include <sys/param.h>
37171568Sscottl#include <sys/kernel.h>
38171568Sscottl#include <sys/callout.h>
39171568Sscottl#include <sys/malloc.h>
40171568Sscottl#include <sys/mbuf.h>
41171568Sscottl#include <sys/kthread.h>
42171568Sscottl#include <sys/lock.h>
43171568Sscottl#include <sys/mutex.h>
44171568Sscottl#include <sys/uio.h>
45171568Sscottl#include <sys/sysctl.h>
46211095Sdes#include <sys/sx.h>
47171568Sscottl
48171568Sscottl#include <cam/cam.h>
49171568Sscottl#include <cam/cam_ccb.h>
50171568Sscottl#include <cam/cam_sim.h>
51171568Sscottl#include <cam/cam_xpt_sim.h>
52171568Sscottl#include <cam/cam_periph.h>
53171568Sscottl#include <cam/scsi/scsi_message.h>
54171568Sscottl#include <sys/eventhandler.h>
55171568Sscottl
56254657Strasz#include <dev/iscsi_initiator/iscsi.h>
57254657Strasz#include <dev/iscsi_initiator/iscsivar.h>
58171568Sscottl
59171568Sscottl/*
60171568Sscottl | Interface to the SCSI layer
61171568Sscottl */
62171568Sscottlvoid
63171568Sscottliscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
64171568Sscottl{
65171568Sscottl     union ccb 		*ccb = opq->ccb;
66171568Sscottl     struct ccb_scsiio	*csio = &ccb->csio;
67171568Sscottl     pdu_t		*opp = &opq->pdu;
68171568Sscottl     bhs_t		*bhp = &opp->ipdu.bhs;
69171568Sscottl     r2t_t		*r2t = &pq->pdu.ipdu.r2t;
70171568Sscottl     pduq_t	*wpq;
71171568Sscottl     int	error;
72171568Sscottl
73171568Sscottl     debug_called(8);
74171568Sscottl     sdebug(4, "itt=%x r2tSN=%d bo=%x ddtl=%x W=%d", ntohl(r2t->itt),
75171568Sscottl	   ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl), opp->ipdu.scsi_req.W);
76171568Sscottl
77171568Sscottl     switch(bhp->opcode) {
78171568Sscottl     case ISCSI_SCSI_CMD:
79171568Sscottl	  if(opp->ipdu.scsi_req.W) {
80171568Sscottl	       data_out_t	*cmd;
81171568Sscottl	       u_int		ddtl = ntohl(r2t->ddtl);
82171568Sscottl	       u_int		edtl = ntohl(opp->ipdu.scsi_req.edtlen);
83171568Sscottl	       u_int		bleft, bs, dsn, bo;
84171568Sscottl	       caddr_t		bp = csio->data_ptr;
85171568Sscottl
86171568Sscottl	       bo = ntohl(r2t->bo);
87226208Skib	       bp += MIN(bo, edtl - ddtl);
88171568Sscottl	       bleft = ddtl;
89171568Sscottl
90171568Sscottl	       if(sp->opt.maxXmitDataSegmentLength > 0) // danny's RFC
91171568Sscottl		    bs = MIN(sp->opt.maxXmitDataSegmentLength, ddtl);
92171568Sscottl	       else
93171568Sscottl		    bs = ddtl;
94171568Sscottl	       dsn = 0;
95171568Sscottl	       sdebug(4, "edtl=%x ddtl=%x bo=%x dsn=%x bs=%x maxX=%x",
96171568Sscottl		      edtl, ddtl, bo, dsn, bs, sp->opt.maxXmitDataSegmentLength);
97171568Sscottl	       while(bleft > 0) {
98185289Sscottl		    wpq = pdu_alloc(sp->isc, M_NOWAIT); // testing ...
99171568Sscottl		    if(wpq == NULL) {
100185289Sscottl			 sdebug(3, "itt=%x r2tSN=%d bo=%x ddtl=%x W=%d", ntohl(r2t->itt),
101185289Sscottl				ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl), opp->ipdu.scsi_req.W);
102185289Sscottl			 sdebug(1, "npdu_max=%d npdu_alloc=%d", sp->isc->npdu_max, sp->isc->npdu_alloc);
103185289Sscottl
104185289Sscottl			 while((wpq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) {
105185289Sscottl			      sdebug(2, "waiting...");
106185289Sscottl#if __FreeBSD_version >= 700000
107185289Sscottl			      pause("isc_r2t", 5*hz);
108185289Sscottl#else
109185289Sscottl			      tsleep(sp->isc, 0, "isc_r2t", 5*hz);
110185289Sscottl#endif
111185289Sscottl			 }
112171568Sscottl		    }
113171568Sscottl		    cmd = &wpq->pdu.ipdu.data_out;
114171568Sscottl		    cmd->opcode = ISCSI_WRITE_DATA;
115171568Sscottl		    cmd->lun[0]	= r2t->lun[0];
116171568Sscottl		    cmd->lun[1]	= r2t->lun[1];
117171568Sscottl		    cmd->ttt	= r2t->ttt;
118171568Sscottl		    cmd->itt	= r2t->itt;
119171568Sscottl
120171568Sscottl		    cmd->dsn	= htonl(dsn);
121171568Sscottl		    cmd->bo	= htonl(bo);
122171568Sscottl
123171568Sscottl		    cmd->F 	= (bs < bleft)? 0: 1; // is this the last one?
124171568Sscottl		    bs = MIN(bs, bleft);
125171568Sscottl
126171568Sscottl		    wpq->pdu.ds_len	= bs;
127211095Sdes		    wpq->pdu.ds_addr	= bp;
128171568Sscottl
129171568Sscottl		    error = isc_qout(sp, wpq);
130171568Sscottl		    sdebug(6, "bs=%x bo=%x bp=%p dsn=%x error=%d", bs, bo, bp, dsn, error);
131171568Sscottl		    if(error)
132171568Sscottl			 break;
133171568Sscottl		    bo += bs;
134171568Sscottl		    bp += bs;
135171568Sscottl		    bleft -= bs;
136171568Sscottl		    dsn++;
137171568Sscottl	       }
138171568Sscottl	  }
139171568Sscottl	  break;
140171568Sscottl
141171568Sscottl     default:
142171568Sscottl	  // XXX: should not happen ...
143171568Sscottl	  xdebug("huh? opcode=0x%x", bhp->opcode);
144171568Sscottl     }
145171568Sscottl}
146171568Sscottl
147171568Sscottlstatic int
148171568SscottlgetSenseData(u_int status, union ccb *ccb, pduq_t *pq)
149171568Sscottl{
150171568Sscottl     pdu_t		*pp = &pq->pdu;
151171568Sscottl     struct		ccb_scsiio *scsi = (struct ccb_scsiio *)ccb;
152171568Sscottl     struct		scsi_sense_data *sense = &scsi->sense_data;
153171568Sscottl     struct mbuf	*m = pq->mp;
154171568Sscottl     scsi_rsp_t		*cmd = &pp->ipdu.scsi_rsp;
155171568Sscottl     caddr_t		bp;
156171568Sscottl     int		sense_len, mustfree = 0;
157234233Sjpaetzel     int                error_code, sense_key, asc, ascq;
158171568Sscottl
159171568Sscottl     bp = mtod(pq->mp, caddr_t);
160171568Sscottl     if((sense_len = scsi_2btoul(bp)) == 0)
161171568Sscottl	  return 0;
162171568Sscottl     debug(4, "sense_len=%d", sense_len);
163171568Sscottl     /*
164171568Sscottl      | according to the specs, the sense data cannot
165171568Sscottl      | be larger than 252 ...
166171568Sscottl      */
167171568Sscottl     if(sense_len > m->m_len) {
168171568Sscottl	  bp = malloc(sense_len, M_ISCSI, M_WAITOK);
169171568Sscottl	  debug(3, "calling i_mbufcopy(len=%d)", sense_len);
170171568Sscottl	  i_mbufcopy(pq->mp, bp, sense_len);
171171568Sscottl	  mustfree++;
172171568Sscottl     }
173171568Sscottl     scsi->scsi_status = status;
174171568Sscottl
175171568Sscottl     bcopy(bp+2, sense, min(sense_len, scsi->sense_len));
176171568Sscottl     scsi->sense_resid = 0;
177171568Sscottl     if(cmd->flag & (BIT(1)|BIT(2)))
178171568Sscottl	  scsi->sense_resid = ntohl(pp->ipdu.scsi_rsp.rcnt);
179225950Sken     scsi_extract_sense_len(sense, scsi->sense_len - scsi->sense_resid,
180234233Sjpaetzel       &error_code, &sense_key, &asc, &ascq, /*show_errors*/ 1);
181225950Sken
182171568Sscottl     debug(3, "sense_len=%d rcnt=%d sense_resid=%d dsl=%d error_code=%x flags=%x",
183171568Sscottl	   sense_len,
184171568Sscottl	   ntohl(pp->ipdu.scsi_rsp.rcnt), scsi->sense_resid,
185225950Sken	   pp->ds_len, error_code, sense_key);
186171568Sscottl
187171568Sscottl     if(mustfree)
188171568Sscottl	  free(bp, M_ISCSI);
189171568Sscottl
190171568Sscottl     return 1;
191171568Sscottl}
192171568Sscottl
193171568Sscottl/*
194171568Sscottl | Some information is from SAM draft.
195171568Sscottl */
196171568Sscottlstatic void
197211095Sdes_scsi_done(isc_session_t *sp, u_int response, u_int status, union ccb *ccb, pduq_t *pq)
198171568Sscottl{
199171568Sscottl     struct ccb_hdr	*ccb_h = &ccb->ccb_h;
200171568Sscottl
201171568Sscottl     debug_called(8);
202171568Sscottl
203171568Sscottl     if(status || response) {
204211095Sdes	  sdebug(3, "response=%x status=%x ccb=%p pq=%p", response, status, ccb, pq);
205171568Sscottl	  if(pq != NULL)
206211095Sdes	       sdebug(3, "mp=%p buf=%p len=%d", pq->mp, pq->buf, pq->len);
207171568Sscottl     }
208171568Sscottl     ccb_h->status = 0;
209171568Sscottl     switch(response) {
210171568Sscottl     case 0: // Command Completed at Target
211171568Sscottl	  switch(status) {
212171568Sscottl	  case 0:	// Good, all is ok
213171568Sscottl	       ccb_h->status = CAM_REQ_CMP;
214171568Sscottl	       break;
215171568Sscottl
216171568Sscottl	  case 0x02: 	// Check Condition
217171568Sscottl	       if((pq != NULL) && (pq->mp != NULL) && getSenseData(status, ccb, pq))
218171568Sscottl		    ccb_h->status |= CAM_AUTOSNS_VALID;
219171568Sscottl
220171568Sscottl	  case 0x14:	// Intermediate-Condition Met
221171568Sscottl	  case 0x10:	// Intermediate
222171568Sscottl	  case 0x04:	// Condition Met
223171568Sscottl	       ccb_h->status |= CAM_SCSI_STATUS_ERROR;
224171568Sscottl	       break;
225171568Sscottl
226171568Sscottl	  case 0x08:
227171568Sscottl	       ccb_h->status = CAM_BUSY;
228171568Sscottl	       break;
229171568Sscottl
230171568Sscottl	  case 0x18: // Reservation Conflict
231171568Sscottl	  case 0x28: // Task Set Full
232171568Sscottl	       ccb_h->status = CAM_REQUEUE_REQ;
233171568Sscottl	       break;
234171568Sscottl	  default:
235171568Sscottl	       //case 0x22: // Command Terminated
236171568Sscottl	       //case 0x30: // ACA Active
237171568Sscottl	       //case 0x40: // Task Aborted
238185289Sscottl	       ccb_h->status = CAM_REQ_CMP_ERR; //CAM_REQ_ABORTED;
239171568Sscottl	  }
240171568Sscottl	  break;
241171568Sscottl
242171568Sscottl     default:
243171568Sscottl	  if((response >= 0x80) && (response <= 0xFF)) {
244171568Sscottl	       // Vendor specific ...
245171568Sscottl	  }
246171568Sscottl     case 1: // target failure
247171568Sscottl	  ccb_h->status = CAM_REQ_CMP_ERR; //CAM_REQ_ABORTED;
248171568Sscottl	  break;
249171568Sscottl     }
250211095Sdes     sdebug(5, "ccb_h->status=%x", ccb_h->status);
251171568Sscottl
252211095Sdes     XPT_DONE(sp, ccb);
253171568Sscottl}
254171568Sscottl
255171568Sscottl/*
256171568Sscottl | returns the lowest cmdseq that was not acked
257171568Sscottl */
258171568Sscottlint
259171568Sscottliscsi_requeue(isc_session_t *sp)
260171568Sscottl{
261171568Sscottl     pduq_t	*pq;
262171568Sscottl     u_int	i, n, last;
263171568Sscottl
264171568Sscottl     debug_called(8);
265211095Sdes     i = last = 0;
266185289Sscottl     sp->flags |= ISC_HOLD;
267171568Sscottl     while((pq = i_dqueue_hld(sp)) != NULL) {
268171568Sscottl	  i++;
269211095Sdes	  if(pq->ccb != NULL) {
270211095Sdes	       _scsi_done(sp, 0, 0x28, pq->ccb, NULL);
271211095Sdes	       n = ntohl(pq->pdu.ipdu.bhs.CmdSN);
272211095Sdes	       if(last==0 || (last > n))
273211095Sdes		    last = n;
274211095Sdes	       sdebug(2, "last=%x n=%x", last, n);
275211095Sdes	  }
276171568Sscottl	  pdu_free(sp->isc, pq);
277171568Sscottl     }
278185289Sscottl     sp->flags &= ~ISC_HOLD;
279171568Sscottl     return i? last: sp->sn.cmd;
280171568Sscottl}
281171568Sscottl
282171568Sscottlint
283171568Sscottli_pdu_flush(isc_session_t *sp)
284171568Sscottl{
285171568Sscottl     int	n = 0;
286171568Sscottl     pduq_t	*pq;
287171568Sscottl
288171568Sscottl     debug_called(8);
289171568Sscottl     while((pq = i_dqueue_rsp(sp)) != NULL) {
290171568Sscottl	  pdu_free(sp->isc, pq);
291171568Sscottl	  n++;
292171568Sscottl     }
293171568Sscottl     while((pq = i_dqueue_rsv(sp)) != NULL) {
294171568Sscottl	  pdu_free(sp->isc, pq);
295171568Sscottl	  n++;
296171568Sscottl     }
297171568Sscottl     while((pq = i_dqueue_snd(sp, -1)) != NULL) {
298171568Sscottl	  pdu_free(sp->isc, pq);
299171568Sscottl	  n++;
300171568Sscottl     }
301171568Sscottl     while((pq = i_dqueue_hld(sp)) != NULL) {
302171568Sscottl	  pdu_free(sp->isc, pq);
303171568Sscottl	  n++;
304171568Sscottl     }
305185289Sscottl     while((pq = i_dqueue_wsnd(sp)) != NULL) {
306185289Sscottl	  pdu_free(sp->isc, pq);
307185289Sscottl	  n++;
308185289Sscottl     }
309171568Sscottl     if(n != 0)
310171568Sscottl	  xdebug("%d pdus recovered, should have been ZERO!", n);
311171568Sscottl     return n;
312171568Sscottl}
313171568Sscottl/*
314171568Sscottl | called from ism_destroy.
315171568Sscottl */
316171568Sscottlvoid
317171568Sscottliscsi_cleanup(isc_session_t *sp)
318171568Sscottl{
319171568Sscottl     pduq_t *pq, *pqtmp;
320171568Sscottl
321171568Sscottl     debug_called(8);
322171568Sscottl
323171568Sscottl     TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, pqtmp) {
324171568Sscottl	  sdebug(3, "hld pq=%p", pq);
325171568Sscottl	  if(pq->ccb)
326211095Sdes	       _scsi_done(sp, 1, 0x40, pq->ccb, NULL);
327171568Sscottl	  TAILQ_REMOVE(&sp->hld, pq, pq_link);
328211095Sdes	  if(pq->buf) {
329211095Sdes	       free(pq->buf, M_ISCSIBUF);
330211095Sdes	       pq->buf = NULL;
331211095Sdes	  }
332171568Sscottl	  pdu_free(sp->isc, pq);
333171568Sscottl     }
334171568Sscottl     while((pq = i_dqueue_snd(sp, BIT(0)|BIT(1)|BIT(2))) != NULL) {
335171568Sscottl	  sdebug(3, "pq=%p", pq);
336171568Sscottl	  if(pq->ccb)
337211095Sdes	       _scsi_done(sp, 1, 0x40, pq->ccb, NULL);
338211095Sdes	  if(pq->buf) {
339211095Sdes	       free(pq->buf, M_ISCSIBUF);
340211095Sdes	       pq->buf = NULL;
341211095Sdes	  }
342171568Sscottl	  pdu_free(sp->isc, pq);
343171568Sscottl     }
344171568Sscottl
345171568Sscottl     wakeup(&sp->rsp);
346171568Sscottl}
347171568Sscottl
348171568Sscottlvoid
349171568Sscottliscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
350171568Sscottl{
351171568Sscottl     pdu_t		*pp = &pq->pdu;
352171568Sscottl     scsi_rsp_t		*cmd = &pp->ipdu.scsi_rsp;
353171568Sscottl
354171568Sscottl     debug_called(8);
355171568Sscottl
356211095Sdes     _scsi_done(sp, cmd->response, cmd->status, opq->ccb, pq);
357171568Sscottl
358171568Sscottl     pdu_free(sp->isc, opq);
359171568Sscottl}
360171568Sscottl
361171568Sscottl// see RFC 3720, 10.9.1 page 146
362185289Sscottl/*
363185289Sscottl | NOTE:
364185289Sscottl | the call to isc_stop_receiver is a kludge,
365185289Sscottl | instead, it should be handled by the userland controller,
366185289Sscottl | but that means that there should be a better way, other than
367185289Sscottl | sending a signal. Somehow, this packet should be supplied to
368185289Sscottl | the userland via read.
369185289Sscottl */
370171568Sscottlvoid
371171568Sscottliscsi_async(isc_session_t *sp, pduq_t *pq)
372171568Sscottl{
373171568Sscottl     pdu_t		*pp = &pq->pdu;
374171568Sscottl     async_t		*cmd = &pp->ipdu.async;
375171568Sscottl
376171568Sscottl     debug_called(8);
377171568Sscottl
378171568Sscottl     sdebug(3, "asyncevent=0x%x asyncVCode=0x%0x", cmd->asyncEvent, cmd->asyncVCode);
379171568Sscottl     switch(cmd->asyncEvent) {
380171568Sscottl     case 0: // check status ...
381171568Sscottl	  break;
382185289Sscottl
383171568Sscottl     case 1: // target request logout
384185289Sscottl	  isc_stop_receiver(sp);	// XXX: temporary solution
385171568Sscottl	  break;
386185289Sscottl
387171568Sscottl     case 2: // target indicates it wants to drop connection
388185289Sscottl	  isc_stop_receiver(sp);	// XXX: temporary solution
389171568Sscottl	  break;
390171568Sscottl
391171568Sscottl     case 3: // target indicates it will drop all connections.
392185289Sscottl	  isc_stop_receiver(sp);	// XXX: temporary solution
393171568Sscottl	  break;
394171568Sscottl
395171568Sscottl     case 4: // target request parameter negotiation
396171568Sscottl	  break;
397185289Sscottl
398171568Sscottl     default:
399171568Sscottl	  break;
400171568Sscottl     }
401171568Sscottl}
402171568Sscottl
403171568Sscottlvoid
404171568Sscottliscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
405171568Sscottl{
406171568Sscottl     union ccb 		*ccb = opq->ccb;
407171568Sscottl     //reject_t		*reject = &pq->pdu.ipdu.reject;
408171568Sscottl
409171568Sscottl     debug_called(8);
410171568Sscottl     //XXX: check RFC 10.17.1 (page 176)
411171568Sscottl     ccb->ccb_h.status = CAM_REQ_ABORTED;
412211095Sdes     XPT_DONE(sp, ccb);
413171568Sscottl
414171568Sscottl     pdu_free(sp->isc, opq);
415171568Sscottl}
416171568Sscottl
417171568Sscottl/*
418171568Sscottl | deal with lun
419171568Sscottl */
420171568Sscottlstatic int
421171568Sscottldwl(isc_session_t *sp, int lun, u_char *lp)
422171568Sscottl{
423171568Sscottl     debug_called(8);
424211095Sdes     sdebug(4, "lun=%d", lun);
425171568Sscottl     /*
426171568Sscottl      | mapping LUN to iSCSI LUN
427171568Sscottl      | check the SAM-2 specs
428171568Sscottl      | hint: maxLUNS is a small number, cam's LUN is 32bits
429171568Sscottl      | iSCSI is 64bits, scsi is ?
430171568Sscottl      */
431171568Sscottl     // XXX: check if this will pass the endian test
432171568Sscottl     if(lun < 256) {
433171568Sscottl	  lp[0] = 0;
434171568Sscottl	  lp[1] = lun;
435171568Sscottl     } else
436171568Sscottl     if(lun < 16384) {
437171568Sscottl	  lp[0] = (1 << 5) | ((lun >> 8) & 0x3f);
438171568Sscottl	  lp[1] = lun & 0xff;
439171568Sscottl     }
440171568Sscottl     else {
441171568Sscottl	  xdebug("lun %d: is unsupported!", lun);
442171568Sscottl	  return -1;
443171568Sscottl     }
444171568Sscottl
445171568Sscottl     return 0;
446171568Sscottl}
447171568Sscottl
448171568Sscottl/*
449171568Sscottl | encapsulate the scsi command and
450171568Sscottl */
451171568Sscottlint
452171568Sscottlscsi_encap(struct cam_sim *sim, union ccb *ccb)
453171568Sscottl{
454211095Sdes     isc_session_t	*sp = cam_sim_softc(sim);
455171568Sscottl     struct ccb_scsiio	*csio = &ccb->csio;
456171568Sscottl     struct ccb_hdr	*ccb_h = &ccb->ccb_h;
457171568Sscottl     pduq_t		*pq;
458171568Sscottl     scsi_req_t		*cmd;
459171568Sscottl
460171568Sscottl     debug_called(8);
461171568Sscottl
462171568Sscottl     debug(4, "ccb->sp=%p", ccb_h->spriv_ptr0);
463171568Sscottl     sp = ccb_h->spriv_ptr0;
464171568Sscottl
465211095Sdes     if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) {
466185289Sscottl	  debug(2, "ccb->sp=%p", ccb_h->spriv_ptr0);
467185289Sscottl	  sdebug(1, "pdu_alloc failed sc->npdu_max=%d npdu_alloc=%d",
468185289Sscottl		 sp->isc->npdu_max, sp->isc->npdu_alloc);
469185289Sscottl	  while((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) {
470211095Sdes	       sdebug(2, "waiting...");
471185289Sscottl#if __FreeBSD_version >= 700000
472185289Sscottl	       pause("isc_encap", 5*hz);
473185289Sscottl#else
474185289Sscottl	       tsleep(sp->isc, 0, "isc_encap", 5*hz);
475185289Sscottl#endif
476185289Sscottl	  }
477171568Sscottl     }
478171568Sscottl     cmd = &pq->pdu.ipdu.scsi_req;
479171568Sscottl     cmd->opcode = ISCSI_SCSI_CMD;
480171568Sscottl     cmd->F = 1;
481234233Sjpaetzel#if 0
482234233Sjpaetzel// this breaks at least Isilon's iscsi target.
483171568Sscottl     /*
484171568Sscottl      | map tag option, default is UNTAGGED
485171568Sscottl      */
486171568Sscottl     switch(csio->tag_action) {
487171568Sscottl     case MSG_SIMPLE_Q_TAG:	cmd->attr = iSCSI_TASK_SIMPLE;	break;
488211095Sdes     case MSG_HEAD_OF_Q_TAG:	cmd->attr = iSCSI_TASK_HOFQ;	break;
489211095Sdes     case MSG_ORDERED_Q_TAG:	cmd->attr = iSCSI_TASK_ORDER;	break;
490171568Sscottl     case MSG_ACA_TASK:		cmd->attr = iSCSI_TASK_ACA;	break;
491171568Sscottl     }
492234233Sjpaetzel#else
493234233Sjpaetzel     cmd->attr = iSCSI_TASK_SIMPLE;
494234233Sjpaetzel#endif
495171568Sscottl
496171568Sscottl     dwl(sp, ccb_h->target_lun, (u_char *)&cmd->lun);
497171568Sscottl
498171568Sscottl     if((ccb_h->flags & CAM_CDB_POINTER) != 0) {
499171568Sscottl	  if((ccb_h->flags & CAM_CDB_PHYS) == 0) {
500171568Sscottl	       if(csio->cdb_len > 16) {
501171568Sscottl		    sdebug(3, "oversize cdb %d > 16", csio->cdb_len);
502171568Sscottl		    goto invalid;
503171568Sscottl	       }
504171568Sscottl	  }
505171568Sscottl	  else {
506171568Sscottl	       sdebug(3, "not phys");
507171568Sscottl	       goto invalid;
508171568Sscottl	  }
509171568Sscottl     }
510171568Sscottl
511171568Sscottl     if(csio->cdb_len > sizeof(cmd->cdb))
512171568Sscottl	  xdebug("guevalt! %d > %ld", csio->cdb_len, (long)sizeof(cmd->cdb));
513171568Sscottl
514171568Sscottl     memcpy(cmd->cdb,
515171568Sscottl	    ccb_h->flags & CAM_CDB_POINTER? csio->cdb_io.cdb_ptr: csio->cdb_io.cdb_bytes,
516171568Sscottl	    csio->cdb_len);
517171568Sscottl
518171568Sscottl     cmd->W = (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT;
519171568Sscottl     cmd->R = (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN;
520171568Sscottl     cmd->edtlen = htonl(csio->dxfer_len);
521171568Sscottl
522171568Sscottl     pq->ccb = ccb;
523171568Sscottl     /*
524171568Sscottl      | place it in the out queue
525171568Sscottl      */
526171568Sscottl     if(isc_qout(sp, pq) == 0)
527171568Sscottl	  return 1;
528171568Sscottl invalid:
529171568Sscottl     ccb->ccb_h.status = CAM_REQ_INVALID;
530211095Sdes     pdu_free(sp->isc, pq);
531211095Sdes
532171568Sscottl     return 0;
533171568Sscottl}
534171568Sscottl
535171568Sscottlint
536171568Sscottlscsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
537171568Sscottl{
538171568Sscottl     union ccb 		*ccb = opq->ccb;
539171568Sscottl     struct ccb_scsiio	*csio = &ccb->csio;
540171568Sscottl     pdu_t		*opp = &opq->pdu;
541171568Sscottl     bhs_t		*bhp = &opp->ipdu.bhs;
542171568Sscottl
543171568Sscottl     debug_called(8);
544171568Sscottl     sdebug(6, "pq=%p opq=%p bhp->opcode=0x%x len=%d",
545171568Sscottl	    pq, opq, bhp->opcode, pq->pdu.ds_len);
546171568Sscottl     if(ccb == NULL) {
547171568Sscottl	  sdebug(1, "itt=0x%x pq=%p opq=%p bhp->opcode=0x%x len=%d",
548171568Sscottl		 ntohl(pq->pdu.ipdu.bhs.itt),
549171568Sscottl		 pq, opq, bhp->opcode, pq->pdu.ds_len);
550171568Sscottl	  xdebug("%d] ccb == NULL!", sp->sid);
551171568Sscottl	  return 0;
552171568Sscottl     }
553171568Sscottl     if(pq->pdu.ds_len != 0) {
554171568Sscottl	  switch(bhp->opcode) {
555171568Sscottl	  case ISCSI_SCSI_CMD: {
556171568Sscottl	       scsi_req_t *cmd = &opp->ipdu.scsi_req;
557171568Sscottl	       sdebug(5, "itt=0x%x opcode=%x R=%d",
558171568Sscottl		      ntohl(pq->pdu.ipdu.bhs.itt),
559171568Sscottl		      pq->pdu.ipdu.bhs.opcode, cmd->R);
560171568Sscottl
561171568Sscottl	       switch(pq->pdu.ipdu.bhs.opcode) {
562171568Sscottl	       case ISCSI_READ_DATA: // SCSI Data in
563171568Sscottl	       {
564185289Sscottl		    caddr_t	bp = NULL; // = mtod(pq->mp, caddr_t);
565171568Sscottl		    data_in_t 	*rcmd = &pq->pdu.ipdu.data_in;
566171568Sscottl
567171568Sscottl		    if(cmd->R) {
568185289Sscottl			 sdebug(5, "copy to=%p from=%p l1=%d l2=%d mp@%p",
569185289Sscottl				csio->data_ptr, bp? mtod(pq->mp, caddr_t): 0,
570185289Sscottl				ntohl(cmd->edtlen), pq->pdu.ds_len, pq->mp);
571171568Sscottl			 if(ntohl(cmd->edtlen) >= pq->pdu.ds_len) {
572211095Sdes			      int	offset, len = pq->pdu.ds_len;
573185289Sscottl
574185289Sscottl			      if(pq->mp != NULL) {
575211095Sdes				   caddr_t		dp;
576171568Sscottl
577211095Sdes				   offset = ntohl(rcmd->bo);
578211095Sdes				   dp = csio->data_ptr + offset;
579211095Sdes				   i_mbufcopy(pq->mp, dp, len);
580211095Sdes			      }
581171568Sscottl			 }
582171568Sscottl			 else {
583171568Sscottl			      xdebug("edtlen=%d < ds_len=%d",
584171568Sscottl				     ntohl(cmd->edtlen), pq->pdu.ds_len);
585171568Sscottl			 }
586171568Sscottl		    }
587171568Sscottl		    if(rcmd->S) {
588171568Sscottl			 /*
589171568Sscottl			  | contains also the SCSI Status
590171568Sscottl			  */
591211095Sdes			 _scsi_done(sp, 0, rcmd->status, opq->ccb, NULL);
592171568Sscottl			 return 0;
593171568Sscottl		    } else
594171568Sscottl			 return 1;
595171568Sscottl	       }
596171568Sscottl	       break;
597171568Sscottl	       }
598171568Sscottl	  }
599171568Sscottl	  default:
600171568Sscottl	       sdebug(3, "opcode=%02x", bhp->opcode);
601171568Sscottl	       break;
602171568Sscottl	  }
603171568Sscottl     }
604171568Sscottl     /*
605171568Sscottl      | XXX: error ...
606171568Sscottl      */
607171568Sscottl     return 1;
608171568Sscottl}
609