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