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