1 /*
2  * Copyright (C) 2008-2015 Daisuke Aoyama <aoyama@peach.ne.jp>.
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 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 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 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <inttypes.h>
33 #include <stdint.h>
34 
35 #include <stdio.h>
36 #include <string.h>
37 #include <pthread.h>
38 
39 #include <fcntl.h>
40 #include <unistd.h>
41 
42 #ifdef HAVE_LIBCAM
43 #include <camlib.h>
44 #include <bus/cam/cam.h>
45 #include <bus/cam/cam_ccb.h>
46 #include <bus/cam/scsi/scsi_message.h>
47 
48 #include "istgt.h"
49 #include "istgt_ver.h"
50 #include "istgt_log.h"
51 #include "istgt_misc.h"
52 #include "istgt_lu.h"
53 #include "istgt_proto.h"
54 #include "istgt_scsi.h"
55 
56 #if !defined(__GNUC__)
57 #undef __attribute__
58 #define __attribute__(x)
59 #endif
60 
61 //#define ISTGT_TRACE_PASS
62 
63 #define ISTGT_LU_CAM_TIMEOUT 60000 /* 60sec. */
64 
65 typedef struct istgt_lu_pass_t {
66 	ISTGT_LU_Ptr lu;
67 	int num;
68 	int lun;
69 
70 	const char *file;
71 	uint64_t size;
72 	uint64_t blocklen;
73 	uint64_t blockcnt;
74 
75 	char *device;
76 	int unit;
77 	struct cam_device *cam_dev;
78 	union ccb *ccb;
79 
80 	int timeout;
81 
82 	uint8_t *inq_standard;
83 	int inq_standard_len;
84 	int inq_pd;
85 	int inq_rmb;
86 	int inq_ver;
87 	int inq_fmt;
88 	uint64_t ms_blocklen;
89 	uint64_t ms_blockcnt;
90 } ISTGT_LU_PASS;
91 
92 #define BUILD_SENSE(SK,ASC,ASCQ)					\
93 	do {								\
94 		*sense_len =						\
95 			istgt_lu_pass_build_sense_data(spec, sense_data, \
96 			    ISTGT_SCSI_SENSE_ ## SK,			\
97 			    (ASC), (ASCQ));				\
98 	} while (0)
99 
100 static int istgt_lu_pass_build_sense_data(ISTGT_LU_PASS *spec, uint8_t *data, int sk, int asc, int ascq);
101 
102 static void
istgt_lu_pass_parse_sense_key(uint8_t * sense_data,int * skp,int * ascp,int * ascqp)103 istgt_lu_pass_parse_sense_key(uint8_t *sense_data, int *skp, int *ascp, int *ascqp)
104 {
105 	int rsp;
106 	int sk, asc, ascq;
107 
108 	if (sense_data == NULL) {
109 		if (skp != NULL)
110 			*skp = -1;
111 		if (ascp != NULL)
112 			*ascp = -1;
113 		if (ascqp != NULL)
114 			*ascqp = -1;
115 		return;
116 	}
117 
118 	rsp = BGET8W(&sense_data[0], 6, 7);
119 	switch (rsp) {
120 	case 0x70: /* Current Fixed */
121 		sk = BGET8W(&sense_data[2], 3, 4);
122 		asc = sense_data[12];
123 		ascq = sense_data[13];
124 		break;
125 	case 0x71: /* Deferred Fixed */
126 		sk = BGET8W(&sense_data[2], 3, 4);
127 		asc = sense_data[12];
128 		ascq = sense_data[13];
129 		break;
130 	case 0x72: /* Current Descriptor */
131 		sk = BGET8W(&sense_data[2], 3, 4);
132 		asc = sense_data[2];
133 		ascq = sense_data[3];
134 		break;
135 	case 0x73: /* Deferred Descriptor */
136 		sk = BGET8W(&sense_data[2], 3, 4);
137 		asc = sense_data[2];
138 		ascq = sense_data[3];
139 		break;
140 	default:
141 		sk = asc = ascq = -1;
142 		break;
143 	}
144 
145 	if (skp != NULL)
146 		*skp = sk;
147 	if (ascp != NULL)
148 		*ascp = asc;
149 	if (ascqp != NULL)
150 		*ascqp = ascq;
151 }
152 
153 static void
istgt_lu_pass_print_sense_key(uint8_t * sense_data)154 istgt_lu_pass_print_sense_key(uint8_t *sense_data)
155 {
156 	int sk, asc, ascq;
157 
158 	istgt_lu_pass_parse_sense_key(sense_data, &sk, &asc, &ascq);
159 	if (sk >= 0) {
160 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
161 		    "SK=0x%x, ASC=0x%x, ASCQ=0x%x\n",
162 		    sk, asc, ascq);
163 	}
164 }
165 
166 static int
istgt_lu_pass_set_inquiry(ISTGT_LU_PASS * spec)167 istgt_lu_pass_set_inquiry(ISTGT_LU_PASS *spec)
168 {
169 	uint8_t buf[MAX_TMPBUF];
170 	uint8_t cdb[16];
171 	uint32_t flags;
172 	uint8_t *data;
173 	int cdb_len;
174 	int data_len;
175 	int data_alloc_len;
176 	int retry = 1;
177 	int rc;
178 
179 	memset(buf, 0, sizeof buf);
180 	memset(cdb, 0, sizeof cdb);
181 	data = buf;
182 	if (sizeof buf > 0xfc) {
183 		data_alloc_len = 0xfc;
184 	} else {
185 		data_alloc_len = sizeof buf;
186 	}
187 
188 	/* issue standard INQUIRY */
189 	cdb[0] = SPC_INQUIRY;
190 	cdb[1] = 0;
191 	cdb[2] = 0;
192 	DSET16(&cdb[3], data_alloc_len); /* ALLOCATION LENGTH */
193 	cdb[5] = 0;
194 	cdb_len = 6;
195 	ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
196 
197 	memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
198 	flags = CAM_DIR_IN;
199 	flags |= CAM_DEV_QFRZDIS;
200 	cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
201 	    data, data_alloc_len, SSD_FULL_SIZE, cdb_len,
202 	    spec->timeout);
203 	rc = cam_send_ccb(spec->cam_dev, spec->ccb);
204 	if (rc < 0) {
205 		ISTGT_ERRLOG("cam_send_ccb() failed\n");
206 		return -1;
207 	}
208 
209 	if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
210 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
211 		    "request error CAM=0x%x, SCSI=0x%x\n",
212 		    spec->ccb->ccb_h.status,
213 		    spec->ccb->csio.scsi_status);
214 		ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
215 		    (uint8_t *) &spec->ccb->csio.sense_data,
216 		    SSD_FULL_SIZE);
217 		istgt_lu_pass_print_sense_key((uint8_t *) &spec->ccb->csio.sense_data);
218 		return -1;
219 	}
220 	data_len = spec->ccb->csio.dxfer_len;
221 	data_len -= spec->ccb->csio.resid;
222 
223 	ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "INQUIRY", data, data_len);
224 	spec->inq_standard = xmalloc(data_len);
225 	spec->inq_standard_len = data_len;
226 	memcpy(spec->inq_standard, data, data_len);
227 
228 	return 0;
229 }
230 
231 static int
istgt_lu_pass_set_modesense(ISTGT_LU_PASS * spec)232 istgt_lu_pass_set_modesense(ISTGT_LU_PASS *spec)
233 {
234 	uint8_t buf[MAX_TMPBUF];
235 	uint8_t cdb[16];
236 	uint32_t flags;
237 	uint8_t *data;
238 	int cdb_len;
239 	int data_len;
240 	int data_alloc_len;
241 	int req_len;
242 	int retry = 1;
243 	int sk, asc, ascq;
244 	int rc;
245 
246 	memset(buf, 0, sizeof buf);
247 	memset(cdb, 0, sizeof cdb);
248 	data = buf;
249 	if (sizeof buf > 0xfc) {
250 		data_alloc_len = 0xfc;
251 	} else {
252 		data_alloc_len = sizeof buf;
253 	}
254 
255 	if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DVD) {
256 		/* MMC have only 10 */
257 		goto retry_sense10;
258 	}
259  retry_sense6:
260 	spec->ms_blockcnt = 0;
261 	spec->ms_blocklen = 0;
262 	memset(cdb, 0, sizeof cdb);
263 	/* issue MODE SENSE(6) */
264 	data_alloc_len = 4 + 8;         /* only block descriptor */
265 	req_len = 4 + 8;
266 	cdb[0] = SPC_MODE_SENSE_6;
267 	BDADD8(&cdb[1], 0, 3);          /* DBD */
268 	BDSET8W(&cdb[2], 0x00, 7, 2);   /* PC */
269 	//BDADD8W(&cdb[2], 0x00, 5, 6);   /* PAGE CODE */
270 	BDADD8W(&cdb[2], 0x3f, 5, 6);   /* PAGE CODE */
271 	cdb[3] = 0x00;                  /* SUBPAGE CODE */
272 	cdb[4] = data_alloc_len;        /* ALLOCATION LENGTH */
273 	cdb_len = 6;
274 	ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
275 
276 	memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
277 	flags = CAM_DIR_IN;
278 	flags |= CAM_DEV_QFRZDIS;
279 	cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
280 	    data, data_alloc_len, SSD_FULL_SIZE, cdb_len,
281 	    spec->timeout);
282 	rc = cam_send_ccb(spec->cam_dev, spec->ccb);
283 	if (rc < 0) {
284 		ISTGT_ERRLOG("cam_send_ccb() failed\n");
285 		return -1;
286 	}
287 
288 	if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
289 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
290 		    "request error CAM=0x%x, SCSI=0x%x\n",
291 		    spec->ccb->ccb_h.status,
292 		    spec->ccb->csio.scsi_status);
293 		ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
294 		    (uint8_t *) &spec->ccb->csio.sense_data,
295 		    SSD_FULL_SIZE);
296 		istgt_lu_pass_print_sense_key((uint8_t *) &spec->ccb->csio.sense_data);
297 		istgt_lu_pass_parse_sense_key((uint8_t *) &spec->ccb->csio.sense_data,
298 		    &sk, &asc, &ascq);
299 		if (sk == ISTGT_SCSI_SENSE_ILLEGAL_REQUEST) {
300 			if (asc == 0x20 && ascq == 0x00) {
301 				/* INVALID COMMAND OPERATION CODE */
302 				goto retry_sense10;
303 			} else if (asc == 0x24 && ascq == 0x00) {
304 				/* INVALID FIELD IN CDB */
305 				goto retry_sense10;
306 			}
307 		}
308 		if (sk == ISTGT_SCSI_SENSE_UNIT_ATTENTION) {
309 			if (asc == 0x28 && ascq == 0x00) {
310 				/* NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED */
311 				goto retry_sense6;
312 			}
313 			if (asc == 0x29 && ascq == 0x00) {
314 				/* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
315 				goto retry_sense6;
316 			} else if (asc == 0x29 && ascq == 0x01) {
317 				/* POWER ON OCCURRED */
318 				goto retry_sense6;
319 			} else if (asc == 0x29 && ascq == 0x02) {
320 				/* SCSI BUS RESET OCCURRED */
321 				goto retry_sense6;
322 			} else if (asc == 0x29 && ascq == 0x03) {
323 				/* BUS DEVICE RESET FUNCTION OCCURRED */
324 				goto retry_sense6;
325 			} else if (asc == 0x29 && ascq == 0x04) {
326 				/* DEVICE INTERNAL RESET */
327 				goto retry_sense6;
328 			} else if (asc == 0x29 && ascq == 0x05) {
329 				/* TRANSCEIVER MODE CHANGED TO SINGLE-ENDED */
330 				goto retry_sense6;
331 			} else if (asc == 0x29 && ascq == 0x06) {
332 				/* TRANSCEIVER MODE CHANGED TO LVD */
333 				goto retry_sense6;
334 			} else if (asc == 0x29 && ascq == 0x07) {
335 				/* I_T NEXUS LOSS OCCURRED */
336 				goto retry_sense6;
337 			}
338 		}
339 		return -1;
340 	}
341 	data_len = spec->ccb->csio.dxfer_len;
342 	data_len -= spec->ccb->csio.resid;
343 	if (data_len < req_len) {
344 		ISTGT_ERRLOG("result is short\n");
345 		return -1;
346 	}
347 
348 	ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "MODE SENSE(6)", data, data_len);
349 	if (DGET8(&data[3]) != 0) { /* BLOCK DESCRIPTOR LENGTH */
350 		if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DISK) {
351 			spec->ms_blockcnt = DGET32(&data[4+0]);
352 			spec->ms_blocklen = DGET24(&data[4+5]);
353 		} else {
354 			spec->ms_blockcnt = DGET24(&data[4+1]);
355 			spec->ms_blocklen = DGET24(&data[4+5]);
356 		}
357 	} else {
358 		goto retry_sense10;
359 	}
360 
361 	if ((spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DISK
362 		 && spec->ms_blockcnt == 0xffffffffU)
363 		|| (spec->inq_pd != SPC_PERIPHERAL_DEVICE_TYPE_DISK
364 			&& spec->ms_blockcnt == 0x00ffffffU)) {
365 	retry_sense10:
366 		spec->ms_blockcnt = 0;
367 		spec->ms_blocklen = 0;
368 		memset(cdb, 0, sizeof cdb);
369 		/* issue MODE SENSE(10) */
370 		data_alloc_len = 8 + 16;        /* only block descriptor */
371 		req_len = 8 + 16;
372 		cdb[0] = SPC_MODE_SENSE_10;
373 		BDSET8(&cdb[1], 1, 4);          /* LLBAA */
374 		BDADD8(&cdb[1], 0, 3);          /* DBD */
375 		BDSET8W(&cdb[2], 0x00, 7, 2);   /* PC */
376 		//BDADD8W(&cdb[2], 0x00, 5, 6);   /* PAGE CODE */
377 		BDADD8W(&cdb[2], 0x3f, 5, 6);   /* PAGE CODE */
378 		cdb[3] = 0x00;                  /* SUBPAGE CODE */
379 		DSET16(&cdb[7], data_alloc_len); /* ALLOCATION LENGTH */
380 		cdb_len = 10;
381 		ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
382 
383 		memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
384 		flags = CAM_DIR_IN;
385 		flags |= CAM_DEV_QFRZDIS;
386 		cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
387 		    data, data_alloc_len, SSD_FULL_SIZE, cdb_len,
388 		    spec->timeout);
389 		rc = cam_send_ccb(spec->cam_dev, spec->ccb);
390 		if (rc < 0) {
391 			ISTGT_ERRLOG("cam_send_ccb() failed\n");
392 			return -1;
393 		}
394 
395 		if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
396 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
397 			    "request error CAM=0x%x, SCSI=0x%x\n",
398 			    spec->ccb->ccb_h.status,
399 			    spec->ccb->csio.scsi_status);
400 			ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
401 			    (uint8_t *) &spec->ccb->csio.sense_data,
402 			    SSD_FULL_SIZE);
403 			istgt_lu_pass_print_sense_key((uint8_t *) &spec->ccb->csio.sense_data);
404 			istgt_lu_pass_parse_sense_key((uint8_t *) &spec->ccb->csio.sense_data,
405 			    &sk, &asc, &ascq);
406 			if (sk == ISTGT_SCSI_SENSE_ILLEGAL_REQUEST) {
407 				if (spec->inq_ver < SPC_VERSION_SPC3) {
408 					//ISTGT_WARNLOG("MODE SENSE was not supported\n");
409 					return 0;
410 				}
411 				if (asc == 0x20 && ascq == 0x00) {
412 					/* INVALID COMMAND OPERATION CODE */
413 					return 0;
414 				} else if (asc == 0x24 && ascq == 0x00) {
415 					/* INVALID FIELD IN CDB */
416 					return 0;
417 				}
418 			}
419 			if (sk == ISTGT_SCSI_SENSE_UNIT_ATTENTION) {
420 				if (asc == 0x28 && ascq == 0x00) {
421 					/* NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED */
422 					goto retry_sense10;
423 				}
424 				if (asc == 0x29 && ascq == 0x00) {
425 					/* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
426 					goto retry_sense10;
427 				} else if (asc == 0x29 && ascq == 0x01) {
428 					/* POWER ON OCCURRED */
429 					goto retry_sense10;
430 				} else if (asc == 0x29 && ascq == 0x02) {
431 					/* SCSI BUS RESET OCCURRED */
432 					goto retry_sense10;
433 				} else if (asc == 0x29 && ascq == 0x03) {
434 					/* BUS DEVICE RESET FUNCTION OCCURRED */
435 					goto retry_sense10;
436 				} else if (asc == 0x29 && ascq == 0x04) {
437 					/* DEVICE INTERNAL RESET */
438 					goto retry_sense10;
439 				} else if (asc == 0x29 && ascq == 0x05) {
440 					/* TRANSCEIVER MODE CHANGED TO SINGLE-ENDED */
441 					goto retry_sense10;
442 				} else if (asc == 0x29 && ascq == 0x06) {
443 					/* TRANSCEIVER MODE CHANGED TO LVD */
444 					goto retry_sense10;
445 				} else if (asc == 0x29 && ascq == 0x07) {
446 					/* I_T NEXUS LOSS OCCURRED */
447 					goto retry_sense10;
448 				}
449 			}
450 			return -1;
451 		}
452 		data_len = spec->ccb->csio.dxfer_len;
453 		data_len -= spec->ccb->csio.resid;
454 		if (data_len < req_len) {
455 			ISTGT_ERRLOG("result is short\n");
456 			return -1;
457 		}
458 
459 		ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "MODE SENSE(10)", data, data_len);
460 		if (DGET16(&data[6]) != 0) { /* BLOCK DESCRIPTOR LENGTH */
461 			spec->ms_blockcnt = DGET64(&data[8+0]);
462 			spec->ms_blocklen = DGET32(&data[8+12]);
463 		}
464 	}
465 
466 	return 0;
467 }
468 
469 static int
istgt_lu_pass_set_capacity(ISTGT_LU_PASS * spec)470 istgt_lu_pass_set_capacity(ISTGT_LU_PASS *spec)
471 {
472 	uint8_t buf[MAX_TMPBUF];
473 	uint8_t cdb[16];
474 	uint32_t flags;
475 	uint8_t *data;
476 	int cdb_len;
477 	int data_len;
478 	int data_alloc_len;
479 	int req_len;
480 	int retry = 1;
481 	int sk, asc, ascq;
482 	int rc;
483 
484 	memset(buf, 0, sizeof buf);
485 	memset(cdb, 0, sizeof cdb);
486 	data = buf;
487 	if (sizeof buf > 0xfc) {
488 		data_alloc_len = 0xfc;
489 	} else {
490 		data_alloc_len = sizeof buf;
491 	}
492 
493 	/* issue READ CAPACITY (10) */
494  retry_capacity10:
495 	memset(cdb, 0, sizeof cdb);
496 	data_alloc_len = 8;
497 	req_len = 8;
498 	if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DISK) {
499 		cdb[0] = SBC_READ_CAPACITY_10;
500 		cdb_len = 10;
501 	} else if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DVD) {
502 		cdb[0] = MMC_READ_CAPACITY;
503 		cdb_len = 10;
504 	} else {
505 		ISTGT_ERRLOG("unsupported device\n");
506 		return -1;
507 	}
508 	ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
509 
510 	memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
511 	flags = CAM_DIR_IN;
512 	flags |= CAM_DEV_QFRZDIS;
513 	cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
514 	    data, data_alloc_len, SSD_FULL_SIZE, cdb_len,
515 	    spec->timeout);
516 	rc = cam_send_ccb(spec->cam_dev, spec->ccb);
517 	if (rc < 0) {
518 		ISTGT_ERRLOG("cam_send_ccb() failed\n");
519 		return -1;
520 	}
521 
522 	if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
523 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
524 		    "request error CAM=0x%x, SCSI=0x%x\n",
525 		    spec->ccb->ccb_h.status,
526 		    spec->ccb->csio.scsi_status);
527 		ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
528 		    (uint8_t *) &spec->ccb->csio.sense_data,
529 		    SSD_FULL_SIZE);
530 		istgt_lu_pass_print_sense_key((uint8_t *) &spec->ccb->csio.sense_data);
531 		istgt_lu_pass_parse_sense_key((uint8_t *) &spec->ccb->csio.sense_data,
532 		    &sk, &asc, &ascq);
533 		if (sk == ISTGT_SCSI_SENSE_NOT_READY) {
534 			if (asc == 0x04 && ascq == 0x01) {
535 				/* LOGICAL UNIT IS IN PROCESS OF BECOMING READY */
536 				sleep(2);
537 				goto retry_capacity10;
538 			}
539 			if (asc == 0x3a && ascq == 0x00) {
540 				/* MEDIUM NOT PRESENT */
541 				goto medium_not_present;
542 			} else if (asc == 0x3a && ascq == 0x01) {
543 				/* MEDIUM NOT PRESENT - TRAY CLOSED */
544 				goto medium_not_present;
545 			} else if (asc == 0x3a && ascq == 0x02) {
546 				/* MEDIUM NOT PRESENT - TRAY OPEN */
547 				goto medium_not_present;
548 			} else if (asc == 0x3a && ascq == 0x03) {
549 				/* MEDIUM NOT PRESENT - LOADABLE */
550 				goto medium_not_present;
551 			} else if (asc == 0x3a && ascq == 0x04) {
552 				/* MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE */
553 				goto medium_not_present;
554 			}
555 			ISTGT_ERRLOG("device not ready\n");
556 			return -1;
557 		}
558 		if (sk == ISTGT_SCSI_SENSE_UNIT_ATTENTION) {
559 			if (asc == 0x28 && ascq == 0x00) {
560 				/* NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED */
561 				goto retry_capacity10;
562 			}
563 			if (asc == 0x29 && ascq == 0x00) {
564 				/* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
565 				goto retry_capacity10;
566 			} else if (asc == 0x29 && ascq == 0x01) {
567 				/* POWER ON OCCURRED */
568 				goto retry_capacity10;
569 			} else if (asc == 0x29 && ascq == 0x02) {
570 				/* SCSI BUS RESET OCCURRED */
571 				goto retry_capacity10;
572 			} else if (asc == 0x29 && ascq == 0x03) {
573 				/* BUS DEVICE RESET FUNCTION OCCURRED */
574 				goto retry_capacity10;
575 			} else if (asc == 0x29 && ascq == 0x04) {
576 				/* DEVICE INTERNAL RESET */
577 				goto retry_capacity10;
578 			} else if (asc == 0x29 && ascq == 0x05) {
579 				/* TRANSCEIVER MODE CHANGED TO SINGLE-ENDED */
580 				goto retry_capacity10;
581 			} else if (asc == 0x29 && ascq == 0x06) {
582 				/* TRANSCEIVER MODE CHANGED TO LVD */
583 				goto retry_capacity10;
584 			} else if (asc == 0x29 && ascq == 0x07) {
585 				/* I_T NEXUS LOSS OCCURRED */
586 				goto retry_capacity10;
587 			}
588 		}
589 		return -1;
590 	}
591 	data_len = spec->ccb->csio.dxfer_len;
592 	data_len -= spec->ccb->csio.resid;
593 	if (data_len < req_len) {
594 		ISTGT_ERRLOG("result is short\n");
595 		return -1;
596 	}
597 
598 	ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "READ CAPACITY(10)", data, data_len);
599 	spec->blockcnt = (uint64_t) DGET32(&data[0]); // last LBA
600 	spec->blocklen = (uint64_t) DGET32(&data[4]);
601 
602 	if (spec->blockcnt == 0xffffffffU) {
603 	retry_capacity16:
604 		memset(cdb, 0, sizeof cdb);
605 		/* issue READ CAPACITY(16) */
606 		data_alloc_len = 32;
607 		req_len = 32;
608 		if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DISK) {
609 			cdb[0] = SPC_SERVICE_ACTION_IN_16;
610 			/* SERVICE ACTION */
611 			BDSET8W(&cdb[1], SBC_SAI_READ_CAPACITY_16, 4, 5);
612 			/* ALLOCATION LENGTH */
613 			DSET16(&cdb[10], data_alloc_len);
614 			cdb_len = 16;
615 		} else if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DVD) {
616 			ISTGT_ERRLOG("unsupported device\n");
617 			return -1;
618 		} else {
619 			ISTGT_ERRLOG("unsupported device\n");
620 			return -1;
621 		}
622 		ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
623 
624 		memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
625 		flags = CAM_DIR_IN;
626 		flags |= CAM_DEV_QFRZDIS;
627 		cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
628 		    data, data_alloc_len, SSD_FULL_SIZE, cdb_len,
629 		    spec->timeout);
630 		rc = cam_send_ccb(spec->cam_dev, spec->ccb);
631 		if (rc < 0) {
632 			ISTGT_ERRLOG("cam_send_ccb() failed\n");
633 			return -1;
634 		}
635 
636 		if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
637 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
638 			    "request error CAM=0x%x, SCSI=0x%x\n",
639 			    spec->ccb->ccb_h.status,
640 			    spec->ccb->csio.scsi_status);
641 			ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
642 			    (uint8_t *) &spec->ccb->csio.sense_data,
643 			    SSD_FULL_SIZE);
644 			istgt_lu_pass_print_sense_key((uint8_t *) &spec->ccb->csio.sense_data);
645 			istgt_lu_pass_parse_sense_key((uint8_t *) &spec->ccb->csio.sense_data,
646 			    &sk, &asc, &ascq);
647 			if (sk == ISTGT_SCSI_SENSE_NOT_READY) {
648 				if (asc == 0x04 && ascq == 0x01) {
649 					/* LOGICAL UNIT IS IN PROCESS OF BECOMING READY */
650 					sleep(2);
651 					goto retry_capacity16;
652 				}
653 				if (asc == 0x3a && ascq == 0x00) {
654 					/* MEDIUM NOT PRESENT */
655 					goto medium_not_present;
656 				} else if (asc == 0x3a && ascq == 0x01) {
657 					/* MEDIUM NOT PRESENT - TRAY CLOSED */
658 					goto medium_not_present;
659 				} else if (asc == 0x3a && ascq == 0x02) {
660 					/* MEDIUM NOT PRESENT - TRAY OPEN */
661 					goto medium_not_present;
662 				} else if (asc == 0x3a && ascq == 0x03) {
663 					/* MEDIUM NOT PRESENT - LOADABLE */
664 					goto medium_not_present;
665 				} else if (asc == 0x3a && ascq == 0x04) {
666 					/* MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE */
667 					goto medium_not_present;
668 				}
669 				ISTGT_ERRLOG("device not ready\n");
670 				return -1;
671 			}
672 			if (sk == ISTGT_SCSI_SENSE_UNIT_ATTENTION) {
673 				if (asc == 0x28 && ascq == 0x00) {
674 					/* NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED */
675 					goto retry_capacity16;
676 				}
677 				if (asc == 0x29 && ascq == 0x00) {
678 					/* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
679 					goto retry_capacity16;
680 				} else if (asc == 0x29 && ascq == 0x01) {
681 					/* POWER ON OCCURRED */
682 					goto retry_capacity16;
683 				} else if (asc == 0x29 && ascq == 0x02) {
684 					/* SCSI BUS RESET OCCURRED */
685 					goto retry_capacity16;
686 				} else if (asc == 0x29 && ascq == 0x03) {
687 					/* BUS DEVICE RESET FUNCTION OCCURRED */
688 					goto retry_capacity16;
689 				} else if (asc == 0x29 && ascq == 0x04) {
690 					/* DEVICE INTERNAL RESET */
691 					goto retry_capacity16;
692 				} else if (asc == 0x29 && ascq == 0x05) {
693 					/* TRANSCEIVER MODE CHANGED TO SINGLE-ENDED */
694 					goto retry_capacity16;
695 				} else if (asc == 0x29 && ascq == 0x06) {
696 					/* TRANSCEIVER MODE CHANGED TO LVD */
697 					goto retry_capacity16;
698 				} else if (asc == 0x29 && ascq == 0x07) {
699 					/* I_T NEXUS LOSS OCCURRED */
700 					goto retry_capacity16;
701 				}
702 			}
703 			return -1;
704 		}
705 		data_len = spec->ccb->csio.dxfer_len;
706 		data_len -= spec->ccb->csio.resid;
707 		if (data_len < req_len) {
708 			ISTGT_ERRLOG("result is short\n");
709 			return -1;
710 		}
711 
712 		ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "READ CAPACITY(16)",
713 		    data, data_len);
714 		spec->blockcnt = DGET64(&data[0]); // last LBA
715 		spec->blocklen = (uint64_t) DGET32(&data[8]);
716 	}
717 
718 	spec->blockcnt++;
719 	spec->size = spec->blockcnt * spec->blocklen;
720 	return 0;
721 
722  medium_not_present:
723 	spec->blockcnt = 0;
724 	spec->blocklen = 0;
725 	spec->size = 0;
726 	return 0;
727 }
728 
729 int
istgt_lu_pass_init(ISTGT_Ptr istgt,ISTGT_LU_Ptr lu)730 istgt_lu_pass_init(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu)
731 {
732 	char buf[MAX_TMPBUF];
733 	ISTGT_LU_PASS *spec;
734 	uint64_t gb_size;
735 	uint64_t mb_size;
736 	int mb_digit;
737 	int flags;
738 	int rc;
739 	int pq, pd, rmb;
740 	int ver, fmt;
741 	int i;
742 
743 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_pass_init\n");
744 
745 	printf("LU%d PASS-THROUGH UNIT\n", lu->num);
746 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
747 				   lu->num, lu->name);
748 	for (i = 0; i < lu->maxlun; i++) {
749 		if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
750 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
751 			    lu->num, i);
752 			lu->lun[i].spec = NULL;
753 			continue;
754 		}
755 		if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_DEVICE) {
756 			ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
757 			return -1;
758 		}
759 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d device\n",
760 		    lu->num, i);
761 
762 		spec = xmalloc(sizeof *spec);
763 		memset(spec, 0, sizeof *spec);
764 		spec->lu = lu;
765 		spec->num = lu->num;
766 		spec->lun = i;
767 
768 		spec->timeout = ISTGT_LU_CAM_TIMEOUT;
769 		spec->inq_standard = NULL;
770 		spec->inq_standard_len = 0;
771 		spec->inq_pd = 0;
772 		spec->inq_rmb = 0;
773 		spec->inq_ver = 0;
774 
775 		spec->file = lu->lun[i].u.device.file;
776 		spec->size = 0;
777 		spec->blocklen = 0;
778 		spec->blockcnt = 0;
779 
780 		printf("LU%d: LUN%d file=%s\n",
781 		    lu->num, i, spec->file);
782 
783 		flags = lu->readonly ? O_RDONLY : O_RDWR;
784 		rc = cam_get_device(spec->file, buf, sizeof buf,
785 		    &spec->unit);
786 		if (rc < 0) {
787 			ISTGT_ERRLOG("LU%d: LUN%d: cam_get_device() failed\n", lu->num, i);
788 			xfree(spec);
789 			return -1;
790 		}
791 		spec->device = xstrdup(buf);
792 		spec->cam_dev = cam_open_spec_device(spec->device, spec->unit,
793 		    flags, NULL);
794 		if (spec->cam_dev == NULL) {
795 			ISTGT_ERRLOG("LU%d: LUN%d: cam_open() failed\n", lu->num, i);
796 			xfree(spec->device);
797 			xfree(spec);
798 			return -1;
799 		}
800 		spec->ccb = cam_getccb(spec->cam_dev);
801 		if (spec->ccb == NULL) {
802 			ISTGT_ERRLOG("LU%d: LUN%d: cam_getccb() failed\n", lu->num, i);
803 			cam_close_spec_device(spec->cam_dev);
804 			xfree(spec->device);
805 			xfree(spec);
806 			return -1;
807 		}
808 		memset((uint8_t *) spec->ccb + sizeof(struct ccb_hdr), 0,
809 			   sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
810 
811 		rc = istgt_lu_pass_set_inquiry(spec);
812 		if (rc < 0) {
813 			ISTGT_ERRLOG("LU%d: LUN%d: lu_pass_set_inquiry() failed\n",
814 			    lu->num, i);
815 		error_return:
816 			cam_freeccb(spec->ccb);
817 			cam_close_spec_device(spec->cam_dev);
818 			xfree(spec->device);
819 			xfree(spec);
820 			return -1;
821 		}
822 
823 		/* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
824 		pq = BGET8W(&spec->inq_standard[0], 7, 3);
825 		pd = BGET8W(&spec->inq_standard[0], 4, 5);
826 		/* RMB(7) */
827 		rmb = BGET8W(&spec->inq_standard[1], 7, 1);
828 		/* VERSION ANSI(2-0) */
829 		ver = BGET8W(&spec->inq_standard[2], 2, 3);
830 		/* NORMACA(5) HISUP(4) RESPONSE DATA FORMAT(3-0) */
831 		fmt = BGET8W(&spec->inq_standard[3], 3, 4);
832 
833 		printf("LU%d: LUN%d pq=0x%x, pd=0x%x, rmb=%d, ver=%d, fmt=%d\n",
834 			   lu->num, i,
835 			   pq, pd, rmb, ver, fmt);
836 
837 		if (pq != 0x00) {
838 			ISTGT_ERRLOG("unsupported peripheral qualifier (%x)\n", pq);
839 			goto error_return;
840 		}
841 
842 		switch (pd) {
843 		case SPC_PERIPHERAL_DEVICE_TYPE_DISK:
844 			printf("LU%d: LUN%d Direct access block device\n", lu->num, i);
845 			break;
846 		case SPC_PERIPHERAL_DEVICE_TYPE_TAPE:
847 			printf("LU%d: LUN%d Sequential-access device\n", lu->num, i);
848 			break;
849 		case SPC_PERIPHERAL_DEVICE_TYPE_DVD:
850 			printf("LU%d: LUN%d CD/DVD device\n", lu->num, i);
851 			break;
852 		case SPC_PERIPHERAL_DEVICE_TYPE_CHANGER:
853 			printf("LU%d: LUN%d Medium changer device\n", lu->num, i);
854 			break;
855 		default:
856 			ISTGT_ERRLOG("unsupported peripheral device type (%x)\n", pd);
857 			goto error_return;
858 		}
859 
860 		switch (ver) {
861 		case SPC_VERSION_NONE:
862 			printf("LU%d: LUN%d version NONE\n", lu->num, i);
863 			break;
864 		case SPC_VERSION_SPC:
865 			printf("LU%d: LUN%d version SPC\n", lu->num, i);
866 			break;
867 		case SPC_VERSION_SPC2:
868 			printf("LU%d: LUN%d version SPC2\n", lu->num, i);
869 			break;
870 		case SPC_VERSION_SPC3:
871 			printf("LU%d: LUN%d version SPC3\n", lu->num, i);
872 			break;
873 		case SPC_VERSION_SPC4:
874 			printf("LU%d: LUN%d version SPC4\n", lu->num, i);
875 			break;
876 		case 0x01:
877 			printf("LU%d: LUN%d version SCSI1\n", lu->num, i);
878 			break;
879 		case 0x02:
880 			printf("LU%d: LUN%d version SCSI2\n", lu->num, i);
881 			break;
882 		default:
883 			ISTGT_ERRLOG("LU%d: LUN%d: unsupported version(%d)\n",
884 			    lu->num, i, ver);
885 			goto error_return;
886 		}
887 		switch (fmt) {
888 		case 0x00:
889 			printf("LU%d: LUN%d format SCSI1\n", lu->num, i);
890 			break;
891 		case 0x01:
892 			printf("LU%d: LUN%d format CCS\n", lu->num, i);
893 			break;
894 		case 0x02:
895 			printf("LU%d: LUN%d format SCSI2/SPC\n", lu->num, i);
896 			break;
897 		default:
898 			ISTGT_ERRLOG("LU%d: LUN%d: unsupported format(%d)\n",
899 			    lu->num, i, fmt);
900 			goto error_return;
901 		}
902 
903 		spec->inq_pd = pd;
904 		spec->inq_rmb = rmb;
905 		spec->inq_ver = ver;
906 		spec->inq_fmt = fmt;
907 
908 		if (pd != SPC_PERIPHERAL_DEVICE_TYPE_CHANGER) {
909 			rc = istgt_lu_pass_set_modesense(spec);
910 			if (rc < 0) {
911 #if 0
912 				ISTGT_ERRLOG("LU%d: LUN%d: lu_pass_set_modesense() failed\n",
913 				    lu->num, i);
914 				goto error_return;
915 #else
916 				spec->ms_blockcnt = 0;
917 				spec->ms_blocklen = 0;
918 #endif
919 			}
920 		} else {
921 			spec->ms_blockcnt = 0;
922 			spec->ms_blocklen = 0;
923 		}
924 
925 		if (pd == SPC_PERIPHERAL_DEVICE_TYPE_TAPE
926 			|| pd == SPC_PERIPHERAL_DEVICE_TYPE_CHANGER) {
927 			spec->timeout *= 10;
928 		}
929 		if (pd == SPC_PERIPHERAL_DEVICE_TYPE_DISK
930 			|| pd == SPC_PERIPHERAL_DEVICE_TYPE_DVD) {
931 			rc = istgt_lu_pass_set_capacity(spec);
932 			if (rc < 0) {
933 				ISTGT_ERRLOG("LU%d: LUN%d: lu_pass_set_capacity() failed\n",
934 				    lu->num, i);
935 				goto error_return;
936 			}
937 		} else {
938 			spec->blockcnt = 0;
939 			spec->blocklen = 0;
940 			spec->size = 0;
941 		}
942 		if (spec->ms_blocklen == 0) {
943 			if (spec->blocklen == 0) {
944 				if (pd == SPC_PERIPHERAL_DEVICE_TYPE_DVD) {
945 					spec->ms_blocklen = 2048;
946 				} else {
947 					spec->ms_blocklen = 512;
948 				}
949 			} else {
950 				spec->ms_blocklen = spec->blocklen;
951 			}
952 		}
953 
954 		if (pd != SPC_PERIPHERAL_DEVICE_TYPE_CHANGER) {
955 			printf("LU%d: LUN%d block descriptor\n", lu->num, i);
956 			printf("LU%d: LUN%d %"PRIu64" blocks, %"PRIu64" bytes/block\n",
957 			    lu->num, i, spec->ms_blockcnt, spec->ms_blocklen);
958 
959 			if (spec->inq_rmb && spec->blockcnt == 0) {
960 				printf("LU%d: LUN%d medium not present\n", lu->num, i);
961 			} else {
962 				printf("LU%d: LUN%d medium capacity\n", lu->num, i);
963 				printf("LU%d: LUN%d %"PRIu64" blocks, %"PRIu64" bytes/block\n",
964 					   lu->num, i, spec->blockcnt, spec->blocklen);
965 
966 				gb_size = spec->size / ISTGT_LU_1GB;
967 				mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB;
968 				if (gb_size > 0) {
969 					mb_digit = (int) (((mb_size * 100) / 1024) / 10);
970 					printf("LU%d: LUN%d %"PRIu64".%dGB\n",
971 					    lu->num, i, gb_size, mb_digit);
972 				} else {
973 					printf("LU%d: LUN%d %"PRIu64"MB\n",
974 					    lu->num, i, mb_size);
975 				}
976 			}
977 		}
978 
979 		printf("LU%d: LUN%d %spass through for %s\n",
980 			   lu->num, i,
981 			   lu->readonly ? "readonly " : "", lu->name);
982 
983 		lu->lun[i].spec = spec;
984 	}
985 
986 	return 0;
987 }
988 
989 int
istgt_lu_pass_shutdown(ISTGT_Ptr istgt,ISTGT_LU_Ptr lu)990 istgt_lu_pass_shutdown(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu)
991 {
992 	ISTGT_LU_PASS *spec;
993 	int i;
994 
995 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_pass_shutdown\n");
996 
997 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
998 				   lu->num, lu->name);
999 	for (i = 0; i < lu->maxlun; i++) {
1000 		if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
1001 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
1002 			    lu->num, i);
1003 			continue;
1004 		}
1005 		if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_DEVICE) {
1006 			ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
1007 			return -1;
1008 		}
1009 		spec = (ISTGT_LU_PASS *) lu->lun[i].spec;
1010 
1011 		if (spec->ccb != NULL) {
1012 			cam_freeccb(spec->ccb);
1013 			spec->ccb = NULL;
1014 		}
1015 		if (spec->cam_dev != NULL) {
1016 			cam_close_spec_device(spec->cam_dev);
1017 			spec->cam_dev = NULL;
1018 		}
1019 		if (spec->device != NULL) {
1020 			xfree(spec->device);
1021 			spec->device = NULL;
1022 		}
1023 		xfree(spec);
1024 		lu->lun[i].spec = NULL;
1025 	}
1026 
1027 	return 0;
1028 }
1029 
1030 static int
istgt_scsi_get_cdb_len(uint8_t * cdb)1031 istgt_scsi_get_cdb_len(uint8_t *cdb)
1032 {
1033 	int group;
1034 	int cdblen = 0;
1035 
1036 	if (cdb == NULL)
1037 		return 0;
1038 
1039 	group = (cdb[0] >> 5) & 0x07;
1040 	switch (group) {
1041 	case 0x00:
1042 		/* 6byte commands */
1043 		cdblen = 6;
1044 		break;
1045 	case 0x01:
1046 		/* 10byte commands */
1047 		cdblen = 10;
1048 		break;
1049 	case 0x02:
1050 		/* 10byte commands */
1051 		cdblen = 10;
1052 		break;
1053 	case 0x03:
1054 		/* reserved */
1055 		if (cdb[0] == 0x7f) {
1056 			/* variable length */
1057 			cdblen = 8 + (cdb[7] & 0xff);
1058 		} else {
1059 			/* XXX */
1060 			cdblen = 6;
1061 		}
1062 		break;
1063 	case 0x04:
1064 		/* 16byte commands */
1065 		cdblen = 16;
1066 		break;
1067 	case 0x05:
1068 		/* 12byte commands */
1069 		cdblen = 12;
1070 		break;
1071 	case 0x06:
1072 	case 0x07:
1073 		/* vendor specific */
1074 		cdblen = 6;
1075 		break;
1076 	}
1077 	return cdblen;
1078 }
1079 
1080 static int
istgt_lu_pass_transfer_data(CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint8_t * buf,size_t bufsize,size_t len)1081 istgt_lu_pass_transfer_data(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *buf, size_t bufsize, size_t len)
1082 {
1083 	int rc;
1084 
1085 	if (len > bufsize) {
1086 		ISTGT_ERRLOG("bufsize(%zd) too small\n", bufsize);
1087 		return -1;
1088 	}
1089 	rc = istgt_iscsi_transfer_out(conn, lu_cmd, buf, bufsize, len);
1090 	if (rc < 0) {
1091 		ISTGT_ERRLOG("iscsi_transfer_out()\n");
1092 		return -1;
1093 	}
1094 	return 0;
1095 }
1096 
1097 static int
istgt_lu_pass_do_cam(ISTGT_LU_PASS * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)1098 istgt_lu_pass_do_cam(ISTGT_LU_PASS *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd)
1099 {
1100 	uint32_t flags;
1101 	uint8_t *cdb;
1102 	uint8_t *data;
1103 	int cdb_len;
1104 	int data_len;
1105 	uint8_t *sense_data;
1106 	size_t *sense_len;
1107 	size_t len;
1108 	int R_bit, W_bit;
1109 	int transfer_len;
1110 	int retry = 1;
1111 	int sk, asc, ascq;
1112 	int rc;
1113 
1114 	cdb = lu_cmd->cdb;
1115 	data = lu_cmd->data;
1116 	//data_alloc_len = lu_cmd->alloc_len;
1117 	sense_data = lu_cmd->sense_data;
1118 	sense_len = &lu_cmd->sense_data_len;
1119 	*sense_len = 0;
1120 	R_bit = lu_cmd->R_bit;
1121 	W_bit = lu_cmd->W_bit;
1122 	transfer_len = lu_cmd->transfer_len;
1123 
1124 	cdb_len = istgt_scsi_get_cdb_len(cdb);
1125 	ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
1126 
1127 	memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
1128 	flags = CAM_DIR_NONE;
1129 	if (R_bit != 0) {
1130 		flags = CAM_DIR_IN;
1131 	} else if (W_bit != 0) {
1132 		flags = CAM_DIR_OUT;
1133 	}
1134 	flags |= CAM_DEV_QFRZDIS;
1135 	cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
1136 	    data, transfer_len, SSD_FULL_SIZE, cdb_len,
1137 	    spec->timeout);
1138 	rc = cam_send_ccb(spec->cam_dev, spec->ccb);
1139 	if (rc < 0) {
1140 		ISTGT_ERRLOG("cam_send_ccb() failed\n");
1141 		/* INTERNAL TARGET FAILURE */
1142 		BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
1143 		lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1144 		return -1;
1145 	}
1146 
1147 	if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1148 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1149 		    "request error CAM=0x%x, SCSI=0x%x\n",
1150 		    spec->ccb->ccb_h.status,
1151 		    spec->ccb->csio.scsi_status);
1152 		ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
1153 		    (uint8_t *) &spec->ccb->csio.sense_data,
1154 		    SSD_FULL_SIZE);
1155 		if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK)
1156 			== CAM_SCSI_STATUS_ERROR) {
1157 			memcpy(sense_data + 2, &spec->ccb->csio.sense_data, SSD_FULL_SIZE);
1158 			DSET16(&sense_data[0], SSD_FULL_SIZE);
1159 			*sense_len = SSD_FULL_SIZE + 2;
1160 			lu_cmd->status = spec->ccb->csio.scsi_status;
1161 #if 0
1162 			if (lu_cmd->status == 0) {
1163 				/* INTERNAL TARGET FAILURE */
1164 				BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
1165 				lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1166 			}
1167 #endif
1168 			/* adjust fixed format length */
1169 			if (BGET8W(&sense_data[2+0], 6, 7) == 0x70
1170 				|| BGET8W(&sense_data[2+0], 6, 7) == 0x71) {
1171 				len = DGET8(&sense_data[2+7]);
1172 				len += 8;
1173 				if (len < SSD_FULL_SIZE) {
1174 					*sense_len = len + 2;
1175 					DSET16(&sense_data[0], len);
1176 				}
1177 			}
1178 			istgt_lu_pass_print_sense_key(sense_data + 2);
1179 			istgt_lu_pass_parse_sense_key(sense_data + 2,
1180 			    &sk, &asc, &ascq);
1181 		} else {
1182 #if 0
1183 			/* INTERNAL TARGET FAILURE */
1184 			BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
1185 			lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1186 #endif
1187 			memcpy(sense_data + 2, &spec->ccb->csio.sense_data, SSD_FULL_SIZE);
1188 			DSET16(&sense_data[0], SSD_FULL_SIZE);
1189 			*sense_len = SSD_FULL_SIZE + 2;
1190 			lu_cmd->status = spec->ccb->csio.scsi_status;
1191 			/* adjust fixed format length */
1192 			if (BGET8W(&sense_data[2+0], 6, 7) == 0x70
1193 				|| BGET8W(&sense_data[2+0], 6, 7) == 0x71) {
1194 				len = DGET8(&sense_data[2+7]);
1195 				len += 8;
1196 				if (len < SSD_FULL_SIZE) {
1197 					*sense_len = len + 2;
1198 					DSET16(&sense_data[0], len);
1199 				}
1200 			}
1201 			istgt_lu_pass_print_sense_key(sense_data + 2);
1202 			istgt_lu_pass_parse_sense_key(sense_data + 2,
1203 			    &sk, &asc, &ascq);
1204 		}
1205 		if (lu_cmd->status == 0) {
1206 			/* XXX don't return with zero */
1207 			lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1208 		}
1209 		return -1;
1210 	}
1211 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "dxfer=%d, resid=%d, sense=%d\n",
1212 	    spec->ccb->csio.dxfer_len,
1213 	    spec->ccb->csio.resid,
1214 	    spec->ccb->csio.sense_resid);
1215 	data_len = spec->ccb->csio.dxfer_len;
1216 	data_len -= spec->ccb->csio.resid;
1217 
1218 	if (R_bit != 0 || W_bit != 0) {
1219 #if 0
1220 		if (data_len > 256) {
1221 			ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DOCAM", data, 256);
1222 		} else {
1223 			ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DOCAM", data, data_len);
1224 		}
1225 #endif
1226 		lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1227 	} else {
1228 		lu_cmd->data_len = 0;
1229 	}
1230 
1231 	lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
1232 	return 0;
1233 }
1234 
1235 static int
istgt_lu_pass_do_cam_seg(ISTGT_LU_PASS * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)1236 istgt_lu_pass_do_cam_seg(ISTGT_LU_PASS *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd)
1237 {
1238 	uint64_t llba;
1239 	uint32_t lcnt;
1240 	uint32_t flags;
1241 	uint8_t fixcdb[16];
1242 	uint8_t *cdb;
1243 	uint8_t *data;
1244 	int pad_len;
1245 	int cdb_len;
1246 	int data_len;
1247 	int data_alloc_len;
1248 	uint8_t *sense_data;
1249 	size_t *sense_len;
1250 	size_t len, cnt;
1251 	int R_bit, W_bit;
1252 	int transfer_len;
1253 	int retry = 1;
1254 	int offset;
1255 	int seglen;
1256 	int sk, asc, ascq;
1257 	int rc;
1258 
1259 	cdb = lu_cmd->cdb;
1260 	data = lu_cmd->data;
1261 	data_alloc_len = lu_cmd->alloc_len;
1262 	sense_data = lu_cmd->sense_data;
1263 	sense_len = &lu_cmd->sense_data_len;
1264 	*sense_len = 0;
1265 	R_bit = lu_cmd->R_bit;
1266 	W_bit = lu_cmd->W_bit;
1267 	transfer_len = lu_cmd->transfer_len;
1268 
1269 	cdb_len = istgt_scsi_get_cdb_len(cdb);
1270 	ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
1271 
1272 	memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
1273 	flags = CAM_DIR_NONE;
1274 	if (R_bit != 0) {
1275 		flags = CAM_DIR_IN;
1276 	} else if (W_bit != 0) {
1277 		flags = CAM_DIR_OUT;
1278 	}
1279 	flags |= CAM_DEV_QFRZDIS;
1280 
1281 //#define MAX_SEGLEN (65536-4096)
1282 #define MAX_SEGLEN (65536)
1283 	pad_len = (int) ((uintptr_t) data & (4096 - 1));
1284 	if (pad_len != 0) {
1285 		pad_len = 4096 - pad_len;
1286 		data += pad_len;
1287 		data_alloc_len -= pad_len;
1288 	}
1289 	data_len = 0;
1290 	seglen = MAX_SEGLEN;
1291 	seglen -= MAX_SEGLEN % (int) spec->ms_blocklen;
1292 	len = 0;
1293 	for (offset = 0; offset < transfer_len; offset += seglen) {
1294 		len = DMIN32(seglen, (transfer_len - offset));
1295 		cnt = len / (int) spec->ms_blocklen;
1296 		switch(cdb[0]) {
1297 		case SBC_READ_6:
1298 			memcpy(fixcdb, cdb, cdb_len);
1299 			llba = (uint64_t) DGET16(&cdb[2]);
1300 			lcnt = (uint32_t) DGET8(&cdb[4]);
1301 			llba += offset / spec->ms_blocklen;
1302 			lcnt = (uint64_t) cnt;
1303 			DSET16(&fixcdb[2], (uint16_t) llba);
1304 			DSET8(&fixcdb[4], (uint8_t) lcnt);
1305 			memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
1306 			break;
1307 
1308 		case SBC_READ_10:
1309 			memcpy(fixcdb, cdb, cdb_len);
1310 			llba = (uint64_t) DGET32(&cdb[2]);
1311 			lcnt = (uint32_t) DGET16(&cdb[7]);
1312 			llba += offset / spec->ms_blocklen;
1313 			lcnt = (uint64_t) cnt;
1314 			DSET32(&fixcdb[2], (uint32_t) llba);
1315 			DSET16(&fixcdb[7], (uint16_t) lcnt);
1316 			memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
1317 			break;
1318 
1319 		case SBC_READ_12:
1320 			memcpy(fixcdb, cdb, cdb_len);
1321 			llba = (uint64_t) DGET32(&cdb[2]);
1322 			lcnt = (uint32_t) DGET32(&cdb[6]);
1323 			llba += offset / spec->ms_blocklen;
1324 			lcnt = (uint64_t) cnt;
1325 			DSET32(&fixcdb[2], (uint32_t) llba);
1326 			DSET32(&fixcdb[6], (uint32_t) lcnt);
1327 			memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
1328 			break;
1329 
1330 		case SBC_READ_16:
1331 			memcpy(fixcdb, cdb, cdb_len);
1332 			llba = (uint64_t) DGET64(&cdb[2]);
1333 			lcnt = (uint32_t) DGET32(&cdb[10]);
1334 			llba += offset / spec->ms_blocklen;
1335 			lcnt = (uint64_t) cnt;
1336 			DSET64(&fixcdb[2], (uint64_t) llba);
1337 			DSET32(&fixcdb[10], (uint32_t) lcnt);
1338 			memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
1339 			break;
1340 
1341 		case SBC_WRITE_6:
1342 			memcpy(fixcdb, cdb, cdb_len);
1343 			llba = (uint64_t) DGET16(&cdb[2]);
1344 			lcnt = (uint32_t) DGET8(&cdb[4]);
1345 			llba += offset / spec->ms_blocklen;
1346 			lcnt = (uint64_t) cnt;
1347 			DSET16(&fixcdb[2], (uint16_t) llba);
1348 			DSET8(&fixcdb[4], (uint8_t) lcnt);
1349 			memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
1350 			break;
1351 
1352 		case SBC_WRITE_10:
1353 		case SBC_WRITE_AND_VERIFY_10:
1354 			memcpy(fixcdb, cdb, cdb_len);
1355 			llba = (uint64_t) DGET32(&cdb[2]);
1356 			lcnt = (uint32_t) DGET16(&cdb[7]);
1357 			llba += offset / spec->ms_blocklen;
1358 			lcnt = (uint64_t) cnt;
1359 			DSET32(&fixcdb[2], (uint32_t) llba);
1360 			DSET16(&fixcdb[7], (uint16_t) lcnt);
1361 			memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
1362 			break;
1363 
1364 		case SBC_WRITE_12:
1365 		case SBC_WRITE_AND_VERIFY_12:
1366 			memcpy(fixcdb, cdb, cdb_len);
1367 			llba = (uint64_t) DGET32(&cdb[2]);
1368 			lcnt = (uint32_t) DGET32(&cdb[6]);
1369 			llba += offset / spec->ms_blocklen;
1370 			lcnt = (uint64_t) cnt;
1371 			DSET32(&fixcdb[2], (uint32_t) llba);
1372 			DSET32(&fixcdb[6], (uint32_t) lcnt);
1373 			memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
1374 			break;
1375 
1376 		case SBC_WRITE_16:
1377 		case SBC_WRITE_AND_VERIFY_16:
1378 			memcpy(fixcdb, cdb, cdb_len);
1379 			llba = (uint64_t) DGET64(&cdb[2]);
1380 			lcnt = (uint32_t) DGET32(&cdb[10]);
1381 			llba += offset / spec->ms_blocklen;
1382 			lcnt = (uint64_t) cnt;
1383 			DSET64(&fixcdb[2], (uint64_t) llba);
1384 			DSET32(&fixcdb[10], (uint32_t) lcnt);
1385 			memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
1386 			break;
1387 
1388 		default:
1389 			ISTGT_ERRLOG("unsupported OP=0x%x\n", cdb[0]);
1390 			/* INTERNAL TARGET FAILURE */
1391 			BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
1392 			lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1393 			return -1;
1394 		}
1395 
1396 		cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
1397 		    data + offset, len, SSD_FULL_SIZE, cdb_len,
1398 		    spec->timeout);
1399 		rc = cam_send_ccb(spec->cam_dev, spec->ccb);
1400 		if (rc < 0) {
1401 			ISTGT_ERRLOG("cam_send_ccb() failed\n");
1402 			/* INTERNAL TARGET FAILURE */
1403 			BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
1404 			lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1405 			return -1;
1406 		}
1407 
1408 		if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1409 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1410 			    "request error CAM=0x%x, SCSI=0x%x\n",
1411 			    spec->ccb->ccb_h.status,
1412 			    spec->ccb->csio.scsi_status);
1413 			ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
1414 			    (uint8_t *) &spec->ccb->csio.sense_data,
1415 			    SSD_FULL_SIZE);
1416 			if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK)
1417 			    == CAM_SCSI_STATUS_ERROR) {
1418 				memcpy(sense_data + 2, &spec->ccb->csio.sense_data, SSD_FULL_SIZE);
1419 				DSET16(&sense_data[0], SSD_FULL_SIZE);
1420 				*sense_len = SSD_FULL_SIZE + 2;
1421 				lu_cmd->status = spec->ccb->csio.scsi_status;
1422 #if 0
1423 				if (lu_cmd->status == 0) {
1424 					/* INTERNAL TARGET FAILURE */
1425 					BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
1426 					lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1427 				}
1428 #endif
1429 				/* adjust fixed format length */
1430 				if (BGET8W(&sense_data[2+0], 6, 7) == 0x70
1431 				    || BGET8W(&sense_data[2+0], 6, 7) == 0x71) {
1432 					len = DGET8(&sense_data[2+7]);
1433 					len += 8;
1434 					if (len < SSD_FULL_SIZE) {
1435 						*sense_len = len + 2;
1436 						DSET16(&sense_data[0], len);
1437 					}
1438 				}
1439 				istgt_lu_pass_print_sense_key(sense_data + 2);
1440 				istgt_lu_pass_parse_sense_key(sense_data + 2,
1441 				    &sk, &asc, &ascq);
1442 			} else {
1443 #if 0
1444 				/* INTERNAL TARGET FAILURE */
1445 				BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
1446 				lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1447 #endif
1448 				memcpy(sense_data + 2, &spec->ccb->csio.sense_data, SSD_FULL_SIZE);
1449 				DSET16(&sense_data[0], SSD_FULL_SIZE);
1450 				*sense_len = SSD_FULL_SIZE + 2;
1451 				lu_cmd->status = spec->ccb->csio.scsi_status;
1452 				/* adjust fixed format length */
1453 				if (BGET8W(&sense_data[2+0], 6, 7) == 0x70
1454 				    || BGET8W(&sense_data[2+0], 6, 7) == 0x71) {
1455 					len = DGET8(&sense_data[2+7]);
1456 					len += 8;
1457 					if (len < SSD_FULL_SIZE) {
1458 						*sense_len = len + 2;
1459 						DSET16(&sense_data[0], len);
1460 					}
1461 				}
1462 				istgt_lu_pass_print_sense_key(sense_data + 2);
1463 				istgt_lu_pass_parse_sense_key(sense_data + 2,
1464 				    &sk, &asc, &ascq);
1465 			}
1466 			if (lu_cmd->status == 0) {
1467 				/* XXX don't return with zero */
1468 				lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1469 			}
1470 			return -1;
1471 		}
1472 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "dxfer=%d, resid=%d, sense=%d\n",
1473 		    spec->ccb->csio.dxfer_len,
1474 		    spec->ccb->csio.resid,
1475 		    spec->ccb->csio.sense_resid);
1476 		if (spec->ccb->csio.resid != 0) {
1477 			/* INTERNAL TARGET FAILURE */
1478 			BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
1479 			lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1480 			return -1;
1481 		}
1482 		data_len += spec->ccb->csio.dxfer_len;
1483 		data_len -= spec->ccb->csio.resid;
1484 	}
1485 
1486 	if (pad_len != 0) {
1487 		memcpy(lu_cmd->data, lu_cmd->data + pad_len, data_len);
1488 	}
1489 	if (R_bit !=0 || W_bit != 0) {
1490 #if 0
1491 		if (data_len > 256) {
1492 			ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DOCAM", data, 256);
1493 		} else {
1494 			ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DOCAM", data, data_len);
1495 		}
1496 #endif
1497 		lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1498 	} else {
1499 		lu_cmd->data_len = 0;
1500 	}
1501 
1502 	lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
1503 	return 0;
1504 }
1505 
1506 static int
istgt_lu_pass_build_sense_data(ISTGT_LU_PASS * spec,uint8_t * data,int sk,int asc,int ascq)1507 istgt_lu_pass_build_sense_data(ISTGT_LU_PASS *spec __attribute__((__unused__)), uint8_t *data, int sk, int asc, int ascq)
1508 {
1509 	int rc;
1510 
1511 	rc = istgt_lu_scsi_build_sense_data(data, sk, asc, ascq);
1512 	if (rc < 0) {
1513 		return -1;
1514 	}
1515 	return rc;
1516 }
1517 
1518 int
istgt_lu_pass_reset(ISTGT_LU_Ptr lu,int lun)1519 istgt_lu_pass_reset(ISTGT_LU_Ptr lu, int lun)
1520 {
1521 	ISTGT_LU_PASS *spec;
1522 
1523 	if (lun >= lu->maxlun) {
1524 		return -1;
1525 	}
1526 	if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
1527 		return -1;
1528 	}
1529 	spec = (ISTGT_LU_PASS *) lu->lun[lun].spec;
1530 
1531 #if 0
1532 	if (spec->lock) {
1533 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "unlock by reset\n");
1534 		spec->lock = 0;
1535 	}
1536 #endif
1537 
1538 	return 0;
1539 }
1540 
1541 int
istgt_lu_pass_execute(CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)1542 istgt_lu_pass_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
1543 {
1544 	ISTGT_LU_Ptr lu;
1545 	ISTGT_LU_PASS *spec;
1546 	uint8_t *data;
1547 	uint8_t *cdb;
1548 	uint64_t fmt_lun;
1549 	uint64_t lun;
1550 	uint64_t method;
1551 	uint32_t allocation_len;
1552 	int data_len;
1553 	int data_alloc_len;
1554 	uint32_t transfer_len;
1555 	uint8_t *sense_data;
1556 	size_t *sense_len;
1557 	int rc;
1558 
1559 	if (lu_cmd == NULL)
1560 		return -1;
1561 	lu = lu_cmd->lu;
1562 	if (lu == NULL) {
1563 		lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1564 		return -1;
1565 	}
1566 	spec = NULL;
1567 	cdb = lu_cmd->cdb;
1568 	data = lu_cmd->data;
1569 	data_alloc_len = lu_cmd->alloc_len;
1570 	sense_data = lu_cmd->sense_data;
1571 	sense_len = &lu_cmd->sense_data_len;
1572 	*sense_len = 0;
1573 
1574 	fmt_lun = lu_cmd->lun;
1575 	method = (fmt_lun >> 62) & 0x03U;
1576 	fmt_lun = fmt_lun >> 48;
1577 	if (method == 0x00U) {
1578 		lun = fmt_lun & 0x00ffU;
1579 	} else if (method == 0x01U) {
1580 		lun = fmt_lun & 0x3fffU;
1581 	} else {
1582 		lun = 0xffffU;
1583 	}
1584 	if (lun >= (uint64_t) lu->maxlun) {
1585 #ifdef ISTGT_TRACE_PASS
1586 		ISTGT_ERRLOG("LU%d: LUN%4.4"PRIx64" invalid\n",
1587 		    lu->num, lun);
1588 #endif /* ISTGT_TRACE_PASS */
1589 		if (cdb[0] == SPC_INQUIRY) {
1590 			allocation_len = DGET16(&cdb[3]);
1591 			if (allocation_len > (size_t) data_alloc_len) {
1592 				ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1593 				    data_alloc_len);
1594 				lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1595 				return -1;
1596 			}
1597 			memset(data, 0, allocation_len);
1598 			/* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1599 			BDSET8W(&data[0], 0x03, 7, 3);
1600 			BDADD8W(&data[0], 0x1f, 4, 5);
1601 			data_len = 96;
1602 			memset(&data[1], 0, data_len - 1);
1603 			/* ADDITIONAL LENGTH */
1604 			data[4] = data_len - 5;
1605 			lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1606 			lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
1607 			return 0;
1608 		} else {
1609 			/* LOGICAL UNIT NOT SUPPORTED */
1610 			BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
1611 			lu_cmd->data_len = 0;
1612 			lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1613 			return 0;
1614 		}
1615 	}
1616 	spec = (ISTGT_LU_PASS *) lu->lun[lun].spec;
1617 	if (spec == NULL) {
1618 		/* LOGICAL UNIT NOT SUPPORTED */
1619 		BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
1620 		lu_cmd->data_len = 0;
1621 		lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1622 		return 0;
1623 	}
1624 
1625 	ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SCSI OP=0x%x, LUN=0x%16.16"PRIx64"\n",
1626 	    cdb[0], lu_cmd->lun);
1627 #ifdef ISTGT_TRACE_PASS
1628 	if (cdb[0] != SPC_TEST_UNIT_READY) {
1629 		istgt_scsi_dump_cdb(cdb);
1630 	}
1631 #endif /* ISTGT_TRACE_DISK */
1632 
1633 	if (lu_cmd->W_bit != 0) {
1634 		transfer_len = lu_cmd->transfer_len;
1635 		rc = istgt_lu_pass_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
1636 		    lu_cmd->iobufsize, transfer_len);
1637 		if (rc < 0) {
1638 			ISTGT_ERRLOG("lu_pass_transfer_data() failed\n");
1639 			lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1640 			return -1;
1641 		}
1642 		lu_cmd->data = lu_cmd->iobuf;
1643 		lu_cmd->alloc_len = lu_cmd->iobufsize;
1644 	}
1645 
1646 	switch (spec->inq_pd) {
1647 	case SPC_PERIPHERAL_DEVICE_TYPE_DISK:
1648 		switch (cdb[0]) {
1649 		case SBC_READ_6:
1650 		case SBC_READ_10:
1651 		case SBC_READ_12:
1652 		case SBC_READ_16:
1653 		case SBC_WRITE_6:
1654 		case SBC_WRITE_12:
1655 		case SBC_WRITE_AND_VERIFY_12:
1656 		case SBC_WRITE_10:
1657 		case SBC_WRITE_AND_VERIFY_10:
1658 		case SBC_WRITE_16:
1659 		case SBC_WRITE_AND_VERIFY_16:
1660 			lu_cmd->data = lu_cmd->iobuf;
1661 			lu_cmd->alloc_len = lu_cmd->iobufsize;
1662 			if (lu_cmd->transfer_len > lu_cmd->alloc_len) {
1663 				ISTGT_ERRLOG("alloc_len(%zd) too small\n", lu_cmd->alloc_len);
1664 				lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1665 				return -1;
1666 			}
1667 			rc = istgt_lu_pass_do_cam_seg(spec, conn, lu_cmd);
1668 			if (rc < 0) {
1669 				/* build by function */
1670 				break;
1671 			}
1672 			lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
1673 			break;
1674 		default:
1675 			rc = istgt_lu_pass_do_cam(spec, conn, lu_cmd);
1676 			if (rc < 0) {
1677 				/* build by function */
1678 				break;
1679 			}
1680 			lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
1681 			break;
1682 		}
1683 		break;
1684 	case SPC_PERIPHERAL_DEVICE_TYPE_TAPE:
1685 		switch (cdb[0]) {
1686 		default:
1687 			rc = istgt_lu_pass_do_cam(spec, conn, lu_cmd);
1688 			if (rc < 0) {
1689 				/* build by function */
1690 				break;
1691 			}
1692 			lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
1693 			break;
1694 		}
1695 		break;
1696 	case SPC_PERIPHERAL_DEVICE_TYPE_DVD:
1697 		switch (cdb[0]) {
1698 		case MMC_READ_10:
1699 		case MMC_READ_12:
1700 		case MMC_WRITE_10:
1701 		case MMC_WRITE_AND_VERIFY_10:
1702 		case MMC_WRITE_12:
1703 			lu_cmd->data = lu_cmd->iobuf;
1704 			lu_cmd->alloc_len = lu_cmd->iobufsize;
1705 			if (lu_cmd->transfer_len > lu_cmd->alloc_len) {
1706 				ISTGT_ERRLOG("alloc_len(%zd) too small\n", lu_cmd->alloc_len);
1707 				lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1708 				return -1;
1709 			}
1710 			rc = istgt_lu_pass_do_cam_seg(spec, conn, lu_cmd);
1711 			if (rc < 0) {
1712 				/* build by function */
1713 				break;
1714 			}
1715 			lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
1716 			break;
1717 #ifdef ISTGT_TRACE_PASS
1718 		case MMC_GET_EVENT_STATUS_NOTIFICATION:
1719 			rc = istgt_lu_pass_do_cam(spec, conn, lu_cmd);
1720 			if (rc < 0) {
1721 				/* build by function */
1722 				break;
1723 			}
1724 			ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "EVENT",
1725 			    lu_cmd->data, lu_cmd->data_len);
1726 			lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
1727 			break;
1728 #endif /* ISTGT_TRACE_PASS */
1729 		default:
1730 			rc = istgt_lu_pass_do_cam(spec, conn, lu_cmd);
1731 			if (rc < 0) {
1732 				/* build by function */
1733 				break;
1734 			}
1735 			lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
1736 			break;
1737 		}
1738 		break;
1739 	case SPC_PERIPHERAL_DEVICE_TYPE_CHANGER:
1740 		switch (cdb[0]) {
1741 		default:
1742 			rc = istgt_lu_pass_do_cam(spec, conn, lu_cmd);
1743 			if (rc < 0) {
1744 				/* build by function */
1745 				break;
1746 			}
1747 			lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
1748 			break;
1749 		}
1750 		break;
1751 	default:
1752 		ISTGT_ERRLOG("unsupported peripheral device type (%x)\n",
1753 		    spec->inq_pd);
1754 		/* LOGICAL UNIT NOT SUPPORTED */
1755 		BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
1756 		lu_cmd->data_len = 0;
1757 		lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
1758 		break;
1759 	}
1760 
1761 	ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1762 	    "SCSI OP=0x%x, LUN=0x%16.16"PRIx64" status=0x%x,"
1763 	    " complete\n",
1764 	    cdb[0], lu_cmd->lun, lu_cmd->status);
1765 	return 0;
1766 }
1767 #else /* HAVE_LIBCAM */
1768 #include "istgt.h"
1769 #include "istgt_ver.h"
1770 #include "istgt_log.h"
1771 #include "istgt_misc.h"
1772 #include "istgt_lu.h"
1773 #include "istgt_proto.h"
1774 #include "istgt_scsi.h"
1775 
1776 int
istgt_lu_pass_init(ISTGT_Ptr istgt,ISTGT_LU_Ptr lu)1777 istgt_lu_pass_init(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu __attribute__((__unused__)))
1778 {
1779 	return 0;
1780 }
1781 
1782 int
istgt_lu_pass_shutdown(ISTGT_Ptr istgt,ISTGT_LU_Ptr lu)1783 istgt_lu_pass_shutdown(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu __attribute__((__unused__)))
1784 {
1785 	return 0;
1786 }
1787 
1788 int
istgt_lu_pass_reset(ISTGT_LU_Ptr lu,int lun)1789 istgt_lu_pass_reset(ISTGT_LU_Ptr lu __attribute__((__unused__)), int lun __attribute__((__unused__)))
1790 {
1791 	return 0;
1792 }
1793 
1794 int
istgt_lu_pass_execute(CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)1795 istgt_lu_pass_execute(CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd __attribute__((__unused__)))
1796 {
1797 	ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "unsupported unit\n");
1798 	return -1;
1799 }
1800 #endif /* HAVE_LIBCAM */
1801