1 /*
2 * Copyright (C) 2008-2014 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 <errno.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <pthread.h>
39 #include <time.h>
40
41 #include <fcntl.h>
42 #include <unistd.h>
43
44 #ifdef HAVE_UUID_H
45 #include <uuid.h>
46 #endif
47
48 #include "istgt.h"
49 #include "istgt_ver.h"
50 #include "istgt_log.h"
51 #include "istgt_conf.h"
52 #include "istgt_sock.h"
53 #include "istgt_misc.h"
54 #include "istgt_crc32c.h"
55 #include "istgt_md5.h"
56 #include "istgt_iscsi.h"
57 #include "istgt_lu.h"
58 #include "istgt_proto.h"
59 #include "istgt_scsi.h"
60 #include "istgt_queue.h"
61
62 #if !defined(__GNUC__)
63 #undef __attribute__
64 #define __attribute__(x)
65 #endif
66
67 #ifndef O_FSYNC
68 #define O_FSYNC O_SYNC
69 #endif
70
71 //#define ISTGT_TRACE_DISK
72
73 typedef enum {
74 ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE = 0x01,
75 ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS = 0x03,
76 ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY = 0x05,
77 ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY = 0x06,
78 ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS = 0x07,
79 ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS = 0x08,
80 } ISTGT_LU_PR_TYPE;
81
82 #define PR_ALLOW(WE,EA,ALLRR,WERR,EARR) \
83 ((((WE)&1) << 4) | (((EA)&1) << 3) | (((ALLRR)&1) << 2) \
84 | (((WERR)&1) << 1) | (((EARR)&1) << 0))
85 #define PR_ALLOW_WE 0x0010
86 #define PR_ALLOW_EA 0x0008
87 #define PR_ALLOW_ALLRR 0x0004
88 #define PR_ALLOW_WERR 0x0002
89 #define PR_ALLOW_EARR 0x0001
90
91 #define BUILD_SENSE(SK,ASC,ASCQ) \
92 do { \
93 *sense_len = \
94 istgt_lu_disk_build_sense_data(spec, sense_data, \
95 ISTGT_SCSI_SENSE_ ## SK, \
96 (ASC), (ASCQ)); \
97 } while (0)
98 #define BUILD_SENSE2(SK,ASC,ASCQ) \
99 do { \
100 *sense_len = \
101 istgt_lu_disk_build_sense_data2(spec, sense_data, \
102 ISTGT_SCSI_SENSE_ ## SK, \
103 (ASC), (ASCQ)); \
104 } while (0)
105
106 static void istgt_lu_disk_free_pr_key(ISTGT_LU_PR_KEY *prkey);
107 static int istgt_lu_disk_build_sense_data(ISTGT_LU_DISK *spec, uint8_t *data, int sk, int asc, int ascq);
108 static int istgt_lu_disk_queue_abort_ITL(ISTGT_LU_DISK *spec, const char *initiator_port);
109
110 static int
istgt_lu_disk_open_raw(ISTGT_LU_DISK * spec,int flags,int mode)111 istgt_lu_disk_open_raw(ISTGT_LU_DISK *spec, int flags, int mode)
112 {
113 int rc;
114
115 rc = open(spec->file, flags, mode);
116 if (rc < 0) {
117 return -1;
118 }
119 spec->fd = rc;
120 spec->foffset = 0;
121 return 0;
122 }
123
124 static int
istgt_lu_disk_close_raw(ISTGT_LU_DISK * spec)125 istgt_lu_disk_close_raw(ISTGT_LU_DISK *spec)
126 {
127 int rc;
128
129 if (spec->fd == -1)
130 return 0;
131 rc = close(spec->fd);
132 if (rc < 0) {
133 return -1;
134 }
135 spec->fd = -1;
136 spec->foffset = 0;
137 return 0;
138 }
139
140 #if 0
141 static off_t
142 istgt_lu_disk_lseek_raw(ISTGT_LU_DISK *spec, off_t offset, int whence)
143 {
144 off_t rc;
145
146 rc = lseek(spec->fd, offset, whence);
147 if (rc < 0) {
148 return -1;
149 }
150 spec->foffset = offset;
151 return rc;
152 }
153 #endif
154
155 static int64_t
istgt_lu_disk_seek_raw(ISTGT_LU_DISK * spec,uint64_t offset)156 istgt_lu_disk_seek_raw(ISTGT_LU_DISK *spec, uint64_t offset)
157 {
158 off_t rc;
159
160 rc = lseek(spec->fd, (off_t) offset, SEEK_SET);
161 if (rc < 0) {
162 return -1;
163 }
164 spec->foffset = offset;
165 return 0;
166 }
167
168 static int64_t
istgt_lu_disk_read_raw(ISTGT_LU_DISK * spec,void * buf,uint64_t nbytes)169 istgt_lu_disk_read_raw(ISTGT_LU_DISK *spec, void *buf, uint64_t nbytes)
170 {
171 int64_t rc;
172
173 if (spec->lu->istgt->swmode >= ISTGT_SWMODE_EXPERIMENTAL) {
174 if (spec->foffset + nbytes <= spec->fsize) {
175 /* inside media */
176 rc = (int64_t) read(spec->fd, buf, (size_t) nbytes);
177 } else if (spec->foffset >= spec->fsize) {
178 /* outside media */
179 memset(buf, 0, nbytes);
180 rc = nbytes;
181 if (spec->foffset + nbytes >= spec->size) {
182 rc = spec->size - spec->foffset;
183 }
184 } else if (spec->foffset + nbytes > spec->fsize) {
185 /* both */
186 uint64_t request = spec->fsize - spec->foffset;
187 memset(buf, 0, nbytes);
188 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
189 "read %"PRIu64" bytes at %"PRIu64"/%"PRIu64"\n",
190 request, spec->foffset, spec->fsize);
191 rc = (int64_t) read(spec->fd, buf, (size_t) request);
192 if (rc < 0) {
193 return -1;
194 }
195 if ((uint64_t) rc != request) {
196 /* read size < request */
197 if (spec->foffset + rc >= spec->size) {
198 rc = spec->size - spec->foffset;
199 }
200 spec->foffset += rc;
201 return rc;
202 }
203 rc = nbytes;
204 if (spec->foffset + nbytes >= spec->size) {
205 rc = spec->size - spec->foffset;
206 }
207 } else {
208 rc = -1;
209 }
210 if (rc < 0) {
211 return -1;
212 }
213 spec->foffset += rc;
214 return rc;
215 }
216 rc = (int64_t) read(spec->fd, buf, (size_t) nbytes);
217 if (rc < 0) {
218 return -1;
219 }
220 spec->foffset += rc;
221 return rc;
222 }
223
224 static int64_t
istgt_lu_disk_write_raw(ISTGT_LU_DISK * spec,const void * buf,uint64_t nbytes)225 istgt_lu_disk_write_raw(ISTGT_LU_DISK *spec, const void *buf, uint64_t nbytes)
226 {
227 int64_t rc;
228
229 if (spec->lu->istgt->swmode >= ISTGT_SWMODE_EXPERIMENTAL) {
230 if (spec->foffset + nbytes <= spec->fsize) {
231 /* inside media */
232 rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
233 } else if (spec->foffset + nbytes <= ISTGT_LU_MEDIA_SIZE_MIN) {
234 /* allways write in minimum size */
235 rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
236 } else if (spec->foffset >= spec->fsize) {
237 /* outside media */
238 const uint8_t *p = (const uint8_t *) buf;
239 uint64_t n;
240 for (n = 0; n < nbytes; n++) {
241 if (p[n] != 0)
242 break;
243 }
244 if (n == nbytes) {
245 /* write all zero (skip) */
246 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
247 "write zero %"PRIu64" bytes at %"PRIu64"/%"PRIu64"\n",
248 nbytes, spec->foffset, spec->fsize);
249 rc = nbytes;
250 spec->foffset += rc;
251 return rc;
252 }
253 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
254 "write %"PRIu64" bytes at %"PRIu64"/%"PRIu64"\n",
255 nbytes, spec->foffset, spec->fsize);
256 rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
257 } else if (spec->foffset + nbytes > spec->fsize) {
258 /* both */
259 rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
260 } else {
261 rc = -1;
262 }
263 if (rc < 0) {
264 return -1;
265 }
266 spec->foffset += rc;
267 if (spec->foffset > spec->fsize) {
268 spec->fsize = spec->foffset;
269 }
270 return rc;
271 }
272 rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
273 if (rc < 0) {
274 return -1;
275 }
276 spec->foffset += rc;
277 if (spec->foffset > spec->fsize) {
278 spec->fsize = spec->foffset;
279 }
280 return rc;
281 }
282
283 static int64_t
istgt_lu_disk_sync_raw(ISTGT_LU_DISK * spec,uint64_t offset,uint64_t nbytes)284 istgt_lu_disk_sync_raw(ISTGT_LU_DISK *spec, uint64_t offset, uint64_t nbytes)
285 {
286 int64_t rc;
287
288 rc = (int64_t) fsync(spec->fd);
289 if (rc < 0) {
290 return -1;
291 }
292 spec->foffset = offset + nbytes;
293 return rc;
294 }
295
296 static int
istgt_lu_disk_allocate_raw(ISTGT_LU_DISK * spec)297 istgt_lu_disk_allocate_raw(ISTGT_LU_DISK *spec)
298 {
299 uint8_t *data;
300 uint64_t fsize;
301 uint64_t size;
302 uint64_t blocklen;
303 uint64_t offset;
304 uint64_t nbytes;
305 int64_t rc;
306
307 size = spec->size;
308 blocklen = spec->blocklen;
309 nbytes = blocklen;
310 data = xmalloc(nbytes);
311 memset(data, 0, nbytes);
312
313 fsize = istgt_lu_get_filesize(spec->file);
314 if (fsize > size) {
315 xfree(data);
316 return 0;
317 }
318 spec->fsize = fsize;
319
320 offset = size - nbytes;
321 rc = istgt_lu_disk_seek_raw(spec, offset);
322 if (rc == -1) {
323 ISTGT_ERRLOG("lu_disk_seek() failed\n");
324 xfree(data);
325 return -1;
326 }
327 rc = istgt_lu_disk_read_raw(spec, data, nbytes);
328 /* EOF is OK */
329 if (rc == -1) {
330 ISTGT_ERRLOG("lu_disk_read() failed\n");
331 xfree(data);
332 return -1;
333 }
334 if (spec->lu->istgt->swmode >= ISTGT_SWMODE_EXPERIMENTAL) {
335 /* allocate minimum size */
336 if (fsize < ISTGT_LU_MEDIA_SIZE_MIN) {
337 fsize = ISTGT_LU_MEDIA_SIZE_MIN;
338 if (size < ISTGT_LU_MEDIA_SIZE_MIN) {
339 fsize = size;
340 }
341 offset = fsize - nbytes;
342 rc = istgt_lu_disk_seek_raw(spec, offset);
343 if (rc == -1) {
344 ISTGT_ERRLOG("lu_disk_seek() failed\n");
345 xfree(data);
346 return -1;
347 }
348 rc = istgt_lu_disk_write_raw(spec, data, nbytes);
349 if (rc == -1 || (uint64_t) rc != nbytes) {
350 ISTGT_ERRLOG("lu_disk_write() failed\n");
351 xfree(data);
352 return -1;
353 }
354 spec->fsize = fsize;
355 spec->foffset = fsize;
356 }
357 } else {
358 /* allocate complete size */
359 rc = istgt_lu_disk_seek_raw(spec, offset);
360 if (rc == -1) {
361 ISTGT_ERRLOG("lu_disk_seek() failed\n");
362 xfree(data);
363 return -1;
364 }
365 rc = istgt_lu_disk_write_raw(spec, data, nbytes);
366 if (rc == -1 || (uint64_t) rc != nbytes) {
367 ISTGT_ERRLOG("lu_disk_write() failed\n");
368 xfree(data);
369 return -1;
370 }
371 spec->foffset = size;
372 }
373
374 xfree(data);
375 return 0;
376 }
377
378 static int
istgt_lu_disk_setcache_raw(ISTGT_LU_DISK * spec)379 istgt_lu_disk_setcache_raw(ISTGT_LU_DISK *spec)
380 {
381 int flags;
382 int rc;
383 int fd;
384
385 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_setcache\n");
386
387 fd = spec->fd;
388 if (spec->read_cache) {
389 /* not implement */
390 } else {
391 /* not implement */
392 }
393 flags = fcntl(fd , F_GETFL, 0);
394 if (flags != -1) {
395 if (spec->write_cache) {
396 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "write cache enable\n");
397 rc = fcntl(fd, F_SETFL, (flags & ~O_FSYNC));
398 spec->write_cache = 1;
399 } else {
400 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "write cache disable\n");
401 rc = fcntl(fd, F_SETFL, (flags | O_FSYNC));
402 spec->write_cache = 0;
403 }
404 if (rc == -1) {
405 #if 0
406 ISTGT_ERRLOG("LU%d: LUN%d: fcntl(F_SETFL) failed(errno=%d)\n",
407 spec->num, spec->lun, errno);
408 #endif
409 }
410 } else {
411 ISTGT_ERRLOG("LU%d: LUN%d: fcntl(F_GETFL) failed(errno=%d)\n",
412 spec->num, spec->lun, errno);
413 }
414 return 0;
415 }
416
417 static const char *
istgt_get_disktype_by_ext(const char * file)418 istgt_get_disktype_by_ext(const char *file)
419 {
420 size_t n;
421
422 if (file == NULL || file[0] == '\n')
423 return "RAW";
424
425 n = strlen(file);
426 if (n > 4 && strcasecmp(file + (n - 4), ".vdi") == 0)
427 return "VDI";
428 if (n > 4 && strcasecmp(file + (n - 4), ".vhd") == 0)
429 return "VHD";
430 if (n > 5 && strcasecmp(file + (n - 5), ".vmdk") == 0)
431 return "VMDK";
432
433 if (n > 5 && strcasecmp(file + (n - 5), ".qcow") == 0)
434 return "QCOW";
435 if (n > 6 && strcasecmp(file + (n - 6), ".qcow2") == 0)
436 return "QCOW";
437 if (n > 4 && strcasecmp(file + (n - 4), ".qed") == 0)
438 return "QED";
439 if (n > 5 && strcasecmp(file + (n - 5), ".vhdx") == 0)
440 return "VHDX";
441
442 return "RAW";
443 }
444
445 int
istgt_lu_disk_init(ISTGT_Ptr istgt,ISTGT_LU_Ptr lu)446 istgt_lu_disk_init(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu)
447 {
448 ISTGT_LU_DISK *spec;
449 uint64_t gb_size;
450 uint64_t mb_size;
451 #ifdef HAVE_UUID_H
452 uint32_t status;
453 #endif /* HAVE_UUID_H */
454 int mb_digit;
455 int flags;
456 int newfile;
457 int rc;
458 int i, j;
459
460 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_init\n");
461
462 printf("LU%d HDD UNIT\n", lu->num);
463 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
464 lu->num, lu->name);
465 for (i = 0; i < lu->maxlun; i++) {
466 if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
467 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
468 lu->num, i);
469 lu->lun[i].spec = NULL;
470 continue;
471 }
472 if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) {
473 ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
474 return -1;
475 }
476 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d storage\n",
477 lu->num, i);
478
479 spec = xmalloc(sizeof *spec);
480 memset(spec, 0, sizeof *spec);
481 spec->lu = lu;
482 spec->num = lu->num;
483 spec->lun = i;
484 spec->fd = -1;
485 if (spec->lu->lun[i].readcache) {
486 spec->read_cache = 1;
487 } else {
488 spec->read_cache = 0;
489 }
490 if (spec->lu->lun[i].writecache) {
491 spec->write_cache = 1;
492 } else {
493 spec->write_cache = 0;
494 }
495 if (spec->lu->istgt->swmode >= ISTGT_SWMODE_EXPERIMENTAL) {
496 spec->wbufsize = ISTGT_LU_MAX_WRITE_CACHE_SIZE;
497 spec->wbuf = xmalloc(spec->wbufsize);
498 memset(spec->wbuf, 0, spec->wbufsize);
499 } else {
500 spec->wbufsize = 0;
501 spec->wbuf = NULL;
502 }
503 spec->woffset = 0;
504 spec->wnbytes = 0;
505 spec->req_write_cache = 0;
506 spec->err_write_cache = 0;
507 spec->thin_provisioning = 0;
508 spec->watssize = 0;
509 spec->watsbuf = NULL;
510
511 rc = pthread_mutex_init(&spec->ats_mutex, NULL);
512 if (rc != 0) {
513 ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
514 return -1;
515 }
516
517 spec->queue_depth = lu->queue_depth;
518 rc = pthread_mutex_init(&spec->cmd_queue_mutex, &istgt->mutex_attr);
519 if (rc != 0) {
520 ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
521 return -1;
522 }
523 istgt_queue_init(&spec->cmd_queue);
524 rc = pthread_mutex_init(&spec->wait_lu_task_mutex, NULL);
525 if (rc != 0) {
526 ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
527 return -1;
528 }
529 spec->wait_lu_task = NULL;
530
531 spec->npr_keys = 0;
532 /* spec is cleared, only pointer is handled */
533 for (j = 0; j < MAX_LU_RESERVE; j++) {
534 spec->pr_keys[j].registered_initiator_port = NULL;
535 spec->pr_keys[j].registered_target_port = NULL;
536 spec->pr_keys[j].initiator_ports = NULL;
537 }
538 spec->pr_generation = 0;
539 spec->rsv_port = NULL;
540 spec->rsv_key = 0;
541 spec->rsv_scope = 0;
542 spec->rsv_type = 0;
543
544 spec->sense = 0;
545 {
546 int sk, asc, ascq;
547 /* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
548 sk = ISTGT_SCSI_SENSE_UNIT_ATTENTION;
549 asc = 0x29;
550 ascq = 0x00;
551 spec->sense = (((sk & 0xffU) << 16)
552 | ((asc & 0xffU) << 8)
553 | ((ascq & 0xffU) << 0));
554 }
555
556 #ifdef HAVE_UUID_H
557 uuid_create(&spec->uuid, &status);
558 if (status != uuid_s_ok) {
559 ISTGT_ERRLOG("LU%d: LUN%d: uuid_create() failed\n", lu->num, i);
560 (void) pthread_mutex_destroy(&spec->wait_lu_task_mutex);
561 (void) pthread_mutex_destroy(&spec->cmd_queue_mutex);
562 (void) pthread_mutex_destroy(&spec->ats_mutex);
563 istgt_queue_destroy(&spec->cmd_queue);
564 xfree(spec);
565 return -1;
566 }
567 #endif /* HAVE_UUID_H */
568
569 spec->file = lu->lun[i].u.storage.file;
570 spec->size = lu->lun[i].u.storage.size;
571 spec->disktype = istgt_get_disktype_by_ext(spec->file);
572 if (strcasecmp(spec->disktype, "VDI") == 0
573 || strcasecmp(spec->disktype, "VHD") == 0
574 || strcasecmp(spec->disktype, "VMDK") == 0
575 || strcasecmp(spec->disktype, "QCOW") == 0
576 || strcasecmp(spec->disktype, "QED") == 0
577 || strcasecmp(spec->disktype, "VHDX") == 0) {
578 rc = istgt_lu_disk_vbox_lun_init(spec, istgt, lu);
579 if (rc < 0) {
580 ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_vbox_lun_init() failed\n",
581 lu->num, i);
582 goto error_return;
583 }
584 } else if (strcasecmp(spec->disktype, "RAW") == 0) {
585 spec->open = istgt_lu_disk_open_raw;
586 spec->close = istgt_lu_disk_close_raw;
587 spec->seek = istgt_lu_disk_seek_raw;
588 spec->read = istgt_lu_disk_read_raw;
589 spec->write = istgt_lu_disk_write_raw;
590 spec->sync = istgt_lu_disk_sync_raw;
591 spec->allocate = istgt_lu_disk_allocate_raw;
592 spec->setcache = istgt_lu_disk_setcache_raw;
593
594 spec->blocklen = lu->blocklen;
595 if (spec->blocklen != 512
596 && spec->blocklen != 1024
597 && spec->blocklen != 2048
598 && spec->blocklen != 4096
599 && spec->blocklen != 8192
600 && spec->blocklen != 16384
601 && spec->blocklen != 32768
602 && spec->blocklen != 65536
603 && spec->blocklen != 131072
604 && spec->blocklen != 262144
605 && spec->blocklen != 524288) {
606 ISTGT_ERRLOG("LU%d: LUN%d: invalid blocklen %"PRIu64"\n",
607 lu->num, i, spec->blocklen);
608 error_return:
609 (void) pthread_mutex_destroy(&spec->wait_lu_task_mutex);
610 (void) pthread_mutex_destroy(&spec->cmd_queue_mutex);
611 (void) pthread_mutex_destroy(&spec->ats_mutex);
612 istgt_queue_destroy(&spec->cmd_queue);
613 xfree(spec);
614 return -1;
615 }
616 spec->blockcnt = spec->size / spec->blocklen;
617 if (spec->blockcnt == 0) {
618 ISTGT_ERRLOG("LU%d: LUN%d: size zero\n", lu->num, i);
619 goto error_return;
620 }
621
622 #if 0
623 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
624 "LU%d: LUN%d file=%s, size=%"PRIu64"\n",
625 lu->num, i, spec->file, spec->size);
626 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
627 "LU%d: LUN%d %"PRIu64" blocks, %"
628 PRIu64" bytes/block\n",
629 lu->num, i, spec->blockcnt, spec->blocklen);
630 #endif
631 printf("LU%d: LUN%d file=%s, size=%"PRIu64"\n",
632 lu->num, i, spec->file, spec->size);
633 printf("LU%d: LUN%d %"PRIu64" blocks, %"PRIu64" bytes/block\n",
634 lu->num, i, spec->blockcnt, spec->blocklen);
635
636 flags = lu->readonly ? O_RDONLY : O_RDWR;
637 newfile = 0;
638 rc = spec->open(spec, flags, 0666);
639 if (rc < 0) {
640 newfile = 1;
641 flags = lu->readonly ? O_RDONLY : (O_CREAT | O_EXCL | O_RDWR);
642 rc = spec->open(spec, flags, 0666);
643 if (rc < 0) {
644 ISTGT_ERRLOG("LU%d: LUN%d: open error(errno=%d)\n",
645 lu->num, i, errno);
646 goto error_return;
647 }
648 }
649 if (!lu->readonly) {
650 rc = spec->allocate(spec);
651 if (rc < 0) {
652 ISTGT_ERRLOG("LU%d: LUN%d: allocate error\n",
653 lu->num, i);
654 goto error_return;
655 }
656 }
657 rc = spec->setcache(spec);
658 if (rc < 0) {
659 ISTGT_ERRLOG("LU%d: LUN%d: setcache error\n", lu->num, i);
660 goto error_return;
661 }
662 } else {
663 ISTGT_ERRLOG("LU%d: LUN%d: unsupported format\n", lu->num, i);
664 goto error_return;
665 }
666
667 gb_size = spec->size / ISTGT_LU_1GB;
668 mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB;
669 if (gb_size > 0) {
670 mb_digit = (int) (((mb_size * 100) / 1024) / 10);
671 #if 0
672 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
673 "LU%d LUN%d %"PRIu64".%dGB %sstorage for %s\n",
674 lu->num, i, gb_size, mb_digit,
675 lu->readonly ? "readonly " : "", lu->name);
676 #endif
677 printf("LU%d: LUN%d %"PRIu64".%dGB %sstorage for %s\n",
678 lu->num, i, gb_size, mb_digit,
679 lu->readonly ? "readonly " : "", lu->name);
680 } else {
681 #if 0
682 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
683 "LU%d: LUN%d %"PRIu64"MB %sstorage for %s\n",
684 lu->num, i, mb_size,
685 lu->readonly ? "readonly " : "", lu->name);
686 #endif
687 printf("LU%d: LUN%d %"PRIu64"MB %sstorage for %s\n",
688 lu->num, i, mb_size,
689 lu->readonly ? "readonly " : "", lu->name);
690 }
691 if (spec->lu->lun[i].serial != NULL) {
692 printf("LU%d: LUN%d serial %s\n",
693 lu->num, i, spec->lu->lun[i].serial);
694 } else {
695 printf("LU%d: LUN%d serial %s\n",
696 lu->num, i, spec->lu->inq_serial);
697 }
698 printf("LU%d: LUN%d ", lu->num, i);
699 if (spec->read_cache) {
700 printf("read cache enabled");
701 } else {
702 printf("read cache disabled");
703 }
704 printf(", ");
705 if (spec->write_cache) {
706 printf("write cache enabled");
707 } else {
708 printf("write cache disabled");
709 }
710 printf("\n");
711 if (spec->queue_depth != 0) {
712 printf("LU%d: LUN%d command queuing enabled, depth %d\n",
713 lu->num, i, spec->queue_depth);
714 } else {
715 printf("LU%d: LUN%d command queuing disabled\n",
716 lu->num, i);
717 }
718 #if 0
719 if (spec->write_cache && spec->wbufsize) {
720 mb_size = (spec->wbufsize / ISTGT_LU_1MB);
721 printf("LU%d: LUN%d write buffer %"PRIu64"MB\n",
722 lu->num, i, mb_size);
723 }
724 #endif
725
726 lu->lun[i].spec = spec;
727 }
728
729 return 0;
730 }
731
732 int
istgt_lu_disk_shutdown(ISTGT_Ptr istgt,ISTGT_LU_Ptr lu)733 istgt_lu_disk_shutdown(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu)
734 {
735 ISTGT_LU_DISK *spec;
736 ISTGT_LU_PR_KEY *prkey;
737 int rc;
738 int i, j;
739
740 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_shutdown\n");
741
742 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
743 lu->num, lu->name);
744 for (i = 0; i < lu->maxlun; i++) {
745 if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
746 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
747 lu->num, i);
748 continue;
749 }
750 if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) {
751 ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
752 return -1;
753 }
754 spec = (ISTGT_LU_DISK *) lu->lun[i].spec;
755
756 if (strcasecmp(spec->disktype, "VDI") == 0
757 || strcasecmp(spec->disktype, "VHD") == 0
758 || strcasecmp(spec->disktype, "VMDK") == 0
759 || strcasecmp(spec->disktype, "QCOW") == 0
760 || strcasecmp(spec->disktype, "QED") == 0
761 || strcasecmp(spec->disktype, "VHDX") == 0) {
762 rc = istgt_lu_disk_vbox_lun_shutdown(spec, istgt, lu);
763 if (rc < 0) {
764 ISTGT_ERRLOG("LU%d: lu_disk_vbox_lun_shutdown() failed\n",
765 lu->num);
766 /* ignore error */
767 }
768 } else if (strcasecmp(spec->disktype, "RAW") == 0) {
769 if (!spec->lu->readonly) {
770 rc = spec->sync(spec, 0, spec->size);
771 if (rc < 0) {
772 //ISTGT_ERRLOG("LU%d: lu_disk_sync() failed\n", lu->num);
773 /* ignore error */
774 }
775 }
776 rc = spec->close(spec);
777 if (rc < 0) {
778 //ISTGT_ERRLOG("LU%d: lu_disk_close() failed\n", lu->num);
779 /* ignore error */
780 }
781 } else {
782 ISTGT_ERRLOG("LU%d: LUN%d: unsupported format\n", lu->num, i);
783 return -1;
784 }
785
786 for (j = 0; j < spec->npr_keys; j++) {
787 prkey = &spec->pr_keys[j];
788 istgt_lu_disk_free_pr_key(prkey);
789 }
790 if (spec->rsv_key != 0) {
791 xfree(spec->rsv_port);
792 spec->rsv_port = NULL;
793 }
794
795 rc = pthread_mutex_destroy(&spec->ats_mutex);
796 if (rc != 0) {
797 //ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
798 /* ignore error */
799 }
800
801 istgt_queue_destroy(&spec->cmd_queue);
802 rc = pthread_mutex_destroy(&spec->cmd_queue_mutex);
803 if (rc != 0) {
804 //ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
805 /* ignore error */
806 }
807 rc = pthread_mutex_destroy(&spec->wait_lu_task_mutex);
808 if (rc != 0) {
809 //ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
810 /* ignore error */
811 }
812 xfree(spec->watsbuf);
813 xfree(spec->wbuf);
814 xfree(spec);
815 lu->lun[i].spec = NULL;
816 }
817
818 return 0;
819 }
820
821 void
istgt_scsi_dump_cdb(uint8_t * cdb)822 istgt_scsi_dump_cdb(uint8_t *cdb)
823 {
824 int group;
825 int cdblen = 0;
826 int i;
827
828 if (cdb == NULL)
829 return;
830
831 group = (cdb[0] >> 5) & 0x07;
832 switch (group) {
833 case 0x00:
834 /* 6byte commands */
835 cdblen = 6;
836 break;
837 case 0x01:
838 /* 10byte commands */
839 cdblen = 10;
840 break;
841 case 0x02:
842 /* 10byte commands */
843 cdblen = 10;
844 break;
845 case 0x03:
846 /* reserved */
847 if (cdb[0] == 0x7f) {
848 /* variable length */
849 cdblen = 8 + (cdb[7] & 0xff);
850 } else {
851 /* XXX */
852 cdblen = 6;
853 }
854 break;
855 case 0x04:
856 /* 16byte commands */
857 cdblen = 16;
858 break;
859 case 0x05:
860 /* 12byte commands */
861 cdblen = 12;
862 break;
863 case 0x06:
864 case 0x07:
865 /* vendor specific */
866 cdblen = 6;
867 break;
868 }
869
870 printf("CDB=");
871 for (i = 0; i < cdblen; i++) {
872 printf("%2.2x ", cdb[i]);
873 }
874 printf("\n");
875 }
876
877 void
istgt_strcpy_pad(uint8_t * dst,size_t size,const char * src,int pad)878 istgt_strcpy_pad(uint8_t *dst, size_t size, const char *src, int pad)
879 {
880 size_t len;
881
882 len = strlen(src);
883 if (len < size) {
884 memcpy(dst, src, len);
885 memset(dst + len, pad, (size - len));
886 } else {
887 memcpy(dst, src, size);
888 }
889 }
890
891 #ifdef HAVE_UUID_H
892 uint64_t
istgt_uuid2uint64(uuid_t * uuid)893 istgt_uuid2uint64(uuid_t *uuid)
894 {
895 uint64_t low, mid, hi;
896 uint64_t r;
897
898 low = (uint64_t) uuid->time_low;
899 mid = (uint64_t) uuid->time_mid;
900 hi = (uint64_t) uuid->time_hi_and_version;
901 r = (hi & 0xffffULL) << 48;
902 r |= (mid & 0xffffULL) << 32;
903 r |= (low & 0xffffffffULL);
904 return r;
905 }
906 #endif /* HAVE_UUID_H */
907
908 uint64_t
istgt_get_lui(const char * name,int lun)909 istgt_get_lui(const char *name, int lun)
910 {
911 char buf[MAX_TMPBUF];
912 uint32_t crc32c;
913 uint64_t r;
914
915 if (lun >= 0) {
916 snprintf(buf, sizeof buf, "%s,%d",
917 name, lun);
918 } else {
919 snprintf(buf, sizeof buf, "%s",
920 name);
921 }
922 crc32c = istgt_crc32c((uint8_t *) buf, strlen(buf));
923 r = (uint64_t) crc32c;
924 return r;
925 }
926
927 uint64_t
istgt_get_rkey(const char * initiator_name,uint64_t lui)928 istgt_get_rkey(const char *initiator_name, uint64_t lui)
929 {
930 ISTGT_MD5CTX md5ctx;
931 uint8_t rkeymd5[ISTGT_MD5DIGEST_LEN];
932 char buf[MAX_TMPBUF];
933 uint64_t rkey;
934 int idx;
935 int i;
936
937 snprintf(buf, sizeof buf, "%s,%16.16" PRIx64,
938 initiator_name, lui);
939
940 istgt_md5init(&md5ctx);
941 istgt_md5update(&md5ctx, buf, strlen(buf));
942 istgt_md5final(rkeymd5, &md5ctx);
943
944 rkey = 0U;
945 idx = ISTGT_MD5DIGEST_LEN - 8;
946 if (idx < 0) {
947 ISTGT_WARNLOG("missing MD5 length\n");
948 idx = 0;
949 }
950 for (i = idx; i < ISTGT_MD5DIGEST_LEN; i++) {
951 rkey |= (uint64_t) rkeymd5[i];
952 rkey = rkey << 8;
953 }
954 return rkey;
955 }
956
957 /* XXX */
958 #define COMPANY_ID 0xACDE48U // 24bits
959
960 int
istgt_lu_set_lid(uint8_t * buf,uint64_t vid)961 istgt_lu_set_lid(uint8_t *buf, uint64_t vid)
962 {
963 uint64_t naa;
964 uint64_t enc;
965 int total;
966
967 naa = 0x3; // Locally Assigned
968
969 /* NAA + LOCALLY ADMINISTERED VALUE */
970 enc = (naa & 0xfULL) << (64-4); // 4bits
971 enc |= vid & 0xfffffffffffffffULL; //60bits
972 DSET64(&buf[0], enc);
973
974 total = 8;
975 return total;
976 }
977
978 int
istgt_lu_set_id(uint8_t * buf,uint64_t vid)979 istgt_lu_set_id(uint8_t *buf, uint64_t vid)
980 {
981 uint64_t naa;
982 uint64_t cid;
983 uint64_t enc;
984 int total;
985
986 naa = 0x5; // IEEE Registered
987 cid = COMPANY_ID; //IEEE COMPANY_ID
988
989 /* NAA + COMPANY_ID + VENDOR SPECIFIC IDENTIFIER */
990 enc = (naa & 0xfULL) << (64-4); // 4bits
991 enc |= (cid & 0xffffffULL) << (64-4-24); // 24bits
992 enc |= vid & 0xfffffffffULL; //36bits
993 DSET64(&buf[0], enc);
994
995 total = 8;
996 return total;
997 }
998
999 int
istgt_lu_set_extid(uint8_t * buf,uint64_t vid,uint64_t vide)1000 istgt_lu_set_extid(uint8_t *buf, uint64_t vid, uint64_t vide)
1001 {
1002 uint64_t naa;
1003 uint64_t cid;
1004 uint64_t enc;
1005 int total;
1006
1007 naa = 0x6; // IEEE Registered Extended
1008 cid = COMPANY_ID; //IEEE COMPANY_ID
1009
1010 /* NAA + COMPANY_ID + VENDOR SPECIFIC IDENTIFIER */
1011 enc = (naa & 0xfULL) << (64-4); // 4bits
1012 enc |= (cid & 0xffffffULL) << (64-4-24); // 24bits
1013 enc |= vid & 0xfffffffffULL; //36bits
1014 DSET64(&buf[0], enc);
1015 /* VENDOR SPECIFIC IDENTIFIER EXTENSION */
1016 DSET64(&buf[8], vide);
1017
1018 total = 16;
1019 return total;
1020 }
1021
1022 static int
istgt_lu_disk_scsi_report_luns(ISTGT_LU_Ptr lu,CONN_Ptr conn,uint8_t * cdb,int sel,uint8_t * data,int alloc_len)1023 istgt_lu_disk_scsi_report_luns(ISTGT_LU_Ptr lu, CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int sel, uint8_t *data, int alloc_len)
1024 {
1025 uint64_t fmt_lun, lun, method;
1026 int hlen = 0, len = 0;
1027 int i;
1028
1029 if (alloc_len < 8) {
1030 return -1;
1031 }
1032
1033 if (sel == 0x00) {
1034 /* logical unit with addressing method */
1035 } else if (sel == 0x01) {
1036 /* well known logical unit */
1037 } else if (sel == 0x02) {
1038 /* logical unit */
1039 } else {
1040 return -1;
1041 }
1042
1043 /* LUN LIST LENGTH */
1044 DSET32(&data[0], 0);
1045 /* Reserved */
1046 DSET32(&data[4], 0);
1047 hlen = 8;
1048
1049 for (i = 0; i < lu->maxlun; i++) {
1050 if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
1051 #if 0
1052 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
1053 lu->num, i);
1054 #endif
1055 continue;
1056 }
1057 if (alloc_len - (hlen + len) < 8) {
1058 return -1;
1059 }
1060 lun = (uint64_t) i;
1061 if (lu->maxlun <= 0x0100) {
1062 /* below 256 */
1063 method = 0x00U;
1064 fmt_lun = (method & 0x03U) << 62;
1065 fmt_lun |= (lun & 0x00ffU) << 48;
1066 } else if (lu->maxlun <= 0x4000) {
1067 /* below 16384 */
1068 method = 0x01U;
1069 fmt_lun = (method & 0x03U) << 62;
1070 fmt_lun |= (lun & 0x3fffU) << 48;
1071 } else {
1072 /* XXX */
1073 fmt_lun = 0;
1074 }
1075 /* LUN */
1076 DSET64(&data[hlen + len], fmt_lun);
1077 len += 8;
1078 }
1079 /* LUN LIST LENGTH */
1080 DSET32(&data[0], len);
1081 return hlen + len;
1082 }
1083
1084 static int
istgt_lu_disk_scsi_inquiry(ISTGT_LU_DISK * spec,CONN_Ptr conn,uint8_t * cdb,uint8_t * data,int alloc_len)1085 istgt_lu_disk_scsi_inquiry(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, uint8_t *data, int alloc_len)
1086 {
1087 uint64_t LUI;
1088 uint8_t *cp, *cp2;
1089 uint32_t blocks;
1090 int hlen = 0, len = 0, plen, plen2;
1091 int pc;
1092 int pq, pd;
1093 int rmb;
1094 int evpd;
1095 int pg_tag;
1096 int i, j;
1097
1098 if (alloc_len < 0xff) {
1099 return -1;
1100 }
1101
1102 pq = 0x00;
1103 pd = SPC_PERIPHERAL_DEVICE_TYPE_DISK;
1104 rmb = 0;
1105
1106 #if 0
1107 LUI = istgt_uuid2uint64(&spec->uuid);
1108 #else
1109 LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU);
1110 #endif
1111
1112 pc = cdb[2];
1113 evpd = BGET8(&cdb[1], 0);
1114 if (evpd) {
1115 /* Vital product data */
1116 switch (pc) {
1117 case SPC_VPD_SUPPORTED_VPD_PAGES:
1118 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1119 BDSET8W(&data[0], pq, 7, 3);
1120 BDADD8W(&data[0], pd, 4, 5);
1121 /* PAGE CODE */
1122 data[1] = pc;
1123 /* Reserved */
1124 data[2] = 0;
1125 /* PAGE LENGTH */
1126 data[3] = 0;
1127 hlen = 4;
1128
1129 data[4] = SPC_VPD_SUPPORTED_VPD_PAGES; /* 0x00 */
1130 data[5] = SPC_VPD_UNIT_SERIAL_NUMBER; /* 0x80 */
1131 data[6] = SPC_VPD_DEVICE_IDENTIFICATION; /* 0x83 */
1132 data[7] = SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES; /* 0x85 */
1133 data[8] = SPC_VPD_EXTENDED_INQUIRY_DATA; /* 0x86 */
1134 data[9] = SPC_VPD_MODE_PAGE_POLICY; /* 0x87 */
1135 data[10]= SPC_VPD_SCSI_PORTS; /* 0x88 */
1136 data[11]= 0xb0; /* SBC Block Limits */
1137 data[12]= 0xb1; /* SBC Block Device Characteristics */
1138 len = 13 - hlen;
1139 if (spec->thin_provisioning) {
1140 data[13]= 0xb2; /* SBC Thin Provisioning */
1141 len++;
1142 }
1143
1144 /* PAGE LENGTH */
1145 data[3] = len;
1146 break;
1147
1148 case SPC_VPD_UNIT_SERIAL_NUMBER:
1149 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1150 BDSET8W(&data[0], pq, 7, 3);
1151 BDADD8W(&data[0], pd, 4, 5);
1152 /* PAGE CODE */
1153 data[1] = pc;
1154 /* Reserved */
1155 data[2] = 0;
1156 /* PAGE LENGTH */
1157 data[3] = 0;
1158 hlen = 4;
1159
1160 /* PRODUCT SERIAL NUMBER */
1161 if (spec->lu->lun[spec->lun].serial != NULL) {
1162 len = strlen(spec->lu->lun[spec->lun].serial);
1163 if (len > MAX_LU_SERIAL_STRING) {
1164 len = MAX_LU_SERIAL_STRING;
1165 }
1166 istgt_strcpy_pad(&data[4], len,
1167 spec->lu->lun[spec->lun].serial, ' ');
1168 } else {
1169 len = strlen(spec->lu->inq_serial);
1170 if (len > MAX_LU_SERIAL_STRING) {
1171 len = MAX_LU_SERIAL_STRING;
1172 }
1173 istgt_strcpy_pad(&data[4], len,
1174 spec->lu->inq_serial, ' ');
1175 }
1176
1177 /* PAGE LENGTH */
1178 data[3] = len;
1179 break;
1180
1181 case SPC_VPD_DEVICE_IDENTIFICATION:
1182 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1183 BDSET8W(&data[0], pq, 7, 3);
1184 BDADD8W(&data[0], pd, 4, 5);
1185 /* PAGE CODE */
1186 data[1] = pc;
1187 /* PAGE LENGTH */
1188 DSET16(&data[2], 0);
1189 hlen = 4;
1190
1191 /* Identification descriptor 1 */
1192 /* Logical Unit */
1193 cp = &data[hlen + len];
1194
1195 /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
1196 BDSET8W(&cp[0], 0, 7, 4);
1197 BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
1198 /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
1199 BDSET8W(&cp[1], 0, 7, 1); /* PIV=0 */
1200 BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2);
1201 BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_NAA, 3, 4);
1202 /* Reserved */
1203 cp[2] = 0;
1204 /* IDENTIFIER LENGTH */
1205 cp[3] = 0;
1206
1207 /* IDENTIFIER */
1208 #if 0
1209 /* 16bytes ID */
1210 plen = istgt_lu_set_extid(&cp[4], 0, LUI);
1211 #else
1212 plen = istgt_lu_set_lid(&cp[4], LUI);
1213 #endif
1214
1215 cp[3] = plen;
1216 len += 4 + plen;
1217
1218 /* Identification descriptor 2 */
1219 /* T10 VENDOR IDENTIFICATION */
1220 cp = &data[hlen + len];
1221
1222 /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
1223 BDSET8W(&cp[0], 0, 7, 4);
1224 BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
1225 /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
1226 BDSET8W(&cp[1], 0, 7, 1); /* PIV=0 */
1227 BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2);
1228 BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_T10_VENDOR_ID, 3, 4);
1229 /* Reserved */
1230 cp[2] = 0;
1231 /* IDENTIFIER LENGTH */
1232 cp[3] = 0;
1233
1234 /* IDENTIFIER */
1235 /* T10 VENDOR IDENTIFICATION */
1236 istgt_strcpy_pad(&cp[4], 8, spec->lu->inq_vendor, ' ');
1237 plen = 8;
1238 /* VENDOR SPECIFIC IDENTIFIER */
1239 /* PRODUCT IDENTIFICATION */
1240 istgt_strcpy_pad(&cp[12], 16, spec->lu->inq_product, ' ');
1241 /* PRODUCT SERIAL NUMBER */
1242 if (spec->lu->lun[spec->lun].serial != NULL) {
1243 istgt_strcpy_pad(&cp[28], MAX_LU_SERIAL_STRING,
1244 spec->lu->lun[spec->lun].serial, ' ');
1245 } else {
1246 istgt_strcpy_pad(&cp[28], MAX_LU_SERIAL_STRING,
1247 spec->lu->inq_serial, ' ');
1248 }
1249 plen += 16 + MAX_LU_SERIAL_STRING;
1250
1251 cp[3] = plen;
1252 len += 4 + plen;
1253
1254 /* Identification descriptor 3 */
1255 /* Target Device */
1256 cp = &data[hlen + len];
1257
1258 /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
1259 BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
1260 BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
1261 /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
1262 BDSET8W(&cp[1], 1, 7, 1); /* PIV */
1263 BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_DEVICE, 5, 2);
1264 BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
1265 /* Reserved */
1266 cp[2] = 0;
1267 /* IDENTIFIER LENGTH */
1268 cp[3] = 0;
1269
1270 /* IDENTIFIER */
1271 plen = snprintf((char *) &cp[4], MAX_TARGET_NAME,
1272 "%s", spec->lu->name);
1273 cp[3] = plen;
1274 len += 4 + plen;
1275
1276 /* Identification descriptor 4 */
1277 /* Target Port */
1278 cp = &data[hlen + len];
1279
1280 /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
1281 BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
1282 BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
1283 /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
1284 BDSET8W(&cp[1], 1, 7, 1); /* PIV */
1285 BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
1286 BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
1287 /* Reserved */
1288 cp[2] = 0;
1289 /* IDENTIFIER LENGTH */
1290 cp[3] = 0;
1291
1292 /* IDENTIFIER */
1293 plen = snprintf((char *) &cp[4], MAX_TARGET_NAME,
1294 "%s"",t,0x""%4.4x", spec->lu->name, conn->portal.tag);
1295 cp[3] = plen;
1296 len += 4 + plen;
1297
1298 /* Identification descriptor 5 */
1299 /* Relative Target Port */
1300 cp = &data[hlen + len];
1301
1302 /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
1303 BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
1304 BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
1305 /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
1306 BDSET8W(&cp[1], 1, 7, 1); /* PIV */
1307 BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
1308 BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_RELATIVE_TARGET_PORT,
1309 3, 4);
1310 /* Reserved */
1311 cp[2] = 0;
1312 /* IDENTIFIER LENGTH */
1313 cp[3] = 0;
1314
1315 /* IDENTIFIER */
1316 /* Obsolete */
1317 DSET16(&cp[4], 0);
1318 /* Relative Target Port Identifier */
1319 //DSET16(&cp[6], 1); /* port1 as port A */
1320 //DSET16(&cp[6], 2); /* port2 as port B */
1321 DSET16(&cp[6], (uint16_t) (1 + conn->portal.idx));
1322 plen = 4;
1323
1324 cp[3] = plen;
1325 len += 4 + plen;
1326
1327 /* Identification descriptor 6 */
1328 /* Target port group */
1329 cp = &data[hlen + len];
1330
1331 /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
1332 BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
1333 BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
1334 /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
1335 BDSET8W(&cp[1], 1, 7, 1); /* PIV */
1336 BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
1337 BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_TARGET_PORT_GROUP,
1338 3, 4);
1339 /* Reserved */
1340 cp[2] = 0;
1341 /* IDENTIFIER LENGTH */
1342 cp[3] = 0;
1343
1344 /* IDENTIFIER */
1345 /* Reserved */
1346 DSET16(&cp[4], 0);
1347 /* TARGET PORT GROUP */
1348 DSET16(&cp[6], (uint16_t) (conn->portal.tag));
1349 plen = 4;
1350
1351 cp[3] = plen;
1352 len += 4 + plen;
1353
1354 /* Identification descriptor 7 */
1355 /* Logical unit group */
1356 cp = &data[hlen + len];
1357
1358 /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
1359 BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
1360 BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
1361 /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
1362 BDSET8W(&cp[1], 1, 7, 1); /* PIV */
1363 BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
1364 BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_LOGICAL_UNIT_GROUP,
1365 3, 4);
1366 /* Reserved */
1367 cp[2] = 0;
1368 /* IDENTIFIER LENGTH */
1369 cp[3] = 0;
1370
1371 /* IDENTIFIER */
1372 /* Reserved */
1373 DSET16(&cp[4], 0);
1374 /* LOGICAL UNIT GROUP */
1375 DSET16(&cp[6], (uint16_t) (spec->lu->num));
1376 plen = 4;
1377
1378 cp[3] = plen;
1379 len += 4 + plen;
1380
1381 /* PAGE LENGTH */
1382 if (len > 0xffff) {
1383 len = 0xffff;
1384 }
1385 DSET16(&data[2], len);
1386 break;
1387
1388 case SPC_VPD_EXTENDED_INQUIRY_DATA:
1389 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1390 BDSET8W(&data[0], pq, 7, 3);
1391 BDADD8W(&data[0], pd, 4, 5);
1392 /* PAGE CODE */
1393 data[1] = pc;
1394 /* Reserved */
1395 data[2] = 0;
1396 /* PAGE LENGTH */
1397 data[3] = 0;
1398 hlen = 4;
1399
1400 /* RTO(3) GRD_CHK(2) APP_CHK(1) REF_CHK(0) */
1401 data[4] = 0;
1402 /* GROUP_SUP(4) PRIOR_SUP(3) HEADSUP(2) ORDSUP(1) SIMPSUP(0) */
1403 data[5] = 0;
1404 if (spec->queue_depth != 0) {
1405 BDADD8(&data[5], 1, 2); /* HEADSUP */
1406 //BDADD8(&data[5], 1, 1); /* ORDSUP */
1407 BDADD8(&data[5], 1, 0); /* SIMPSUP */
1408 }
1409 /* NV_SUP(1) V_SUP(0) */
1410 data[6] = 0;
1411 /* Reserved[7-63] */
1412 memset(&data[7], 0, (64 - 7));
1413 len = 64 - hlen;
1414
1415 /* PAGE LENGTH */
1416 data[3] = len;
1417 break;
1418
1419 case SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES:
1420 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1421 BDSET8W(&data[0], pq, 7, 3);
1422 BDADD8W(&data[0], pd, 4, 5);
1423 /* PAGE CODE */
1424 data[1] = pc;
1425 /* PAGE LENGTH */
1426 DSET16(&data[2], 0);
1427 hlen = 4;
1428
1429 #if 0
1430 /* Network services descriptor N */
1431 cp = &data[hlen + len];
1432
1433 /* ASSOCIATION(6-5) SERVICE TYPE(4-0) */
1434 BDSET8W(&cp[0], 0x00, 6, 2);
1435 BDADD8W(&cp[0], 0x00, 4, 5);
1436 /* Reserved */
1437 cp[1] = 0;
1438 /* NETWORK ADDRESS LENGTH */
1439 DSET16(&cp[2], 0);
1440 /* NETWORK ADDRESS */
1441 cp[4] = 0;
1442 /* ... */
1443 plen = 0;
1444 DSET16(&cp[2], plen);
1445 len += 4 + plen;
1446 #endif
1447
1448 /* PAGE LENGTH */
1449 if (len > 0xffff) {
1450 len = 0xffff;
1451 }
1452 DSET16(&data[2], len);
1453 break;
1454
1455 case SPC_VPD_MODE_PAGE_POLICY:
1456 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1457 BDSET8W(&data[0], pq, 7, 3);
1458 BDADD8W(&data[0], pd, 4, 5);
1459 /* PAGE CODE */
1460 data[1] = pc;
1461 /* PAGE LENGTH */
1462 DSET16(&data[2], 0);
1463 hlen = 4;
1464
1465 /* Mode page policy descriptor 1 */
1466 cp = &data[hlen + len];
1467
1468 /* POLICY PAGE CODE(5-0) */
1469 BDSET8W(&cp[0], 0x3f, 5, 6); /* all page code */
1470 /* POLICY SUBPAGE CODE */
1471 cp[1] = 0xff; /* all sub page */
1472 /* MLUS(7) MODE PAGE POLICY(1-0) */
1473 //BDSET8(&cp[2], 1, 7); /* multiple logical units share */
1474 BDSET8(&cp[2], 0, 7); /* own copy */
1475 BDADD8W(&cp[2], 0x00, 1, 2); /* Shared */
1476 //BDADD8W(&cp[2], 0x01, 1, 2); /* Per target port */
1477 //BDADD8W(&cp[2], 0x02, 1, 2); /* Per initiator port */
1478 //BDADD8W(&cp[2], 0x03, 1, 2); /* Per I_T nexus */
1479 /* Reserved */
1480 cp[3] = 0;
1481 len += 4;
1482
1483 /* PAGE LENGTH */
1484 if (len > 0xffff) {
1485 len = 0xffff;
1486 }
1487 DSET16(&data[2], len);
1488 break;
1489
1490 case SPC_VPD_SCSI_PORTS:
1491 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1492 BDSET8W(&data[0], pq, 7, 3);
1493 BDADD8W(&data[0], pd, 4, 5);
1494 /* PAGE CODE */
1495 data[1] = pc;
1496 /* PAGE LENGTH */
1497 DSET16(&data[2], 0);
1498 hlen = 4;
1499
1500 /* Identification descriptor list */
1501 for (i = 0; i < spec->lu->maxmap; i++) {
1502 pg_tag = spec->lu->map[i].pg_tag;
1503 /* skip same pg_tag */
1504 for (j = 0; j < i; j++) {
1505 if (spec->lu->map[j].pg_tag == pg_tag) {
1506 goto skip_pg_tag;
1507 }
1508 }
1509
1510 /* Identification descriptor N */
1511 cp = &data[hlen + len];
1512
1513 /* Reserved */
1514 DSET16(&cp[0], 0);
1515 /* RELATIVE PORT IDENTIFIER */
1516 DSET16(&cp[2], (uint16_t) (1 + pg_tag));
1517 /* Reserved */
1518 DSET16(&cp[4], 0);
1519 /* INITIATOR PORT TRANSPORTID LENGTH */
1520 DSET16(&cp[6], 0);
1521 /* Reserved */
1522 DSET16(&cp[8], 0);
1523 /* TARGET PORT DESCRIPTORS LENGTH */
1524 DSET16(&cp[10], 0);
1525 len += 12;
1526
1527 plen2 = 0;
1528 /* Target port descriptor 1 */
1529 cp2 = &data[hlen + len + plen2];
1530
1531 /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
1532 BDSET8W(&cp2[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
1533 BDADD8W(&cp2[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
1534 /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
1535 BDSET8W(&cp2[1], 1, 7, 1); /* PIV */
1536 BDADD8W(&cp2[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
1537 BDADD8W(&cp2[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
1538 /* Reserved */
1539 cp2[2] = 0;
1540 /* IDENTIFIER LENGTH */
1541 cp2[3] = 0;
1542
1543 /* IDENTIFIER */
1544 plen = snprintf((char *) &cp2[4], MAX_TARGET_NAME,
1545 "%s"",t,0x""%4.4x", spec->lu->name, pg_tag);
1546 cp2[3] = plen;
1547 plen2 += 4 + plen;
1548
1549 /* TARGET PORT DESCRIPTORS LENGTH */
1550 DSET16(&cp[10], plen2);
1551 len += plen2;
1552 skip_pg_tag:
1553 ;
1554 }
1555
1556 /* PAGE LENGTH */
1557 if (len > 0xffff) {
1558 len = 0xffff;
1559 }
1560 DSET16(&data[2], len);
1561 break;
1562
1563 case 0xb0: /* SBC Block Limits */
1564 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1565 BDSET8W(&data[0], pq, 7, 3);
1566 BDADD8W(&data[0], pd, 4, 5);
1567 /* PAGE CODE */
1568 data[1] = pc;
1569 /* PAGE LENGTH */
1570 DSET16(&data[2], 0);
1571 hlen = 4;
1572
1573 /* WSNZ(0) */
1574 BDSET8(&data[4], 0, 0); /* support zero length in WRITE SAME */
1575 /* MAXIMUM COMPARE AND WRITE LENGTH */
1576 blocks = ISTGT_LU_WORK_ATS_BLOCK_SIZE / (uint32_t) spec->blocklen;
1577 if (blocks > 0xff) {
1578 blocks = 0xff;
1579 }
1580 data[5] = (uint8_t) blocks;
1581 if (spec->lu->istgt->swmode == ISTGT_SWMODE_TRADITIONAL) {
1582 /* no support compare and write */
1583 data[5] = 0;
1584 }
1585
1586 /* force align to 4KB */
1587 if (spec->blocklen < 4096) {
1588 blocks = 4096 / (uint32_t) spec->blocklen;
1589 /* OPTIMAL TRANSFER LENGTH GRANULARITY */
1590 DSET16(&data[6], blocks);
1591 /* MAXIMUM TRANSFER LENGTH */
1592 DSET32(&data[8], 0); /* no limit */
1593 /* OPTIMAL TRANSFER LENGTH */
1594 blocks = ISTGT_LU_WORK_BLOCK_SIZE / (uint32_t) spec->blocklen;
1595 DSET32(&data[12], blocks);
1596 /* MAXIMUM PREFETCH XDREAD XDWRITE TRANSFER LENGTH */
1597 DSET32(&data[16], 0);
1598 } else {
1599 blocks = 1;
1600 /* OPTIMAL TRANSFER LENGTH GRANULARITY */
1601 DSET16(&data[6], blocks);
1602 /* MAXIMUM TRANSFER LENGTH */
1603 DSET32(&data[8], 0); /* no limit */
1604 /* OPTIMAL TRANSFER LENGTH */
1605 blocks = ISTGT_LU_WORK_BLOCK_SIZE / (uint32_t) spec->blocklen;
1606 DSET32(&data[12], blocks);
1607 /* MAXIMUM PREFETCH XDREAD XDWRITE TRANSFER LENGTH */
1608 DSET32(&data[16], 0);
1609 }
1610 len = 20 - hlen;
1611
1612 if (1 || spec->thin_provisioning) {
1613 /* MAXIMUM UNMAP LBA COUNT */
1614 DSET32(&data[20], 0); /* not implement UNMAP */
1615 /* MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT */
1616 DSET32(&data[24], 0); /* not implement UNMAP */
1617 /* OPTIMAL UNMAP GRANULARITY */
1618 DSET32(&data[28], 0); /* not specified */
1619 /* UNMAP GRANULARITY ALIGNMENT */
1620 DSET32(&data[32], (0 & 0x7fffffffU));
1621 /* UGAVALID(7) */
1622 BDADD8(&data[32], 0, 7); /* not valid ALIGNMENT */
1623 /* MAXIMUM WRITE SAME LENGTH */
1624 DSET64(&data[36], 0); /* no limit */
1625 /* Reserved */
1626 memset(&data[44], 0x00, 64-44);
1627 len = 64 - hlen;
1628 }
1629
1630 DSET16(&data[2], len);
1631 break;
1632
1633 case 0xb1: /* SBC Block Device Characteristics */
1634 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1635 BDSET8W(&data[0], pq, 7, 3);
1636 BDADD8W(&data[0], pd, 4, 5);
1637 /* PAGE CODE */
1638 data[1] = pc;
1639 /* PAGE LENGTH */
1640 DSET16(&data[2], 0);
1641 hlen = 4;
1642
1643 /* MEDIUM ROTATION RATE */
1644 //DSET16(&data[4], 0x0000); /* not reported */
1645 //DSET16(&data[4], 0x0001); /* Non-rotating medium (solid state) */
1646 //DSET16(&data[4], 5400); /* rotation rate (5400rpm) */
1647 //DSET16(&data[4], 7200); /* rotation rate (7200rpm) */
1648 //DSET16(&data[4], 10000); /* rotation rate (10000rpm) */
1649 //DSET16(&data[4], 15000); /* rotation rate (15000rpm) */
1650 DSET16(&data[4], spec->lu->lun[spec->lun].rotationrate);
1651 /* Reserved */
1652 data[6] = 0;
1653 /* NOMINAL FORM FACTOR(3-0) */
1654 //BDSET8W(&data[7], 0x00, 3, 4); /* not reported */
1655 //BDSET8W(&data[7], 0x01, 3, 4); /* 5.25 inch */
1656 //BDSET8W(&data[7], 0x02, 3, 4); /* 3.5 inch */
1657 //BDSET8W(&data[7], 0x03, 3, 4); /* 2.5 inch */
1658 //BDSET8W(&data[7], 0x04, 3, 4); /* 1.8 inch */
1659 //BDSET8W(&data[7], 0x05, 3, 4); /* less 1.8 inch */
1660 BDSET8W(&data[7], spec->lu->lun[spec->lun].formfactor, 3, 4);
1661 /* Reserved */
1662 memset(&data[8], 0x00, 64-8);
1663
1664 len = 64 - hlen;
1665 DSET16(&data[2], len);
1666 break;
1667
1668 case 0xb2: /* SBC Thin Provisioning */
1669 if (!spec->thin_provisioning) {
1670 ISTGT_ERRLOG("unsupported INQUIRY VPD page 0x%x\n", pc);
1671 return -1;
1672 }
1673
1674 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1675 BDSET8W(&data[0], pq, 7, 3);
1676 BDADD8W(&data[0], pd, 4, 5);
1677 /* PAGE CODE */
1678 data[1] = pc;
1679 /* PAGE LENGTH */
1680 DSET16(&data[2], 0);
1681 hlen = 4;
1682
1683 /* THRESHOLD EXPONENT */
1684 data[4] = 0;
1685 /* DP(0) */
1686 BDSET8(&data[5], 0, 0);
1687 /* Reserved */
1688 DSET16(&data[6], 0);
1689 len = 6 - hlen;
1690 #if 0
1691 /* XXX not yet */
1692 /* PROVISIONING GROUP DESCRIPTOR ... */
1693 DSET16(&data[8], 0);
1694 len = 8 - hlen;
1695 #endif
1696
1697 DSET16(&data[2], len);
1698 break;
1699
1700 default:
1701 if (pc >= 0xc0 && pc <= 0xff) {
1702 ISTGT_WARNLOG("Vendor specific INQUIRY VPD page 0x%x\n", pc);
1703 } else {
1704 ISTGT_ERRLOG("unsupported INQUIRY VPD page 0x%x\n", pc);
1705 }
1706 return -1;
1707 }
1708 } else {
1709 /* Standard INQUIRY data */
1710 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
1711 BDSET8W(&data[0], pq, 7, 3);
1712 BDADD8W(&data[0], pd, 4, 5);
1713 /* RMB(7) */
1714 BDSET8W(&data[1], rmb, 7, 1);
1715 /* VERSION */
1716 /* See SPC3/SBC2/MMC4/SAM2 for more details */
1717 data[2] = SPC_VERSION_SPC3;
1718 /* NORMACA(5) HISUP(4) RESPONSE DATA FORMAT(3-0) */
1719 BDSET8W(&data[3], 2, 3, 4); /* format 2 */
1720 BDADD8(&data[1], 1, 4); /* hierarchical support */
1721 /* ADDITIONAL LENGTH */
1722 data[4] = 0;
1723 hlen = 5;
1724
1725 /* SCCS(7) ACC(6) TPGS(5-4) 3PC(3) PROTECT(0) */
1726 data[5] = 0;
1727 //BDADD8W(&data[5], 1, 7, 1); /* storage array controller */
1728 BDADD8W(&data[5], 0x00, 5, 2); /* Not support TPGS */
1729 //BDADD8W(&data[5], 0x01, 5, 2); /* Only implicit */
1730 //BDADD8W(&data[5], 0x02, 5, 2); /* Only explicit */
1731 //BDADD8W(&data[5], 0x03, 5, 2); /* Both explicit and implicit */
1732 /* BQUE(7) ENCSERV(6) VS(5) MULTIP(4) MCHNGR(3) ADDR16(0) */
1733 data[6] = 0;
1734 BDADD8W(&data[6], 1, 4, 1); /* MULTIP */
1735 /* WBUS16(5) SYNC(4) LINKED(3) CMDQUE(1) VS(0) */
1736 data[7] = 0;
1737 if (spec->queue_depth != 0) {
1738 BDADD8(&data[7], 1, 1); /* CMDQUE */
1739 }
1740 /* T10 VENDOR IDENTIFICATION */
1741 istgt_strcpy_pad(&data[8], 8, spec->lu->inq_vendor, ' ');
1742 /* PRODUCT IDENTIFICATION */
1743 istgt_strcpy_pad(&data[16], 16, spec->lu->inq_product, ' ');
1744 /* PRODUCT REVISION LEVEL */
1745 istgt_strcpy_pad(&data[32], 4, spec->lu->inq_revision, ' ');
1746 /* Vendor specific */
1747 memset(&data[36], 0x20, 20);
1748 /* CLOCKING(3-2) QAS(1) IUS(0) */
1749 data[56] = 0;
1750 /* Reserved */
1751 data[57] = 0;
1752 /* VERSION DESCRIPTOR 1-8 */
1753 DSET16(&data[58], 0x0960); /* iSCSI (no version claimed) */
1754 DSET16(&data[60], 0x0300); /* SPC-3 (no version claimed) */
1755 DSET16(&data[62], 0x0320); /* SBC-2 (no version claimed) */
1756 DSET16(&data[64], 0x0040); /* SAM-2 (no version claimed) */
1757 DSET16(&data[66], 0x0000);
1758 DSET16(&data[68], 0x0000);
1759 DSET16(&data[70], 0x0000);
1760 DSET16(&data[72], 0x0000);
1761 /* Reserved[74-95] */
1762 memset(&data[74], 0, (96 - 74));
1763 /* Vendor specific parameters[96-n] */
1764 //data[96] = 0;
1765 len = 96 - hlen;
1766
1767 /* ADDITIONAL LENGTH */
1768 data[4] = len;
1769 }
1770
1771 return hlen + len;
1772 }
1773
1774 #define MODE_SENSE_PAGE_INIT(B,L,P,SP) \
1775 do { \
1776 memset((B), 0, (L)); \
1777 if ((SP) != 0x00) { \
1778 (B)[0] = (P) | 0x40; /* PAGE + SPF=1 */ \
1779 (B)[1] = (SP); \
1780 DSET16(&(B)[2], (L) - 4); \
1781 } else { \
1782 (B)[0] = (P); \
1783 (B)[1] = (L) - 2; \
1784 } \
1785 } while (0)
1786
1787 static int
istgt_lu_disk_scsi_mode_sense_page(ISTGT_LU_DISK * spec,CONN_Ptr conn,uint8_t * cdb,int pc,int page,int subpage,uint8_t * data,int alloc_len)1788 istgt_lu_disk_scsi_mode_sense_page(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int pc, int page, int subpage, uint8_t *data, int alloc_len)
1789 {
1790 uint8_t *cp;
1791 int len = 0;
1792 int plen;
1793 int rc;
1794 int i;
1795
1796 #if 0
1797 printf("pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage);
1798 #endif
1799 #if 0
1800 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE: pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage);
1801 #endif
1802
1803 if (pc == 0x00) {
1804 /* Current values */
1805 } else if (pc == 0x01) {
1806 /* Changeable values */
1807 if (page != 0x08) {
1808 /* not supported */
1809 return -1;
1810 }
1811 } else if (pc == 0x02) {
1812 /* Default values */
1813 } else {
1814 /* Saved values */
1815 }
1816
1817 cp = &data[len];
1818 switch (page) {
1819 case 0x00:
1820 /* Vendor specific */
1821 break;
1822 case 0x01:
1823 /* Read-Write Error Recovery */
1824 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Read-Write Error Recovery\n");
1825 if (subpage != 0x00)
1826 break;
1827 plen = 0x0a + 2;
1828 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1829 len += plen;
1830 break;
1831 case 0x02:
1832 /* Disconnect-Reconnect */
1833 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Disconnect-Reconnect\n");
1834 if (subpage != 0x00)
1835 break;
1836 plen = 0x0e + 2;
1837 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1838 len += plen;
1839 break;
1840 case 0x03:
1841 /* Obsolete (Format Device) */
1842 break;
1843 case 0x04:
1844 /* Obsolete (Rigid Disk Geometry) */
1845 break;
1846 case 0x05:
1847 /* Obsolete (Rigid Disk Geometry) */
1848 break;
1849 case 0x06:
1850 /* Reserved */
1851 break;
1852 case 0x07:
1853 /* Verify Error Recovery */
1854 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Verify Error Recovery\n");
1855 if (subpage != 0x00)
1856 break;
1857 plen = 0x0a + 2;
1858 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1859 len += plen;
1860 break;
1861 case 0x08:
1862 /* Caching */
1863 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Caching\n");
1864 if (subpage != 0x00)
1865 break;
1866
1867 plen = 0x12 + 2;
1868 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1869 BDADD8(&cp[0], 1, 7); /* PS */
1870 if (pc == 0x01) {
1871 // Changeable values
1872 BDADD8(&cp[2], 1, 2); /* WCE */
1873 BDADD8(&cp[2], 1, 0); /* RCD */
1874 len += plen;
1875 break;
1876 }
1877 BDADD8(&cp[2], 1, 2); /* WCE */
1878 //BDADD8(&cp[2], 1, 0); /* RCD */
1879 {
1880 int fd;
1881 fd = spec->fd;
1882 rc = fcntl(fd , F_GETFL, 0);
1883 if (rc != -1 && !(rc & O_FSYNC)) {
1884 BDADD8(&cp[2], 1, 2); /* WCE=1 */
1885 } else {
1886 BDADD8(&cp[2], 0, 2); /* WCE=0 */
1887 }
1888 }
1889 if (spec->read_cache == 0) {
1890 BDADD8(&cp[2], 1, 0); /* RCD=1 */
1891 } else {
1892 BDADD8(&cp[2], 0, 0); /* RCD=0 */
1893 }
1894 len += plen;
1895 break;
1896 case 0x09:
1897 /* Obsolete */
1898 break;
1899 case 0x0a:
1900 switch (subpage) {
1901 case 0x00:
1902 /* Control */
1903 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Control\n");
1904 plen = 0x0a + 2;
1905 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1906 len += plen;
1907 break;
1908 case 0x01:
1909 /* Control Extension */
1910 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Control Extension\n");
1911 plen = 0x1c + 4;
1912 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1913 len += plen;
1914 break;
1915 case 0xff:
1916 /* All subpages */
1917 len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, 0x00, &data[len], alloc_len);
1918 len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, 0x01, &data[len], alloc_len);
1919 break;
1920 default:
1921 /* 0x02-0x3e: Reserved */
1922 break;
1923 }
1924 break;
1925 case 0x0b:
1926 /* Obsolete (Medium Types Supported) */
1927 break;
1928 case 0x0c:
1929 /* Obsolete (Notch And Partitio) */
1930 break;
1931 case 0x0d:
1932 /* Obsolete */
1933 break;
1934 case 0x0e:
1935 case 0x0f:
1936 /* Reserved */
1937 break;
1938 case 0x10:
1939 /* XOR Control */
1940 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE XOR Control\n");
1941 if (subpage != 0x00)
1942 break;
1943 plen = 0x16 + 2;
1944 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1945 len += plen;
1946 break;
1947 case 0x11:
1948 case 0x12:
1949 case 0x13:
1950 /* Reserved */
1951 break;
1952 case 0x14:
1953 /* Enclosure Services Management */
1954 break;
1955 case 0x15:
1956 case 0x16:
1957 case 0x17:
1958 /* Reserved */
1959 break;
1960 case 0x18:
1961 /* Protocol-Specific LUN */
1962 #if 0
1963 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Protocol-Specific LUN\n");
1964 if (subpage != 0x00)
1965 break;
1966 plen = 0x04 + 0x00 + 2;
1967 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1968 len += plen;
1969 #endif
1970 break;
1971 case 0x19:
1972 /* Protocol-Specific Port */
1973 #if 0
1974 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Protocol-Specific Port\n");
1975 if (subpage != 0x00)
1976 break;
1977 plen = 0x04 + 0x00 + 2;
1978 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1979 len += plen;
1980 #endif
1981 break;
1982 case 0x1a:
1983 /* Power Condition */
1984 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Power Condition\n");
1985 if (subpage != 0x00)
1986 break;
1987 plen = 0x0a + 2;
1988 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1989 len += plen;
1990 break;
1991 case 0x1b:
1992 /* Reserved */
1993 break;
1994 case 0x1c:
1995 /* Informational Exceptions Control */
1996 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Informational Exceptions Control\n");
1997 if (subpage != 0x00)
1998 break;
1999
2000 plen = 0x0a + 2;
2001 MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
2002 len += plen;
2003 break;
2004 case 0x1d:
2005 case 0x1e:
2006 case 0x1f:
2007 /* Reserved */
2008 break;
2009 case 0x20:
2010 case 0x21:
2011 case 0x22:
2012 case 0x23:
2013 case 0x24:
2014 case 0x25:
2015 case 0x26:
2016 case 0x27:
2017 case 0x28:
2018 case 0x29:
2019 case 0x2a:
2020 case 0x2b:
2021 case 0x2c:
2022 case 0x2d:
2023 case 0x2e:
2024 case 0x2f:
2025 case 0x30:
2026 case 0x31:
2027 case 0x32:
2028 case 0x33:
2029 case 0x34:
2030 case 0x35:
2031 case 0x36:
2032 case 0x37:
2033 case 0x38:
2034 case 0x39:
2035 case 0x3a:
2036 case 0x3b:
2037 case 0x3c:
2038 case 0x3d:
2039 case 0x3e:
2040 /* Vendor-specific */
2041 break;
2042 case 0x3f:
2043 switch (subpage) {
2044 case 0x00:
2045 /* All mode pages */
2046 for (i = 0x00; i < 0x3e; i ++) {
2047 len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
2048 }
2049 break;
2050 case 0xff:
2051 /* All mode pages and subpages */
2052 for (i = 0x00; i < 0x3e; i ++) {
2053 len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
2054 }
2055 for (i = 0x00; i < 0x3e; i ++) {
2056 len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0xff, &cp[len], alloc_len);
2057 }
2058 break;
2059 default:
2060 /* 0x01-0x3e: Reserved */
2061 break;
2062 }
2063 }
2064
2065 return len;
2066 }
2067
2068 static int
istgt_lu_disk_scsi_mode_sense6(ISTGT_LU_DISK * spec,CONN_Ptr conn,uint8_t * cdb,int dbd,int pc,int page,int subpage,uint8_t * data,int alloc_len)2069 istgt_lu_disk_scsi_mode_sense6(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int dbd, int pc, int page, int subpage, uint8_t *data, int alloc_len)
2070 {
2071 uint8_t *cp;
2072 int hlen = 0, len = 0, plen;
2073 int total;
2074 int llbaa = 0;
2075
2076 data[0] = 0; /* Mode Data Length */
2077 data[1] = 0; /* Medium Type */
2078 data[2] = 0; /* Device-Specific Parameter */
2079 if (spec->lu->readonly) {
2080 BDADD8(&data[2], 1, 7); /* WP */
2081 }
2082 data[3] = 0; /* Block Descripter Length */
2083 hlen = 4;
2084
2085 cp = &data[4];
2086 if (dbd) { /* Disable Block Descripters */
2087 len = 0;
2088 } else {
2089 if (llbaa) {
2090 /* Number of Blocks */
2091 DSET64(&cp[0], spec->blockcnt);
2092 /* Reserved */
2093 DSET32(&cp[8], 0);
2094 /* Block Length */
2095 DSET32(&cp[12], (uint32_t) spec->blocklen);
2096 len = 16;
2097 } else {
2098 /* Number of Blocks */
2099 if (spec->blockcnt > 0xffffffffULL) {
2100 DSET32(&cp[0], 0xffffffffUL);
2101 } else {
2102 DSET32(&cp[0], (uint32_t) spec->blockcnt);
2103 }
2104 /* Block Length */
2105 DSET32(&cp[4], (uint32_t) spec->blocklen);
2106 len = 8;
2107 }
2108 cp += len;
2109 }
2110 data[3] = len; /* Block Descripter Length */
2111
2112 plen = istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
2113 if (plen < 0) {
2114 return -1;
2115 }
2116 cp += plen;
2117
2118 total = hlen + len + plen;
2119 data[0] = total - 1; /* Mode Data Length */
2120
2121 return total;
2122 }
2123
2124 static int
istgt_lu_disk_scsi_mode_sense10(ISTGT_LU_DISK * spec,CONN_Ptr conn,uint8_t * cdb,int dbd,int llbaa,int pc,int page,int subpage,uint8_t * data,int alloc_len)2125 istgt_lu_disk_scsi_mode_sense10(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int dbd, int llbaa, int pc, int page, int subpage, uint8_t *data, int alloc_len)
2126 {
2127 uint8_t *cp;
2128 int hlen = 0, len = 0, plen;
2129 int total;
2130
2131 DSET16(&data[0], 0); /* Mode Data Length */
2132 data[2] = 0; /* Medium Type */
2133 data[3] = 0; /* Device-Specific Parameter */
2134 if (spec->lu->readonly) {
2135 BDADD8(&data[3], 1, 7); /* WP */
2136 }
2137 if (llbaa) {
2138 BDSET8(&data[4], 1, 1); /* Long LBA */
2139 } else {
2140 BDSET8(&data[4], 0, 1); /* Short LBA */
2141 }
2142 data[5] = 0; /* Reserved */
2143 DSET16(&data[6], 0); /* Block Descripter Length */
2144 hlen = 8;
2145
2146 cp = &data[8];
2147 if (dbd) { /* Disable Block Descripters */
2148 len = 0;
2149 } else {
2150 if (llbaa) {
2151 /* Number of Blocks */
2152 DSET64(&cp[0], spec->blockcnt);
2153 /* Reserved */
2154 DSET32(&cp[8], 0);
2155 /* Block Length */
2156 DSET32(&cp[12], (uint32_t) spec->blocklen);
2157 len = 16;
2158 } else {
2159 /* Number of Blocks */
2160 if (spec->blockcnt > 0xffffffffULL) {
2161 DSET32(&cp[0], 0xffffffffUL);
2162 } else {
2163 DSET32(&cp[0], (uint32_t) spec->blockcnt);
2164 }
2165 /* Block Length */
2166 DSET32(&cp[4], (uint32_t) spec->blocklen);
2167 len = 8;
2168 }
2169 cp += len;
2170 }
2171 DSET16(&data[6], len); /* Block Descripter Length */
2172
2173 plen = istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
2174 if (plen < 0) {
2175 return -1;
2176 }
2177 cp += plen;
2178
2179 total = hlen + len + plen;
2180 DSET16(&data[0], total - 2); /* Mode Data Length */
2181
2182 return total;
2183 }
2184
2185 static int
istgt_lu_disk_transfer_data(CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint8_t * buf,size_t bufsize,size_t len)2186 istgt_lu_disk_transfer_data(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *buf, size_t bufsize, size_t len)
2187 {
2188 int rc;
2189
2190 if (lu_cmd->lu->queue_depth == 0) {
2191 if (len > bufsize) {
2192 ISTGT_ERRLOG("bufsize(%zd) too small\n", bufsize);
2193 return -1;
2194 }
2195 rc = istgt_iscsi_transfer_out(conn, lu_cmd, buf, bufsize, len);
2196 if (rc < 0) {
2197 ISTGT_ERRLOG("iscsi_transfer_out()\n");
2198 return -1;
2199 }
2200 }
2201 return 0;
2202 }
2203
2204 static int
istgt_lu_disk_scsi_mode_select_page(ISTGT_LU_DISK * spec,CONN_Ptr conn,uint8_t * cdb,int pf,int sp,uint8_t * data,size_t len)2205 istgt_lu_disk_scsi_mode_select_page(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int pf, int sp, uint8_t *data, size_t len)
2206 {
2207 size_t hlen, plen;
2208 int ps, spf, page, subpage;
2209 int rc;
2210
2211 if (pf == 0) {
2212 /* vendor specific */
2213 return 0;
2214 }
2215
2216 if (len < 1)
2217 return 0;
2218 ps = BGET8(&data[0], 7);
2219 spf = BGET8(&data[0], 6);
2220 page = data[0] & 0x3f;
2221 if (spf) {
2222 /* Sub_page mode page format */
2223 hlen = 4;
2224 if (len < hlen)
2225 return 0;
2226 subpage = data[1];
2227
2228 plen = DGET16(&data[2]);
2229 } else {
2230 /* Page_0 mode page format */
2231 hlen = 2;
2232 if (len < hlen)
2233 return 0;
2234 subpage = 0;
2235 plen = data[1];
2236 }
2237 plen += hlen;
2238 if (len < plen)
2239 return 0;
2240
2241 #if 0
2242 printf("ps=%d, page=%2.2x, subpage=%2.2x\n", ps, page, subpage);
2243 #endif
2244 switch (page) {
2245 case 0x08:
2246 /* Caching */
2247 {
2248 int wce, rcd;
2249
2250 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Caching\n");
2251 if (subpage != 0x00)
2252 break;
2253 if (plen != 0x12 + hlen) {
2254 /* unknown format */
2255 break;
2256 }
2257 wce = BGET8(&data[2], 2); /* WCE */
2258 rcd = BGET8(&data[2], 0); /* RCD */
2259
2260 {
2261 int fd;
2262 fd = spec->fd;
2263 rc = fcntl(fd , F_GETFL, 0);
2264 if (rc != -1) {
2265 if (wce) {
2266 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Writeback cache enable\n");
2267 rc = fcntl(fd, F_SETFL, (rc & ~O_FSYNC));
2268 spec->write_cache = 1;
2269 } else {
2270 rc = fcntl(fd, F_SETFL, (rc | O_FSYNC));
2271 spec->write_cache = 0;
2272 }
2273 if (rc == -1) {
2274 /* XXX */
2275 //ISTGT_ERRLOG("fcntl(F_SETFL) failed\n");
2276 }
2277 }
2278 }
2279 if (rcd) {
2280 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Read cache disable\n");
2281 spec->read_cache = 0;
2282 } else {
2283 spec->read_cache = 1;
2284 }
2285 }
2286 break;
2287 default:
2288 /* not supported */
2289 break;
2290 }
2291
2292 len -= plen;
2293 if (len != 0) {
2294 rc = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[plen], len);
2295 if (rc < 0) {
2296 return rc;
2297 }
2298 }
2299 return 0;
2300 }
2301
2302 static int
istgt_lu_disk_scsi_read_defect10(ISTGT_LU_DISK * spec,CONN_Ptr conn,uint8_t * cdb,int req_plist,int req_glist,int list_format,uint8_t * data,int alloc_len)2303 istgt_lu_disk_scsi_read_defect10(ISTGT_LU_DISK *spec __attribute__((__unused__)), CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int req_plist, int req_glist, int list_format, uint8_t *data, int alloc_len)
2304 {
2305 uint8_t *cp;
2306 int hlen = 0, len = 0;
2307 int total;
2308
2309 if (alloc_len < 4) {
2310 return -1;
2311 }
2312
2313 data[0] = 0; /* Reserved */
2314 data[1] = 0;
2315 if (req_plist) {
2316 BDADD8(&data[1], 1, 4); /* PLISTV */
2317 }
2318 if (req_glist) {
2319 BDADD8(&data[1], 1, 3); /* GLISTV */
2320 }
2321 BDADD8W(&data[1], list_format, 2, 3); /* DEFECT LIST FORMAT */
2322 DSET16(&data[2], 0); /* DEFECT LIST LENGTH */
2323 hlen = 4;
2324
2325 cp = &data[4];
2326 /* defect list (if any) */
2327 len = 0;
2328
2329 total = hlen + len;
2330 DSET16(&data[2], total - hlen); /* DEFECT LIST LENGTH */
2331 return total;
2332 }
2333
2334 static int
istgt_lu_disk_scsi_read_defect12(ISTGT_LU_DISK * spec,CONN_Ptr conn,uint8_t * cdb,int req_plist,int req_glist,int list_format,uint8_t * data,int alloc_len)2335 istgt_lu_disk_scsi_read_defect12(ISTGT_LU_DISK *spec __attribute__((__unused__)), CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int req_plist, int req_glist, int list_format, uint8_t *data, int alloc_len)
2336 {
2337 uint8_t *cp;
2338 int hlen = 0, len = 0;
2339 int total;
2340
2341 if (alloc_len < 8) {
2342 return -1;
2343 }
2344
2345 data[0] = 0; /* Reserved */
2346 data[1] = 0;
2347 if (req_plist) {
2348 BDADD8(&data[1], 1, 4); /* PLISTV */
2349 }
2350 if (req_glist) {
2351 BDADD8(&data[1], 1, 3); /* GLISTV */
2352 }
2353 BDADD8W(&data[1], list_format, 2, 3); /* DEFECT LIST FORMAT */
2354 data[2] = 0; /* Reserved */
2355 data[3] = 0; /* Reserved */
2356 DSET32(&data[4], 0); /* DEFECT LIST LENGTH */
2357 hlen = 8;
2358
2359 cp = &data[8];
2360 /* defect list (if any) */
2361 len = 0;
2362
2363 total = hlen + len;
2364 DSET32(&data[4], total - hlen); /* DEFECT LIST LENGTH */
2365 return total;
2366 }
2367
2368 #if 0
2369 static int
2370 istgt_lu_disk_scsi_request_sense(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int desc, uint8_t *data, int alloc_len)
2371 {
2372 int len = 0, plen;
2373
2374 if (alloc_len < 18) {
2375 ISTGT_ERRLOG("alloc_len(%d) too small\n", alloc_len);
2376 return -1;
2377 }
2378
2379 /* XXX TODO: fix */
2380 if (desc == 0) {
2381 /* fixed format */
2382 /* NO ADDITIONAL SENSE INFORMATION */
2383 /* BUILD_SENSE(NO_SENSE, 0x00, 0x00); */
2384
2385 /* VALID(7) RESPONSE CODE(6-0) */
2386 BDSET8(&data[0], 0, 7);
2387 BDADD8W(&data[0], 0x70, 6, 7);
2388 /* Obsolete */
2389 data[1] = 0;
2390 /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
2391 BDSET8W(&data[2], ISTGT_SCSI_SENSE_NO_SENSE, 3, 4);
2392 /* INFORMATION */
2393 memset(&data[3], 0, 4);
2394 /* ADDITIONAL SENSE LENGTH */
2395 data[7] = 0;
2396 len = 8;
2397
2398 /* COMMAND-SPECIFIC INFORMATION */
2399 memset(&data[8], 0, 4);
2400 /* ADDITIONAL SENSE CODE */
2401 data[12] = 0x00;
2402 /* ADDITIONAL SENSE CODE QUALIFIER */
2403 data[13] = 0x00;
2404 /* FIELD REPLACEABLE UNIT CODE */
2405 data[14] = 0;
2406 /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
2407 data[15] = 0;
2408 data[16] = 0;
2409 data[17] = 0;
2410 plen = 18 - len;
2411
2412 /* ADDITIONAL SENSE LENGTH */
2413 data[7] = plen;
2414 } else {
2415 /* descriptor format */
2416 /* NO ADDITIONAL SENSE INFORMATION */
2417 /* BUILD_SENSE(NO_SENSE, 0x00, 0x00); */
2418
2419 /* RESPONSE CODE(6-0) */
2420 BDSET8W(&data[0], 0x72, 6, 7);
2421 /* SENSE KEY(3-0) */
2422 BDSET8W(&data[1], ISTGT_SCSI_SENSE_NO_SENSE, 3, 4);
2423 /* ADDITIONAL SENSE CODE */
2424 data[2] = 0x00;
2425 /* ADDITIONAL SENSE CODE QUALIFIER */
2426 data[3] = 0x00;
2427 /* Reserved */
2428 data[4] = 0;
2429 data[5] = 0;
2430 data[6] = 0;
2431 /* ADDITIONAL SENSE LENGTH */
2432 data[7] = 0;
2433 len = 8;
2434
2435 /* Sense data descriptor(s) */
2436 plen = 8 - len;
2437
2438 /* ADDITIONAL SENSE LENGTH */
2439 data[7] = plen;
2440 }
2441 return len;
2442 }
2443 #endif
2444
2445 static int
istgt_lu_disk_scsi_report_target_port_groups(ISTGT_LU_DISK * spec,CONN_Ptr conn,uint8_t * cdb,uint8_t * data,int alloc_len)2446 istgt_lu_disk_scsi_report_target_port_groups(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb __attribute__((__unused__)), uint8_t *data, int alloc_len)
2447 {
2448 ISTGT_Ptr istgt;
2449 ISTGT_LU_Ptr lu;
2450 uint8_t *cp;
2451 uint8_t *cp_count;
2452 int hlen = 0, len = 0, plen;
2453 int total;
2454 int pg_tag;
2455 int nports;
2456 int i, j, k;
2457 int ridx;
2458
2459 if (alloc_len < 0xfff) {
2460 return -1;
2461 }
2462
2463 istgt = conn->istgt;
2464 lu = spec->lu;
2465
2466 /* RETURN DATA LENGTH */
2467 DSET32(&data[0], 0);
2468 hlen = 4;
2469
2470 MTX_LOCK(&istgt->mutex);
2471 for (i = 0; i < lu->maxmap; i++) {
2472 pg_tag = lu->map[i].pg_tag;
2473 /* skip same pg_tag */
2474 for (j = 0; j < i; j++) {
2475 if (lu->map[j].pg_tag == pg_tag) {
2476 goto skip_pg_tag;
2477 }
2478 }
2479
2480 /* Target port group descriptor N */
2481 cp = &data[hlen + len];
2482
2483 /* PREF(7) ASYMMETRIC ACCESS STATE(3-0) */
2484 cp[0] = 0;
2485 BDSET8(&cp[0], 1, 7); /* PREF */
2486 switch (lu->map[j].pg_aas & 0x0f) {
2487 case AAS_ACTIVE_OPTIMIZED:
2488 BDADD8W(&cp[0], AAS_ACTIVE_OPTIMIZED, 3, 4);
2489 break;
2490 case AAS_ACTIVE_NON_OPTIMIZED:
2491 BDADD8W(&cp[0], AAS_ACTIVE_NON_OPTIMIZED, 3, 4);
2492 break;
2493 case AAS_STANDBY:
2494 BDADD8W(&cp[0], AAS_STANDBY, 3, 4);
2495 break;
2496 case AAS_UNAVAILABLE:
2497 BDADD8W(&cp[0], AAS_UNAVAILABLE, 3, 4);
2498 break;
2499 case AAS_TRANSITIONING:
2500 BDADD8W(&cp[0], AAS_TRANSITIONING, 3, 4);
2501 break;
2502 default:
2503 ISTGT_ERRLOG("unsupported AAS\n");
2504 break;
2505 }
2506 /* T_SUP(7) U_SUP(3) S_SUP(2) S_SUP AN_SUP(1) AO_SUP(0) */
2507 cp[1] = 0;
2508 //BDADD8(&cp[1], 1, 7); /* transitioning supported */
2509 //BDADD8(&cp[1], 1, 3); /* unavailable supported */
2510 //BDADD8(&cp[1], 1, 2); /* standby supported */
2511 BDADD8(&cp[1], 1, 1); /* active/non-optimized supported */
2512 BDADD8(&cp[1], 1, 0); /* active/optimized supported */
2513 /* TARGET PORT GROUP */
2514 DSET16(&cp[2], pg_tag);
2515 /* Reserved */
2516 cp[4] = 0;
2517 /* STATUS CODE */
2518 if (lu->map[j].pg_aas & AAS_STATUS_IMPLICIT) {
2519 cp[5] = 0x02; /* by implicit */
2520 } else if (lu->map[j].pg_aas & AAS_STATUS_STPG) {
2521 cp[5] = 0x01; /* by SET TARGET PORT GROUPS */
2522 } else {
2523 cp[5] = 0; /* No status */
2524 }
2525 /* Vendor specific */
2526 cp[6] = 0;
2527 /* TARGET PORT COUNT */
2528 cp[7] = 0;
2529 cp_count = &cp[7];
2530 plen = 8;
2531 len += plen;
2532
2533 nports = 0;
2534 ridx = 0;
2535 MTX_LOCK(&istgt->mutex);
2536 for (j = 0; j < istgt->nportal_group; j++) {
2537 if (istgt->portal_group[j].tag == pg_tag) {
2538 for (k = 0; k < istgt->portal_group[j].nportals; k++) {
2539 /* Target port descriptor(s) */
2540 cp = &data[hlen + len];
2541 /* Obsolete */
2542 DSET16(&cp[0], 0);
2543 /* RELATIVE TARGET PORT IDENTIFIER */
2544 DSET16(&cp[2], (uint16_t) (1 + ridx));
2545 plen = 4;
2546 len += plen;
2547 nports++;
2548 ridx++;
2549 }
2550 } else {
2551 ridx += istgt->portal_group[j].nportals;
2552 }
2553 }
2554 MTX_UNLOCK(&istgt->mutex);
2555
2556 if (nports > 0xff) {
2557 ISTGT_ERRLOG("too many portals in portal group\n");
2558 MTX_UNLOCK(&istgt->mutex);
2559 return -1;
2560 }
2561
2562 /* TARGET PORT COUNT */
2563 cp_count[0] = nports;
2564
2565 skip_pg_tag:
2566 ;
2567 }
2568 MTX_UNLOCK(&istgt->mutex);
2569
2570 total = hlen + len;
2571 if (total > alloc_len) {
2572 ISTGT_ERRLOG("alloc_len(%d) too small\n", alloc_len);
2573 return -1;
2574 }
2575
2576 /* RETURN DATA LENGTH */
2577 DSET32(&data[0], total - 4);
2578
2579 return total;
2580 }
2581
2582 static int
istgt_lu_disk_scsi_set_target_port_groups(ISTGT_LU_DISK * spec,CONN_Ptr conn,uint8_t * cdb,uint8_t * data,int len)2583 istgt_lu_disk_scsi_set_target_port_groups(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, uint8_t *data, int len)
2584 {
2585 ISTGT_LU_Ptr lu;
2586 int pg_tag;
2587 int aas;
2588 int pg;
2589 int rc;
2590 int i;
2591
2592 if (len < 4) {
2593 return -1;
2594 }
2595
2596 lu = spec->lu;
2597
2598 aas = BGET8W(&data[0], 3, 4);
2599 pg = DGET16(&data[2]);
2600
2601 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AAS=0x%x, PG=0x%4.4x\n", aas, pg);
2602
2603 for (i = 0; i < lu->maxmap; i++) {
2604 pg_tag = lu->map[i].pg_tag;
2605 if (pg != pg_tag)
2606 continue;
2607
2608 switch (aas) {
2609 case AAS_ACTIVE_OPTIMIZED:
2610 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Active/optimized\n");
2611 break;
2612 case AAS_ACTIVE_NON_OPTIMIZED:
2613 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Active/non-optimized\n");
2614 break;
2615 #if 0
2616 case AAS_STANDBY:
2617 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Standby\n");
2618 break;
2619 case AAS_UNAVAILABLE:
2620 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Unavailable\n");
2621 break;
2622 #endif
2623 case AAS_TRANSITIONING:
2624 return -1;
2625 default:
2626 ISTGT_ERRLOG("unsupported AAS 0x%x\n", aas);
2627 return -1;
2628 }
2629 lu->map[i].pg_aas = aas;
2630 lu->map[i].pg_aas |= AAS_STATUS_STPG;
2631 }
2632
2633 len -=4;
2634 if (len != 0) {
2635 rc = istgt_lu_disk_scsi_set_target_port_groups(spec, conn, cdb, data, len);
2636 if (rc < 0) {
2637 return rc;
2638 }
2639 }
2640 return 0;
2641 }
2642
2643 static void
istgt_lu_disk_free_pr_key(ISTGT_LU_PR_KEY * prkey)2644 istgt_lu_disk_free_pr_key(ISTGT_LU_PR_KEY *prkey)
2645 {
2646 int i;
2647
2648 if (prkey == NULL)
2649 return;
2650 xfree(prkey->registered_initiator_port);
2651 prkey->registered_initiator_port = NULL;
2652 xfree(prkey->registered_target_port);
2653 prkey->registered_target_port = NULL;
2654 prkey->pg_idx = 0;
2655 prkey->pg_tag = 0;
2656 for (i = 0; i < prkey->ninitiator_ports; i++) {
2657 xfree(prkey->initiator_ports[i]);
2658 prkey->initiator_ports[i] = NULL;
2659 }
2660 xfree(prkey->initiator_ports);
2661 prkey->initiator_ports = NULL;
2662 prkey->all_tpg = 0;
2663 }
2664
2665 static ISTGT_LU_PR_KEY *
istgt_lu_disk_find_pr_key(ISTGT_LU_DISK * spec,const char * initiator_port,const char * target_port,uint64_t key)2666 istgt_lu_disk_find_pr_key(ISTGT_LU_DISK *spec, const char *initiator_port, const char *target_port, uint64_t key)
2667 {
2668 ISTGT_LU_PR_KEY *prkey;
2669 int i;
2670
2671 /* return pointer if I_T nexus is registered */
2672 #ifdef ISTGT_TRACE_DISK
2673 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2674 "find prkey=0x%16.16"PRIx64", port=%s\n",
2675 key, ((initiator_port != NULL) ? initiator_port : "N/A"));
2676 #endif /* ISTGT_TRACE_DISK */
2677
2678 if (initiator_port == NULL)
2679 return NULL;
2680 for (i = 0; i < spec->npr_keys; i++) {
2681 prkey = &spec->pr_keys[i];
2682 if (prkey == NULL)
2683 continue;
2684 #ifdef ISTGT_TRACE_DISK
2685 if (key != 0) {
2686 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2687 "prkey=0x%16.16"PRIx64"\n",
2688 prkey->key);
2689 }
2690 #endif /* ISTGT_TRACE_DISK */
2691 if (key != 0 && prkey->key != key)
2692 continue;
2693 #ifdef ISTGT_TRACE_DISK
2694 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "pript=%s, ipt=%s\n",
2695 prkey->registered_initiator_port,
2696 initiator_port);
2697 #endif /* ISTGT_TRACE_DISK */
2698 if (strcmp(prkey->registered_initiator_port,
2699 initiator_port) == 0) {
2700 #ifdef ISTGT_TRACE_DISK
2701 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "prtpt=%s, tpt=%s\n",
2702 prkey->registered_target_port,
2703 target_port);
2704 #endif /* ISTGT_TRACE_DISK */
2705 if (prkey->all_tpg != 0
2706 || target_port == NULL
2707 || strcmp(prkey->registered_target_port,
2708 target_port) == 0) {
2709 return prkey;
2710 }
2711 }
2712 }
2713 return NULL;
2714 }
2715
2716 static int
istgt_lu_disk_remove_other_pr_key(ISTGT_LU_DISK * spec,CONN_Ptr conn,const char * initiator_port,const char * target_port,uint64_t key)2717 istgt_lu_disk_remove_other_pr_key(ISTGT_LU_DISK *spec, CONN_Ptr conn __attribute__((__unused__)), const char *initiator_port, const char *target_port, uint64_t key)
2718 {
2719 ISTGT_LU_PR_KEY *prkey, *prkey1, *prkey2;
2720 int i, j;
2721
2722 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2723 "remove prkey=0x%16.16"PRIx64", iniport=%s, tgtport=%s\n",
2724 key, ((initiator_port != NULL) ? initiator_port : "N/A"),
2725 ((target_port != NULL) ? target_port : "N/A"));
2726
2727 if (spec->npr_keys == 0)
2728 return 0;
2729
2730 /* remove specified prkey from end of array */
2731 for (i = spec->npr_keys - 1; i >= 0; i--) {
2732 prkey = &spec->pr_keys[i];
2733 if (prkey == NULL)
2734 continue;
2735 if (key == 0 || prkey->key == key)
2736 continue;
2737 /* NULL means all initiator/target */
2738 if (initiator_port == NULL ||
2739 strcasecmp(prkey->registered_initiator_port,
2740 initiator_port) == 0)
2741 continue;
2742 if (prkey->all_tpg != 0
2743 || target_port == NULL
2744 || strcasecmp(prkey->registered_target_port,
2745 target_port) == 0)
2746 continue;
2747
2748 /* this prkey will remove */
2749 istgt_lu_disk_free_pr_key(prkey);
2750 /* move used array */
2751 for (j = i; j < spec->npr_keys - 1; j++) {
2752 prkey1 = &spec->pr_keys[j];
2753 prkey2 = &spec->pr_keys[j+1];
2754 *prkey1 = *prkey2;
2755 }
2756 /* last array is cleared */
2757 prkey1 = &spec->pr_keys[j];
2758 memset(prkey1, 0, sizeof(*prkey1));
2759 prkey1->registered_initiator_port = NULL;
2760 prkey1->registered_target_port = NULL;
2761 prkey1->initiator_ports = NULL;
2762 /* update counts */
2763 spec->npr_keys--;
2764 }
2765 #ifdef ISTGT_TRACE_DISK
2766 if (g_trace_flag) {
2767 for (i = 0; i < spec->npr_keys; i++) {
2768 prkey = &spec->pr_keys[i];
2769 if (prkey == NULL)
2770 continue;
2771 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2772 "keylist: prkey=0x%16.16"PRIx64", iniport=%s, tgtport=%s\n",
2773 prkey->key, prkey->registered_initiator_port,
2774 prkey->registered_target_port);
2775 }
2776 }
2777 #endif /* ISTGT_TRACE_DISK */
2778 return 0;
2779 }
2780
2781 static int
istgt_lu_disk_remove_pr_key(ISTGT_LU_DISK * spec,CONN_Ptr conn,const char * initiator_port,const char * target_port,uint64_t key)2782 istgt_lu_disk_remove_pr_key(ISTGT_LU_DISK *spec, CONN_Ptr conn __attribute__((__unused__)), const char *initiator_port, const char *target_port, uint64_t key)
2783 {
2784 ISTGT_LU_PR_KEY *prkey, *prkey1, *prkey2;
2785 int i, j;
2786
2787 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2788 "remove prkey=0x%16.16"PRIx64", iniport=%s, tgtport=%s\n",
2789 key, ((initiator_port != NULL) ? initiator_port : "N/A"),
2790 ((target_port != NULL) ? target_port : "N/A"));
2791
2792 if (spec->npr_keys == 0)
2793 return 0;
2794
2795 /* remove specified prkey from end of array */
2796 for (i = spec->npr_keys - 1; i >= 0; i--) {
2797 prkey = &spec->pr_keys[i];
2798 if (prkey == NULL)
2799 continue;
2800 if (key != 0 && prkey->key != key)
2801 continue;
2802 /* NULL means all initiator/target */
2803 if (initiator_port != NULL
2804 && strcasecmp(prkey->registered_initiator_port,
2805 initiator_port) != 0)
2806 continue;
2807 if (prkey->all_tpg == 0
2808 && target_port != NULL
2809 && strcasecmp(prkey->registered_target_port,
2810 target_port) != 0)
2811 continue;
2812
2813 /* this prkey will remove */
2814 istgt_lu_disk_free_pr_key(prkey);
2815 /* move used array */
2816 for (j = i; j < spec->npr_keys - 1; j++) {
2817 prkey1 = &spec->pr_keys[j];
2818 prkey2 = &spec->pr_keys[j+1];
2819 *prkey1 = *prkey2;
2820 }
2821 /* last array is cleared */
2822 prkey1 = &spec->pr_keys[j];
2823 memset(prkey1, 0, sizeof(*prkey1));
2824 prkey1->registered_initiator_port = NULL;
2825 prkey1->registered_target_port = NULL;
2826 prkey1->initiator_ports = NULL;
2827 /* update counts */
2828 spec->npr_keys--;
2829 }
2830 #ifdef ISTGT_TRACE_DISK
2831 if (g_trace_flag) {
2832 for (i = 0; i < spec->npr_keys; i++) {
2833 prkey = &spec->pr_keys[i];
2834 if (prkey == NULL)
2835 continue;
2836 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2837 "keylist: prkey=0x%16.16"PRIx64", iniport=%s, tgtport=%s\n",
2838 prkey->key, prkey->registered_initiator_port,
2839 prkey->registered_target_port);
2840 }
2841 }
2842 #endif /* ISTGT_TRACE_DISK */
2843 return 0;
2844 }
2845
2846 static int
istgt_lu_parse_transport_id(char ** tid,uint8_t * data,int len)2847 istgt_lu_parse_transport_id(char **tid, uint8_t *data, int len)
2848 {
2849 int fc, pi;
2850 int hlen, plen;
2851
2852 if (tid == NULL)
2853 return -1;
2854 if (data == NULL)
2855 return -1;
2856
2857 fc = BGET8W(&data[0], 7, 2);
2858 pi = BGET8W(&data[0], 3, 4);
2859 if (fc != 0) {
2860 ISTGT_ERRLOG("FORMAT CODE != 0\n");
2861 return -1;
2862 }
2863 if (pi != SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME) {
2864 ISTGT_ERRLOG("PROTOCOL IDENTIFIER != ISCSI\n");
2865 return -1;
2866 }
2867
2868 /* PROTOCOL IDENTIFIER = 0x05 */
2869 hlen = 4;
2870 /* ADDITIONAL LENGTH */
2871 plen = DGET16(&data[2]);
2872 if (plen > len) {
2873 ISTGT_ERRLOG("invalid length %d (expected %d)\n",
2874 plen, len);
2875 return -1;
2876 }
2877 if (plen > MAX_ISCSI_NAME) {
2878 ISTGT_ERRLOG("invalid length %d (expected %d)\n",
2879 plen, MAX_ISCSI_NAME);
2880 return -1;
2881 }
2882
2883 /* ISCSI NAME */
2884 *tid = xmalloc(plen + 1);
2885 memcpy(*tid, data, plen);
2886 (*tid)[plen] = '\0';
2887 strlwr(*tid);
2888
2889 return hlen + plen;
2890 }
2891
2892 static int
istgt_lu_disk_scsi_persistent_reserve_in(ISTGT_LU_DISK * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,int sa,uint8_t * data,int alloc_len)2893 istgt_lu_disk_scsi_persistent_reserve_in(ISTGT_LU_DISK *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd, int sa, uint8_t *data, int alloc_len __attribute__((__unused__)))
2894 {
2895 ISTGT_LU_PR_KEY *prkey;
2896 size_t hlen = 0, len = 0, plen;
2897 uint8_t *sense_data;
2898 size_t *sense_len;
2899 uint8_t *cp;
2900 int total;
2901 int i;
2902
2903 sense_data = lu_cmd->sense_data;
2904 sense_len = &lu_cmd->sense_data_len;
2905 *sense_len = 0;
2906
2907 cp = &data[hlen + len];
2908 total = 0;
2909 switch (sa) {
2910 case 0x00: /* READ KEYS */
2911 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ KEYS\n");
2912
2913 /* PRGENERATION */
2914 DSET32(&data[0], spec->pr_generation);
2915 /* ADDITIONAL LENGTH */
2916 DSET32(&data[4], 0);
2917 hlen = 8;
2918
2919 for (i = 0; i < spec->npr_keys; i++) {
2920 prkey = &spec->pr_keys[i];
2921 /* reservation key N */
2922 cp = &data[hlen + len];
2923 DSET64(&cp[0], prkey->key);
2924 len += 8;
2925 }
2926 total = hlen + len;
2927 /* ADDITIONAL LENGTH */
2928 DSET32(&data[4], total - hlen);
2929 break;
2930
2931 case 0x01: /* READ RESERVATION */
2932 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ RESERVATION\n");
2933
2934 /* PRGENERATION */
2935 DSET32(&data[0], spec->pr_generation);
2936 /* ADDITIONAL LENGTH */
2937 DSET32(&data[4], 0);
2938 hlen = 8;
2939
2940 if (spec->rsv_key != 0) {
2941 /* RESERVATION KEY */
2942 DSET64(&data[8], spec->rsv_key);
2943 /* Obsolete */
2944 DSET32(&data[16], 0);
2945 /* Reserved */
2946 data[20] = 0;
2947 /* SCOPE(7-4) TYPE(3-0) */
2948 BDSET8W(&data[21], spec->rsv_scope, 7, 4);
2949 BDADD8W(&data[21], spec->rsv_type, 3, 4);
2950 /* Obsolete */
2951 DSET16(&data[22], 0);
2952 len = 24 - hlen;
2953 }
2954
2955 total = hlen + len;
2956 /* ADDITIONAL LENGTH */
2957 DSET32(&data[4], total - hlen);
2958 break;
2959
2960 case 0x02: /* REPORT CAPABILITIES */
2961 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT CAPABILITIES\n");
2962
2963 /* LENGTH */
2964 DSET16(&data[0], 0x0008);
2965 /* CRH(4) SIP_C(3) ATP_C(2) PTPL_C(0) */
2966 data[2] = 0;
2967 //BDADD8(&data[2], 1, 4); /* Compatible Reservation Handling */
2968 BDADD8(&data[2], 1, 3); /* Specify Initiator Ports Capable */
2969 BDADD8(&data[2], 1, 2); /* All Target Ports Capable */
2970 //BDADD8(&data[2], 1, 0); /* Persist Through Power Loss Capable */
2971 /* TMV(7) PTPL_A(0) */
2972 data[3] = 0;
2973 //BDADD8(&data[2], 1, 7); /* Type Mask Valid */
2974 //BDADD8(&data[2], 1, 0); /* Persist Through Power Loss Activated */
2975 /* PERSISTENT RESERVATION TYPE MASK */
2976 DSET16(&data[4], 0);
2977 /* Reserved */
2978 DSET16(&data[6], 0);
2979 hlen = 8;
2980
2981 total = hlen + len;
2982 break;
2983
2984 case 0x03: /* READ FULL STATUS */
2985 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ FULL STATUS\n");
2986
2987 /* PRGENERATION */
2988 DSET32(&data[0], spec->pr_generation);
2989 /* ADDITIONAL LENGTH */
2990 DSET32(&data[4], 0);
2991 hlen = 8;
2992
2993 for (i = 0; i < spec->npr_keys; i++) {
2994 prkey = &spec->pr_keys[i];
2995 /* Full status descriptors N */
2996 cp = &data[hlen + len];
2997
2998 /* RESERVATION KEY */
2999 DSET64(&cp[0], prkey->key);
3000 /* Reserved */
3001 DSET64(&cp[8], 0);
3002 /* ALL_TG_PT(1) R_HOLDER(0) */
3003 cp[12] = 0;
3004 if (prkey->all_tpg) {
3005 BDADD8(&cp[12], 1, 1);
3006 }
3007 /* SCOPE(7-4) TYPE(3-0) */
3008 cp[13] = 0;
3009 if (spec->rsv_key != 0) {
3010 if (spec->rsv_key == prkey->key) {
3011 BDADD8(&cp[12], 1, 0);
3012 BDADD8W(&cp[13], spec->rsv_scope & 0x0f, 7, 4);
3013 BDADD8W(&cp[13], spec->rsv_type & 0x0f, 3, 4);
3014 }
3015 }
3016 /* Reserved */
3017 DSET32(&cp[14], 0);
3018 /* RELATIVE TARGET PORT IDENTIFIER */
3019 DSET16(&cp[18], 1 + prkey->pg_idx);
3020 /* ADDITIONAL DESCRIPTOR LENGTH */
3021 DSET32(&cp[20], 0);
3022
3023 /* TRANSPORTID */
3024 plen = snprintf((char *) &cp[24], MAX_INITIATOR_NAME,
3025 "%s",
3026 prkey->registered_initiator_port);
3027
3028 /* ADDITIONAL DESCRIPTOR LENGTH */
3029 DSET32(&cp[20], plen);
3030 len += 24 + plen;
3031 }
3032
3033 total = hlen + len;
3034 /* ADDITIONAL LENGTH */
3035 DSET32(&data[4], total - hlen);
3036 break;
3037
3038 default:
3039 ISTGT_ERRLOG("unsupported service action 0x%x\n", sa);
3040 /* INVALID FIELD IN CDB */
3041 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3042 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3043 return -1;
3044 }
3045
3046 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3047 return total;
3048 }
3049
3050 static int
istgt_lu_disk_scsi_persistent_reserve_out(ISTGT_LU_DISK * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,int sa,int scope,int type,uint8_t * data,int len)3051 istgt_lu_disk_scsi_persistent_reserve_out(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int sa, int scope, int type, uint8_t *data, int len)
3052 {
3053 ISTGT_LU_PR_KEY *prkey;
3054 uint8_t *sense_data;
3055 size_t *sense_len;
3056 char *old_rsv_port = NULL;
3057 char **initiator_ports;
3058 int maxports, nports;
3059 int plen, total;
3060 uint64_t rkey;
3061 uint64_t sarkey;
3062 int spec_i_pt, all_tg_pt, aptpl;
3063 int task_abort;
3064 int idx;
3065 int rc;
3066 int i;
3067
3068 sense_data = lu_cmd->sense_data;
3069 sense_len = &lu_cmd->sense_data_len;
3070 *sense_len = 0;
3071
3072 rkey = DGET64(&data[0]);
3073 sarkey = DGET64(&data[8]);
3074 spec_i_pt = BGET8(&data[20], 3);
3075 all_tg_pt = BGET8(&data[20], 2);
3076 aptpl = BGET8(&data[20], 0);
3077
3078 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3079 "sa=0x%2.2x, key=0x%16.16"PRIx64", sakey=0x%16.16"PRIx64
3080 ", ipt=%d, tgpt=%d, aptpl=%d\n",
3081 sa, rkey, sarkey, spec_i_pt, all_tg_pt, aptpl);
3082 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "port=%s\n",
3083 conn->initiator_port);
3084
3085 switch (sa) {
3086 case 0x00: /* REGISTER */
3087 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REGISTER\n");
3088
3089 if (aptpl != 0) {
3090 /* Activate Persist Through Power Loss */
3091 ISTGT_ERRLOG("unsupport Activate Persist Through Power Loss\n");
3092 /* INVALID FIELD IN PARAMETER LIST */
3093 BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3094 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3095 return -1;
3096 }
3097 /* lost reservations if daemon restart */
3098
3099 prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3100 conn->target_port, 0);
3101 if (prkey == NULL) {
3102 /* unregistered port */
3103 if (rkey != 0) {
3104 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3105 return -1;
3106 }
3107 if (sarkey != 0) {
3108 /* XXX check spec_i_pt */
3109 }
3110 } else {
3111 /* registered port */
3112 if (spec_i_pt) {
3113 /* INVALID FIELD IN CDB */
3114 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3115 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3116 return -1;
3117 }
3118
3119 prkey = istgt_lu_disk_find_pr_key(spec,
3120 conn->initiator_port, conn->target_port, rkey);
3121 if (prkey == NULL) {
3122 /* not found key */
3123 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3124 return -1;
3125 }
3126 /* remove existing keys */
3127 rc = istgt_lu_disk_remove_pr_key(spec, conn,
3128 conn->initiator_port, conn->target_port, 0);
3129 if (rc < 0) {
3130 ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3131 /* INTERNAL TARGET FAILURE */
3132 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3133 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3134 return -1;
3135 }
3136 }
3137
3138 /* unregister? */
3139 if (sarkey == 0) {
3140 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3141 return 0;
3142 }
3143
3144 goto do_register;
3145
3146 case 0x01: /* RESERVE */
3147 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE\n");
3148
3149 prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3150 conn->target_port, 0);
3151 if (prkey == NULL) {
3152 /* unregistered port */
3153 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3154 return -1;
3155 }
3156
3157 prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3158 conn->target_port, rkey);
3159 if (prkey == NULL) {
3160 /* not found key */
3161 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3162 return -1;
3163 }
3164 if (spec->rsv_key == 0) {
3165 /* no reservation */
3166 } else {
3167 if (prkey->key != spec->rsv_key) {
3168 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3169 return -1;
3170 }
3171 if (strcasecmp(spec->rsv_port, conn->initiator_port) != 0) {
3172 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3173 return -1;
3174 }
3175 #if 0
3176 /* registrants can change the prkey */
3177 if (g_trace_flag) {
3178 ISTGT_WARNLOG("LU%d: duplicate reserve\n", spec->lu->num);
3179 }
3180 #endif
3181 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3182 return 0;
3183 }
3184
3185 if (scope != 0x00) { // !LU_SCOPE
3186 /* INVALID FIELD IN CDB */
3187 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3188 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3189 return -1;
3190 }
3191 if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
3192 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
3193 && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
3194 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
3195 && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
3196 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
3197 ISTGT_ERRLOG("unsupported type 0x%x\n", type);
3198 /* INVALID FIELD IN CDB */
3199 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3200 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3201 return -1;
3202 }
3203
3204 /* establish reservation by key */
3205 xfree(spec->rsv_port);
3206 spec->rsv_port = xstrdup(conn->initiator_port);
3207 strlwr(spec->rsv_port);
3208 spec->rsv_key = rkey;
3209 spec->rsv_scope = scope;
3210 spec->rsv_type = type;
3211
3212 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3213 "LU%d: reserved (scope=%d, type=%d) by key=0x%16.16"
3214 PRIx64"\n",
3215 spec->lu->num, scope, type, rkey);
3216 break;
3217
3218 case 0x02: /* RELEASE */
3219 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE\n");
3220
3221 prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3222 conn->target_port, 0);
3223 if (prkey == NULL) {
3224 /* unregistered port */
3225 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3226 return -1;
3227 }
3228
3229 prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3230 conn->target_port, rkey);
3231 if (prkey == NULL) {
3232 /* not found key */
3233 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3234 return -1;
3235 }
3236 if (spec->rsv_key == 0) {
3237 /* no reservation */
3238 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3239 return 0;
3240 }
3241 if (prkey->key != spec->rsv_key) {
3242 /* INVALID RELEASE OF PERSISTENT RESERVATION */
3243 BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04);
3244 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3245 return -1;
3246 }
3247 if (strcasecmp(spec->rsv_port, conn->initiator_port) != 0) {
3248 /* INVALID RELEASE OF PERSISTENT RESERVATION */
3249 BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04);
3250 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3251 return -1;
3252 }
3253
3254 if (scope != 0x00) { // !LU_SCOPE
3255 /* INVALID FIELD IN CDB */
3256 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3257 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3258 return -1;
3259 }
3260 if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
3261 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
3262 && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
3263 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
3264 && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
3265 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
3266 ISTGT_ERRLOG("unsupported type 0x%x\n", type);
3267 /* INVALID FIELD IN CDB */
3268 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3269 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3270 return -1;
3271 }
3272 if (spec->rsv_scope != scope || spec->rsv_type != type) {
3273 /* INVALID RELEASE OF PERSISTENT RESERVATION */
3274 BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04);
3275 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3276 return -1;
3277 }
3278
3279 /* release reservation by key */
3280 xfree(spec->rsv_port);
3281 spec->rsv_port = NULL;
3282 spec->rsv_key = 0;
3283 spec->rsv_scope = 0;
3284 spec->rsv_type = 0;
3285
3286 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3287 "LU%d: released (scope=%d, type=%d) by key=0x%16.16"
3288 PRIx64"\n",
3289 spec->lu->num, scope, type, rkey);
3290 break;
3291
3292 case 0x03: /* CLEAR */
3293 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "CLEAR\n");
3294
3295 prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3296 conn->target_port, 0);
3297 if (prkey == NULL) {
3298 /* unregistered port */
3299 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3300 return -1;
3301 }
3302
3303 /* release reservation */
3304 xfree(spec->rsv_port);
3305 spec->rsv_port = NULL;
3306 spec->rsv_key = 0;
3307 spec->rsv_scope = 0;
3308 spec->rsv_type = 0;
3309
3310 /* remove all registrations */
3311 for (i = 0; i < spec->npr_keys; i++) {
3312 prkey = &spec->pr_keys[i];
3313 istgt_lu_disk_free_pr_key(prkey);
3314 }
3315 spec->npr_keys = 0;
3316 break;
3317
3318 case 0x04: /* PREEMPT */
3319 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PREEMPT\n");
3320
3321 task_abort = 0;
3322 do_preempt:
3323 prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3324 conn->target_port, 0);
3325 if (prkey == NULL) {
3326 /* unregistered port */
3327 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3328 return -1;
3329 }
3330
3331 if (spec->rsv_key == 0) {
3332 /* no reservation */
3333 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no reservation\n");
3334 /* remove registration */
3335 rc = istgt_lu_disk_remove_pr_key(spec, conn,
3336 NULL, NULL, sarkey);
3337 if (rc < 0) {
3338 ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3339 /* INTERNAL TARGET FAILURE */
3340 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3341 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3342 return -1;
3343 }
3344
3345 /* update generation */
3346 spec->pr_generation++;
3347
3348 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3349 break;
3350 }
3351 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "rsv_key=0x%16.16"PRIx64"\n",
3352 spec->rsv_key);
3353
3354 if (spec->rsv_type == ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
3355 || spec->rsv_type == ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
3356 if (sarkey != 0) {
3357 /* remove registration */
3358 rc = istgt_lu_disk_remove_pr_key(spec, conn,
3359 NULL, NULL, sarkey);
3360 if (rc < 0) {
3361 ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3362 /* INTERNAL TARGET FAILURE */
3363 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3364 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3365 return -1;
3366 }
3367
3368 /* update generation */
3369 spec->pr_generation++;
3370
3371 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3372 break;
3373 } else {
3374 /* remove other registrations */
3375 rc = istgt_lu_disk_remove_other_pr_key(spec, conn,
3376 conn->initiator_port,
3377 conn->target_port,
3378 rkey);
3379 if (rc < 0) {
3380 ISTGT_ERRLOG("lu_disk_remove_other_pr_key() failed\n");
3381 /* INTERNAL TARGET FAILURE */
3382 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3383 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3384 return -1;
3385 }
3386
3387 if (scope != 0x00) { // !LU_SCOPE
3388 /* INVALID FIELD IN CDB */
3389 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3390 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3391 return -1;
3392 }
3393 if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
3394 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
3395 && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
3396 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
3397 && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
3398 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
3399 ISTGT_ERRLOG("unsupported type 0x%x\n", type);
3400 /* INVALID FIELD IN CDB */
3401 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3402 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3403 return -1;
3404 }
3405
3406 /* release reservation */
3407 //xfree(spec->rsv_port);
3408 old_rsv_port = spec->rsv_port;
3409 spec->rsv_port = NULL;
3410 spec->rsv_key = 0;
3411 spec->rsv_scope = 0;
3412 spec->rsv_type = 0;
3413 /* establish new reservation */
3414 spec->rsv_port = xstrdup(conn->initiator_port);
3415 strlwr(spec->rsv_port);
3416 spec->rsv_key = rkey;
3417 spec->rsv_scope = scope;
3418 spec->rsv_type = type;
3419
3420 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3421 "LU%d: reserved (scope=%d, type=%d)"
3422 "by key=0x%16.16"PRIx64"\n",
3423 spec->lu->num, scope, type, rkey);
3424
3425 /* update generation */
3426 spec->pr_generation++;
3427
3428 /* XXX TODO fix */
3429 if (task_abort) {
3430 /* abort all tasks for preempted I_T nexus */
3431 if (old_rsv_port != NULL) {
3432 rc = istgt_lu_disk_queue_abort_ITL(spec, old_rsv_port);
3433 xfree(old_rsv_port);
3434 old_rsv_port = NULL;
3435 if (rc < 0) {
3436 /* INTERNAL TARGET FAILURE */
3437 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3438 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3439 return -1;
3440 }
3441 }
3442 }
3443 if (old_rsv_port != NULL) {
3444 xfree(old_rsv_port);
3445 old_rsv_port = NULL;
3446 }
3447
3448 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3449 break;
3450 }
3451 }
3452
3453 prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3454 conn->target_port, rkey);
3455
3456 if (prkey == NULL) {
3457 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3458 "prkey == NULL\n");
3459 } else {
3460 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3461 "prkey key=%16.16"PRIx64"\n",
3462 prkey->key);
3463 }
3464
3465 if (prkey == NULL
3466 || sarkey != spec->rsv_key) {
3467 if (sarkey != 0) {
3468 /* remove registration */
3469 rc = istgt_lu_disk_remove_pr_key(spec, conn,
3470 NULL, NULL, sarkey);
3471 if (rc < 0) {
3472 ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3473 /* INTERNAL TARGET FAILURE */
3474 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3475 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3476 return -1;
3477 }
3478 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3479 break;
3480 } else {
3481 /* INVALID FIELD IN PARAMETER LIST */
3482 BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3483 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3484 return -1;
3485 }
3486 }
3487
3488 /* remove registration */
3489 rc = istgt_lu_disk_remove_pr_key(spec, conn,
3490 NULL, NULL, sarkey);
3491 if (rc < 0) {
3492 ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3493 /* INTERNAL TARGET FAILURE */
3494 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3495 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3496 return -1;
3497 }
3498
3499 if (scope != 0x00) { // !LU_SCOPE
3500 /* INVALID FIELD IN CDB */
3501 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3502 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3503 return -1;
3504 }
3505 if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
3506 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
3507 && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
3508 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
3509 && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
3510 && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
3511 ISTGT_ERRLOG("unsupported type 0x%x\n", type);
3512 /* INVALID FIELD IN CDB */
3513 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3514 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3515 return -1;
3516 }
3517
3518 /* release reservation */
3519 //xfree(spec->rsv_port);
3520 old_rsv_port = spec->rsv_port;
3521 spec->rsv_port = NULL;
3522 spec->rsv_key = 0;
3523 spec->rsv_scope = 0;
3524 spec->rsv_type = 0;
3525 /* establish new reservation */
3526 spec->rsv_port = xstrdup(conn->initiator_port);
3527 strlwr(spec->rsv_port);
3528 spec->rsv_key = rkey;
3529 spec->rsv_scope = scope;
3530 spec->rsv_type = type;
3531
3532 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3533 "LU%d: reserved (scope=%d, type=%d) by key=0x%16.16"
3534 PRIx64"\n",
3535 spec->lu->num, scope, type, rkey);
3536
3537 /* update generation */
3538 spec->pr_generation++;
3539
3540 /* XXX TODO fix */
3541 if (task_abort) {
3542 /* abort all tasks for preempted I_T nexus */
3543 if (old_rsv_port != NULL) {
3544 rc = istgt_lu_disk_queue_abort_ITL(spec, old_rsv_port);
3545 xfree(old_rsv_port);
3546 old_rsv_port = NULL;
3547 if (rc < 0) {
3548 /* INTERNAL TARGET FAILURE */
3549 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3550 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3551 return -1;
3552 }
3553 }
3554 }
3555 if (old_rsv_port != NULL) {
3556 xfree(old_rsv_port);
3557 old_rsv_port = NULL;
3558 }
3559
3560 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3561 break;
3562
3563 case 0x05: /* PREEMPT AND ABORT */
3564 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PREEMPT AND ABORT\n");
3565
3566 task_abort = 1;
3567 goto do_preempt;
3568
3569 case 0x06: /* REGISTER AND IGNORE EXISTING KEY */
3570 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REGISTER AND IGNORE EXISTING KEY\n");
3571
3572 if (aptpl != 0) {
3573 /* Activate Persist Through Power Loss */
3574 ISTGT_ERRLOG("unsupport Activate Persist Through Power Loss\n");
3575 /* INVALID FIELD IN PARAMETER LIST */
3576 BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3577 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3578 return -1;
3579 }
3580 /* lost reservations if daemon restart */
3581
3582 prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3583 conn->target_port, 0);
3584 if (prkey == NULL) {
3585 /* unregistered port */
3586 if (sarkey != 0) {
3587 if (spec_i_pt) {
3588 /* INVALID FIELD IN CDB */
3589 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3590 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3591 return -1;
3592 }
3593 }
3594 /* unregister? */
3595 if (sarkey == 0) {
3596 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3597 return 0;
3598 }
3599 } else {
3600 /* registered port */
3601 if (spec_i_pt) {
3602 /* INVALID FIELD IN CDB */
3603 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3604 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3605 return -1;
3606 }
3607 }
3608
3609 /* remove existing keys */
3610 rc = istgt_lu_disk_remove_pr_key(spec, conn,
3611 conn->initiator_port,
3612 conn->target_port, 0);
3613 if (rc < 0) {
3614 ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3615 /* INTERNAL TARGET FAILURE */
3616 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3617 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3618 return -1;
3619 }
3620
3621 /* unregister? */
3622 if (sarkey == 0) {
3623 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3624 return 0;
3625 }
3626
3627 do_register:
3628 /* specified port? */
3629 nports = 0;
3630 initiator_ports = NULL;
3631 if (spec_i_pt) {
3632 if (len < 28) {
3633 /* INVALID FIELD IN PARAMETER LIST */
3634 BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3635 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3636 return -1;
3637 }
3638
3639 /* TRANSPORTID PARAMETER DATA LENGTH */
3640 plen = DGET32(&data[24]);
3641 if (28 + plen > len) {
3642 ISTGT_ERRLOG("invalid length %d (expect %d)\n",
3643 len, 28 + plen);
3644 /* INVALID FIELD IN PARAMETER LIST */
3645 BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3646 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3647 return -1;
3648 }
3649
3650 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3651 "TransportID parameter data length %d\n",
3652 plen);
3653 if (plen != 0) {
3654 maxports = MAX_LU_RESERVE_IPT;
3655 initiator_ports = xmalloc(sizeof (char *) * maxports);
3656 memset(initiator_ports, 0, sizeof (char *) * maxports);
3657 nports = 0;
3658 total = 0;
3659 while (total < plen) {
3660 if (nports >= MAX_LU_RESERVE_IPT) {
3661 ISTGT_ERRLOG("maximum transport IDs\n");
3662 /* INSUFFICIENT REGISTRATION RESOURCES */
3663 BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04);
3664 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3665 return -1;
3666 }
3667 rc = istgt_lu_parse_transport_id
3668 (&initiator_ports[nports],
3669 &data[24] + total, plen - total);
3670 if (rc < 0) {
3671 /* INVALID FIELD IN PARAMETER LIST */
3672 BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3673 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3674 return -1;
3675 }
3676 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "got TransportID %s\n",
3677 initiator_ports[nports]);
3678 total += rc;
3679 nports++;
3680 }
3681 }
3682 /* check all port unregistered? */
3683 for (i = 0; i < nports; i++) {
3684 prkey = istgt_lu_disk_find_pr_key(spec,
3685 initiator_ports[i], NULL, 0);
3686 if (prkey != NULL) {
3687 /* registered port */
3688 /* INVALID FIELD IN CDB */
3689 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3690 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3691 return -1;
3692 }
3693 }
3694 /* OK, all port unregistered */
3695 idx = spec->npr_keys;
3696 if (idx + nports >= MAX_LU_RESERVE) {
3697 /* INSUFFICIENT REGISTRATION RESOURCES */
3698 BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04);
3699 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3700 return -1;
3701 }
3702 /* register each I_T nexus */
3703 for (i = 0; i < nports; i++) {
3704 prkey = &spec->pr_keys[idx + i];
3705
3706 /* register new key */
3707 prkey->key = sarkey;
3708
3709 /* command received port */
3710 prkey->registered_initiator_port
3711 = xstrdup(conn->initiator_port);
3712 strlwr(prkey->registered_initiator_port);
3713 prkey->registered_target_port
3714 = xstrdup(conn->target_port);
3715 strlwr(prkey->registered_target_port);
3716 prkey->pg_idx = conn->portal.idx;
3717 prkey->pg_tag = conn->portal.tag;
3718
3719 /* specified ports */
3720 prkey->ninitiator_ports = 0;
3721 prkey->initiator_ports = NULL;
3722 prkey->all_tpg = (all_tg_pt) ? 1 : 0;
3723 }
3724 spec->npr_keys = idx + nports;
3725 }
3726
3727 idx = spec->npr_keys;
3728 if (idx >= MAX_LU_RESERVE) {
3729 /* INSUFFICIENT REGISTRATION RESOURCES */
3730 BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04);
3731 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3732 return -1;
3733 }
3734 prkey = &spec->pr_keys[idx];
3735
3736 /* register new key */
3737 prkey->key = sarkey;
3738 /* replace existing reservation */
3739 if (rkey != 0 && spec->rsv_key == rkey)
3740 spec->rsv_key = sarkey;
3741
3742 /* command received port */
3743 prkey->registered_initiator_port = xstrdup(conn->initiator_port);
3744 strlwr(prkey->registered_initiator_port);
3745 prkey->registered_target_port = xstrdup(conn->target_port);
3746 strlwr(prkey->registered_target_port);
3747 prkey->pg_idx = conn->portal.idx;
3748 prkey->pg_tag = conn->portal.tag;
3749
3750 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3751 "Register Key:0x%16.16"PRIx64", InitiatorPort: %s, TargetPort: %s\n",
3752 prkey->key, prkey->registered_initiator_port,
3753 prkey->registered_target_port);
3754
3755 /* specified ports */
3756 prkey->ninitiator_ports = nports;
3757 prkey->initiator_ports = initiator_ports;
3758 prkey->all_tpg = (all_tg_pt) ? 1 : 0;
3759
3760 /* count up keys */
3761 idx++;
3762 spec->npr_keys = idx;
3763
3764 /* update generation */
3765 spec->pr_generation++;
3766 break;
3767
3768 case 0x07: /* REGISTER AND MOVE */
3769 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REGISTER AND MOVE\n");
3770 /* INVALID FIELD IN CDB */
3771 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3772 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3773 return -1;
3774
3775 default:
3776 ISTGT_ERRLOG("unsupported service action 0x%x\n", sa);
3777 /* INVALID FIELD IN CDB */
3778 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3779 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3780 return -1;
3781 }
3782
3783 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3784 return 0;
3785 }
3786
3787 static int
istgt_lu_disk_check_pr(ISTGT_LU_DISK * spec,CONN_Ptr conn,int pr_allow)3788 istgt_lu_disk_check_pr(ISTGT_LU_DISK *spec, CONN_Ptr conn, int pr_allow)
3789 {
3790 ISTGT_LU_PR_KEY *prkey;
3791
3792 #ifdef ISTGT_TRACE_DISK
3793 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3794 "RSV_KEY=0x%16.16"PRIx64", RSV_TYPE=0x%x, PR_ALLOW=0x%x\n",
3795 spec->rsv_key, spec->rsv_type, pr_allow);
3796 #endif /* ISTGT_TRACE_DISK */
3797
3798 prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3799 conn->target_port, 0);
3800 if (prkey != NULL) {
3801 #ifdef ISTGT_TRACE_DISK
3802 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3803 "PRKEY(0x%16.16"PRIx64") found for %s\n",
3804 prkey->key, conn->initiator_port);
3805 #endif /* ISTGT_TRACE_DISK */
3806
3807 if (spec->rsv_key == prkey->key) {
3808 /* reservation holder */
3809 return 0;
3810 }
3811
3812 switch (spec->rsv_type) {
3813 case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS:
3814 if (pr_allow & PR_ALLOW_ALLRR)
3815 return 0;
3816 return -1;
3817 case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS:
3818 if (pr_allow & PR_ALLOW_ALLRR)
3819 return 0;
3820 return -1;
3821 case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY:
3822 if (pr_allow & PR_ALLOW_ALLRR)
3823 return 0;
3824 return -1;
3825 case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY:
3826 if (pr_allow & PR_ALLOW_ALLRR)
3827 return 0;
3828 return -1;
3829 }
3830 } else {
3831 #ifdef ISTGT_TRACE_DISK
3832 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3833 "PRKEY not found for %s\n",
3834 conn->initiator_port);
3835 #endif /* ISTGT_TRACE_DISK */
3836
3837 switch (spec->rsv_type) {
3838 case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS:
3839 if (pr_allow & PR_ALLOW_WERR)
3840 return 0;
3841 return -1;
3842 case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY:
3843 if (pr_allow & PR_ALLOW_WERR)
3844 return 0;
3845 return -1;
3846 case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS:
3847 if (pr_allow & PR_ALLOW_EARR)
3848 return 0;
3849 return -1;
3850 case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY:
3851 if (pr_allow & PR_ALLOW_EARR)
3852 return 0;
3853 return -1;
3854 }
3855 }
3856
3857 #ifdef ISTGT_TRACE_DISK
3858 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "non registrans type\n");
3859 #endif /* ISTGT_TRACE_DISK */
3860 /* any I_T nexus */
3861 switch (spec->rsv_type) {
3862 case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE:
3863 if (pr_allow & PR_ALLOW_WE)
3864 return 0;
3865 return -1;
3866 case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS:
3867 if (pr_allow & PR_ALLOW_EA)
3868 return 0;
3869 return -1;
3870 }
3871
3872 /* NG */
3873 return -1;
3874 }
3875
3876 static int
istgt_lu_disk_scsi_release(ISTGT_LU_DISK * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)3877 istgt_lu_disk_scsi_release(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
3878 {
3879 ISTGT_LU_CMD lu_cmd2;
3880 uint8_t *sense_data;
3881 size_t *sense_len;
3882 uint64_t LUI;
3883 uint64_t rkey;
3884 uint8_t cdb[10];
3885 uint8_t PRO_data[24];
3886 int parameter_len;
3887 int rc;
3888
3889 sense_data = lu_cmd->sense_data;
3890 sense_len = &lu_cmd->sense_data_len;
3891 *sense_len = 0;
3892
3893 memset(&lu_cmd2, 0, sizeof lu_cmd2);
3894 lu_cmd2.sense_data = lu_cmd->sense_data;
3895 lu_cmd2.sense_data_len = lu_cmd->sense_data_len;
3896 memset(&cdb, 0, sizeof cdb);
3897 parameter_len = sizeof PRO_data;
3898
3899 LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU);
3900 rkey = istgt_get_rkey(conn->initiator_name, LUI);
3901
3902 /* issue release action of PERSISTENT RESERVE OUT */
3903 cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
3904 BDSET8W(&cdb[1], 0x02, 4, 5); /* RELEASE */
3905 BDSET8W(&cdb[2], 0x00, 7, 4); /* LU_SCOPE */
3906 BDADD8W(&cdb[2], 0x03, 3, 4); /* ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS */
3907 cdb[3] = 0;
3908 cdb[4] = 0;
3909 DSET32(&cdb[5], parameter_len);
3910 cdb[9] = 0;
3911 lu_cmd2.cdb = &cdb[0];
3912
3913 memset(&PRO_data, 0, sizeof PRO_data);
3914 DSET64(&PRO_data[0], rkey); // RESERVATION KEY
3915 DSET64(&PRO_data[8], 0);
3916
3917 rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
3918 0x02, 0x00, 0x03,
3919 PRO_data, parameter_len);
3920 if (rc < 0) {
3921 lu_cmd->status = lu_cmd2.status;
3922 if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
3923 return -1;
3924 }
3925 /* INTERNAL TARGET FAILURE */
3926 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3927 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3928 return -1;
3929 }
3930
3931 /* issue unregister action of PERSISTENT RESERVE OUT */
3932 cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
3933 BDSET8W(&cdb[1], 0x06, 4, 5); /* REGISTER AND IGNORE EXISTING KEY */
3934 cdb[2] = 0;
3935 cdb[3] = 0;
3936 cdb[4] = 0;
3937 DSET32(&cdb[5], parameter_len);
3938 cdb[9] = 0;
3939 lu_cmd2.cdb = &cdb[0];
3940
3941 memset(&PRO_data, 0, sizeof PRO_data);
3942 DSET64(&PRO_data[0], rkey); // RESERVATION KEY
3943 DSET64(&PRO_data[8], 0); // unregister
3944
3945 rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
3946 0x06, 0, 0,
3947 PRO_data, parameter_len);
3948 if (rc < 0) {
3949 lu_cmd->status = lu_cmd2.status;
3950 if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
3951 return -1;
3952 }
3953 /* INTERNAL TARGET FAILURE */
3954 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3955 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3956 return -1;
3957 }
3958
3959 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3960 return 0;
3961 }
3962
3963 static int
istgt_lu_disk_scsi_reserve(ISTGT_LU_DISK * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)3964 istgt_lu_disk_scsi_reserve(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
3965 {
3966 ISTGT_LU_CMD lu_cmd2;
3967 uint8_t *sense_data;
3968 size_t *sense_len;
3969 uint64_t LUI;
3970 uint64_t rkey;
3971 uint8_t cdb[10];
3972 uint8_t PRO_data[24];
3973 int parameter_len;
3974 int rc;
3975
3976 sense_data = lu_cmd->sense_data;
3977 sense_len = &lu_cmd->sense_data_len;
3978 *sense_len = 0;
3979
3980 memset(&lu_cmd2, 0, sizeof lu_cmd2);
3981 lu_cmd2.sense_data = lu_cmd->sense_data;
3982 lu_cmd2.sense_data_len = lu_cmd->sense_data_len;
3983 memset(&cdb, 0, sizeof cdb);
3984 parameter_len = sizeof PRO_data;
3985
3986 LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU);
3987 rkey = istgt_get_rkey(conn->initiator_name, LUI);
3988
3989 /* issue register action of PERSISTENT RESERVE OUT */
3990 cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
3991 BDSET8W(&cdb[1], 0x06, 4, 5); /* REGISTER AND IGNORE EXISTING KEY */
3992 cdb[2] = 0;
3993 cdb[3] = 0;
3994 cdb[4] = 0;
3995 DSET32(&cdb[5], parameter_len);
3996 cdb[9] = 0;
3997 lu_cmd2.cdb = &cdb[0];
3998
3999 memset(&PRO_data, 0, sizeof PRO_data);
4000 DSET64(&PRO_data[0], 0);
4001 DSET64(&PRO_data[8], rkey); // SERVICE ACTION RESERVATION KEY
4002
4003 rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
4004 0x06, 0, 0,
4005 PRO_data, parameter_len);
4006 if (rc < 0) {
4007 lu_cmd->status = lu_cmd2.status;
4008 if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
4009 return -1;
4010 }
4011 /* INTERNAL TARGET FAILURE */
4012 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
4013 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4014 return -1;
4015 }
4016
4017 /* issue reserve action of PERSISTENT RESERVE OUT */
4018 cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
4019 BDSET8W(&cdb[1], 0x01, 4, 5); /* RESERVE */
4020 BDSET8W(&cdb[2], 0x00, 7, 4); /* LU_SCOPE */
4021 BDADD8W(&cdb[2], 0x03, 3, 4); /* ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS */
4022 cdb[3] = 0;
4023 cdb[4] = 0;
4024 DSET32(&cdb[5], parameter_len);
4025 cdb[9] = 0;
4026 lu_cmd2.cdb = &cdb[0];
4027
4028 memset(&PRO_data, 0, sizeof PRO_data);
4029 DSET64(&PRO_data[0], rkey); // RESERVATION KEY
4030 DSET64(&PRO_data[8], 0);
4031
4032 rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
4033 0x01, 0x00, 0x03,
4034 PRO_data, parameter_len);
4035 if (rc < 0) {
4036 lu_cmd->status = lu_cmd2.status;
4037 if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
4038 return -1;
4039 }
4040 /* INTERNAL TARGET FAILURE */
4041 BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
4042 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4043 return -1;
4044 }
4045
4046 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
4047 return 0;
4048 }
4049
4050 static int
istgt_lu_disk_lbread(ISTGT_LU_DISK * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lba,uint32_t len)4051 istgt_lu_disk_lbread(ISTGT_LU_DISK *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
4052 {
4053 uint8_t *data;
4054 uint64_t maxlba;
4055 uint64_t llen;
4056 uint64_t blen;
4057 uint64_t offset;
4058 uint64_t nbytes;
4059 int64_t rc;
4060
4061 if (len == 0) {
4062 lu_cmd->data = NULL;
4063 lu_cmd->data_len = 0;
4064 return 0;
4065 }
4066
4067 maxlba = spec->blockcnt;
4068 llen = (uint64_t) len;
4069 blen = spec->blocklen;
4070 offset = lba * blen;
4071 nbytes = llen * blen;
4072
4073 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4074 "Read: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
4075 maxlba, lba, len);
4076
4077 if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
4078 ISTGT_ERRLOG("end of media\n");
4079 return -1;
4080 }
4081
4082 if (nbytes > lu_cmd->iobufsize) {
4083 ISTGT_ERRLOG("nbytes(%zu) > iobufsize(%zu)\n",
4084 (size_t) nbytes, lu_cmd->iobufsize);
4085 return -1;
4086 }
4087 data = lu_cmd->iobuf;
4088
4089 rc = spec->seek(spec, offset);
4090 if (rc < 0) {
4091 ISTGT_ERRLOG("lu_disk_seek() failed\n");
4092 return -1;
4093 }
4094
4095 rc = spec->read(spec, data, nbytes);
4096 if (rc < 0) {
4097 ISTGT_ERRLOG("lu_disk_read() failed\n");
4098 return -1;
4099 }
4100 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Read %"PRId64"/%"PRIu64" bytes\n",
4101 rc, nbytes);
4102
4103 lu_cmd->data = data;
4104 lu_cmd->data_len = rc;
4105
4106 return 0;
4107 }
4108
4109 static int
istgt_lu_disk_lbwrite(ISTGT_LU_DISK * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lba,uint32_t len)4110 istgt_lu_disk_lbwrite(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
4111 {
4112 uint8_t *data;
4113 uint64_t maxlba;
4114 uint64_t llen;
4115 uint64_t blen;
4116 uint64_t offset;
4117 uint64_t nbytes;
4118 int64_t rc;
4119
4120 if (len == 0) {
4121 lu_cmd->data_len = 0;
4122 return 0;
4123 }
4124
4125 maxlba = spec->blockcnt;
4126 llen = (uint64_t) len;
4127 blen = spec->blocklen;
4128 offset = lba * blen;
4129 nbytes = llen * blen;
4130
4131 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4132 "Write: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
4133 maxlba, lba, len);
4134
4135 if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
4136 ISTGT_ERRLOG("end of media\n");
4137 return -1;
4138 }
4139
4140 if (nbytes > lu_cmd->iobufsize) {
4141 ISTGT_ERRLOG("nbytes(%zu) > iobufsize(%zu)\n",
4142 (size_t) nbytes, lu_cmd->iobufsize);
4143 return -1;
4144 }
4145 data = lu_cmd->iobuf;
4146
4147 rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
4148 lu_cmd->iobufsize, nbytes);
4149 if (rc < 0) {
4150 ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
4151 return -1;
4152 }
4153
4154 if (spec->lu->readonly) {
4155 ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
4156 return -1;
4157 }
4158
4159 spec->req_write_cache = 0;
4160 rc = spec->seek(spec, offset);
4161 if (rc < 0) {
4162 ISTGT_ERRLOG("lu_disk_seek() failed\n");
4163 return -1;
4164 }
4165
4166 rc = spec->write(spec, data, nbytes);
4167 if (rc < 0 || (uint64_t) rc != nbytes) {
4168 ISTGT_ERRLOG("lu_disk_write() failed\n");
4169 return -1;
4170 }
4171 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
4172 rc, nbytes);
4173
4174 lu_cmd->data_len = rc;
4175
4176 return 0;
4177 }
4178
4179 static int
istgt_lu_disk_lbwrite_same(ISTGT_LU_DISK * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lba,uint32_t len)4180 istgt_lu_disk_lbwrite_same(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
4181 {
4182 uint8_t *data;
4183 uint64_t maxlba;
4184 uint64_t llen;
4185 uint64_t blen;
4186 uint64_t offset;
4187 uint64_t nbytes;
4188 uint64_t nblocks;
4189 uint64_t wblocks;
4190 int64_t rc;
4191
4192 maxlba = spec->blockcnt;
4193 llen = (uint64_t) len;
4194 if (llen == 0) {
4195 if (lba >= maxlba) {
4196 ISTGT_ERRLOG("end of media\n");
4197 return -1;
4198 }
4199 llen = maxlba - lba;
4200 }
4201 blen = spec->blocklen;
4202 offset = lba * blen;
4203 nbytes = 1 * blen;
4204
4205 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4206 "Write Same: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
4207 maxlba, lba, len);
4208
4209 if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
4210 ISTGT_ERRLOG("end of media\n");
4211 return -1;
4212 }
4213
4214 if (nbytes > lu_cmd->iobufsize) {
4215 ISTGT_ERRLOG("nbytes(%zu) > iobufsize(%zu)\n",
4216 (size_t) nbytes, lu_cmd->iobufsize);
4217 return -1;
4218 }
4219 data = lu_cmd->iobuf;
4220
4221 rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
4222 lu_cmd->iobufsize, nbytes);
4223 if (rc < 0) {
4224 ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
4225 return -1;
4226 }
4227
4228 if (spec->lu->readonly) {
4229 ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
4230 return -1;
4231 }
4232
4233 if (conn->workbuf == NULL) {
4234 conn->worksize = ISTGT_LU_WORK_BLOCK_SIZE;
4235 conn->workbuf = xmalloc(conn->worksize);
4236 }
4237 wblocks = (int64_t)conn->worksize / nbytes;
4238 if (wblocks == 0) {
4239 ISTGT_ERRLOG("work buffer is too small\n");
4240 return -1;
4241 }
4242
4243 spec->req_write_cache = 0;
4244 rc = spec->seek(spec, offset);
4245 if (rc < 0) {
4246 ISTGT_ERRLOG("lu_disk_seek() failed\n");
4247 return -1;
4248 }
4249
4250 #if 0
4251 nblocks = 0;
4252 while (nblocks < llen) {
4253 rc = spec->write(spec, data, nbytes);
4254 if (rc < 0 || rc != nbytes) {
4255 ISTGT_ERRLOG("lu_disk_write() failed\n");
4256 return -1;
4257 }
4258 nblocks++;
4259 }
4260 #else
4261 nblocks = 0;
4262 while (nblocks < wblocks) {
4263 memcpy(conn->workbuf + (nblocks * nbytes), data, nbytes);
4264 nblocks++;
4265 }
4266
4267 nblocks = 0;
4268 while (nblocks < llen) {
4269 uint64_t reqblocks = DMIN64(wblocks, (llen - nblocks));
4270 rc = spec->write(spec, conn->workbuf, (reqblocks * nbytes));
4271 if (rc < 0 || (uint64_t) rc != (reqblocks * nbytes)) {
4272 ISTGT_ERRLOG("lu_disk_write() failed\n");
4273 return -1;
4274 }
4275 nblocks += reqblocks;
4276 }
4277 #endif
4278 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
4279 (nblocks * nbytes), (llen * nbytes));
4280
4281 lu_cmd->data_len = nbytes;
4282
4283 return 0;
4284 }
4285
4286 static int
istgt_lu_disk_lbwrite_ats(ISTGT_LU_DISK * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lba,uint32_t len)4287 istgt_lu_disk_lbwrite_ats(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
4288 {
4289 uint8_t *data;
4290 uint64_t maxlba;
4291 uint64_t llen;
4292 uint64_t blen;
4293 uint64_t offset;
4294 uint64_t nbytes;
4295 int64_t rc;
4296 uint8_t *sense_data;
4297 size_t *sense_len;
4298
4299 if (len == 0) {
4300 lu_cmd->data_len = 0;
4301 return 0;
4302 }
4303
4304 sense_data = lu_cmd->sense_data;
4305 sense_len = &lu_cmd->sense_data_len;
4306 *sense_len = 0;
4307
4308 maxlba = spec->blockcnt;
4309 llen = (uint64_t) len;
4310 blen = spec->blocklen;
4311 offset = lba * blen;
4312 nbytes = llen * blen;
4313
4314 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4315 "Write ATS: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
4316 maxlba, lba, len);
4317
4318 if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
4319 ISTGT_ERRLOG("end of media\n");
4320 return -1;
4321 }
4322
4323 if (nbytes > lu_cmd->iobufsize) {
4324 ISTGT_ERRLOG("nbytes(%zu) > iobufsize(%zu)\n",
4325 (size_t) nbytes, lu_cmd->iobufsize);
4326 return -1;
4327 }
4328 data = lu_cmd->iobuf;
4329
4330 rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
4331 lu_cmd->iobufsize, nbytes * 2);
4332 if (rc < 0) {
4333 ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
4334 return -1;
4335 }
4336
4337 if (spec->lu->readonly) {
4338 ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
4339 return -1;
4340 }
4341
4342 if (spec->watsbuf == NULL) {
4343 spec->watssize = ISTGT_LU_WORK_ATS_BLOCK_SIZE;
4344 spec->watsbuf = xmalloc(spec->watssize);
4345 }
4346 if (nbytes > (uint64_t) spec->watssize) {
4347 ISTGT_ERRLOG("nbytes(%zu) > watssize(%zu)\n",
4348 (size_t) nbytes, (size_t) spec->watssize);
4349 return -1;
4350 }
4351
4352 spec->req_write_cache = 0;
4353 /* start atomic test and set */
4354 MTX_LOCK(&spec->ats_mutex);
4355
4356 rc = spec->seek(spec, offset);
4357 if (rc < 0) {
4358 MTX_UNLOCK(&spec->ats_mutex);
4359 ISTGT_ERRLOG("lu_disk_seek() failed\n");
4360 return -1;
4361 }
4362
4363 rc = spec->read(spec, spec->watsbuf, nbytes);
4364 if (rc < 0 || (uint64_t) rc != nbytes) {
4365 MTX_UNLOCK(&spec->ats_mutex);
4366 ISTGT_ERRLOG("lu_disk_read() failed\n");
4367 return -1;
4368 }
4369
4370 #if 0
4371 ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS VERIFY", data, nbytes);
4372 ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS WRITE", data + nbytes, nbytes);
4373 ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS DATA", spec->watsbuf, nbytes);
4374 #endif
4375 if (memcmp(spec->watsbuf, data, nbytes) != 0) {
4376 MTX_UNLOCK(&spec->ats_mutex);
4377 //ISTGT_ERRLOG("compare failed\n");
4378 /* MISCOMPARE DURING VERIFY OPERATION */
4379 BUILD_SENSE(MISCOMPARE, 0x1d, 0x00);
4380 return -1;
4381 }
4382
4383 rc = spec->seek(spec, offset);
4384 if (rc < 0) {
4385 MTX_UNLOCK(&spec->ats_mutex);
4386 ISTGT_ERRLOG("lu_disk_seek() failed\n");
4387 return -1;
4388 }
4389 rc = spec->write(spec, data + nbytes, nbytes);
4390 if (rc < 0 || (uint64_t) rc != nbytes) {
4391 MTX_UNLOCK(&spec->ats_mutex);
4392 ISTGT_ERRLOG("lu_disk_write() failed\n");
4393 return -1;
4394 }
4395 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
4396 rc, nbytes);
4397
4398 MTX_UNLOCK(&spec->ats_mutex);
4399 /* end atomic test and set */
4400
4401 lu_cmd->data_len = nbytes * 2;
4402
4403 return 0;
4404 }
4405
4406 static int
istgt_lu_disk_lbsync(ISTGT_LU_DISK * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lba,uint32_t len)4407 istgt_lu_disk_lbsync(ISTGT_LU_DISK *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd __attribute__((__unused__)), uint64_t lba, uint32_t len)
4408 {
4409 uint64_t maxlba;
4410 uint64_t llen;
4411 uint64_t blen;
4412 uint64_t offset;
4413 uint64_t nbytes;
4414 int64_t rc;
4415
4416 maxlba = spec->blockcnt;
4417 if (len == 0 && lba < maxlba) {
4418 llen = maxlba - lba;
4419 } else {
4420 llen = (uint64_t) len;
4421 }
4422 blen = spec->blocklen;
4423 offset = lba * blen;
4424 nbytes = llen * blen;
4425
4426 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4427 "Sync: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
4428 maxlba, lba, len);
4429
4430 if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
4431 ISTGT_ERRLOG("end of media\n");
4432 return -1;
4433 }
4434
4435 rc = spec->sync(spec, offset, nbytes);
4436 if (rc < 0) {
4437 ISTGT_ERRLOG("lu_disk_sync() failed\n");
4438 return -1;
4439 }
4440
4441 return 0;
4442 }
4443
4444 int
istgt_lu_scsi_build_sense_data(uint8_t * data,int sk,int asc,int ascq)4445 istgt_lu_scsi_build_sense_data(uint8_t *data, int sk, int asc, int ascq)
4446 {
4447 uint8_t *cp;
4448 int resp_code;
4449 int hlen = 0, len = 0, plen;
4450 int total;
4451
4452 resp_code = 0x70; /* Current + Fixed format */
4453
4454 /* SenseLength */
4455 DSET16(&data[0], 0);
4456 hlen = 2;
4457
4458 /* Sense Data */
4459 cp = &data[hlen + len];
4460
4461 /* VALID(7) RESPONSE CODE(6-0) */
4462 BDSET8(&cp[0], 1, 7);
4463 BDADD8W(&cp[0], resp_code, 6, 7);
4464 /* Obsolete */
4465 cp[1] = 0;
4466 /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
4467 BDSET8W(&cp[2], sk, 3, 4);
4468 /* INFORMATION */
4469 memset(&cp[3], 0, 4);
4470 /* ADDITIONAL SENSE LENGTH */
4471 cp[7] = 0;
4472 len = 8;
4473
4474 /* COMMAND-SPECIFIC INFORMATION */
4475 memset(&cp[8], 0, 4);
4476 /* ADDITIONAL SENSE CODE */
4477 cp[12] = asc;
4478 /* ADDITIONAL SENSE CODE QUALIFIER */
4479 cp[13] = ascq;
4480 /* FIELD REPLACEABLE UNIT CODE */
4481 cp[14] = 0;
4482 /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
4483 cp[15] = 0;
4484 cp[16] = 0;
4485 cp[17] = 0;
4486 /* Additional sense bytes */
4487 //data[18] = 0;
4488 plen = 18 - len;
4489
4490 /* ADDITIONAL SENSE LENGTH */
4491 cp[7] = plen;
4492
4493 total = hlen + len + plen;
4494
4495 /* SenseLength */
4496 DSET16(&data[0], total - 2);
4497
4498 return total;
4499 }
4500
4501 static int
istgt_lu_disk_build_sense_data(ISTGT_LU_DISK * spec,uint8_t * data,int sk,int asc,int ascq)4502 istgt_lu_disk_build_sense_data(ISTGT_LU_DISK *spec __attribute__((__unused__)), uint8_t *data, int sk, int asc, int ascq)
4503 {
4504 int rc;
4505
4506 rc = istgt_lu_scsi_build_sense_data(data, sk, asc, ascq);
4507 if (rc < 0) {
4508 return -1;
4509 }
4510 return rc;
4511 }
4512
4513 int
istgt_lu_scsi_build_sense_data2(uint8_t * data,int sk,int asc,int ascq)4514 istgt_lu_scsi_build_sense_data2(uint8_t *data, int sk, int asc, int ascq)
4515 {
4516 uint8_t *cp;
4517 int resp_code;
4518 int hlen = 0, len = 0, plen;
4519 int total;
4520
4521 resp_code = 0x71; /* Deferred + Fixed format */
4522
4523 /* SenseLength */
4524 DSET16(&data[0], 0);
4525 hlen = 2;
4526
4527 /* Sense Data */
4528 cp = &data[hlen + len];
4529
4530 /* VALID(7) RESPONSE CODE(6-0) */
4531 BDSET8(&cp[0], 1, 7);
4532 BDADD8W(&cp[0], resp_code, 6, 7);
4533 /* Obsolete */
4534 cp[1] = 0;
4535 /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
4536 BDSET8W(&cp[2], sk, 3, 4);
4537 /* INFORMATION */
4538 memset(&cp[3], 0, 4);
4539 /* ADDITIONAL SENSE LENGTH */
4540 cp[7] = 0;
4541 len = 8;
4542
4543 /* COMMAND-SPECIFIC INFORMATION */
4544 memset(&cp[8], 0, 4);
4545 /* ADDITIONAL SENSE CODE */
4546 cp[12] = asc;
4547 /* ADDITIONAL SENSE CODE QUALIFIER */
4548 cp[13] = ascq;
4549 /* FIELD REPLACEABLE UNIT CODE */
4550 cp[14] = 0;
4551 /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
4552 cp[15] = 0;
4553 cp[16] = 0;
4554 cp[17] = 0;
4555 /* Additional sense bytes */
4556 //data[18] = 0;
4557 plen = 18 - len;
4558
4559 /* ADDITIONAL SENSE LENGTH */
4560 cp[7] = plen;
4561
4562 total = hlen + len + plen;
4563
4564 /* SenseLength */
4565 DSET16(&data[0], total - 2);
4566
4567 return total;
4568 }
4569
4570 static int
istgt_lu_disk_build_sense_data2(ISTGT_LU_DISK * spec,uint8_t * data,int sk,int asc,int ascq)4571 istgt_lu_disk_build_sense_data2(ISTGT_LU_DISK *spec __attribute__((__unused__)), uint8_t *data, int sk, int asc, int ascq)
4572 {
4573 int rc;
4574
4575 rc = istgt_lu_scsi_build_sense_data2(data, sk, asc, ascq);
4576 if (rc < 0) {
4577 return -1;
4578 }
4579 return rc;
4580 }
4581
4582 int
istgt_lu_disk_reset(ISTGT_LU_Ptr lu,int lun)4583 istgt_lu_disk_reset(ISTGT_LU_Ptr lu, int lun)
4584 {
4585 ISTGT_LU_DISK *spec;
4586 int flags;
4587 int rc;
4588
4589 if (lu == NULL) {
4590 return -1;
4591 }
4592 if (lun >= lu->maxlun) {
4593 return -1;
4594 }
4595 if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
4596 return -1;
4597 }
4598 if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) {
4599 return -1;
4600 }
4601 spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
4602
4603 #if 0
4604 if (spec->lock) {
4605 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "unlock by reset\n");
4606 spec->lock = 0;
4607 }
4608 #endif
4609
4610 if (lu->queue_depth != 0) {
4611 rc = istgt_lu_disk_queue_clear_all(lu, lun);
4612 if (rc < 0) {
4613 ISTGT_ERRLOG("lu_disk_queue_clear_all() failed\n");
4614 return -1;
4615 }
4616 }
4617
4618 /* re-open file */
4619 if (!spec->lu->readonly) {
4620 rc = spec->sync(spec, 0, spec->size);
4621 if (rc < 0) {
4622 ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_sync() failed\n",
4623 lu->num, lun);
4624 /* ignore error */
4625 }
4626 }
4627 rc = spec->close(spec);
4628 if (rc < 0) {
4629 ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_close() failed\n",
4630 lu->num, lun);
4631 /* ignore error */
4632 }
4633 flags = lu->readonly ? O_RDONLY : O_RDWR;
4634 rc = spec->open(spec, flags, 0666);
4635 if (rc < 0) {
4636 ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_open() failed\n",
4637 lu->num, lun);
4638 return -1;
4639 }
4640
4641 return 0;
4642 }
4643
4644 static int
istgt_lu_disk_queue_clear_internal(ISTGT_LU_DISK * spec,const char * initiator_port,int all_cmds,uint32_t CmdSN)4645 istgt_lu_disk_queue_clear_internal(ISTGT_LU_DISK *spec, const char *initiator_port, int all_cmds, uint32_t CmdSN)
4646 {
4647 ISTGT_LU_TASK_Ptr lu_task;
4648 ISTGT_QUEUE saved_queue;
4649 time_t now;
4650 int rc;
4651
4652 if (spec == NULL)
4653 return -1;
4654
4655 if (all_cmds != 0) {
4656 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by port=%s\n",
4657 initiator_port);
4658 } else {
4659 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by port=%s, CmdSN=%u\n",
4660 initiator_port, CmdSN);
4661 }
4662
4663 istgt_queue_init(&saved_queue);
4664
4665 now = time(NULL);
4666 MTX_LOCK(&spec->cmd_queue_mutex);
4667 while (1) {
4668 lu_task = istgt_queue_dequeue(&spec->cmd_queue);
4669 if (lu_task == NULL)
4670 break;
4671 if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN))
4672 && (strcasecmp(lu_task->initiator_port,
4673 initiator_port) == 0)) {
4674 ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%lu cleared\n",
4675 lu_task->lu_cmd.CmdSN,
4676 lu_task->lu_cmd.cdb[0],
4677 (unsigned long) (now - lu_task->create_time));
4678 rc = istgt_lu_destroy_task(lu_task);
4679 if (rc < 0) {
4680 MTX_UNLOCK(&spec->cmd_queue_mutex);
4681 ISTGT_ERRLOG("lu_destory_task() failed\n");
4682 goto error_return;
4683 }
4684 continue;
4685 }
4686 rc = istgt_queue_enqueue(&saved_queue, lu_task);
4687 if (rc < 0) {
4688 MTX_UNLOCK(&spec->cmd_queue_mutex);
4689 ISTGT_ERRLOG("queue_enqueue() failed\n");
4690 goto error_return;
4691 }
4692 }
4693 while (1) {
4694 lu_task = istgt_queue_dequeue(&saved_queue);
4695 if (lu_task == NULL)
4696 break;
4697 rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
4698 if (rc < 0) {
4699 MTX_UNLOCK(&spec->cmd_queue_mutex);
4700 ISTGT_ERRLOG("queue_enqueue() failed\n");
4701 goto error_return;
4702 }
4703 }
4704 MTX_UNLOCK(&spec->cmd_queue_mutex);
4705
4706 /* check wait task */
4707 MTX_LOCK(&spec->wait_lu_task_mutex);
4708 lu_task = spec->wait_lu_task;
4709 if (lu_task != NULL) {
4710 if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN))
4711 && (strcasecmp(lu_task->initiator_port,
4712 initiator_port) == 0)) {
4713 /* conn had gone? */
4714 rc = pthread_mutex_trylock(&lu_task->trans_mutex);
4715 if (rc == 0) {
4716 ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%lu aborted\n",
4717 lu_task->lu_cmd.CmdSN,
4718 lu_task->lu_cmd.cdb[0],
4719 (unsigned long) (now - lu_task->create_time));
4720 /* force error */
4721 lu_task->error = 1;
4722 lu_task->abort = 1;
4723 rc = pthread_cond_broadcast(&lu_task->trans_cond);
4724 if (rc != 0) {
4725 /* ignore error */
4726 }
4727 MTX_UNLOCK(&lu_task->trans_mutex);
4728 }
4729 }
4730 }
4731 MTX_UNLOCK(&spec->wait_lu_task_mutex);
4732
4733 rc = istgt_queue_count(&saved_queue);
4734 if (rc != 0) {
4735 ISTGT_ERRLOG("temporary queue is not empty\n");
4736 goto error_return;
4737 }
4738
4739 istgt_queue_destroy(&saved_queue);
4740 return 0;
4741
4742 error_return:
4743 istgt_queue_destroy(&saved_queue);
4744 return -1;
4745 }
4746
4747 static int
istgt_lu_disk_queue_abort_ITL(ISTGT_LU_DISK * spec,const char * initiator_port)4748 istgt_lu_disk_queue_abort_ITL(ISTGT_LU_DISK *spec, const char *initiator_port)
4749 {
4750 int rc;
4751
4752 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue abort by port=%s\n",
4753 initiator_port);
4754
4755 rc = istgt_lu_disk_queue_clear_internal(spec, initiator_port,
4756 1, 0U); /* ALL, CmdSN=0 */
4757 return rc;
4758 }
4759
4760 int
istgt_lu_disk_queue_clear_IT(CONN_Ptr conn,ISTGT_LU_Ptr lu)4761 istgt_lu_disk_queue_clear_IT(CONN_Ptr conn, ISTGT_LU_Ptr lu)
4762 {
4763 ISTGT_LU_DISK *spec;
4764 int rc;
4765 int i;
4766
4767 if (lu == NULL)
4768 return -1;
4769
4770 for (i = 0; i < lu->maxlun; i++) {
4771 if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
4772 #if 0
4773 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
4774 lu->num, i);
4775 #endif
4776 continue;
4777 }
4778 if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) {
4779 ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
4780 return -1;
4781 }
4782 spec = (ISTGT_LU_DISK *) lu->lun[i].spec;
4783 if (spec == NULL) {
4784 continue;
4785 }
4786
4787 rc = istgt_lu_disk_queue_clear_ITL(conn, lu, i);
4788 if (rc < 0) {
4789 return -1;
4790 }
4791 }
4792
4793 return 0;
4794 }
4795
4796 int
istgt_lu_disk_queue_clear_ITL(CONN_Ptr conn,ISTGT_LU_Ptr lu,int lun)4797 istgt_lu_disk_queue_clear_ITL(CONN_Ptr conn, ISTGT_LU_Ptr lu, int lun)
4798 {
4799 ISTGT_LU_DISK *spec;
4800 int rc;
4801
4802 if (lu == NULL)
4803 return -1;
4804 if (lun >= lu->maxlun)
4805 return -1;
4806
4807 spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
4808 if (spec == NULL)
4809 return -1;
4810
4811 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by name=%s, port=%s\n",
4812 conn->initiator_name, conn->initiator_port);
4813
4814 rc = istgt_lu_disk_queue_clear_internal(spec, conn->initiator_port,
4815 1, 0U); /* ALL, CmdSN=0 */
4816 return rc;
4817 }
4818
4819 int
istgt_lu_disk_queue_clear_ITLQ(CONN_Ptr conn,ISTGT_LU_Ptr lu,int lun,uint32_t CmdSN)4820 istgt_lu_disk_queue_clear_ITLQ(CONN_Ptr conn, ISTGT_LU_Ptr lu, int lun, uint32_t CmdSN)
4821 {
4822 ISTGT_LU_DISK *spec;
4823 int rc;
4824
4825 if (lu == NULL)
4826 return -1;
4827 if (lun >= lu->maxlun)
4828 return -1;
4829
4830 spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
4831 if (spec == NULL)
4832 return -1;
4833
4834 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by name=%s, port=%s\n",
4835 conn->initiator_name, conn->initiator_port);
4836
4837 rc = istgt_lu_disk_queue_clear_internal(spec, conn->initiator_port,
4838 0, CmdSN);
4839 return rc;
4840 }
4841
4842 int
istgt_lu_disk_queue_clear_all(ISTGT_LU_Ptr lu,int lun)4843 istgt_lu_disk_queue_clear_all(ISTGT_LU_Ptr lu, int lun)
4844 {
4845 ISTGT_LU_TASK_Ptr lu_task;
4846 ISTGT_LU_DISK *spec;
4847 time_t now;
4848 int rc;
4849
4850 if (lu == NULL)
4851 return -1;
4852 if (lun >= lu->maxlun)
4853 return -1;
4854
4855 if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
4856 return -1;
4857 }
4858 if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) {
4859 return -1;
4860 }
4861 spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
4862 if (spec == NULL)
4863 return -1;
4864
4865 now = time(NULL);
4866 MTX_LOCK(&spec->cmd_queue_mutex);
4867 while (1) {
4868 lu_task = istgt_queue_dequeue(&spec->cmd_queue);
4869 if (lu_task == NULL)
4870 break;
4871 ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%lu cleared\n",
4872 lu_task->lu_cmd.CmdSN,
4873 lu_task->lu_cmd.cdb[0],
4874 (unsigned long) (now - lu_task->create_time));
4875 rc = istgt_lu_destroy_task(lu_task);
4876 if (rc < 0) {
4877 MTX_UNLOCK(&spec->cmd_queue_mutex);
4878 ISTGT_ERRLOG("lu_destory_task() failed\n");
4879 return -1;
4880 }
4881 }
4882 MTX_UNLOCK(&spec->cmd_queue_mutex);
4883
4884 /* check wait task */
4885 MTX_LOCK(&spec->wait_lu_task_mutex);
4886 lu_task = spec->wait_lu_task;
4887 if (lu_task != NULL) {
4888 /* conn had gone? */
4889 rc = pthread_mutex_trylock(&lu_task->trans_mutex);
4890 if (rc == 0) {
4891 ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%lu aborted\n",
4892 lu_task->lu_cmd.CmdSN,
4893 lu_task->lu_cmd.cdb[0],
4894 (unsigned long) (now - lu_task->create_time));
4895 /* force error */
4896 lu_task->error = 1;
4897 lu_task->abort = 1;
4898 rc = pthread_cond_broadcast(&lu_task->trans_cond);
4899 if (rc != 0) {
4900 /* ignore error */
4901 }
4902 MTX_UNLOCK(&lu_task->trans_mutex);
4903 }
4904 }
4905 MTX_UNLOCK(&spec->wait_lu_task_mutex);
4906
4907 MTX_LOCK(&spec->cmd_queue_mutex);
4908 rc = istgt_queue_count(&spec->cmd_queue);
4909 MTX_UNLOCK(&spec->cmd_queue_mutex);
4910 if (rc != 0) {
4911 ISTGT_ERRLOG("cmd queue is not empty\n");
4912 return -1;
4913 }
4914
4915 return 0;
4916 }
4917
4918 int
istgt_lu_disk_queue(CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)4919 istgt_lu_disk_queue(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
4920 {
4921 ISTGT_LU_TASK_Ptr lu_task;
4922 ISTGT_LU_Ptr lu;
4923 ISTGT_LU_DISK *spec;
4924 uint8_t *data;
4925 uint8_t *cdb;
4926 uint32_t allocation_len;
4927 int data_len;
4928 int data_alloc_len;
4929 uint8_t *sense_data;
4930 size_t *sense_len;
4931 int lun_i;
4932 int maxq;
4933 int qcnt;
4934 int rc;
4935
4936 if (lu_cmd == NULL)
4937 return -1;
4938 lu = lu_cmd->lu;
4939 if (lu == NULL) {
4940 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4941 return -1;
4942 }
4943 spec = NULL;
4944 cdb = lu_cmd->cdb;
4945 data = lu_cmd->data;
4946 data_alloc_len = lu_cmd->alloc_len;
4947 sense_data = lu_cmd->sense_data;
4948 sense_len = &lu_cmd->sense_data_len;
4949 *sense_len = 0;
4950
4951 lun_i = istgt_lu_islun2lun(lu_cmd->lun);
4952 if (lun_i >= lu->maxlun) {
4953 #ifdef ISTGT_TRACE_DISK
4954 ISTGT_ERRLOG("LU%d: LUN%d invalid\n",
4955 lu->num, lun_i);
4956 #endif /* ISTGT_TRACE_DISK */
4957 if (cdb[0] == SPC_INQUIRY) {
4958 allocation_len = DGET16(&cdb[3]);
4959 if (allocation_len > (size_t) data_alloc_len) {
4960 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
4961 data_alloc_len);
4962 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4963 return -1;
4964 }
4965 memset(data, 0, allocation_len);
4966 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
4967 BDSET8W(&data[0], 0x03, 7, 3);
4968 BDADD8W(&data[0], 0x1f, 4, 5);
4969 data_len = 96;
4970 memset(&data[1], 0, data_len - 1);
4971 /* ADDITIONAL LENGTH */
4972 data[4] = data_len - 5;
4973 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
4974 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
4975 return ISTGT_LU_TASK_RESULT_IMMEDIATE;
4976 } else {
4977 /* LOGICAL UNIT NOT SUPPORTED */
4978 BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
4979 lu_cmd->data_len = 0;
4980 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4981 return ISTGT_LU_TASK_RESULT_IMMEDIATE;
4982 }
4983 }
4984 spec = (ISTGT_LU_DISK *) lu->lun[lun_i].spec;
4985 if (spec == NULL) {
4986 /* LOGICAL UNIT NOT SUPPORTED */
4987 BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
4988 lu_cmd->data_len = 0;
4989 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4990 return ISTGT_LU_TASK_RESULT_IMMEDIATE;
4991 }
4992 /* ready to enqueue, spec is valid for LUN access */
4993
4994 /* allocate task and copy LU_CMD(PDU) */
4995 lu_task = xmalloc(sizeof *lu_task);
4996 memset(lu_task, 0, sizeof *lu_task);
4997 rc = istgt_lu_create_task(conn, lu_cmd, lu_task, lun_i);
4998 if (rc < 0) {
4999 ISTGT_ERRLOG("lu_create_task() failed\n");
5000 xfree(lu_task);
5001 return -1;
5002 }
5003
5004 /* enqueue SCSI command */
5005 MTX_LOCK(&spec->cmd_queue_mutex);
5006 rc = istgt_queue_count(&spec->cmd_queue);
5007 maxq = spec->queue_depth * lu->istgt->MaxSessions;
5008 if (rc > maxq) {
5009 MTX_UNLOCK(&spec->cmd_queue_mutex);
5010 lu_cmd->data_len = 0;
5011 lu_cmd->status = ISTGT_SCSI_STATUS_TASK_SET_FULL;
5012 rc = istgt_lu_destroy_task(lu_task);
5013 if (rc < 0) {
5014 ISTGT_ERRLOG("lu_destroy_task() failed\n");
5015 return -1;
5016 }
5017 return ISTGT_LU_TASK_RESULT_QUEUE_FULL;
5018 }
5019 qcnt = rc;
5020 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
5021 "Queue(%d), CmdSN=%u, OP=0x%x, LUN=0x%16.16"PRIx64"\n",
5022 qcnt, lu_cmd->CmdSN, lu_cmd->cdb[0], lu_cmd->lun);
5023
5024 /* enqueue task to LUN */
5025 switch (lu_cmd->Attr_bit) {
5026 case 0x03: /* Head of Queue */
5027 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Head of Queue\n");
5028 rc = istgt_queue_enqueue_first(&spec->cmd_queue, lu_task);
5029 break;
5030 case 0x00: /* Untagged */
5031 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Untagged\n");
5032 rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
5033 break;
5034 case 0x01: /* Simple */
5035 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Simple\n");
5036 rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
5037 break;
5038 case 0x02: /* Ordered */
5039 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Ordered\n");
5040 rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
5041 break;
5042 case 0x04: /* ACA */
5043 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert ACA\n");
5044 rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
5045 break;
5046 default: /* Reserved */
5047 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Reserved Attribute\n");
5048 rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
5049 break;
5050 }
5051 MTX_UNLOCK(&spec->cmd_queue_mutex);
5052 if (rc < 0) {
5053 ISTGT_ERRLOG("queue_enqueue() failed\n");
5054 error_return:
5055 rc = istgt_lu_destroy_task(lu_task);
5056 if (rc < 0) {
5057 ISTGT_ERRLOG("lu_destroy_task() failed\n");
5058 return -1;
5059 }
5060 return -1;
5061 }
5062
5063 /* notify LUN thread */
5064 MTX_LOCK(&lu->queue_mutex);
5065 lu->queue_check = 1;
5066 rc = pthread_cond_broadcast(&lu->queue_cond);
5067 MTX_UNLOCK(&lu->queue_mutex);
5068 if (rc != 0) {
5069 ISTGT_ERRLOG("LU%d: cond_broadcast() failed\n", lu->num);
5070 goto error_return;
5071 }
5072
5073 return ISTGT_LU_TASK_RESULT_QUEUE_OK;
5074 }
5075
5076 int
istgt_lu_disk_queue_count(ISTGT_LU_Ptr lu,int * lun)5077 istgt_lu_disk_queue_count(ISTGT_LU_Ptr lu, int *lun)
5078 {
5079 ISTGT_LU_DISK *spec;
5080 int qcnt;
5081 int luns;
5082 int i;
5083
5084 if (lun == NULL)
5085 return -1;
5086
5087 i = *lun;
5088 if (i >= lu->maxlun) {
5089 *lun = 0;
5090 i = 0;
5091 }
5092
5093 qcnt = 0;
5094 for (luns = lu->maxlun; luns >= 0 ; luns--) {
5095 if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
5096 goto next_lun;
5097 }
5098 if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) {
5099 ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
5100 goto next_lun;
5101 }
5102 spec = (ISTGT_LU_DISK *) lu->lun[i].spec;
5103 if (spec == NULL) {
5104 goto next_lun;
5105 }
5106
5107 MTX_LOCK(&spec->cmd_queue_mutex);
5108 qcnt = istgt_queue_count(&spec->cmd_queue);
5109 MTX_UNLOCK(&spec->cmd_queue_mutex);
5110 if (qcnt > 0) {
5111 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5112 "LU%d: LUN%d queue(%d)\n",
5113 lu->num, i, qcnt);
5114 *lun = spec->lun;
5115 break;
5116 }
5117
5118 next_lun:
5119 i++;
5120 if (i >= lu->maxlun) {
5121 i = 0;
5122 }
5123 }
5124 return qcnt;
5125 }
5126
5127 int
istgt_lu_disk_queue_start(ISTGT_LU_Ptr lu,int lun)5128 istgt_lu_disk_queue_start(ISTGT_LU_Ptr lu, int lun)
5129 {
5130 ISTGT_Ptr istgt;
5131 ISTGT_LU_DISK *spec;
5132 ISTGT_LU_TASK_Ptr lu_task;
5133 CONN_Ptr conn;
5134 ISTGT_LU_CMD_Ptr lu_cmd;
5135 struct timespec abstime;
5136 time_t start, now;
5137 uint8_t *iobuf;
5138 char tmp[1];
5139 int abort_task = 0;
5140 int rc;
5141
5142 if (lun < 0 || lun >= lu->maxlun) {
5143 return -1;
5144 }
5145
5146 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LU%d: LUN%d queue start\n",
5147 lu->num, lun);
5148 spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
5149 if (spec == NULL)
5150 return -1;
5151
5152 MTX_LOCK(&spec->cmd_queue_mutex);
5153 lu_task = istgt_queue_dequeue(&spec->cmd_queue);
5154 MTX_UNLOCK(&spec->cmd_queue_mutex);
5155 if (lu_task == NULL) {
5156 /* cleared or empty queue */
5157 return 0;
5158 }
5159 lu_task->thread = pthread_self();
5160 conn = lu_task->conn;
5161 istgt = conn->istgt;
5162 lu_cmd = &lu_task->lu_cmd;
5163
5164 /* XXX need pre-allocate? */
5165 #if 0
5166 /* allocated in istgt_lu_create_task() */
5167 lu_task->data = xmalloc(lu_cmd->alloc_len);
5168 lu_task->sense_data = xmalloc(lu_cmd->sense_alloc_len);
5169 lu_task->iobuf = NULL;
5170 #endif
5171 lu_cmd->data = lu_task->data;
5172 lu_cmd->data_len = 0;
5173 lu_cmd->sense_data = lu_task->sense_data;
5174 lu_cmd->sense_data_len = 0;
5175
5176 tmp[0] = 'Q';
5177 if (lu_cmd->W_bit) {
5178 if (lu_cmd->pdu->data_segment_len >= lu_cmd->transfer_len) {
5179 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5180 "LU%d: LUN%d Task Write Immediate Start\n",
5181 lu->num, lun);
5182 #if 0
5183 iobuf = xmalloc(lu_cmd->pdu->data_segment_len);
5184 memcpy(iobuf, lu_cmd->pdu->data,
5185 lu_cmd->pdu->data_segment_len);
5186 lu_task->iobuf = iobuf;
5187 #else
5188 iobuf = lu_cmd->pdu->data;
5189 lu_task->dup_iobuf = 1;
5190 #endif
5191 lu_cmd->iobuf = iobuf;
5192
5193 MTX_LOCK(&lu_cmd->lu->mutex);
5194 rc = istgt_lu_disk_execute(conn, lu_cmd);
5195 MTX_UNLOCK(&lu_cmd->lu->mutex);
5196 if (rc < 0) {
5197 ISTGT_ERRLOG("lu_disk_execute() failed\n");
5198 error_return:
5199 rc = istgt_lu_destroy_task(lu_task);
5200 if (rc < 0) {
5201 ISTGT_ERRLOG("lu_destroy_task() failed\n");
5202 return -1;
5203 }
5204 return -1;
5205 }
5206 lu_task->execute = 1;
5207
5208 /* response */
5209 if (conn->use_sender == 0) {
5210 MTX_LOCK(&conn->task_queue_mutex);
5211 rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
5212 MTX_UNLOCK(&conn->task_queue_mutex);
5213 if (rc < 0) {
5214 ISTGT_ERRLOG("queue_enqueue() failed\n");
5215 goto error_return;
5216 }
5217 rc = write(conn->task_pipe[1], tmp, 1);
5218 if(rc < 0 || rc != 1) {
5219 ISTGT_ERRLOG("write() failed\n");
5220 goto error_return;
5221 }
5222 } else {
5223 MTX_LOCK(&conn->result_queue_mutex);
5224 rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
5225 if (rc < 0) {
5226 MTX_UNLOCK(&conn->result_queue_mutex);
5227 ISTGT_ERRLOG("queue_enqueue() failed\n");
5228 goto error_return;
5229 }
5230 rc = pthread_cond_broadcast(&conn->result_queue_cond);
5231 MTX_UNLOCK(&conn->result_queue_mutex);
5232 if (rc != 0) {
5233 ISTGT_ERRLOG("cond_broadcast() failed\n");
5234 goto error_return;
5235 }
5236 }
5237
5238 #if 0
5239 /* write cache */
5240 if (spec->req_write_cache) {
5241 MTX_LOCK(&lu->mutex);
5242 rc = istgt_lu_disk_write_cache(spec, conn);
5243 MTX_UNLOCK(&lu->mutex);
5244 if (rc < 0) {
5245 ISTGT_ERRLOG("disk_write_cache() failed\n");
5246 return -1;
5247 }
5248 }
5249 #endif
5250 } else {
5251 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5252 "LU%d: LUN%d Task Write Start\n",
5253 lu->num, lun);
5254
5255 #if 0
5256 MTX_LOCK(&spec->wait_lu_task_mutex);
5257 spec->wait_lu_task = NULL;
5258 MTX_UNLOCK(&spec->wait_lu_task_mutex);
5259 #endif
5260 rc = pthread_mutex_init(&lu_task->trans_mutex, NULL);
5261 if (rc != 0) {
5262 ISTGT_ERRLOG("mutex_init() failed\n");
5263 goto error_return;
5264 }
5265 rc = pthread_cond_init(&lu_task->trans_cond, NULL);
5266 if (rc != 0) {
5267 ISTGT_ERRLOG("cond_init() failed\n");
5268 goto error_return;
5269 }
5270 rc = pthread_cond_init(&lu_task->exec_cond, NULL);
5271 if (rc != 0) {
5272 ISTGT_ERRLOG("cond_init() failed\n");
5273 goto error_return;
5274 }
5275 lu_task->use_cond = 1;
5276 #if 0
5277 lu_cmd->iobufsize = lu_cmd->transfer_len + 65536;
5278 iobuf = xmalloc(lu_cmd->iobufsize);
5279 lu_task->iobuf = iobuf;
5280 #else
5281 lu_cmd->iobufsize = lu_task->lu_cmd.iobufsize;
5282 iobuf = lu_task->iobuf;
5283 #endif
5284 lu_cmd->iobuf = iobuf;
5285 lu_task->req_transfer_out = 1;
5286 memset(&abstime, 0, sizeof abstime);
5287 abstime.tv_sec = 0;
5288 abstime.tv_nsec = 0;
5289
5290 MTX_LOCK(&conn->task_queue_mutex);
5291 rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
5292 MTX_UNLOCK(&conn->task_queue_mutex);
5293 if (rc < 0) {
5294 MTX_UNLOCK(&lu_task->trans_mutex);
5295 ISTGT_ERRLOG("queue_enqueue() failed\n");
5296 goto error_return;
5297 }
5298 rc = write(conn->task_pipe[1], tmp, 1);
5299 if(rc < 0 || rc != 1) {
5300 MTX_UNLOCK(&lu_task->trans_mutex);
5301 ISTGT_ERRLOG("write() failed\n");
5302 goto error_return;
5303 }
5304
5305 start = now = time(NULL);
5306 abstime.tv_sec = now + (lu_task->condwait / 1000);
5307 abstime.tv_nsec = (lu_task->condwait % 1000) * 1000000;
5308 #if 0
5309 ISTGT_LOG("wait CmdSN=%u\n", lu_task->lu_cmd.CmdSN);
5310 #endif
5311 MTX_LOCK(&lu_task->trans_mutex);
5312 MTX_LOCK(&spec->wait_lu_task_mutex);
5313 spec->wait_lu_task = lu_task;
5314 MTX_UNLOCK(&spec->wait_lu_task_mutex);
5315 rc = 0;
5316 while (lu_task->req_transfer_out == 1) {
5317 rc = pthread_cond_timedwait(&lu_task->trans_cond,
5318 &lu_task->trans_mutex,
5319 &abstime);
5320 if (rc == ETIMEDOUT) {
5321 if (lu_task->req_transfer_out == 1) {
5322 lu_task->error = 1;
5323 MTX_LOCK(&spec->wait_lu_task_mutex);
5324 spec->wait_lu_task = NULL;
5325 MTX_UNLOCK(&spec->wait_lu_task_mutex);
5326 MTX_UNLOCK(&lu_task->trans_mutex);
5327 now = time(NULL);
5328 ISTGT_ERRLOG("timeout trans_cond CmdSN=%u "
5329 "(time=%d)\n",
5330 lu_task->lu_cmd.CmdSN,
5331 istgt_difftime(now, start));
5332 /* timeout */
5333 return -1;
5334 }
5335 /* OK cond */
5336 rc = 0;
5337 break;
5338 }
5339 if (lu_task->error != 0) {
5340 rc = -1;
5341 break;
5342 }
5343 if (rc != 0) {
5344 break;
5345 }
5346 }
5347 MTX_LOCK(&spec->wait_lu_task_mutex);
5348 spec->wait_lu_task = NULL;
5349 MTX_UNLOCK(&spec->wait_lu_task_mutex);
5350 MTX_UNLOCK(&lu_task->trans_mutex);
5351 if (rc != 0) {
5352 if (rc < 0) {
5353 lu_task->error = 1;
5354 if (lu_task->abort) {
5355 ISTGT_WARNLOG("transfer abort CmdSN=%u\n",
5356 lu_task->lu_cmd.CmdSN);
5357 return -2;
5358 } else {
5359 ISTGT_ERRLOG("transfer error CmdSN=%u\n",
5360 lu_task->lu_cmd.CmdSN);
5361 return -1;
5362 }
5363 }
5364 if (rc == ETIMEDOUT) {
5365 lu_task->error = 1;
5366 now = time(NULL);
5367 ISTGT_ERRLOG("timeout trans_cond CmdSN=%u (time=%d)\n",
5368 lu_task->lu_cmd.CmdSN, istgt_difftime(now, start));
5369 return -1;
5370 }
5371 lu_task->error = 1;
5372 ISTGT_ERRLOG("cond_timedwait rc=%d\n", rc);
5373 return -1;
5374 }
5375
5376 if (lu_task->req_execute == 0) {
5377 ISTGT_ERRLOG("wrong request\n");
5378 goto error_return;
5379 }
5380 MTX_LOCK(&lu_cmd->lu->mutex);
5381 rc = istgt_lu_disk_execute(conn, lu_cmd);
5382 MTX_UNLOCK(&lu_cmd->lu->mutex);
5383 if (rc < 0) {
5384 lu_task->error = 1;
5385 ISTGT_ERRLOG("lu_disk_execute() failed\n");
5386 goto error_return;
5387 }
5388 lu_task->execute = 1;
5389
5390 /* response */
5391 if (conn->use_sender == 0) {
5392 MTX_LOCK(&conn->task_queue_mutex);
5393 rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
5394 MTX_UNLOCK(&conn->task_queue_mutex);
5395 if (rc < 0) {
5396 ISTGT_ERRLOG("queue_enqueue() failed\n");
5397 goto error_return;
5398 }
5399 rc = write(conn->task_pipe[1], tmp, 1);
5400 if(rc < 0 || rc != 1) {
5401 ISTGT_ERRLOG("write() failed\n");
5402 goto error_return;
5403 }
5404 } else {
5405 MTX_LOCK(&conn->result_queue_mutex);
5406 rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
5407 if (rc < 0) {
5408 MTX_UNLOCK(&conn->result_queue_mutex);
5409 ISTGT_ERRLOG("queue_enqueue() failed\n");
5410 goto error_return;
5411 }
5412 rc = pthread_cond_broadcast(&conn->result_queue_cond);
5413 MTX_UNLOCK(&conn->result_queue_mutex);
5414 if (rc != 0) {
5415 ISTGT_ERRLOG("cond_broadcast() failed\n");
5416 goto error_return;
5417 }
5418 }
5419
5420 #if 0
5421 /* write cache */
5422 if (spec->req_write_cache) {
5423 MTX_LOCK(&lu->mutex);
5424 rc = istgt_lu_disk_write_cache(spec, conn);
5425 MTX_UNLOCK(&lu->mutex);
5426 if (rc < 0) {
5427 ISTGT_ERRLOG("disk_write_cache() failed\n");
5428 return -1;
5429 }
5430 }
5431 #endif
5432 }
5433 } else {
5434 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5435 "LU%d: LUN%d Task Read Start\n",
5436 lu->num, lun);
5437 #if 0
5438 lu_cmd->iobufsize = lu_cmd->transfer_len + 65536;
5439 iobuf = xmalloc(lu_cmd->iobufsize);
5440 lu_task->iobuf = iobuf;
5441 #else
5442 lu_cmd->iobufsize = lu_task->lu_cmd.iobufsize;
5443 iobuf = lu_task->iobuf;
5444 #endif
5445 lu_cmd->iobuf = iobuf;
5446 MTX_LOCK(&lu_cmd->lu->mutex);
5447 rc = istgt_lu_disk_execute(conn, lu_cmd);
5448 MTX_UNLOCK(&lu_cmd->lu->mutex);
5449 if (rc < 0) {
5450 ISTGT_ERRLOG("lu_disk_execute() failed\n");
5451 goto error_return;
5452 }
5453 lu_task->execute = 1;
5454
5455 /* response */
5456 if (conn->use_sender == 0) {
5457 MTX_LOCK(&conn->task_queue_mutex);
5458 rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
5459 MTX_UNLOCK(&conn->task_queue_mutex);
5460 if (rc < 0) {
5461 ISTGT_ERRLOG("queue_enqueue() failed\n");
5462 goto error_return;
5463 }
5464 rc = write(conn->task_pipe[1], tmp, 1);
5465 if(rc < 0 || rc != 1) {
5466 ISTGT_ERRLOG("write() failed\n");
5467 goto error_return;
5468 }
5469 } else {
5470 MTX_LOCK(&conn->result_queue_mutex);
5471 rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
5472 if (rc < 0) {
5473 MTX_UNLOCK(&conn->result_queue_mutex);
5474 ISTGT_ERRLOG("queue_enqueue() failed\n");
5475 goto error_return;
5476 }
5477 rc = pthread_cond_broadcast(&conn->result_queue_cond);
5478 MTX_UNLOCK(&conn->result_queue_mutex);
5479 if (rc != 0) {
5480 ISTGT_ERRLOG("cond_broadcast() failed\n");
5481 goto error_return;
5482 }
5483 }
5484 }
5485
5486 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LU%d: LUN%d queue end\n",
5487 lu->num, lun);
5488
5489 if (abort_task) {
5490 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Abort Task\n");
5491 return -1;
5492 }
5493 return 0;
5494 }
5495
5496 int
istgt_lu_disk_execute(CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)5497 istgt_lu_disk_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
5498 {
5499 ISTGT_LU_Ptr lu;
5500 ISTGT_LU_DISK *spec;
5501 uint8_t *data;
5502 uint8_t *cdb;
5503 uint32_t allocation_len;
5504 int data_len;
5505 int data_alloc_len;
5506 uint64_t lba;
5507 uint32_t len;
5508 uint32_t transfer_len;
5509 uint32_t parameter_len;
5510 uint8_t *sense_data;
5511 size_t *sense_len;
5512 int lun_i;
5513 int rc;
5514
5515 if (lu_cmd == NULL)
5516 return -1;
5517 lu = lu_cmd->lu;
5518 if (lu == NULL) {
5519 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5520 return -1;
5521 }
5522 spec = NULL;
5523 cdb = lu_cmd->cdb;
5524 data = lu_cmd->data;
5525 data_alloc_len = lu_cmd->alloc_len;
5526 sense_data = lu_cmd->sense_data;
5527 sense_len = &lu_cmd->sense_data_len;
5528 *sense_len = 0;
5529
5530 lun_i = istgt_lu_islun2lun(lu_cmd->lun);
5531 if (lun_i >= lu->maxlun) {
5532 #ifdef ISTGT_TRACE_DISK
5533 ISTGT_ERRLOG("LU%d: LUN%d invalid\n",
5534 lu->num, lun_i);
5535 #endif /* ISTGT_TRACE_DISK */
5536 if (cdb[0] == SPC_INQUIRY) {
5537 allocation_len = DGET16(&cdb[3]);
5538 if (allocation_len > (size_t) data_alloc_len) {
5539 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5540 data_alloc_len);
5541 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5542 return -1;
5543 }
5544 memset(data, 0, allocation_len);
5545 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
5546 BDSET8W(&data[0], 0x03, 7, 3);
5547 BDADD8W(&data[0], 0x1f, 4, 5);
5548 data_len = 96;
5549 memset(&data[1], 0, data_len - 1);
5550 /* ADDITIONAL LENGTH */
5551 data[4] = data_len - 5;
5552 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
5553 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5554 return 0;
5555 } else {
5556 /* LOGICAL UNIT NOT SUPPORTED */
5557 BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
5558 lu_cmd->data_len = 0;
5559 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5560 return 0;
5561 }
5562 }
5563 spec = (ISTGT_LU_DISK *) lu->lun[lun_i].spec;
5564 if (spec == NULL) {
5565 /* LOGICAL UNIT NOT SUPPORTED */
5566 BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
5567 lu_cmd->data_len = 0;
5568 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5569 return 0;
5570 }
5571
5572 if (spec->sense != 0) {
5573 int sk, asc, ascq;
5574 if (cdb[0] != SPC_INQUIRY
5575 && cdb[0] != SPC_REPORT_LUNS) {
5576 sk = (spec->sense >> 16) & 0xffU;
5577 asc = (spec->sense >> 8) & 0xffU;
5578 ascq = (spec->sense >> 0) & 0xffU;
5579 spec->sense = 0;
5580 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5581 "Generate sk=0x%x, asc=0x%x, ascq=0x%x\n",
5582 sk, asc, ascq);
5583 *sense_len
5584 = istgt_lu_disk_build_sense_data(spec, sense_data,
5585 sk, asc, ascq);
5586 lu_cmd->data_len = 0;
5587 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5588 return 0;
5589 }
5590 }
5591
5592 if (spec->err_write_cache) {
5593 /* WRITE ERROR - AUTO REALLOCATION FAILED */
5594 BUILD_SENSE2(MEDIUM_ERROR, 0x0c, 0x02);
5595 #if 0
5596 /* WRITE ERROR - RECOMMEND REASSIGNMENT */
5597 BUILD_SENSE2(MEDIUM_ERROR, 0x0c, 0x03);
5598 #endif
5599 spec->err_write_cache = 0;
5600 lba = spec->woffset / spec->blocklen;
5601 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5602 "Deferred error (write cache) at %"PRIu64"\n", lba);
5603 if (lba > 0xffffffffULL) {
5604 ISTGT_WARNLOG("lba > 0xffffffff\n");
5605 }
5606 /* COMMAND-SPECIFIC INFORMATION */
5607 DSET32(&sense_data[8], (uint32_t)(lba & 0xffffffffULL));
5608 lu_cmd->data_len = 0;
5609 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5610 return 0;
5611 }
5612
5613 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
5614 "SCSI OP=0x%x, LUN=0x%16.16"PRIx64"\n",
5615 cdb[0], lu_cmd->lun);
5616 #ifdef ISTGT_TRACE_DISK
5617 if (cdb[0] != SPC_TEST_UNIT_READY) {
5618 istgt_scsi_dump_cdb(cdb);
5619 }
5620 #endif /* ISTGT_TRACE_DISK */
5621 switch (cdb[0]) {
5622 case SPC_INQUIRY:
5623 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "INQUIRY\n");
5624 if (lu_cmd->R_bit == 0) {
5625 ISTGT_ERRLOG("R_bit == 0\n");
5626 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5627 return -1;
5628 }
5629 allocation_len = DGET16(&cdb[3]);
5630 if (allocation_len > (size_t) data_alloc_len) {
5631 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5632 data_alloc_len);
5633 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5634 return -1;
5635 }
5636 memset(data, 0, allocation_len);
5637 data_len = istgt_lu_disk_scsi_inquiry(spec, conn, cdb,
5638 data, data_alloc_len);
5639 if (data_len < 0) {
5640 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5641 break;
5642 }
5643 ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "INQUIRY", data, data_len);
5644 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
5645 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5646 break;
5647
5648 case SPC_REPORT_LUNS:
5649 {
5650 int sel;
5651
5652 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT LUNS\n");
5653 if (lu_cmd->R_bit == 0) {
5654 ISTGT_ERRLOG("R_bit == 0\n");
5655 return -1;
5656 }
5657
5658 sel = cdb[2];
5659 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sel=%x\n", sel);
5660
5661 allocation_len = DGET32(&cdb[6]);
5662 if (allocation_len > (size_t) data_alloc_len) {
5663 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5664 data_alloc_len);
5665 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5666 return -1;
5667 }
5668 if (allocation_len < 16) {
5669 /* INVALID FIELD IN CDB */
5670 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
5671 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5672 break;
5673 }
5674 memset(data, 0, allocation_len);
5675 data_len = istgt_lu_disk_scsi_report_luns(lu, conn, cdb, sel,
5676 data, data_alloc_len);
5677 if (data_len < 0) {
5678 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5679 break;
5680 }
5681 ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "REPORT LUNS", data, data_len);
5682 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
5683 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5684 }
5685 break;
5686
5687 case SPC_TEST_UNIT_READY:
5688 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "TEST_UNIT_READY\n");
5689 lu_cmd->data_len = 0;
5690 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5691 break;
5692
5693 case SBC_START_STOP_UNIT:
5694 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "START_STOP_UNIT\n");
5695 {
5696 int pc, loej, start;
5697
5698 pc = BGET8W(&cdb[4], 7, 4);
5699 loej = BGET8(&cdb[4], 1);
5700 start = BGET8(&cdb[4], 0);
5701
5702 if (start != 0 || pc != 0) {
5703 if (spec->rsv_key) {
5704 rc = istgt_lu_disk_check_pr(spec, conn,
5705 PR_ALLOW(0,0,1,0,0));
5706 if (rc != 0) {
5707 lu_cmd->status
5708 = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
5709 break;
5710 }
5711 }
5712 }
5713
5714 lu_cmd->data_len = 0;
5715 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5716 }
5717 break;
5718
5719 case SBC_READ_CAPACITY_10:
5720 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_CAPACITY_10\n");
5721 if (lu_cmd->R_bit == 0) {
5722 ISTGT_ERRLOG("R_bit == 0\n");
5723 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5724 return -1;
5725 }
5726 if (spec->blockcnt - 1 > 0xffffffffULL) {
5727 DSET32(&data[0], 0xffffffffUL);
5728 } else {
5729 DSET32(&data[0], (uint32_t) (spec->blockcnt - 1));
5730 }
5731 DSET32(&data[4], (uint32_t) spec->blocklen);
5732 data_len = 8;
5733 lu_cmd->data_len = data_len;
5734 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5735 ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
5736 "SBC_READ_CAPACITY_10", data, data_len);
5737 break;
5738
5739 case SPC_SERVICE_ACTION_IN_16:
5740 switch (BGET8W(&cdb[1], 4, 5)) { /* SERVICE ACTION */
5741 case SBC_SAI_READ_CAPACITY_16:
5742 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_CAPACITY_16\n");
5743 if (lu_cmd->R_bit == 0) {
5744 ISTGT_ERRLOG("R_bit == 0\n");
5745 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5746 return -1;
5747 }
5748 allocation_len = DGET32(&cdb[10]);
5749 if (allocation_len > (size_t) data_alloc_len) {
5750 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5751 data_alloc_len);
5752 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5753 return -1;
5754 }
5755 memset(data, 0, allocation_len);
5756 DSET64(&data[0], spec->blockcnt - 1);
5757 DSET32(&data[8], (uint32_t) spec->blocklen);
5758 data[12] = 0; /* RTO_EN(1) PROT_EN(0) */
5759 memset(&data[13], 0, 32 - (8 + 4 + 1)); /* Reserved */
5760 data_len = 32;
5761 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
5762 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5763 break;
5764 case SBC_SAI_READ_LONG_16:
5765 default:
5766 /* INVALID COMMAND OPERATION CODE */
5767 BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
5768 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5769 break;
5770 }
5771 break;
5772
5773 case SPC_MODE_SELECT_6:
5774 #if 0
5775 istgt_scsi_dump_cdb(cdb);
5776 #endif
5777 {
5778 int pf, sp, pllen;
5779 int mdlen, mt, dsp, bdlen;
5780
5781 if (spec->rsv_key) {
5782 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
5783 if (rc != 0) {
5784 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
5785 break;
5786 }
5787 }
5788
5789 pf = BGET8(&cdb[1], 4);
5790 sp = BGET8(&cdb[1], 0);
5791 pllen = cdb[4]; /* Parameter List Length */
5792
5793 if (pllen == 0) {
5794 lu_cmd->data_len = 0;
5795 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5796 break;
5797 }
5798 /* Data-Out */
5799 rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
5800 lu_cmd->iobufsize, pllen);
5801 if (rc < 0) {
5802 ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
5803 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5804 break;
5805 }
5806 if (pllen < 4) {
5807 /* INVALID FIELD IN CDB */
5808 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
5809 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5810 break;
5811 }
5812 #if 0
5813 istgt_dump("MODE SELECT(6)", lu_cmd->iobuf, pllen);
5814 #endif
5815 data = lu_cmd->iobuf;
5816 mdlen = data[0]; /* Mode Data Length */
5817 mt = data[1]; /* Medium Type */
5818 dsp = data[2]; /* Device-Specific Parameter */
5819 bdlen = data[3]; /* Block Descriptor Length */
5820
5821 /* Short LBA mode parameter block descriptor */
5822 /* data[4]-data[7] Number of Blocks */
5823 /* data[8]-data[11] Block Length */
5824
5825 /* page data */
5826 data_len = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[4 + bdlen], pllen - (4 + bdlen));
5827 if (data_len != 0) {
5828 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5829 break;
5830 }
5831 lu_cmd->data_len = pllen;
5832 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5833 break;
5834 }
5835
5836 case SPC_MODE_SELECT_10:
5837 #if 0
5838 istgt_scsi_dump_cdb(cdb);
5839 #endif
5840 {
5841 int pf, sp, pllen;
5842 int mdlen, mt, dsp, bdlen;
5843 int llba;
5844
5845 if (spec->rsv_key) {
5846 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
5847 if (rc != 0) {
5848 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
5849 break;
5850 }
5851 }
5852
5853 pf = BGET8(&cdb[1], 4);
5854 sp = BGET8(&cdb[1], 0);
5855 pllen = DGET16(&cdb[7]); /* Parameter List Length */
5856
5857 if (pllen == 0) {
5858 lu_cmd->data_len = 0;
5859 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5860 break;
5861 }
5862 /* Data-Out */
5863 rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
5864 lu_cmd->iobufsize, pllen);
5865 if (rc < 0) {
5866 ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
5867 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5868 break;
5869 }
5870 if (pllen < 4) {
5871 /* INVALID FIELD IN CDB */
5872 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
5873 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5874 break;
5875 }
5876 #if 0
5877 istgt_dump("MODE SELECT(10)", lu_cmd->iobuf, pllen);
5878 #endif
5879 data = lu_cmd->iobuf;
5880 mdlen = DGET16(&data[0]); /* Mode Data Length */
5881 mt = data[2]; /* Medium Type */
5882 dsp = data[3]; /* Device-Specific Parameter */
5883 llba = BGET8(&data[4], 0); /* Long LBA */
5884 bdlen = DGET16(&data[6]); /* Block Descriptor Length */
5885
5886 if (llba) {
5887 /* Long LBA mode parameter block descriptor */
5888 /* data[8]-data[15] Number of Blocks */
5889 /* data[16]-data[19] Reserved */
5890 /* data[20]-data[23] Block Length */
5891 } else {
5892 /* Short LBA mode parameter block descriptor */
5893 /* data[8]-data[11] Number of Blocks */
5894 /* data[12]-data[15] Block Length */
5895 }
5896
5897 /* page data */
5898 data_len = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[8 + bdlen], pllen - (8 + bdlen));
5899 if (data_len != 0) {
5900 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5901 break;
5902 }
5903 lu_cmd->data_len = pllen;
5904 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5905 break;
5906 }
5907
5908 case SPC_MODE_SENSE_6:
5909 #if 0
5910 istgt_scsi_dump_cdb(cdb);
5911 #endif
5912 {
5913 int dbd, pc, page, subpage;
5914
5915 if (spec->rsv_key) {
5916 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
5917 if (rc != 0) {
5918 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
5919 break;
5920 }
5921 }
5922
5923 if (lu_cmd->R_bit == 0) {
5924 ISTGT_ERRLOG("R_bit == 0\n");
5925 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5926 return -1;
5927 }
5928
5929 dbd = BGET8(&cdb[1], 3);
5930 pc = BGET8W(&cdb[2], 7, 2);
5931 page = BGET8W(&cdb[2], 5, 6);
5932 subpage = cdb[3];
5933
5934 allocation_len = cdb[4];
5935 if (allocation_len > (size_t) data_alloc_len) {
5936 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5937 data_alloc_len);
5938 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5939 return -1;
5940 }
5941 memset(data, 0, allocation_len);
5942
5943 data_len = istgt_lu_disk_scsi_mode_sense6(spec, conn, cdb, dbd, pc, page, subpage, data, data_alloc_len);
5944 if (data_len < 0) {
5945 /* INVALID FIELD IN CDB */
5946 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
5947 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5948 break;
5949 }
5950 #if 0
5951 istgt_dump("MODE SENSE(6)", data, data_len);
5952 #endif
5953 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
5954 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5955 break;
5956 }
5957
5958 case SPC_MODE_SENSE_10:
5959 #if 0
5960 istgt_scsi_dump_cdb(cdb);
5961 #endif
5962 {
5963 int dbd, pc, page, subpage;
5964 int llbaa;
5965
5966 if (spec->rsv_key) {
5967 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
5968 if (rc != 0) {
5969 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
5970 break;
5971 }
5972 }
5973
5974 if (lu_cmd->R_bit == 0) {
5975 ISTGT_ERRLOG("R_bit == 0\n");
5976 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5977 return -1;
5978 }
5979
5980 llbaa = BGET8(&cdb[1], 4);
5981 dbd = BGET8(&cdb[1], 3);
5982 pc = BGET8W(&cdb[2], 7, 2);
5983 page = BGET8W(&cdb[2], 5, 6);
5984 subpage = cdb[3];
5985
5986 allocation_len = DGET16(&cdb[7]);
5987 if (allocation_len > (size_t) data_alloc_len) {
5988 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5989 data_alloc_len);
5990 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5991 return -1;
5992 }
5993 memset(data, 0, allocation_len);
5994
5995 data_len = istgt_lu_disk_scsi_mode_sense10(spec, conn, cdb, llbaa, dbd, pc, page, subpage, data, data_alloc_len);
5996 if (data_len < 0) {
5997 /* INVALID FIELD IN CDB */
5998 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
5999 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6000 break;
6001 }
6002 #if 0
6003 istgt_dump("MODE SENSE(10)", data, data_len);
6004 #endif
6005 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
6006 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6007 break;
6008 }
6009
6010 case SPC_LOG_SELECT:
6011 case SPC_LOG_SENSE:
6012 /* INVALID COMMAND OPERATION CODE */
6013 BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6014 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6015 break;
6016
6017 case SPC_REQUEST_SENSE:
6018 {
6019 int desc;
6020 int sk, asc, ascq;
6021
6022 if (lu_cmd->R_bit == 0) {
6023 ISTGT_ERRLOG("R_bit == 0\n");
6024 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6025 return -1;
6026 }
6027
6028 desc = BGET8(&cdb[1], 0);
6029 if (desc != 0) {
6030 /* INVALID FIELD IN CDB */
6031 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6032 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6033 break;
6034 }
6035
6036 allocation_len = cdb[4];
6037 if (allocation_len > (size_t) data_alloc_len) {
6038 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
6039 data_alloc_len);
6040 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6041 return -1;
6042 }
6043 memset(data, 0, allocation_len);
6044
6045 if (!spec->sense) {
6046 /* NO ADDITIONAL SENSE INFORMATION */
6047 sk = ISTGT_SCSI_SENSE_NO_SENSE;
6048 asc = 0x00;
6049 ascq = 0x00;
6050 } else {
6051 sk = (spec->sense >> 16) & 0xffU;
6052 asc = (spec->sense >> 8) & 0xffU;
6053 ascq = spec->sense & 0xffU;
6054 }
6055 data_len = istgt_lu_disk_build_sense_data(spec, sense_data,
6056 sk, asc, ascq);
6057 if (data_len < 0 || data_len < 2) {
6058 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6059 break;
6060 }
6061 /* omit SenseLength */
6062 data_len -= 2;
6063 memcpy(data, sense_data + 2, data_len);
6064 #if 0
6065 istgt_dump("REQUEST SENSE", data, data_len);
6066 #endif
6067 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
6068 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6069 break;
6070 }
6071
6072 case SBC_READ_6:
6073 {
6074 if (spec->rsv_key) {
6075 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6076 if (rc != 0) {
6077 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6078 break;
6079 }
6080 }
6081
6082 if (lu_cmd->R_bit == 0) {
6083 ISTGT_ERRLOG("R_bit == 0\n");
6084 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6085 return -1;
6086 }
6087
6088 lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU);
6089 transfer_len = (uint32_t) DGET8(&cdb[4]);
6090 if (transfer_len == 0) {
6091 transfer_len = 256;
6092 }
6093 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6094 "READ_6(lba %"PRIu64", len %u blocks)\n",
6095 lba, transfer_len);
6096 rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
6097 if (rc < 0) {
6098 ISTGT_ERRLOG("lu_disk_lbread() failed\n");
6099 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6100 break;
6101 }
6102 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6103 break;
6104 }
6105
6106 case SBC_READ_10:
6107 {
6108 int dpo, fua, fua_nv;
6109
6110 if (spec->rsv_key) {
6111 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6112 if (rc != 0) {
6113 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6114 break;
6115 }
6116 }
6117
6118 if (lu_cmd->R_bit == 0) {
6119 ISTGT_ERRLOG("R_bit == 0\n");
6120 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6121 return -1;
6122 }
6123
6124 dpo = BGET8(&cdb[1], 4);
6125 fua = BGET8(&cdb[1], 3);
6126 fua_nv = BGET8(&cdb[1], 1);
6127 lba = (uint64_t) DGET32(&cdb[2]);
6128 transfer_len = (uint32_t) DGET16(&cdb[7]);
6129 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6130 "READ_10(lba %"PRIu64", len %u blocks)\n",
6131 lba, transfer_len);
6132 rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
6133 if (rc < 0) {
6134 ISTGT_ERRLOG("lu_disk_lbread() failed\n");
6135 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6136 break;
6137 }
6138 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6139 break;
6140 }
6141
6142 case SBC_READ_12:
6143 {
6144 int dpo, fua, fua_nv;
6145
6146 if (spec->rsv_key) {
6147 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6148 if (rc != 0) {
6149 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6150 break;
6151 }
6152 }
6153
6154 if (lu_cmd->R_bit == 0) {
6155 ISTGT_ERRLOG("R_bit == 0\n");
6156 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6157 return -1;
6158 }
6159
6160 dpo = BGET8(&cdb[1], 4);
6161 fua = BGET8(&cdb[1], 3);
6162 fua_nv = BGET8(&cdb[1], 1);
6163 lba = (uint64_t) DGET32(&cdb[2]);
6164 transfer_len = (uint32_t) DGET32(&cdb[6]);
6165 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6166 "READ_12(lba %"PRIu64", len %u blocks)\n",
6167 lba, transfer_len);
6168 rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
6169 if (rc < 0) {
6170 ISTGT_ERRLOG("lu_disk_lbread() failed\n");
6171 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6172 break;
6173 }
6174 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6175 break;
6176 }
6177
6178 case SBC_READ_16:
6179 {
6180 int dpo, fua, fua_nv;
6181
6182 if (spec->rsv_key) {
6183 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6184 if (rc != 0) {
6185 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6186 break;
6187 }
6188 }
6189
6190 if (lu_cmd->R_bit == 0) {
6191 ISTGT_ERRLOG("R_bit == 0\n");
6192 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6193 return -1;
6194 }
6195
6196 dpo = BGET8(&cdb[1], 4);
6197 fua = BGET8(&cdb[1], 3);
6198 fua_nv = BGET8(&cdb[1], 1);
6199 lba = (uint64_t) DGET64(&cdb[2]);
6200 transfer_len = (uint32_t) DGET32(&cdb[10]);
6201 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6202 "READ_16(lba %"PRIu64", len %u blocks)\n",
6203 lba, transfer_len);
6204 rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
6205 if (rc < 0) {
6206 ISTGT_ERRLOG("lu_disk_lbread() failed\n");
6207 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6208 break;
6209 }
6210 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6211 break;
6212 }
6213
6214 case SBC_WRITE_6:
6215 {
6216 if (spec->rsv_key) {
6217 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6218 if (rc != 0) {
6219 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6220 break;
6221 }
6222 }
6223
6224 if (lu_cmd->W_bit == 0) {
6225 ISTGT_ERRLOG("W_bit == 0\n");
6226 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6227 return -1;
6228 }
6229
6230 lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU);
6231 transfer_len = (uint32_t) DGET8(&cdb[4]);
6232 if (transfer_len == 0) {
6233 transfer_len = 256;
6234 }
6235 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6236 "WRITE_6(lba %"PRIu64", len %u blocks)\n",
6237 lba, transfer_len);
6238 rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
6239 if (rc < 0) {
6240 ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
6241 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6242 break;
6243 }
6244 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6245 break;
6246 }
6247
6248 case SBC_WRITE_10:
6249 case SBC_WRITE_AND_VERIFY_10:
6250 {
6251 int dpo, fua, fua_nv;
6252
6253 if (spec->rsv_key) {
6254 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6255 if (rc != 0) {
6256 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6257 break;
6258 }
6259 }
6260
6261 if (lu_cmd->W_bit == 0) {
6262 ISTGT_ERRLOG("W_bit == 0\n");
6263 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6264 return -1;
6265 }
6266
6267 dpo = BGET8(&cdb[1], 4);
6268 fua = BGET8(&cdb[1], 3);
6269 fua_nv = BGET8(&cdb[1], 1);
6270 lba = (uint64_t) DGET32(&cdb[2]);
6271 transfer_len = (uint32_t) DGET16(&cdb[7]);
6272 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6273 "WRITE_10(lba %"PRIu64", len %u blocks)\n",
6274 lba, transfer_len);
6275 rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
6276 if (rc < 0) {
6277 ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
6278 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6279 break;
6280 }
6281 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6282 break;
6283 }
6284
6285 case SBC_WRITE_12:
6286 case SBC_WRITE_AND_VERIFY_12:
6287 {
6288 int dpo, fua, fua_nv;
6289
6290 if (spec->rsv_key) {
6291 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6292 if (rc != 0) {
6293 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6294 break;
6295 }
6296 }
6297
6298 if (lu_cmd->W_bit == 0) {
6299 ISTGT_ERRLOG("W_bit == 0\n");
6300 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6301 return -1;
6302 }
6303
6304 dpo = BGET8(&cdb[1], 4);
6305 fua = BGET8(&cdb[1], 3);
6306 fua_nv = BGET8(&cdb[1], 1);
6307 lba = (uint64_t) DGET32(&cdb[2]);
6308 transfer_len = (uint32_t) DGET32(&cdb[6]);
6309 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6310 "WRITE_12(lba %"PRIu64", len %u blocks)\n",
6311 lba, transfer_len);
6312 rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
6313 if (rc < 0) {
6314 ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
6315 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6316 break;
6317 }
6318 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6319 break;
6320 }
6321
6322 case SBC_WRITE_16:
6323 case SBC_WRITE_AND_VERIFY_16:
6324 {
6325 int dpo, fua, fua_nv;
6326
6327 if (spec->rsv_key) {
6328 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6329 if (rc != 0) {
6330 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6331 break;
6332 }
6333 }
6334
6335 if (lu_cmd->W_bit == 0) {
6336 ISTGT_ERRLOG("W_bit == 0\n");
6337 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6338 return -1;
6339 }
6340
6341 dpo = BGET8(&cdb[1], 4);
6342 fua = BGET8(&cdb[1], 3);
6343 fua_nv = BGET8(&cdb[1], 1);
6344 lba = (uint64_t) DGET64(&cdb[2]);
6345 transfer_len = (uint32_t) DGET32(&cdb[10]);
6346 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6347 "WRITE_16(lba %"PRIu64", len %u blocks)\n",
6348 lba, transfer_len);
6349 rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
6350 if (rc < 0) {
6351 ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
6352 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6353 break;
6354 }
6355 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6356 break;
6357 }
6358
6359 case SBC_VERIFY_10:
6360 {
6361 int dpo, bytchk;
6362
6363 if (spec->rsv_key) {
6364 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6365 if (rc != 0) {
6366 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6367 break;
6368 }
6369 }
6370
6371 dpo = BGET8(&cdb[1], 4);
6372 bytchk = BGET8(&cdb[1], 1);
6373 lba = (uint64_t) DGET32(&cdb[2]);
6374 len = (uint32_t) DGET16(&cdb[7]);
6375 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6376 "VERIFY_10(lba %"PRIu64", len %u blocks)\n",
6377 lba, len);
6378 lu_cmd->data_len = 0;
6379 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6380 break;
6381 }
6382
6383 case SBC_VERIFY_12:
6384 {
6385 int dpo, bytchk;
6386
6387 if (spec->rsv_key) {
6388 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6389 if (rc != 0) {
6390 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6391 break;
6392 }
6393 }
6394
6395 dpo = BGET8(&cdb[1], 4);
6396 bytchk = BGET8(&cdb[1], 1);
6397 lba = (uint64_t) DGET32(&cdb[2]);
6398 len = (uint32_t) DGET32(&cdb[6]);
6399 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6400 "VERIFY_12(lba %"PRIu64", len %u blocks)\n",
6401 lba, len);
6402 lu_cmd->data_len = 0;
6403 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6404 break;
6405 }
6406
6407 case SBC_VERIFY_16:
6408 {
6409 int dpo, bytchk;
6410
6411 if (spec->rsv_key) {
6412 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6413 if (rc != 0) {
6414 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6415 break;
6416 }
6417 }
6418
6419 dpo = BGET8(&cdb[1], 4);
6420 bytchk = BGET8(&cdb[1], 1);
6421 lba = (uint64_t) DGET64(&cdb[2]);
6422 len = (uint32_t) DGET32(&cdb[10]);
6423 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6424 "VERIFY_16(lba %"PRIu64", len %u blocks)\n",
6425 lba, len);
6426 lu_cmd->data_len = 0;
6427 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6428 break;
6429 }
6430
6431 case SBC_WRITE_SAME_10:
6432 {
6433 int wprotect, pbdata, lbdata, group_no;
6434
6435 if (spec->rsv_key) {
6436 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6437 if (rc != 0) {
6438 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6439 break;
6440 }
6441 }
6442
6443 if (lu_cmd->W_bit == 0) {
6444 ISTGT_ERRLOG("W_bit == 0\n");
6445 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6446 return -1;
6447 }
6448
6449 wprotect = BGET8W(&cdb[1], 7, 3);
6450 pbdata = BGET8(&cdb[1], 2);
6451 lbdata = BGET8(&cdb[1], 1);
6452 lba = (uint64_t) DGET32(&cdb[2]);
6453 transfer_len = (uint32_t) DGET16(&cdb[7]);
6454 group_no = BGET8W(&cdb[6], 4, 5);
6455
6456 /* only PBDATA=0 and LBDATA=0 support */
6457 if (pbdata || lbdata) {
6458 /* INVALID FIELD IN CDB */
6459 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6460 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6461 break;
6462 }
6463
6464 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6465 "WRITE_SAME_10(lba %"PRIu64", len %u blocks)\n",
6466 lba, transfer_len);
6467 rc = istgt_lu_disk_lbwrite_same(spec, conn, lu_cmd, lba, transfer_len);
6468 if (rc < 0) {
6469 ISTGT_ERRLOG("lu_disk_lbwrite_same() failed\n");
6470 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6471 break;
6472 }
6473 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6474 break;
6475 }
6476
6477 case SBC_WRITE_SAME_16:
6478 {
6479 int wprotect, anchor, unmap, pbdata, lbdata, group_no;
6480
6481 #if 0
6482 istgt_scsi_dump_cdb(cdb);
6483 #endif
6484 if (spec->rsv_key) {
6485 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6486 if (rc != 0) {
6487 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6488 break;
6489 }
6490 }
6491
6492 if (lu_cmd->W_bit == 0) {
6493 ISTGT_ERRLOG("W_bit == 0\n");
6494 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6495 return -1;
6496 }
6497
6498 wprotect = BGET8W(&cdb[1], 7, 3);
6499 anchor = BGET8(&cdb[1], 4);
6500 unmap = BGET8(&cdb[1], 3);
6501 pbdata = BGET8(&cdb[1], 2);
6502 lbdata = BGET8(&cdb[1], 1);
6503 lba = (uint64_t) DGET64(&cdb[2]);
6504 transfer_len = (uint32_t) DGET32(&cdb[10]);
6505 group_no = BGET8W(&cdb[14], 4, 5);
6506
6507 /* only PBDATA=0 and LBDATA=0 support */
6508 if (pbdata || lbdata) {
6509 /* INVALID FIELD IN CDB */
6510 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6511 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6512 break;
6513 }
6514 if (anchor) {
6515 /* INVALID FIELD IN CDB */
6516 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6517 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6518 break;
6519 }
6520
6521 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6522 "WRITE_SAME_16(lba %"PRIu64", len %u blocks)\n",
6523 lba, transfer_len);
6524 rc = istgt_lu_disk_lbwrite_same(spec, conn, lu_cmd, lba, transfer_len);
6525 if (rc < 0) {
6526 ISTGT_ERRLOG("lu_disk_lbwrite_same() failed\n");
6527 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6528 break;
6529 }
6530 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6531 break;
6532 }
6533
6534 case SBC_COMPARE_AND_WRITE:
6535 {
6536 int64_t maxlen;
6537 int wprotect, dpo, fua, fua_nv, group_no;
6538
6539 #if 0
6540 istgt_scsi_dump_cdb(cdb);
6541 #endif
6542 if (spec->lu->istgt->swmode == ISTGT_SWMODE_TRADITIONAL) {
6543 /* INVALID COMMAND OPERATION CODE */
6544 BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6545 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6546 break;
6547 }
6548 if (spec->rsv_key) {
6549 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6550 if (rc != 0) {
6551 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6552 break;
6553 }
6554 }
6555
6556 if (lu_cmd->W_bit == 0) {
6557 ISTGT_ERRLOG("W_bit == 0\n");
6558 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6559 return -1;
6560 }
6561
6562 wprotect = BGET8W(&cdb[1], 7, 3);
6563 dpo = BGET8(&cdb[1], 4);
6564 fua = BGET8(&cdb[1], 3);
6565 fua_nv = BGET8(&cdb[1], 1);
6566 lba = (uint64_t) DGET64(&cdb[2]);
6567 transfer_len = (uint32_t) DGET8(&cdb[13]);
6568 group_no = BGET8W(&cdb[14], 4, 5);
6569
6570 maxlen = ISTGT_LU_WORK_ATS_BLOCK_SIZE / spec->blocklen;
6571 if (maxlen > 0xff) {
6572 maxlen = 0xff;
6573 }
6574 if (transfer_len > maxlen) {
6575 /* INVALID FIELD IN CDB */
6576 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6577 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6578 break;
6579 }
6580
6581 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6582 "COMPARE_AND_WRITE(lba %"PRIu64", len %u blocks)\n",
6583 lba, transfer_len);
6584 rc = istgt_lu_disk_lbwrite_ats(spec, conn, lu_cmd, lba, transfer_len);
6585 if (rc < 0) {
6586 //ISTGT_ERRLOG("lu_disk_lbwrite_ats() failed\n");
6587 /* sense data build by function */
6588 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6589 break;
6590 }
6591 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6592 break;
6593 }
6594
6595 case SBC_SYNCHRONIZE_CACHE_10:
6596 {
6597 int sync_nv, immed;
6598
6599 if (spec->rsv_key) {
6600 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6601 if (rc != 0) {
6602 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6603 break;
6604 }
6605 }
6606
6607 sync_nv = BGET8(&cdb[1], 2);
6608 immed = BGET8(&cdb[1], 1);
6609 lba = (uint64_t) DGET32(&cdb[2]);
6610 len = (uint32_t) DGET16(&cdb[7]);
6611 if (len == 0) {
6612 len = spec->blockcnt;
6613 }
6614 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6615 "SYNCHRONIZE_CACHE_10(lba %"PRIu64
6616 ", len %u blocks)\n",
6617 lba, len);
6618 rc = istgt_lu_disk_lbsync(spec, conn, lu_cmd, lba, len);
6619 if (rc < 0) {
6620 ISTGT_ERRLOG("lu_disk_lbsync() failed\n");
6621 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6622 break;
6623 }
6624 lu_cmd->data_len = 0;
6625 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6626 break;
6627 }
6628
6629 case SBC_SYNCHRONIZE_CACHE_16:
6630 {
6631 int sync_nv, immed;
6632
6633 if (spec->rsv_key) {
6634 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6635 if (rc != 0) {
6636 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6637 break;
6638 }
6639 }
6640
6641 sync_nv = BGET8(&cdb[1], 2);
6642 immed = BGET8(&cdb[1], 1);
6643 lba = (uint64_t) DGET64(&cdb[2]);
6644 len = (uint32_t) DGET32(&cdb[10]);
6645 if (len == 0) {
6646 len = spec->blockcnt;
6647 }
6648 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6649 "SYNCHRONIZE_CACHE_16(lba %"PRIu64
6650 ", len %u blocks)\n",
6651 lba, len);
6652 rc = istgt_lu_disk_lbsync(spec, conn, lu_cmd, lba, len);
6653 if (rc < 0) {
6654 ISTGT_ERRLOG("lu_disk_lbsync() failed\n");
6655 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6656 break;
6657 }
6658 lu_cmd->data_len = 0;
6659 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6660 break;
6661 }
6662
6663 case SBC_READ_DEFECT_DATA_10:
6664 {
6665 int req_plist, req_glist, list_format;
6666
6667 if (lu_cmd->R_bit == 0) {
6668 ISTGT_ERRLOG("R_bit == 0\n");
6669 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6670 return -1;
6671 }
6672
6673 req_plist = BGET8(&cdb[2], 4);
6674 req_glist = BGET8(&cdb[2], 3);
6675 list_format = BGET8W(&cdb[2], 2, 3);
6676
6677 allocation_len = (uint32_t) DGET16(&cdb[7]);
6678 if (allocation_len > (size_t) data_alloc_len) {
6679 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
6680 data_alloc_len);
6681 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6682 return -1;
6683 }
6684 memset(data, 0, allocation_len);
6685
6686 data_len = istgt_lu_disk_scsi_read_defect10(spec, conn, cdb,
6687 req_plist, req_glist, list_format, data, data_alloc_len);
6688 if (data_len < 0) {
6689 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6690 break;
6691 }
6692 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
6693 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6694 break;
6695 }
6696
6697 case SBC_READ_DEFECT_DATA_12:
6698 {
6699 int req_plist, req_glist, list_format;
6700
6701 if (lu_cmd->R_bit == 0) {
6702 ISTGT_ERRLOG("R_bit == 0\n");
6703 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6704 return -1;
6705 }
6706
6707 req_plist = BGET8(&cdb[2], 4);
6708 req_glist = BGET8(&cdb[2], 3);
6709 list_format = BGET8W(&cdb[2], 2, 3);
6710
6711 allocation_len = DGET32(&cdb[6]);
6712 if (allocation_len > (size_t) data_alloc_len) {
6713 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
6714 data_alloc_len);
6715 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6716 return -1;
6717 }
6718 memset(data, 0, allocation_len);
6719
6720 data_len = istgt_lu_disk_scsi_read_defect12(spec, conn, cdb,
6721 req_plist, req_glist, list_format, data, data_alloc_len);
6722 if (data_len < 0) {
6723 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6724 break;
6725 }
6726 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
6727 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6728 break;
6729 }
6730
6731 case SCC_MAINTENANCE_IN:
6732 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MAINTENANCE_IN\n");
6733 switch (BGET8W(&cdb[1], 4, 5)) { /* SERVICE ACTION */
6734 case SPC_MI_REPORT_TARGET_PORT_GROUPS:
6735 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT_TARGET_PORT_GROUPS\n");
6736 if (lu_cmd->R_bit == 0) {
6737 ISTGT_ERRLOG("R_bit == 0\n");
6738 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6739 return -1;
6740 }
6741 allocation_len = DGET32(&cdb[6]);
6742 if (allocation_len > (size_t) data_alloc_len) {
6743 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
6744 data_alloc_len);
6745 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6746 return -1;
6747 }
6748 memset(data, 0, allocation_len);
6749 data_len = istgt_lu_disk_scsi_report_target_port_groups(spec, conn, cdb, data, data_alloc_len);
6750 if (data_len < 0) {
6751 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6752 break;
6753 }
6754 ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
6755 "REPORT_TARGET_PORT_GROUPS", data, data_len);
6756 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
6757 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6758 break;
6759 default:
6760 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "SA=0x%2.2x\n",
6761 BGET8W(&cdb[1], 4, 5));
6762 /* INVALID COMMAND OPERATION CODE */
6763 BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6764 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6765 break;
6766 }
6767 break;
6768
6769 case SCC_MAINTENANCE_OUT:
6770 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MAINTENANCE_OUT\n");
6771 switch (BGET8W(&cdb[1], 4, 5)) { /* SERVICE ACTION */
6772 case SPC_MO_SET_TARGET_PORT_GROUPS:
6773 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SET_TARGET_PORT_GROUPS\n");
6774 if (spec->rsv_key) {
6775 rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6776 if (rc != 0) {
6777 lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6778 break;
6779 }
6780 }
6781 if (lu_cmd->W_bit == 0) {
6782 ISTGT_ERRLOG("W_bit == 0\n");
6783 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6784 return -1;
6785 }
6786 parameter_len = DGET32(&cdb[6]);
6787 if (parameter_len == 0) {
6788 lu_cmd->data_len = 0;
6789 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6790 break;
6791 }
6792 /* Data-Out */
6793 rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
6794 lu_cmd->iobufsize, parameter_len);
6795 if (rc < 0) {
6796 ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
6797 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6798 break;
6799 }
6800 if (parameter_len < 4) {
6801 /* INVALID FIELD IN CDB */
6802 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6803 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6804 break;
6805 }
6806 ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
6807 "SET_TARGET_PORT_GROUPS",
6808 lu_cmd->iobuf, parameter_len);
6809 data = lu_cmd->iobuf;
6810 /* data[0]-data[3] Reserved */
6811 /* Set target port group descriptor(s) */
6812 data_len = istgt_lu_disk_scsi_set_target_port_groups(spec, conn, cdb, &data[4], parameter_len - 4);
6813 if (data_len < 0) {
6814 /* INVALID FIELD IN PARAMETER LIST */
6815 BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
6816 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6817 break;
6818 }
6819 lu_cmd->data_len = parameter_len;
6820 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6821 break;
6822 default:
6823 ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "SA=0x%2.2x\n",
6824 BGET8W(&cdb[1], 4, 5));
6825 /* INVALID COMMAND OPERATION CODE */
6826 BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6827 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6828 break;
6829 }
6830 break;
6831
6832 case SPC_PERSISTENT_RESERVE_IN:
6833 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PERSISTENT_RESERVE_IN\n");
6834 {
6835 int sa;
6836
6837 if (lu_cmd->R_bit == 0) {
6838 ISTGT_ERRLOG("R_bit == 0\n");
6839 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6840 return -1;
6841 }
6842
6843 sa = BGET8W(&cdb[1], 4, 5);
6844 allocation_len = DGET16(&cdb[7]);
6845 if (allocation_len > (size_t) data_alloc_len) {
6846 ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
6847 data_alloc_len);
6848 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6849 return -1;
6850 }
6851 memset(data, 0, allocation_len);
6852
6853 data_len = istgt_lu_disk_scsi_persistent_reserve_in(spec, conn, lu_cmd, sa, data, allocation_len);
6854 if (data_len < 0) {
6855 /* status build by function */
6856 break;
6857 }
6858 ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
6859 "PERSISTENT_RESERVE_IN", data, data_len);
6860 lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
6861 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6862 }
6863 break;
6864
6865 case SPC_PERSISTENT_RESERVE_OUT:
6866 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PERSISTENT_RESERVE_OUT\n");
6867 {
6868 int sa, scope, type;
6869
6870 if (lu_cmd->W_bit == 0) {
6871 ISTGT_ERRLOG("W_bit == 0\n");
6872 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6873 return -1;
6874 }
6875
6876 sa = BGET8W(&cdb[1], 4, 5);
6877 scope = BGET8W(&cdb[2], 7, 4);
6878 type = BGET8W(&cdb[2], 3, 4);
6879 parameter_len = DGET32(&cdb[5]);
6880
6881 /* Data-Out */
6882 rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
6883 lu_cmd->iobufsize, parameter_len);
6884 if (rc < 0) {
6885 ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
6886 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6887 break;
6888 }
6889 if (parameter_len < 24) {
6890 /* INVALID FIELD IN CDB */
6891 BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6892 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6893 break;
6894 }
6895
6896 ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
6897 "PERSISTENT_RESERVE_OUT",
6898 lu_cmd->iobuf, parameter_len);
6899 data = lu_cmd->iobuf;
6900
6901 data_len = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, lu_cmd, sa, scope, type, &data[0], parameter_len);
6902 if (data_len < 0) {
6903 /* status build by function */
6904 break;
6905 }
6906 lu_cmd->data_len = parameter_len;
6907 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6908 }
6909 break;
6910
6911 /* XXX TODO: fix */
6912 case 0x85: /* ATA PASS-THROUGH(16) */
6913 case 0xA1: /* ATA PASS-THROUGH(12) */
6914 /* INVALID COMMAND OPERATION CODE */
6915 BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6916 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6917 break;
6918 case SPC_EXTENDED_COPY:
6919 /* INVALID COMMAND OPERATION CODE */
6920 BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6921 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6922 break;
6923 case SPC2_RELEASE_6:
6924 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_6\n");
6925 rc = istgt_lu_disk_scsi_release(spec, conn, lu_cmd);
6926 if (rc < 0) {
6927 /* build by function */
6928 break;
6929 }
6930 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6931 break;
6932 case SPC2_RELEASE_10:
6933 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_10\n");
6934 rc = istgt_lu_disk_scsi_release(spec, conn, lu_cmd);
6935 if (rc < 0) {
6936 /* build by function */
6937 break;
6938 }
6939 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6940 break;
6941 case SPC2_RESERVE_6:
6942 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_6\n");
6943 rc = istgt_lu_disk_scsi_reserve(spec, conn, lu_cmd);
6944 if (rc < 0) {
6945 /* build by function */
6946 break;
6947 }
6948 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6949 break;
6950 case SPC2_RESERVE_10:
6951 ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_10\n");
6952 rc = istgt_lu_disk_scsi_reserve(spec, conn, lu_cmd);
6953 if (rc < 0) {
6954 /* build by function */
6955 break;
6956 }
6957 lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6958 break;
6959
6960 default:
6961 ISTGT_ERRLOG("unsupported SCSI OP=0x%x\n", cdb[0]);
6962 /* INVALID COMMAND OPERATION CODE */
6963 BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6964 lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6965 break;
6966 }
6967
6968 ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6969 "SCSI OP=0x%x, LUN=0x%16.16"PRIx64" status=0x%x,"
6970 " complete\n",
6971 cdb[0], lu_cmd->lun, lu_cmd->status);
6972 return 0;
6973 }
6974