Annotation of embedaddon/istgt/src/istgt_lu_disk.c, revision 1.1.1.3
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 */
1.1.1.3 ! misho 1867: if (pc == 0x01) {
! 1868: // Changeable values
! 1869: BDADD8(&cp[2], 1, 2); /* WCE */
! 1870: BDADD8(&cp[2], 1, 0); /* RCD */
! 1871: len += plen;
! 1872: break;
! 1873: }
1.1 misho 1874: BDADD8(&cp[2], 1, 2); /* WCE */
1875: //BDADD8(&cp[2], 1, 0); /* RCD */
1876: {
1877: int fd;
1878: fd = spec->fd;
1879: rc = fcntl(fd , F_GETFL, 0);
1880: if (rc != -1 && !(rc & O_FSYNC)) {
1881: BDADD8(&cp[2], 1, 2); /* WCE=1 */
1882: } else {
1883: BDADD8(&cp[2], 0, 2); /* WCE=0 */
1884: }
1885: }
1886: if (spec->read_cache == 0) {
1887: BDADD8(&cp[2], 1, 0); /* RCD=1 */
1888: } else {
1889: BDADD8(&cp[2], 0, 0); /* RCD=0 */
1890: }
1891: len += plen;
1892: break;
1893: case 0x09:
1894: /* Obsolete */
1895: break;
1896: case 0x0a:
1897: switch (subpage) {
1898: case 0x00:
1899: /* Control */
1900: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Control\n");
1901: plen = 0x0a + 2;
1902: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1903: len += plen;
1904: break;
1905: case 0x01:
1906: /* Control Extension */
1907: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Control Extension\n");
1908: plen = 0x1c + 4;
1909: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1910: len += plen;
1911: break;
1912: case 0xff:
1913: /* All subpages */
1914: len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, 0x00, &data[len], alloc_len);
1915: len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, 0x01, &data[len], alloc_len);
1916: break;
1917: default:
1918: /* 0x02-0x3e: Reserved */
1919: break;
1920: }
1921: break;
1922: case 0x0b:
1923: /* Obsolete (Medium Types Supported) */
1924: break;
1925: case 0x0c:
1926: /* Obsolete (Notch And Partitio) */
1927: break;
1928: case 0x0d:
1929: /* Obsolete */
1930: break;
1931: case 0x0e:
1932: case 0x0f:
1933: /* Reserved */
1934: break;
1935: case 0x10:
1936: /* XOR Control */
1937: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE XOR Control\n");
1938: if (subpage != 0x00)
1939: break;
1940: plen = 0x16 + 2;
1941: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1942: len += plen;
1943: break;
1944: case 0x11:
1945: case 0x12:
1946: case 0x13:
1947: /* Reserved */
1948: break;
1949: case 0x14:
1950: /* Enclosure Services Management */
1951: break;
1952: case 0x15:
1953: case 0x16:
1954: case 0x17:
1955: /* Reserved */
1956: break;
1957: case 0x18:
1958: /* Protocol-Specific LUN */
1959: #if 0
1960: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Protocol-Specific LUN\n");
1961: if (subpage != 0x00)
1962: break;
1963: plen = 0x04 + 0x00 + 2;
1964: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1965: len += plen;
1966: #endif
1967: break;
1968: case 0x19:
1969: /* Protocol-Specific Port */
1970: #if 0
1971: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Protocol-Specific Port\n");
1972: if (subpage != 0x00)
1973: break;
1974: plen = 0x04 + 0x00 + 2;
1975: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1976: len += plen;
1977: #endif
1978: break;
1979: case 0x1a:
1980: /* Power Condition */
1981: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Power Condition\n");
1982: if (subpage != 0x00)
1983: break;
1984: plen = 0x0a + 2;
1985: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1986: len += plen;
1987: break;
1988: case 0x1b:
1989: /* Reserved */
1990: break;
1991: case 0x1c:
1992: /* Informational Exceptions Control */
1993: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Informational Exceptions Control\n");
1994: if (subpage != 0x00)
1995: break;
1996:
1997: plen = 0x0a + 2;
1998: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1999: len += plen;
2000: break;
2001: case 0x1d:
2002: case 0x1e:
2003: case 0x1f:
2004: /* Reserved */
2005: break;
2006: case 0x20:
2007: case 0x21:
2008: case 0x22:
2009: case 0x23:
2010: case 0x24:
2011: case 0x25:
2012: case 0x26:
2013: case 0x27:
2014: case 0x28:
2015: case 0x29:
2016: case 0x2a:
2017: case 0x2b:
2018: case 0x2c:
2019: case 0x2d:
2020: case 0x2e:
2021: case 0x2f:
2022: case 0x30:
2023: case 0x31:
2024: case 0x32:
2025: case 0x33:
2026: case 0x34:
2027: case 0x35:
2028: case 0x36:
2029: case 0x37:
2030: case 0x38:
2031: case 0x39:
2032: case 0x3a:
2033: case 0x3b:
2034: case 0x3c:
2035: case 0x3d:
2036: case 0x3e:
2037: /* Vendor-specific */
2038: break;
2039: case 0x3f:
2040: switch (subpage) {
2041: case 0x00:
2042: /* All mode pages */
2043: for (i = 0x00; i < 0x3e; i ++) {
2044: len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
2045: }
2046: break;
2047: case 0xff:
2048: /* All mode pages and subpages */
2049: for (i = 0x00; i < 0x3e; i ++) {
2050: len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
2051: }
2052: for (i = 0x00; i < 0x3e; i ++) {
2053: len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0xff, &cp[len], alloc_len);
2054: }
2055: break;
2056: default:
2057: /* 0x01-0x3e: Reserved */
2058: break;
2059: }
2060: }
2061:
2062: return len;
2063: }
2064:
2065: static int
2066: 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)
2067: {
2068: uint8_t *cp;
2069: int hlen = 0, len = 0, plen;
2070: int total;
2071: int llbaa = 0;
2072:
2073: data[0] = 0; /* Mode Data Length */
2074: data[1] = 0; /* Medium Type */
2075: data[2] = 0; /* Device-Specific Parameter */
2076: if (spec->lu->readonly) {
2077: BDADD8(&data[2], 1, 7); /* WP */
2078: }
2079: data[3] = 0; /* Block Descripter Length */
2080: hlen = 4;
2081:
2082: cp = &data[4];
2083: if (dbd) { /* Disable Block Descripters */
2084: len = 0;
2085: } else {
2086: if (llbaa) {
2087: /* Number of Blocks */
2088: DSET64(&cp[0], spec->blockcnt);
2089: /* Reserved */
2090: DSET32(&cp[8], 0);
2091: /* Block Length */
2092: DSET32(&cp[12], (uint32_t) spec->blocklen);
2093: len = 16;
2094: } else {
2095: /* Number of Blocks */
2096: if (spec->blockcnt > 0xffffffffULL) {
2097: DSET32(&cp[0], 0xffffffffUL);
2098: } else {
2099: DSET32(&cp[0], (uint32_t) spec->blockcnt);
2100: }
2101: /* Block Length */
2102: DSET32(&cp[4], (uint32_t) spec->blocklen);
2103: len = 8;
2104: }
2105: cp += len;
2106: }
2107: data[3] = len; /* Block Descripter Length */
2108:
2109: plen = istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
1.1.1.2 misho 2110: if (plen < 0) {
2111: return -1;
2112: }
1.1 misho 2113: cp += plen;
2114:
2115: total = hlen + len + plen;
2116: data[0] = total - 1; /* Mode Data Length */
2117:
2118: return total;
2119: }
2120:
2121: static int
2122: 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)
2123: {
2124: uint8_t *cp;
2125: int hlen = 0, len = 0, plen;
2126: int total;
2127:
2128: DSET16(&data[0], 0); /* Mode Data Length */
2129: data[2] = 0; /* Medium Type */
2130: data[3] = 0; /* Device-Specific Parameter */
2131: if (spec->lu->readonly) {
2132: BDADD8(&data[3], 1, 7); /* WP */
2133: }
2134: if (llbaa) {
2135: BDSET8(&data[4], 1, 1); /* Long LBA */
2136: } else {
2137: BDSET8(&data[4], 0, 1); /* Short LBA */
2138: }
2139: data[5] = 0; /* Reserved */
2140: DSET16(&data[6], 0); /* Block Descripter Length */
2141: hlen = 8;
2142:
2143: cp = &data[8];
2144: if (dbd) { /* Disable Block Descripters */
2145: len = 0;
2146: } else {
2147: if (llbaa) {
2148: /* Number of Blocks */
2149: DSET64(&cp[0], spec->blockcnt);
2150: /* Reserved */
2151: DSET32(&cp[8], 0);
2152: /* Block Length */
2153: DSET32(&cp[12], (uint32_t) spec->blocklen);
2154: len = 16;
2155: } else {
2156: /* Number of Blocks */
2157: if (spec->blockcnt > 0xffffffffULL) {
2158: DSET32(&cp[0], 0xffffffffUL);
2159: } else {
2160: DSET32(&cp[0], (uint32_t) spec->blockcnt);
2161: }
2162: /* Block Length */
2163: DSET32(&cp[4], (uint32_t) spec->blocklen);
2164: len = 8;
2165: }
2166: cp += len;
2167: }
2168: DSET16(&data[6], len); /* Block Descripter Length */
2169:
2170: plen = istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
1.1.1.2 misho 2171: if (plen < 0) {
2172: return -1;
2173: }
1.1 misho 2174: cp += plen;
2175:
2176: total = hlen + len + plen;
2177: DSET16(&data[0], total - 2); /* Mode Data Length */
2178:
2179: return total;
2180: }
2181:
2182: static int
2183: istgt_lu_disk_transfer_data(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *buf, size_t bufsize, size_t len)
2184: {
2185: int rc;
2186:
2187: if (lu_cmd->lu->queue_depth == 0) {
2188: if (len > bufsize) {
1.1.1.2 misho 2189: ISTGT_ERRLOG("bufsize(%zd) too small\n", bufsize);
1.1 misho 2190: return -1;
2191: }
2192: rc = istgt_iscsi_transfer_out(conn, lu_cmd, buf, bufsize, len);
2193: if (rc < 0) {
2194: ISTGT_ERRLOG("iscsi_transfer_out()\n");
2195: return -1;
2196: }
2197: }
2198: return 0;
2199: }
2200:
2201: static int
2202: 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)
2203: {
1.1.1.2 misho 2204: size_t hlen, plen;
1.1 misho 2205: int ps, spf, page, subpage;
2206: int rc;
2207:
2208: if (pf == 0) {
2209: /* vendor specific */
2210: return 0;
2211: }
2212:
2213: if (len < 1)
2214: return 0;
2215: ps = BGET8(&data[0], 7);
2216: spf = BGET8(&data[0], 6);
2217: page = data[0] & 0x3f;
2218: if (spf) {
2219: /* Sub_page mode page format */
2220: hlen = 4;
2221: if (len < hlen)
2222: return 0;
2223: subpage = data[1];
2224:
2225: plen = DGET16(&data[2]);
2226: } else {
2227: /* Page_0 mode page format */
2228: hlen = 2;
2229: if (len < hlen)
2230: return 0;
2231: subpage = 0;
2232: plen = data[1];
2233: }
2234: plen += hlen;
2235: if (len < plen)
2236: return 0;
2237:
2238: #if 0
2239: printf("ps=%d, page=%2.2x, subpage=%2.2x\n", ps, page, subpage);
2240: #endif
2241: switch (page) {
2242: case 0x08:
2243: /* Caching */
2244: {
2245: int wce, rcd;
2246:
2247: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Caching\n");
2248: if (subpage != 0x00)
2249: break;
2250: if (plen != 0x12 + hlen) {
2251: /* unknown format */
2252: break;
2253: }
2254: wce = BGET8(&data[2], 2); /* WCE */
2255: rcd = BGET8(&data[2], 0); /* RCD */
2256:
2257: {
2258: int fd;
2259: fd = spec->fd;
2260: rc = fcntl(fd , F_GETFL, 0);
2261: if (rc != -1) {
2262: if (wce) {
2263: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Writeback cache enable\n");
2264: rc = fcntl(fd, F_SETFL, (rc & ~O_FSYNC));
2265: spec->write_cache = 1;
2266: } else {
2267: rc = fcntl(fd, F_SETFL, (rc | O_FSYNC));
2268: spec->write_cache = 0;
2269: }
2270: if (rc == -1) {
2271: /* XXX */
2272: //ISTGT_ERRLOG("fcntl(F_SETFL) failed\n");
2273: }
2274: }
2275: }
2276: if (rcd) {
2277: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Read cache disable\n");
2278: spec->read_cache = 0;
2279: } else {
2280: spec->read_cache = 1;
2281: }
2282: }
2283: break;
2284: default:
2285: /* not supported */
2286: break;
2287: }
2288:
2289: len -= plen;
2290: if (len != 0) {
2291: rc = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[plen], len);
2292: if (rc < 0) {
2293: return rc;
2294: }
2295: }
2296: return 0;
2297: }
2298:
1.1.1.2 misho 2299: static int
2300: 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)
2301: {
2302: uint8_t *cp;
2303: int hlen = 0, len = 0;
2304: int total;
2305:
2306: if (alloc_len < 4) {
2307: return -1;
2308: }
2309:
2310: data[0] = 0; /* Reserved */
2311: data[1] = 0;
2312: if (req_plist) {
2313: BDADD8(&data[1], 1, 4); /* PLISTV */
2314: }
2315: if (req_glist) {
2316: BDADD8(&data[1], 1, 3); /* GLISTV */
2317: }
2318: BDADD8W(&data[1], list_format, 2, 3); /* DEFECT LIST FORMAT */
2319: DSET16(&data[2], 0); /* DEFECT LIST LENGTH */
2320: hlen = 4;
2321:
2322: cp = &data[4];
2323: /* defect list (if any) */
2324: len = 0;
2325:
2326: total = hlen + len;
2327: DSET16(&data[2], total - hlen); /* DEFECT LIST LENGTH */
2328: return total;
2329: }
2330:
2331: static int
2332: 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)
2333: {
2334: uint8_t *cp;
2335: int hlen = 0, len = 0;
2336: int total;
2337:
2338: if (alloc_len < 8) {
2339: return -1;
2340: }
2341:
2342: data[0] = 0; /* Reserved */
2343: data[1] = 0;
2344: if (req_plist) {
2345: BDADD8(&data[1], 1, 4); /* PLISTV */
2346: }
2347: if (req_glist) {
2348: BDADD8(&data[1], 1, 3); /* GLISTV */
2349: }
2350: BDADD8W(&data[1], list_format, 2, 3); /* DEFECT LIST FORMAT */
2351: data[2] = 0; /* Reserved */
2352: data[3] = 0; /* Reserved */
2353: DSET32(&data[4], 0); /* DEFECT LIST LENGTH */
2354: hlen = 8;
2355:
2356: cp = &data[8];
2357: /* defect list (if any) */
2358: len = 0;
2359:
2360: total = hlen + len;
2361: DSET32(&data[4], total - hlen); /* DEFECT LIST LENGTH */
2362: return total;
2363: }
2364:
1.1 misho 2365: #if 0
2366: static int
2367: istgt_lu_disk_scsi_request_sense(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int desc, uint8_t *data, int alloc_len)
2368: {
2369: int len = 0, plen;
2370:
2371: if (alloc_len < 18) {
2372: ISTGT_ERRLOG("alloc_len(%d) too small\n", alloc_len);
2373: return -1;
2374: }
2375:
2376: /* XXX TODO: fix */
2377: if (desc == 0) {
2378: /* fixed format */
2379: /* NO ADDITIONAL SENSE INFORMATION */
2380: /* BUILD_SENSE(NO_SENSE, 0x00, 0x00); */
2381:
2382: /* VALID(7) RESPONSE CODE(6-0) */
2383: BDSET8(&data[0], 0, 7);
2384: BDADD8W(&data[0], 0x70, 6, 7);
2385: /* Obsolete */
2386: data[1] = 0;
2387: /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
2388: BDSET8W(&data[2], ISTGT_SCSI_SENSE_NO_SENSE, 3, 4);
2389: /* INFORMATION */
2390: memset(&data[3], 0, 4);
2391: /* ADDITIONAL SENSE LENGTH */
2392: data[7] = 0;
2393: len = 8;
2394:
2395: /* COMMAND-SPECIFIC INFORMATION */
2396: memset(&data[8], 0, 4);
2397: /* ADDITIONAL SENSE CODE */
2398: data[12] = 0x00;
2399: /* ADDITIONAL SENSE CODE QUALIFIER */
2400: data[13] = 0x00;
2401: /* FIELD REPLACEABLE UNIT CODE */
2402: data[14] = 0;
2403: /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
2404: data[15] = 0;
2405: data[16] = 0;
2406: data[17] = 0;
2407: plen = 18 - len;
2408:
2409: /* ADDITIONAL SENSE LENGTH */
2410: data[7] = plen;
2411: } else {
2412: /* descriptor format */
2413: /* NO ADDITIONAL SENSE INFORMATION */
2414: /* BUILD_SENSE(NO_SENSE, 0x00, 0x00); */
2415:
2416: /* RESPONSE CODE(6-0) */
2417: BDSET8W(&data[0], 0x72, 6, 7);
2418: /* SENSE KEY(3-0) */
2419: BDSET8W(&data[1], ISTGT_SCSI_SENSE_NO_SENSE, 3, 4);
2420: /* ADDITIONAL SENSE CODE */
2421: data[2] = 0x00;
2422: /* ADDITIONAL SENSE CODE QUALIFIER */
2423: data[3] = 0x00;
2424: /* Reserved */
2425: data[4] = 0;
2426: data[5] = 0;
2427: data[6] = 0;
2428: /* ADDITIONAL SENSE LENGTH */
2429: data[7] = 0;
2430: len = 8;
2431:
2432: /* Sense data descriptor(s) */
2433: plen = 8 - len;
2434:
2435: /* ADDITIONAL SENSE LENGTH */
2436: data[7] = plen;
2437: }
2438: return len;
2439: }
2440: #endif
2441:
2442: static int
1.1.1.2 misho 2443: 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 2444: {
2445: ISTGT_Ptr istgt;
2446: ISTGT_LU_Ptr lu;
2447: uint8_t *cp;
2448: uint8_t *cp_count;
2449: int hlen = 0, len = 0, plen;
2450: int total;
2451: int pg_tag;
2452: int nports;
1.1.1.2 misho 2453: int i, j, k;
2454: int ridx;
1.1 misho 2455:
2456: if (alloc_len < 0xfff) {
2457: return -1;
2458: }
2459:
2460: istgt = conn->istgt;
2461: lu = spec->lu;
2462:
2463: /* RETURN DATA LENGTH */
2464: DSET32(&data[0], 0);
2465: hlen = 4;
2466:
2467: MTX_LOCK(&istgt->mutex);
2468: for (i = 0; i < lu->maxmap; i++) {
2469: pg_tag = lu->map[i].pg_tag;
2470: /* skip same pg_tag */
2471: for (j = 0; j < i; j++) {
2472: if (lu->map[j].pg_tag == pg_tag) {
2473: goto skip_pg_tag;
2474: }
2475: }
2476:
2477: /* Target port group descriptor N */
2478: cp = &data[hlen + len];
2479:
2480: /* PREF(7) ASYMMETRIC ACCESS STATE(3-0) */
2481: cp[0] = 0;
2482: BDSET8(&cp[0], 1, 7); /* PREF */
2483: switch (lu->map[j].pg_aas & 0x0f) {
2484: case AAS_ACTIVE_OPTIMIZED:
2485: BDADD8W(&cp[0], AAS_ACTIVE_OPTIMIZED, 3, 4);
2486: break;
2487: case AAS_ACTIVE_NON_OPTIMIZED:
2488: BDADD8W(&cp[0], AAS_ACTIVE_NON_OPTIMIZED, 3, 4);
2489: break;
2490: case AAS_STANDBY:
2491: BDADD8W(&cp[0], AAS_STANDBY, 3, 4);
2492: break;
2493: case AAS_UNAVAILABLE:
2494: BDADD8W(&cp[0], AAS_UNAVAILABLE, 3, 4);
2495: break;
2496: case AAS_TRANSITIONING:
2497: BDADD8W(&cp[0], AAS_TRANSITIONING, 3, 4);
2498: break;
2499: default:
2500: ISTGT_ERRLOG("unsupported AAS\n");
2501: break;
2502: }
2503: /* T_SUP(7) U_SUP(3) S_SUP(2) S_SUP AN_SUP(1) AO_SUP(0) */
2504: cp[1] = 0;
2505: //BDADD8(&cp[1], 1, 7); /* transitioning supported */
2506: //BDADD8(&cp[1], 1, 3); /* unavailable supported */
2507: //BDADD8(&cp[1], 1, 2); /* standby supported */
2508: BDADD8(&cp[1], 1, 1); /* active/non-optimized supported */
2509: BDADD8(&cp[1], 1, 0); /* active/optimized supported */
2510: /* TARGET PORT GROUP */
2511: DSET16(&cp[2], pg_tag);
2512: /* Reserved */
2513: cp[4] = 0;
2514: /* STATUS CODE */
2515: if (lu->map[j].pg_aas & AAS_STATUS_IMPLICIT) {
2516: cp[5] = 0x02; /* by implicit */
2517: } else if (lu->map[j].pg_aas & AAS_STATUS_STPG) {
2518: cp[5] = 0x01; /* by SET TARGET PORT GROUPS */
2519: } else {
2520: cp[5] = 0; /* No status */
2521: }
2522: /* Vendor specific */
2523: cp[6] = 0;
2524: /* TARGET PORT COUNT */
2525: cp[7] = 0;
2526: cp_count = &cp[7];
2527: plen = 8;
2528: len += plen;
2529:
2530: nports = 0;
1.1.1.2 misho 2531: ridx = 0;
2532: MTX_LOCK(&istgt->mutex);
2533: for (j = 0; j < istgt->nportal_group; j++) {
2534: if (istgt->portal_group[j].tag == pg_tag) {
2535: for (k = 0; k < istgt->portal_group[j].nportals; k++) {
2536: /* Target port descriptor(s) */
2537: cp = &data[hlen + len];
2538: /* Obsolete */
2539: DSET16(&cp[0], 0);
2540: /* RELATIVE TARGET PORT IDENTIFIER */
2541: DSET16(&cp[2], (uint16_t) (1 + ridx));
2542: plen = 4;
2543: len += plen;
2544: nports++;
2545: ridx++;
2546: }
2547: } else {
2548: ridx += istgt->portal_group[j].nportals;
2549: }
1.1 misho 2550: }
1.1.1.2 misho 2551: MTX_UNLOCK(&istgt->mutex);
1.1 misho 2552:
2553: if (nports > 0xff) {
2554: ISTGT_ERRLOG("too many portals in portal group\n");
2555: MTX_UNLOCK(&istgt->mutex);
2556: return -1;
2557: }
2558:
2559: /* TARGET PORT COUNT */
2560: cp_count[0] = nports;
2561:
2562: skip_pg_tag:
2563: ;
2564: }
2565: MTX_UNLOCK(&istgt->mutex);
2566:
2567: total = hlen + len;
2568: if (total > alloc_len) {
2569: ISTGT_ERRLOG("alloc_len(%d) too small\n", alloc_len);
2570: return -1;
2571: }
2572:
2573: /* RETURN DATA LENGTH */
2574: DSET32(&data[0], total - 4);
2575:
2576: return total;
2577: }
2578:
2579: static int
2580: istgt_lu_disk_scsi_set_target_port_groups(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, uint8_t *data, int len)
2581: {
2582: ISTGT_LU_Ptr lu;
2583: int pg_tag;
2584: int aas;
2585: int pg;
2586: int rc;
2587: int i;
2588:
2589: if (len < 4) {
2590: return -1;
2591: }
2592:
2593: lu = spec->lu;
2594:
2595: aas = BGET8W(&data[0], 3, 4);
2596: pg = DGET16(&data[2]);
2597:
2598: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AAS=0x%x, PG=0x%4.4x\n", aas, pg);
2599:
2600: for (i = 0; i < lu->maxmap; i++) {
2601: pg_tag = lu->map[i].pg_tag;
2602: if (pg != pg_tag)
2603: continue;
2604:
2605: switch (aas) {
2606: case AAS_ACTIVE_OPTIMIZED:
2607: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Active/optimized\n");
2608: break;
2609: case AAS_ACTIVE_NON_OPTIMIZED:
2610: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Active/non-optimized\n");
2611: break;
2612: #if 0
2613: case AAS_STANDBY:
2614: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Standby\n");
2615: break;
2616: case AAS_UNAVAILABLE:
2617: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Unavailable\n");
2618: break;
2619: #endif
2620: case AAS_TRANSITIONING:
2621: return -1;
2622: default:
2623: ISTGT_ERRLOG("unsupported AAS 0x%x\n", aas);
2624: return -1;
2625: }
2626: lu->map[i].pg_aas = aas;
2627: lu->map[i].pg_aas |= AAS_STATUS_STPG;
2628: }
2629:
2630: len -=4;
2631: if (len != 0) {
2632: rc = istgt_lu_disk_scsi_set_target_port_groups(spec, conn, cdb, data, len);
2633: if (rc < 0) {
2634: return rc;
2635: }
2636: }
2637: return 0;
2638: }
2639:
2640: static void
2641: istgt_lu_disk_free_pr_key(ISTGT_LU_PR_KEY *prkey)
2642: {
2643: int i;
2644:
2645: if (prkey == NULL)
2646: return;
2647: xfree(prkey->registered_initiator_port);
2648: prkey->registered_initiator_port = NULL;
2649: xfree(prkey->registered_target_port);
2650: prkey->registered_target_port = NULL;
2651: prkey->pg_idx = 0;
2652: prkey->pg_tag = 0;
2653: for (i = 0; i < prkey->ninitiator_ports; i++) {
2654: xfree(prkey->initiator_ports[i]);
2655: prkey->initiator_ports[i] = NULL;
2656: }
2657: xfree(prkey->initiator_ports);
2658: prkey->initiator_ports = NULL;
2659: prkey->all_tpg = 0;
2660: }
2661:
2662: static ISTGT_LU_PR_KEY *
2663: istgt_lu_disk_find_pr_key(ISTGT_LU_DISK *spec, const char *initiator_port, const char *target_port, uint64_t key)
2664: {
2665: ISTGT_LU_PR_KEY *prkey;
2666: int i;
2667:
2668: /* return pointer if I_T nexus is registered */
2669: #ifdef ISTGT_TRACE_DISK
2670: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2671: "find prkey=0x%16.16"PRIx64", port=%s\n",
2672: key, ((initiator_port != NULL) ? initiator_port : "N/A"));
2673: #endif /* ISTGT_TRACE_DISK */
2674:
2675: if (initiator_port == NULL)
2676: return NULL;
2677: for (i = 0; i < spec->npr_keys; i++) {
2678: prkey = &spec->pr_keys[i];
2679: if (prkey == NULL)
2680: continue;
2681: #ifdef ISTGT_TRACE_DISK
2682: if (key != 0) {
2683: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2684: "prkey=0x%16.16"PRIx64"\n",
2685: prkey->key);
2686: }
2687: #endif /* ISTGT_TRACE_DISK */
2688: if (key != 0 && prkey->key != key)
2689: continue;
2690: #ifdef ISTGT_TRACE_DISK
2691: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "pript=%s, ipt=%s\n",
2692: prkey->registered_initiator_port,
2693: initiator_port);
2694: #endif /* ISTGT_TRACE_DISK */
2695: if (strcmp(prkey->registered_initiator_port,
2696: initiator_port) == 0) {
2697: #ifdef ISTGT_TRACE_DISK
2698: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "prtpt=%s, tpt=%s\n",
2699: prkey->registered_target_port,
2700: target_port);
2701: #endif /* ISTGT_TRACE_DISK */
2702: if (prkey->all_tpg != 0
2703: || target_port == NULL
2704: || strcmp(prkey->registered_target_port,
2705: target_port) == 0) {
2706: return prkey;
2707: }
2708: }
2709: }
2710: return NULL;
2711: }
2712:
2713: static int
1.1.1.2 misho 2714: 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 2715: {
2716: ISTGT_LU_PR_KEY *prkey, *prkey1, *prkey2;
2717: int i, j;
2718:
2719: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2720: "remove other prkey=0x%16.16"PRIx64", port=%s\n",
2721: key, ((initiator_port != NULL) ? initiator_port : "N/A"));
2722:
2723: for (i = 0; i < spec->npr_keys; i++) {
2724: prkey = &spec->pr_keys[i];
2725: if (prkey == NULL)
2726: continue;
2727: if (key == 0 || prkey->key == key)
2728: continue;
2729: if (initiator_port == NULL ||
2730: strcasecmp(prkey->registered_initiator_port,
2731: initiator_port) == 0)
2732: continue;
2733: if (prkey->all_tpg != 0
2734: || target_port == NULL
2735: || strcasecmp(prkey->registered_target_port,
2736: target_port) == 0)
2737: continue;
2738:
2739: istgt_lu_disk_free_pr_key(prkey);
2740: for (j = i; j < spec->npr_keys - 1; j++) {
2741: prkey1 = &spec->pr_keys[j];
2742: prkey2 = &spec->pr_keys[j+1];
2743:
2744: prkey1->registered_initiator_port
2745: = prkey2->registered_initiator_port;
2746: prkey2->registered_initiator_port = NULL;
2747: prkey1->registered_target_port
2748: = prkey2->registered_target_port;
2749: prkey2->registered_target_port = NULL;
2750: prkey1->pg_idx = prkey2->pg_idx;
2751: prkey2->pg_idx = 0;
2752: prkey1->pg_tag = prkey2->pg_tag;
2753: prkey2->pg_tag = 0;
2754: prkey1->ninitiator_ports = prkey2->ninitiator_ports;
2755: prkey2->ninitiator_ports = 0;
2756: prkey1->initiator_ports = prkey2->initiator_ports;
2757: prkey2->initiator_ports = NULL;
2758: prkey1->all_tpg = prkey2->all_tpg;
2759: prkey2->all_tpg = 0;
2760: }
2761: spec->npr_keys--;
2762: }
2763: return 0;
2764: }
2765:
2766: static int
1.1.1.2 misho 2767: 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 2768: {
2769: ISTGT_LU_PR_KEY *prkey, *prkey1, *prkey2;
2770: int i, j;
2771:
2772: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2773: "remove prkey=0x%16.16"PRIx64", port=%s\n",
2774: key, ((initiator_port != NULL) ? initiator_port : "N/A"));
2775:
2776: for (i = 0; i < spec->npr_keys; i++) {
2777: prkey = &spec->pr_keys[i];
2778: if (prkey == NULL)
2779: continue;
2780: if (key != 0 && prkey->key != key)
2781: continue;
2782: if (initiator_port != NULL
2783: && strcasecmp(prkey->registered_initiator_port,
2784: initiator_port) != 0)
2785: continue;
2786: if (prkey->all_tpg == 0
2787: && target_port != NULL
2788: && strcasecmp(prkey->registered_target_port,
2789: target_port) != 0)
2790: continue;
2791:
2792: istgt_lu_disk_free_pr_key(prkey);
2793: for (j = i; j < spec->npr_keys - 1; j++) {
2794: prkey1 = &spec->pr_keys[j];
2795: prkey2 = &spec->pr_keys[j+1];
2796:
2797: prkey1->registered_initiator_port
2798: = prkey2->registered_initiator_port;
2799: prkey2->registered_initiator_port = NULL;
2800: prkey1->registered_target_port
2801: = prkey2->registered_target_port;
2802: prkey2->registered_target_port = NULL;
2803: prkey1->pg_idx = prkey2->pg_idx;
2804: prkey2->pg_idx = 0;
2805: prkey1->pg_tag = prkey2->pg_tag;
2806: prkey2->pg_tag = 0;
2807: prkey1->ninitiator_ports = prkey2->ninitiator_ports;
2808: prkey2->ninitiator_ports = 0;
2809: prkey1->initiator_ports = prkey2->initiator_ports;
2810: prkey2->initiator_ports = NULL;
2811: prkey1->all_tpg = prkey2->all_tpg;
2812: prkey2->all_tpg = 0;
2813: }
2814: spec->npr_keys--;
2815: }
2816: return 0;
2817: }
2818:
2819: static int
2820: istgt_lu_parse_transport_id(char **tid, uint8_t *data, int len)
2821: {
2822: int fc, pi;
2823: int hlen, plen;
2824:
2825: if (tid == NULL)
2826: return -1;
2827: if (data == NULL)
2828: return -1;
2829:
2830: fc = BGET8W(&data[0], 7, 2);
2831: pi = BGET8W(&data[0], 3, 4);
2832: if (fc != 0) {
2833: ISTGT_ERRLOG("FORMAT CODE != 0\n");
2834: return -1;
2835: }
2836: if (pi != SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME) {
2837: ISTGT_ERRLOG("PROTOCOL IDENTIFIER != ISCSI\n");
2838: return -1;
2839: }
2840:
2841: /* PROTOCOL IDENTIFIER = 0x05 */
2842: hlen = 4;
2843: /* ADDITIONAL LENGTH */
2844: plen = DGET16(&data[2]);
2845: if (plen > len) {
2846: ISTGT_ERRLOG("invalid length %d (expected %d)\n",
2847: plen, len);
2848: return -1;
2849: }
2850: if (plen > MAX_ISCSI_NAME) {
2851: ISTGT_ERRLOG("invalid length %d (expected %d)\n",
2852: plen, MAX_ISCSI_NAME);
2853: return -1;
2854: }
2855:
2856: /* ISCSI NAME */
2857: *tid = xmalloc(plen + 1);
2858: memcpy(*tid, data, plen);
2859: (*tid)[plen] = '\0';
2860: strlwr(*tid);
2861:
2862: return hlen + plen;
2863: }
2864:
2865: static int
1.1.1.2 misho 2866: 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 2867: {
2868: ISTGT_LU_PR_KEY *prkey;
1.1.1.2 misho 2869: size_t hlen = 0, len = 0, plen;
1.1 misho 2870: uint8_t *sense_data;
1.1.1.2 misho 2871: size_t *sense_len;
1.1 misho 2872: uint8_t *cp;
2873: int total;
2874: int i;
2875:
2876: sense_data = lu_cmd->sense_data;
2877: sense_len = &lu_cmd->sense_data_len;
2878: *sense_len = 0;
2879:
2880: cp = &data[hlen + len];
2881: total = 0;
2882: switch (sa) {
2883: case 0x00: /* READ KEYS */
2884: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ KEYS\n");
2885:
2886: /* PRGENERATION */
2887: DSET32(&data[0], spec->pr_generation);
2888: /* ADDITIONAL LENGTH */
2889: DSET32(&data[4], 0);
2890: hlen = 8;
2891:
2892: for (i = 0; i < spec->npr_keys; i++) {
2893: prkey = &spec->pr_keys[i];
2894: /* reservation key N */
2895: cp = &data[hlen + len];
2896: DSET64(&cp[0], prkey->key);
2897: len += 8;
2898: }
2899: total = hlen + len;
2900: /* ADDITIONAL LENGTH */
2901: DSET32(&data[4], total - hlen);
2902: break;
2903:
2904: case 0x01: /* READ RESERVATION */
2905: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ RESERVATION\n");
2906:
2907: /* PRGENERATION */
2908: DSET32(&data[0], spec->pr_generation);
2909: /* ADDITIONAL LENGTH */
2910: DSET32(&data[4], 0);
2911: hlen = 8;
2912:
2913: if (spec->rsv_key != 0) {
2914: /* RESERVATION KEY */
2915: DSET64(&data[8], spec->rsv_key);
2916: /* Obsolete */
2917: DSET32(&data[16], 0);
2918: /* Reserved */
2919: data[20] = 0;
2920: /* SCOPE(7-4) TYPE(3-0) */
2921: BDSET8W(&data[21], spec->rsv_scope, 7, 4);
2922: BDADD8W(&data[21], spec->rsv_type, 3, 4);
2923: /* Obsolete */
2924: DSET16(&data[22], 0);
2925: len = 24 - hlen;
2926: }
2927:
2928: total = hlen + len;
2929: /* ADDITIONAL LENGTH */
2930: DSET32(&data[4], total - hlen);
2931: break;
2932:
2933: case 0x02: /* REPORT CAPABILITIES */
2934: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT CAPABILITIES\n");
2935:
2936: /* LENGTH */
2937: DSET16(&data[0], 0x0008);
2938: /* CRH(4) SIP_C(3) ATP_C(2) PTPL_C(0) */
2939: data[2] = 0;
2940: //BDADD8(&data[2], 1, 4); /* Compatible Reservation Handling */
2941: BDADD8(&data[2], 1, 3); /* Specify Initiator Ports Capable */
2942: BDADD8(&data[2], 1, 2); /* All Target Ports Capable */
2943: //BDADD8(&data[2], 1, 0); /* Persist Through Power Loss Capable */
2944: /* TMV(7) PTPL_A(0) */
2945: data[3] = 0;
2946: //BDADD8(&data[2], 1, 7); /* Type Mask Valid */
2947: //BDADD8(&data[2], 1, 0); /* Persist Through Power Loss Activated */
2948: /* PERSISTENT RESERVATION TYPE MASK */
2949: DSET16(&data[4], 0);
2950: /* Reserved */
2951: DSET16(&data[6], 0);
2952: hlen = 8;
2953:
2954: total = hlen + len;
2955: break;
2956:
2957: case 0x03: /* READ FULL STATUS */
2958: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ FULL STATUS\n");
2959:
2960: /* PRGENERATION */
2961: DSET32(&data[0], spec->pr_generation);
2962: /* ADDITIONAL LENGTH */
2963: DSET32(&data[4], 0);
2964: hlen = 8;
2965:
2966: for (i = 0; i < spec->npr_keys; i++) {
2967: prkey = &spec->pr_keys[i];
2968: /* Full status descriptors N */
2969: cp = &data[hlen + len];
2970:
2971: /* RESERVATION KEY */
2972: DSET64(&cp[0], prkey->key);
2973: /* Reserved */
2974: DSET64(&cp[8], 0);
2975: /* ALL_TG_PT(1) R_HOLDER(0) */
2976: cp[12] = 0;
2977: if (prkey->all_tpg) {
2978: BDADD8(&cp[12], 1, 1);
2979: }
2980: /* SCOPE(7-4) TYPE(3-0) */
2981: cp[13] = 0;
2982: if (spec->rsv_key != 0) {
2983: if (spec->rsv_key == prkey->key) {
2984: BDADD8(&cp[12], 1, 0);
2985: BDADD8W(&cp[13], spec->rsv_scope & 0x0f, 7, 4);
2986: BDADD8W(&cp[13], spec->rsv_type & 0x0f, 3, 4);
2987: }
2988: }
2989: /* Reserved */
2990: DSET32(&cp[14], 0);
2991: /* RELATIVE TARGET PORT IDENTIFIER */
2992: DSET16(&cp[18], 1 + prkey->pg_idx);
2993: /* ADDITIONAL DESCRIPTOR LENGTH */
2994: DSET32(&cp[20], 0);
2995:
2996: /* TRANSPORTID */
2997: plen = snprintf((char *) &cp[24], MAX_INITIATOR_NAME,
2998: "%s",
2999: prkey->registered_initiator_port);
3000:
3001: /* ADDITIONAL DESCRIPTOR LENGTH */
3002: DSET32(&cp[20], plen);
3003: len += 24 + plen;
3004: }
3005:
3006: total = hlen + len;
3007: /* ADDITIONAL LENGTH */
3008: DSET32(&data[4], total - hlen);
3009: break;
3010:
3011: default:
3012: ISTGT_ERRLOG("unsupported service action 0x%x\n", sa);
3013: /* INVALID FIELD IN CDB */
3014: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3015: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3016: return -1;
3017: }
3018:
3019: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3020: return total;
3021: }
3022:
3023: static int
3024: 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)
3025: {
3026: ISTGT_LU_PR_KEY *prkey;
3027: uint8_t *sense_data;
1.1.1.2 misho 3028: size_t *sense_len;
1.1 misho 3029: char *old_rsv_port = NULL;
3030: char **initiator_ports;
3031: int maxports, nports;
3032: int plen, total;
3033: uint64_t rkey;
3034: uint64_t sarkey;
3035: int spec_i_pt, all_tg_pt, aptpl;
3036: int task_abort;
3037: int idx;
3038: int rc;
3039: int i;
3040:
3041: sense_data = lu_cmd->sense_data;
3042: sense_len = &lu_cmd->sense_data_len;
3043: *sense_len = 0;
3044:
3045: rkey = DGET64(&data[0]);
3046: sarkey = DGET64(&data[8]);
3047: spec_i_pt = BGET8(&data[20], 3);
3048: all_tg_pt = BGET8(&data[20], 2);
3049: aptpl = BGET8(&data[20], 0);
3050:
3051: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3052: "sa=0x%2.2x, key=0x%16.16"PRIx64", sakey=0x%16.16"PRIx64
3053: ", ipt=%d, tgpt=%d, aptpl=%d\n",
3054: sa, rkey, sarkey, spec_i_pt, all_tg_pt, aptpl);
3055: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "port=%s\n",
3056: conn->initiator_port);
3057:
3058: switch (sa) {
3059: case 0x00: /* REGISTER */
3060: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REGISTER\n");
3061:
3062: if (aptpl != 0) {
3063: /* Activate Persist Through Power Loss */
3064: ISTGT_ERRLOG("unsupport Activate Persist Through Power Loss\n");
3065: /* INVALID FIELD IN PARAMETER LIST */
3066: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3067: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3068: return -1;
3069: }
3070: /* lost reservations if daemon restart */
3071:
3072: prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3073: conn->target_port, 0);
3074: if (prkey == NULL) {
3075: /* unregistered port */
3076: if (rkey != 0) {
3077: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3078: return -1;
3079: }
3080: if (sarkey != 0) {
3081: /* XXX check spec_i_pt */
3082: }
3083: } else {
3084: /* registered port */
3085: if (spec_i_pt) {
3086: /* INVALID FIELD IN CDB */
3087: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3088: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3089: return -1;
3090: }
3091:
3092: prkey = istgt_lu_disk_find_pr_key(spec,
3093: conn->initiator_port, conn->target_port, rkey);
3094: if (prkey == NULL) {
3095: /* not found key */
3096: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3097: return -1;
3098: }
3099: /* remove existing keys */
3100: rc = istgt_lu_disk_remove_pr_key(spec, conn,
1.1.1.2 misho 3101: conn->initiator_port, conn->target_port, 0);
1.1 misho 3102: if (rc < 0) {
3103: ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3104: /* INTERNAL TARGET FAILURE */
3105: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3106: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3107: return -1;
3108: }
3109: }
3110:
3111: /* unregister? */
3112: if (sarkey == 0) {
3113: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3114: return 0;
3115: }
3116:
3117: goto do_register;
3118:
3119: case 0x01: /* RESERVE */
3120: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE\n");
3121:
3122: prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3123: conn->target_port, 0);
3124: if (prkey == NULL) {
3125: /* unregistered port */
3126: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3127: return -1;
3128: }
3129:
3130: prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3131: conn->target_port, rkey);
3132: if (prkey == NULL) {
3133: /* not found key */
3134: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3135: return -1;
3136: }
3137: if (spec->rsv_key == 0) {
3138: /* no reservation */
3139: } else {
3140: if (prkey->key != spec->rsv_key) {
3141: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3142: return -1;
3143: }
3144: if (strcasecmp(spec->rsv_port, conn->initiator_port) != 0) {
3145: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3146: return -1;
3147: }
3148: if (g_trace_flag) {
3149: ISTGT_WARNLOG("LU%d: duplicate reserve\n", spec->lu->num);
3150: }
3151: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3152: return 0;
3153: }
3154:
3155: if (scope != 0x00) { // !LU_SCOPE
3156: /* INVALID FIELD IN CDB */
3157: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3158: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3159: return -1;
3160: }
3161: if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
3162: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
3163: && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
3164: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
3165: && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
3166: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
3167: ISTGT_ERRLOG("unsupported type 0x%x\n", type);
3168: /* INVALID FIELD IN CDB */
3169: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3170: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3171: return -1;
3172: }
3173:
3174: /* establish reservation by key */
3175: xfree(spec->rsv_port);
3176: spec->rsv_port = xstrdup(conn->initiator_port);
3177: strlwr(spec->rsv_port);
3178: spec->rsv_key = rkey;
3179: spec->rsv_scope = scope;
3180: spec->rsv_type = type;
3181:
3182: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3183: "LU%d: reserved (scope=%d, type=%d) by key=0x%16.16"
3184: PRIx64"\n",
3185: spec->lu->num, scope, type, rkey);
3186: break;
3187:
3188: case 0x02: /* RELEASE */
3189: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE\n");
3190:
3191: prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3192: conn->target_port, 0);
3193: if (prkey == NULL) {
3194: /* unregistered port */
3195: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3196: return -1;
3197: }
3198:
3199: prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3200: conn->target_port, rkey);
3201: if (prkey == NULL) {
3202: /* not found key */
3203: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3204: return -1;
3205: }
3206: if (spec->rsv_key == 0) {
3207: /* no reservation */
3208: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3209: return 0;
3210: }
3211: if (prkey->key != spec->rsv_key) {
3212: /* INVALID RELEASE OF PERSISTENT RESERVATION */
3213: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04);
3214: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3215: return -1;
3216: }
3217: if (strcasecmp(spec->rsv_port, conn->initiator_port) != 0) {
3218: /* INVALID RELEASE OF PERSISTENT RESERVATION */
3219: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04);
3220: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3221: return -1;
3222: }
3223:
3224: if (scope != 0x00) { // !LU_SCOPE
3225: /* INVALID FIELD IN CDB */
3226: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3227: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3228: return -1;
3229: }
3230: if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
3231: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
3232: && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
3233: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
3234: && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
3235: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
3236: ISTGT_ERRLOG("unsupported type 0x%x\n", type);
3237: /* INVALID FIELD IN CDB */
3238: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3239: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3240: return -1;
3241: }
3242: if (spec->rsv_scope != scope || spec->rsv_type != type) {
3243: /* INVALID RELEASE OF PERSISTENT RESERVATION */
3244: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04);
3245: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3246: return -1;
3247: }
3248:
3249: /* release reservation by key */
3250: xfree(spec->rsv_port);
3251: spec->rsv_port = NULL;
3252: spec->rsv_key = 0;
3253: spec->rsv_scope = 0;
3254: spec->rsv_type = 0;
3255:
3256: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3257: "LU%d: released (scope=%d, type=%d) by key=0x%16.16"
3258: PRIx64"\n",
3259: spec->lu->num, scope, type, rkey);
3260: break;
3261:
3262: case 0x03: /* CLEAR */
3263: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "CLEAR\n");
3264:
3265: prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3266: conn->target_port, 0);
3267: if (prkey == NULL) {
3268: /* unregistered port */
3269: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3270: return -1;
3271: }
3272:
3273: /* release reservation */
3274: xfree(spec->rsv_port);
3275: spec->rsv_port = NULL;
3276: spec->rsv_key = 0;
3277: spec->rsv_scope = 0;
3278: spec->rsv_type = 0;
3279:
3280: /* remove all registrations */
3281: for (i = 0; i < spec->npr_keys; i++) {
3282: prkey = &spec->pr_keys[i];
3283: istgt_lu_disk_free_pr_key(prkey);
3284: }
3285: spec->npr_keys = 0;
3286: break;
3287:
3288: case 0x04: /* PREEMPT */
3289: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PREEMPT\n");
3290:
3291: task_abort = 0;
3292: do_preempt:
3293: prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3294: conn->target_port, 0);
3295: if (prkey == NULL) {
3296: /* unregistered port */
3297: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
3298: return -1;
3299: }
3300:
3301: if (spec->rsv_key == 0) {
3302: /* no reservation */
3303: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no reservation\n");
3304: /* remove registration */
3305: rc = istgt_lu_disk_remove_pr_key(spec, conn,
3306: NULL, NULL, sarkey);
3307: if (rc < 0) {
3308: ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3309: /* INTERNAL TARGET FAILURE */
3310: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3311: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3312: return -1;
3313: }
3314:
3315: /* update generation */
3316: spec->pr_generation++;
3317:
3318: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3319: break;
3320: }
3321: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "rsv_key=0x%16.16"PRIx64"\n",
3322: spec->rsv_key);
3323:
3324: if (spec->rsv_type == ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
3325: || spec->rsv_type == ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
3326: if (sarkey != 0) {
3327: /* remove registration */
3328: rc = istgt_lu_disk_remove_pr_key(spec, conn,
3329: NULL, NULL, sarkey);
3330: if (rc < 0) {
3331: ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3332: /* INTERNAL TARGET FAILURE */
3333: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3334: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3335: return -1;
3336: }
3337:
3338: /* update generation */
3339: spec->pr_generation++;
3340:
3341: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3342: break;
3343: } else {
3344: /* remove other registrations */
3345: rc = istgt_lu_disk_remove_other_pr_key(spec, conn,
3346: conn->initiator_port,
3347: conn->target_port,
3348: rkey);
3349: if (rc < 0) {
3350: ISTGT_ERRLOG("lu_disk_remove_other_pr_key() failed\n");
3351: /* INTERNAL TARGET FAILURE */
3352: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3353: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3354: return -1;
3355: }
3356:
3357: if (scope != 0x00) { // !LU_SCOPE
3358: /* INVALID FIELD IN CDB */
3359: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3360: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3361: return -1;
3362: }
3363: if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
3364: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
3365: && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
3366: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
3367: && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
3368: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
3369: ISTGT_ERRLOG("unsupported type 0x%x\n", type);
3370: /* INVALID FIELD IN CDB */
3371: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3372: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3373: return -1;
3374: }
3375:
3376: /* release reservation */
3377: //xfree(spec->rsv_port);
3378: old_rsv_port = spec->rsv_port;
3379: spec->rsv_port = NULL;
3380: spec->rsv_key = 0;
3381: spec->rsv_scope = 0;
3382: spec->rsv_type = 0;
3383: /* establish new reservation */
3384: spec->rsv_port = xstrdup(conn->initiator_port);
3385: strlwr(spec->rsv_port);
3386: spec->rsv_key = rkey;
3387: spec->rsv_scope = scope;
3388: spec->rsv_type = type;
3389:
3390: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3391: "LU%d: reserved (scope=%d, type=%d)"
3392: "by key=0x%16.16"PRIx64"\n",
3393: spec->lu->num, scope, type, rkey);
3394:
3395: /* update generation */
3396: spec->pr_generation++;
3397:
3398: /* XXX TODO fix */
3399: if (task_abort) {
3400: /* abort all tasks for preempted I_T nexus */
3401: if (old_rsv_port != NULL) {
3402: rc = istgt_lu_disk_queue_abort_ITL(spec, old_rsv_port);
3403: xfree(old_rsv_port);
3404: old_rsv_port = NULL;
3405: if (rc < 0) {
3406: /* INTERNAL TARGET FAILURE */
3407: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3408: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3409: return -1;
3410: }
3411: }
3412: }
3413: if (old_rsv_port != NULL) {
3414: xfree(old_rsv_port);
3415: old_rsv_port = NULL;
3416: }
3417:
3418: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3419: break;
3420: }
3421: }
3422:
3423: prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3424: conn->target_port, rkey);
3425:
3426: if (prkey == NULL) {
3427: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3428: "prkey == NULL\n");
3429: } else {
3430: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3431: "prkey key=%16.16"PRIx64"\n",
3432: prkey->key);
3433: }
3434:
3435: if (prkey == NULL
3436: || sarkey != spec->rsv_key) {
3437: if (sarkey != 0) {
3438: /* remove registration */
3439: rc = istgt_lu_disk_remove_pr_key(spec, conn,
3440: NULL, NULL, sarkey);
3441: if (rc < 0) {
3442: ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3443: /* INTERNAL TARGET FAILURE */
3444: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3445: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3446: return -1;
3447: }
3448: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3449: break;
3450: } else {
3451: /* INVALID FIELD IN PARAMETER LIST */
3452: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3453: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3454: return -1;
3455: }
3456: }
3457:
3458: /* remove registration */
3459: rc = istgt_lu_disk_remove_pr_key(spec, conn,
3460: NULL, NULL, sarkey);
3461: if (rc < 0) {
3462: ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3463: /* INTERNAL TARGET FAILURE */
3464: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3465: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3466: return -1;
3467: }
3468:
3469: if (scope != 0x00) { // !LU_SCOPE
3470: /* INVALID FIELD IN CDB */
3471: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3472: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3473: return -1;
3474: }
3475: if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
3476: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
3477: && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
3478: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
3479: && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
3480: && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
3481: ISTGT_ERRLOG("unsupported type 0x%x\n", type);
3482: /* INVALID FIELD IN CDB */
3483: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3484: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3485: return -1;
3486: }
3487:
3488: /* release reservation */
3489: //xfree(spec->rsv_port);
3490: old_rsv_port = spec->rsv_port;
3491: spec->rsv_port = NULL;
3492: spec->rsv_key = 0;
3493: spec->rsv_scope = 0;
3494: spec->rsv_type = 0;
3495: /* establish new reservation */
3496: spec->rsv_port = xstrdup(conn->initiator_port);
3497: strlwr(spec->rsv_port);
3498: spec->rsv_key = rkey;
3499: spec->rsv_scope = scope;
3500: spec->rsv_type = type;
3501:
3502: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3503: "LU%d: reserved (scope=%d, type=%d) by key=0x%16.16"
3504: PRIx64"\n",
3505: spec->lu->num, scope, type, rkey);
3506:
3507: /* update generation */
3508: spec->pr_generation++;
3509:
3510: /* XXX TODO fix */
3511: if (task_abort) {
3512: /* abort all tasks for preempted I_T nexus */
3513: if (old_rsv_port != NULL) {
3514: rc = istgt_lu_disk_queue_abort_ITL(spec, old_rsv_port);
3515: xfree(old_rsv_port);
3516: old_rsv_port = NULL;
3517: if (rc < 0) {
3518: /* INTERNAL TARGET FAILURE */
3519: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3520: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3521: return -1;
3522: }
3523: }
3524: }
3525: if (old_rsv_port != NULL) {
3526: xfree(old_rsv_port);
3527: old_rsv_port = NULL;
3528: }
3529:
3530: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3531: break;
3532:
3533: case 0x05: /* PREEMPT AND ABORT */
3534: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PREEMPT AND ABORT\n");
3535:
3536: task_abort = 1;
3537: goto do_preempt;
3538:
3539: case 0x06: /* REGISTER AND IGNORE EXISTING KEY */
3540: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REGISTER AND IGNORE EXISTING KEY\n");
3541:
3542: if (aptpl != 0) {
3543: /* Activate Persist Through Power Loss */
3544: ISTGT_ERRLOG("unsupport Activate Persist Through Power Loss\n");
3545: /* INVALID FIELD IN PARAMETER LIST */
3546: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3547: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3548: return -1;
3549: }
3550: /* lost reservations if daemon restart */
3551:
3552: prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3553: conn->target_port, 0);
3554: if (prkey == NULL) {
3555: /* unregistered port */
3556: if (sarkey != 0) {
3557: if (spec_i_pt) {
3558: /* INVALID FIELD IN CDB */
3559: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3560: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3561: return -1;
3562: }
3563: }
1.1.1.2 misho 3564: /* unregister? */
3565: if (sarkey == 0) {
3566: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3567: return 0;
3568: }
1.1 misho 3569: } else {
3570: /* registered port */
3571: if (spec_i_pt) {
3572: /* INVALID FIELD IN CDB */
3573: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3574: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3575: return -1;
3576: }
3577: }
3578:
3579: /* remove existing keys */
3580: rc = istgt_lu_disk_remove_pr_key(spec, conn,
3581: conn->initiator_port,
3582: conn->target_port, 0);
3583: if (rc < 0) {
3584: ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
3585: /* INTERNAL TARGET FAILURE */
3586: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3587: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3588: return -1;
3589: }
3590:
3591: /* unregister? */
3592: if (sarkey == 0) {
3593: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3594: return 0;
3595: }
3596:
3597: do_register:
3598: /* specified port? */
3599: nports = 0;
3600: initiator_ports = NULL;
3601: if (spec_i_pt) {
3602: if (len < 28) {
3603: /* INVALID FIELD IN PARAMETER LIST */
3604: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3605: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3606: return -1;
3607: }
3608:
3609: /* TRANSPORTID PARAMETER DATA LENGTH */
3610: plen = DGET32(&data[24]);
3611: if (28 + plen > len) {
3612: ISTGT_ERRLOG("invalid length %d (expect %d)\n",
3613: len, 28 + plen);
3614: /* INVALID FIELD IN PARAMETER LIST */
3615: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3616: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3617: return -1;
3618: }
3619:
3620: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3621: "TransportID parameter data length %d\n",
3622: plen);
3623: if (plen != 0) {
3624: maxports = MAX_LU_RESERVE_IPT;
3625: initiator_ports = xmalloc(sizeof (char *) * maxports);
3626: memset(initiator_ports, 0, sizeof (char *) * maxports);
3627: nports = 0;
3628: total = 0;
3629: while (total < plen) {
3630: if (nports >= MAX_LU_RESERVE_IPT) {
3631: ISTGT_ERRLOG("maximum transport IDs\n");
3632: /* INSUFFICIENT REGISTRATION RESOURCES */
3633: BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04);
3634: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3635: return -1;
3636: }
3637: rc = istgt_lu_parse_transport_id
3638: (&initiator_ports[nports],
3639: &data[24] + total, plen - total);
3640: if (rc < 0) {
3641: /* INVALID FIELD IN PARAMETER LIST */
3642: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
3643: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3644: return -1;
3645: }
3646: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "got TransportID %s\n",
3647: initiator_ports[nports]);
3648: total += rc;
3649: nports++;
3650: }
3651: }
3652: /* check all port unregistered? */
3653: for (i = 0; i < nports; i++) {
3654: prkey = istgt_lu_disk_find_pr_key(spec,
3655: initiator_ports[i], NULL, 0);
3656: if (prkey != NULL) {
3657: /* registered port */
3658: /* INVALID FIELD IN CDB */
3659: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3660: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3661: return -1;
3662: }
3663: }
3664: /* OK, all port unregistered */
3665: idx = spec->npr_keys;
3666: if (idx + nports >= MAX_LU_RESERVE) {
3667: /* INSUFFICIENT REGISTRATION RESOURCES */
3668: BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04);
3669: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3670: return -1;
3671: }
3672: /* register each I_T nexus */
3673: for (i = 0; i < nports; i++) {
3674: prkey = &spec->pr_keys[idx + i];
3675:
3676: /* register new key */
3677: prkey->key = sarkey;
3678:
3679: /* command received port */
3680: prkey->registered_initiator_port
3681: = xstrdup(conn->initiator_port);
3682: strlwr(prkey->registered_initiator_port);
3683: prkey->registered_target_port
3684: = xstrdup(conn->target_port);
3685: strlwr(prkey->registered_target_port);
3686: prkey->pg_idx = conn->portal.idx;
3687: prkey->pg_tag = conn->portal.tag;
3688:
3689: /* specified ports */
3690: prkey->ninitiator_ports = 0;
3691: prkey->initiator_ports = NULL;
3692: prkey->all_tpg = (all_tg_pt) ? 1 : 0;
3693: }
3694: spec->npr_keys = idx + nports;
3695: }
3696:
3697: idx = spec->npr_keys;
3698: if (idx >= MAX_LU_RESERVE) {
3699: /* INSUFFICIENT REGISTRATION RESOURCES */
3700: BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04);
3701: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3702: return -1;
3703: }
3704: prkey = &spec->pr_keys[idx];
3705:
3706: /* register new key */
3707: prkey->key = sarkey;
3708:
3709: /* command received port */
3710: prkey->registered_initiator_port = xstrdup(conn->initiator_port);
3711: strlwr(prkey->registered_initiator_port);
3712: prkey->registered_target_port = xstrdup(conn->target_port);
3713: strlwr(prkey->registered_target_port);
3714: prkey->pg_idx = conn->portal.idx;
3715: prkey->pg_tag = conn->portal.tag;
3716:
3717: /* specified ports */
3718: prkey->ninitiator_ports = nports;
3719: prkey->initiator_ports = initiator_ports;
3720: prkey->all_tpg = (all_tg_pt) ? 1 : 0;
3721:
3722: /* count up keys */
3723: idx++;
3724: spec->npr_keys = idx;
3725:
3726: /* update generation */
3727: spec->pr_generation++;
3728: break;
3729:
3730: case 0x07: /* REGISTER AND MOVE */
3731: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REGISTER AND MOVE\n");
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: default:
3738: ISTGT_ERRLOG("unsupported service action 0x%x\n", sa);
3739: /* INVALID FIELD IN CDB */
3740: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3741: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3742: return -1;
3743: }
3744:
3745: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3746: return 0;
3747: }
3748:
3749: static int
3750: istgt_lu_disk_check_pr(ISTGT_LU_DISK *spec, CONN_Ptr conn, int pr_allow)
3751: {
3752: ISTGT_LU_PR_KEY *prkey;
3753:
3754: #ifdef ISTGT_TRACE_DISK
3755: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3756: "RSV_KEY=0x%16.16"PRIx64", RSV_TYPE=0x%x, PR_ALLOW=0x%x\n",
3757: spec->rsv_key, spec->rsv_type, pr_allow);
3758: #endif /* ISTGT_TRACE_DISK */
3759:
3760: prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
3761: conn->target_port, 0);
3762: if (prkey != NULL) {
3763: #ifdef ISTGT_TRACE_DISK
3764: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3765: "PRKEY(0x%16.16"PRIx64") found for %s\n",
3766: prkey->key, conn->initiator_port);
3767: #endif /* ISTGT_TRACE_DISK */
3768:
3769: if (spec->rsv_key == prkey->key) {
3770: /* reservation holder */
3771: return 0;
3772: }
3773:
3774: switch (spec->rsv_type) {
3775: case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS:
3776: if (pr_allow & PR_ALLOW_ALLRR)
3777: return 0;
3778: return -1;
3779: case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS:
3780: if (pr_allow & PR_ALLOW_ALLRR)
3781: return 0;
3782: return -1;
3783: case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY:
3784: if (pr_allow & PR_ALLOW_ALLRR)
3785: return 0;
3786: return -1;
3787: case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY:
3788: if (pr_allow & PR_ALLOW_ALLRR)
3789: return 0;
3790: return -1;
3791: }
3792: } else {
3793: #ifdef ISTGT_TRACE_DISK
3794: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
3795: "PRKEY not found for %s\n",
3796: conn->initiator_port);
3797: #endif /* ISTGT_TRACE_DISK */
3798:
3799: switch (spec->rsv_type) {
3800: case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS:
3801: if (pr_allow & PR_ALLOW_WERR)
3802: return 0;
3803: return -1;
3804: case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY:
3805: if (pr_allow & PR_ALLOW_WERR)
3806: return 0;
3807: return -1;
3808: case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS:
3809: if (pr_allow & PR_ALLOW_EARR)
3810: return 0;
3811: return -1;
3812: case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY:
3813: if (pr_allow & PR_ALLOW_EARR)
3814: return 0;
3815: return -1;
3816: }
3817: }
3818:
3819: #ifdef ISTGT_TRACE_DISK
3820: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "non registrans type\n");
3821: #endif /* ISTGT_TRACE_DISK */
3822: /* any I_T nexus */
3823: switch (spec->rsv_type) {
3824: case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE:
3825: if (pr_allow & PR_ALLOW_WE)
3826: return 0;
3827: return -1;
3828: case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS:
3829: if (pr_allow & PR_ALLOW_EA)
3830: return 0;
3831: return -1;
3832: }
3833:
3834: /* NG */
3835: return -1;
3836: }
3837:
3838: static int
3839: istgt_lu_disk_scsi_release(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
3840: {
3841: ISTGT_LU_CMD lu_cmd2;
3842: uint8_t *sense_data;
1.1.1.2 misho 3843: size_t *sense_len;
1.1 misho 3844: uint64_t LUI;
3845: uint64_t rkey;
3846: uint8_t cdb[10];
3847: uint8_t PRO_data[24];
3848: int parameter_len;
3849: int rc;
3850:
3851: sense_data = lu_cmd->sense_data;
3852: sense_len = &lu_cmd->sense_data_len;
3853: *sense_len = 0;
3854:
3855: memset(&lu_cmd2, 0, sizeof lu_cmd2);
3856: lu_cmd2.sense_data = lu_cmd->sense_data;
3857: lu_cmd2.sense_data_len = lu_cmd->sense_data_len;
3858: memset(&cdb, 0, sizeof cdb);
3859: parameter_len = sizeof PRO_data;
3860:
3861: LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU);
3862: rkey = istgt_get_rkey(conn->initiator_name, LUI);
3863:
3864: /* issue release action of PERSISTENT RESERVE OUT */
3865: cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
3866: BDSET8W(&cdb[1], 0x02, 4, 5); /* RELEASE */
3867: BDSET8W(&cdb[2], 0x00, 7, 4); /* LU_SCOPE */
3868: BDADD8W(&cdb[2], 0x03, 3, 4); /* ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS */
3869: cdb[3] = 0;
3870: cdb[4] = 0;
3871: DSET32(&cdb[5], parameter_len);
3872: cdb[9] = 0;
3873: lu_cmd2.cdb = &cdb[0];
3874:
3875: memset(&PRO_data, 0, sizeof PRO_data);
3876: DSET64(&PRO_data[0], rkey); // RESERVATION KEY
3877: DSET64(&PRO_data[8], 0);
3878:
3879: rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
3880: 0x02, 0x00, 0x03,
3881: PRO_data, parameter_len);
3882: if (rc < 0) {
3883: lu_cmd->status = lu_cmd2.status;
3884: if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
3885: return -1;
3886: }
3887: /* INTERNAL TARGET FAILURE */
3888: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3889: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3890: return -1;
3891: }
3892:
3893: /* issue unregister action of PERSISTENT RESERVE OUT */
3894: cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
3895: BDSET8W(&cdb[1], 0x06, 4, 5); /* REGISTER AND IGNORE EXISTING KEY */
3896: cdb[2] = 0;
3897: cdb[3] = 0;
3898: cdb[4] = 0;
3899: DSET32(&cdb[5], parameter_len);
3900: cdb[9] = 0;
3901: lu_cmd2.cdb = &cdb[0];
3902:
3903: memset(&PRO_data, 0, sizeof PRO_data);
3904: DSET64(&PRO_data[0], rkey); // RESERVATION KEY
3905: DSET64(&PRO_data[8], 0); // unregister
3906:
3907: rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
3908: 0x06, 0, 0,
3909: PRO_data, parameter_len);
3910: if (rc < 0) {
3911: lu_cmd->status = lu_cmd2.status;
3912: if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
3913: return -1;
3914: }
3915: /* INTERNAL TARGET FAILURE */
3916: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3917: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3918: return -1;
3919: }
3920:
3921: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3922: return 0;
3923: }
3924:
3925: static int
3926: istgt_lu_disk_scsi_reserve(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
3927: {
3928: ISTGT_LU_CMD lu_cmd2;
3929: uint8_t *sense_data;
1.1.1.2 misho 3930: size_t *sense_len;
1.1 misho 3931: uint64_t LUI;
3932: uint64_t rkey;
3933: uint8_t cdb[10];
3934: uint8_t PRO_data[24];
3935: int parameter_len;
3936: int rc;
3937:
3938: sense_data = lu_cmd->sense_data;
3939: sense_len = &lu_cmd->sense_data_len;
3940: *sense_len = 0;
3941:
3942: memset(&lu_cmd2, 0, sizeof lu_cmd2);
3943: lu_cmd2.sense_data = lu_cmd->sense_data;
3944: lu_cmd2.sense_data_len = lu_cmd->sense_data_len;
3945: memset(&cdb, 0, sizeof cdb);
3946: parameter_len = sizeof PRO_data;
3947:
3948: LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU);
3949: rkey = istgt_get_rkey(conn->initiator_name, LUI);
3950:
3951: /* issue register action of PERSISTENT RESERVE OUT */
3952: cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
3953: BDSET8W(&cdb[1], 0x06, 4, 5); /* REGISTER AND IGNORE EXISTING KEY */
3954: cdb[2] = 0;
3955: cdb[3] = 0;
3956: cdb[4] = 0;
3957: DSET32(&cdb[5], parameter_len);
3958: cdb[9] = 0;
3959: lu_cmd2.cdb = &cdb[0];
3960:
3961: memset(&PRO_data, 0, sizeof PRO_data);
3962: DSET64(&PRO_data[0], 0);
3963: DSET64(&PRO_data[8], rkey); // SERVICE ACTION RESERVATION KEY
3964:
3965: rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
3966: 0x06, 0, 0,
3967: PRO_data, parameter_len);
3968: if (rc < 0) {
3969: lu_cmd->status = lu_cmd2.status;
3970: if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
3971: return -1;
3972: }
3973: /* INTERNAL TARGET FAILURE */
3974: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3975: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3976: return -1;
3977: }
3978:
3979: /* issue reserve action of PERSISTENT RESERVE OUT */
3980: cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
3981: BDSET8W(&cdb[1], 0x01, 4, 5); /* RESERVE */
3982: BDSET8W(&cdb[2], 0x00, 7, 4); /* LU_SCOPE */
3983: BDADD8W(&cdb[2], 0x03, 3, 4); /* ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS */
3984: cdb[3] = 0;
3985: cdb[4] = 0;
3986: DSET32(&cdb[5], parameter_len);
3987: cdb[9] = 0;
3988: lu_cmd2.cdb = &cdb[0];
3989:
3990: memset(&PRO_data, 0, sizeof PRO_data);
3991: DSET64(&PRO_data[0], rkey); // RESERVATION KEY
3992: DSET64(&PRO_data[8], 0);
3993:
3994: rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
3995: 0x01, 0x00, 0x03,
3996: PRO_data, parameter_len);
3997: if (rc < 0) {
3998: lu_cmd->status = lu_cmd2.status;
3999: if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
4000: return -1;
4001: }
4002: /* INTERNAL TARGET FAILURE */
4003: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
4004: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4005: return -1;
4006: }
4007:
4008: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
4009: return 0;
4010: }
4011:
4012: static int
1.1.1.2 misho 4013: 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 4014: {
4015: uint8_t *data;
4016: uint64_t maxlba;
4017: uint64_t llen;
4018: uint64_t blen;
4019: uint64_t offset;
4020: uint64_t nbytes;
4021: int64_t rc;
4022:
4023: if (len == 0) {
4024: lu_cmd->data = NULL;
4025: lu_cmd->data_len = 0;
4026: return 0;
4027: }
4028:
4029: maxlba = spec->blockcnt;
4030: llen = (uint64_t) len;
4031: blen = spec->blocklen;
4032: offset = lba * blen;
4033: nbytes = llen * blen;
4034:
4035: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4036: "Read: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
4037: maxlba, lba, len);
4038:
4039: if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
4040: ISTGT_ERRLOG("end of media\n");
4041: return -1;
4042: }
4043:
4044: if (nbytes > lu_cmd->iobufsize) {
1.1.1.2 misho 4045: ISTGT_ERRLOG("nbytes(%zu) > iobufsize(%zu)\n",
4046: (size_t) nbytes, lu_cmd->iobufsize);
1.1 misho 4047: return -1;
4048: }
4049: data = lu_cmd->iobuf;
4050:
1.1.1.2 misho 4051: rc = spec->seek(spec, offset);
1.1 misho 4052: if (rc < 0) {
4053: ISTGT_ERRLOG("lu_disk_seek() failed\n");
4054: return -1;
4055: }
4056:
1.1.1.2 misho 4057: rc = spec->read(spec, data, nbytes);
1.1 misho 4058: if (rc < 0) {
4059: ISTGT_ERRLOG("lu_disk_read() failed\n");
4060: return -1;
4061: }
4062: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Read %"PRId64"/%"PRIu64" bytes\n",
4063: rc, nbytes);
4064:
4065: lu_cmd->data = data;
4066: lu_cmd->data_len = rc;
4067:
4068: return 0;
4069: }
4070:
4071: static int
4072: istgt_lu_disk_lbwrite(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
4073: {
4074: uint8_t *data;
4075: uint64_t maxlba;
4076: uint64_t llen;
4077: uint64_t blen;
4078: uint64_t offset;
4079: uint64_t nbytes;
4080: int64_t rc;
4081:
4082: if (len == 0) {
4083: lu_cmd->data_len = 0;
4084: return 0;
4085: }
4086:
4087: maxlba = spec->blockcnt;
4088: llen = (uint64_t) len;
4089: blen = spec->blocklen;
4090: offset = lba * blen;
4091: nbytes = llen * blen;
4092:
4093: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4094: "Write: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
4095: maxlba, lba, len);
4096:
4097: if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
4098: ISTGT_ERRLOG("end of media\n");
4099: return -1;
4100: }
4101:
4102: if (nbytes > lu_cmd->iobufsize) {
1.1.1.2 misho 4103: ISTGT_ERRLOG("nbytes(%zu) > iobufsize(%zu)\n",
4104: (size_t) nbytes, lu_cmd->iobufsize);
1.1 misho 4105: return -1;
4106: }
4107: data = lu_cmd->iobuf;
4108:
4109: rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
4110: lu_cmd->iobufsize, nbytes);
4111: if (rc < 0) {
4112: ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
4113: return -1;
4114: }
4115:
4116: if (spec->lu->readonly) {
4117: ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
4118: return -1;
4119: }
4120:
4121: spec->req_write_cache = 0;
1.1.1.2 misho 4122: rc = spec->seek(spec, offset);
1.1 misho 4123: if (rc < 0) {
4124: ISTGT_ERRLOG("lu_disk_seek() failed\n");
4125: return -1;
4126: }
4127:
1.1.1.2 misho 4128: rc = spec->write(spec, data, nbytes);
4129: if (rc < 0 || (uint64_t) rc != nbytes) {
1.1 misho 4130: ISTGT_ERRLOG("lu_disk_write() failed\n");
4131: return -1;
4132: }
4133: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
4134: rc, nbytes);
4135:
4136: lu_cmd->data_len = rc;
4137:
4138: return 0;
4139: }
4140:
4141: static int
4142: istgt_lu_disk_lbwrite_same(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
4143: {
4144: uint8_t *data;
4145: uint64_t maxlba;
4146: uint64_t llen;
4147: uint64_t blen;
4148: uint64_t offset;
4149: uint64_t nbytes;
4150: uint64_t nblocks;
4151: uint64_t wblocks;
4152: int64_t rc;
4153:
4154: maxlba = spec->blockcnt;
4155: llen = (uint64_t) len;
4156: if (llen == 0) {
4157: if (lba >= maxlba) {
4158: ISTGT_ERRLOG("end of media\n");
4159: return -1;
4160: }
4161: llen = maxlba - lba;
4162: }
4163: blen = spec->blocklen;
4164: offset = lba * blen;
4165: nbytes = 1 * blen;
4166:
4167: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4168: "Write Same: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
4169: maxlba, lba, len);
4170:
4171: if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
4172: ISTGT_ERRLOG("end of media\n");
4173: return -1;
4174: }
4175:
4176: if (nbytes > lu_cmd->iobufsize) {
1.1.1.2 misho 4177: ISTGT_ERRLOG("nbytes(%zu) > iobufsize(%zu)\n",
4178: (size_t) nbytes, lu_cmd->iobufsize);
1.1 misho 4179: return -1;
4180: }
4181: data = lu_cmd->iobuf;
4182:
4183: rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
4184: lu_cmd->iobufsize, nbytes);
4185: if (rc < 0) {
4186: ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
4187: return -1;
4188: }
4189:
4190: if (spec->lu->readonly) {
4191: ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
4192: return -1;
4193: }
4194:
4195: if (conn->workbuf == NULL) {
4196: conn->worksize = ISTGT_LU_WORK_BLOCK_SIZE;
4197: conn->workbuf = xmalloc(conn->worksize);
4198: }
4199: wblocks = (int64_t)conn->worksize / nbytes;
4200: if (wblocks == 0) {
4201: ISTGT_ERRLOG("work buffer is too small\n");
4202: return -1;
4203: }
4204:
4205: spec->req_write_cache = 0;
1.1.1.2 misho 4206: rc = spec->seek(spec, offset);
1.1 misho 4207: if (rc < 0) {
4208: ISTGT_ERRLOG("lu_disk_seek() failed\n");
4209: return -1;
4210: }
4211:
4212: #if 0
4213: nblocks = 0;
4214: while (nblocks < llen) {
1.1.1.2 misho 4215: rc = spec->write(spec, data, nbytes);
1.1 misho 4216: if (rc < 0 || rc != nbytes) {
4217: ISTGT_ERRLOG("lu_disk_write() failed\n");
4218: return -1;
4219: }
4220: nblocks++;
4221: }
4222: #else
4223: nblocks = 0;
4224: while (nblocks < wblocks) {
4225: memcpy(conn->workbuf + (nblocks * nbytes), data, nbytes);
4226: nblocks++;
4227: }
4228:
4229: nblocks = 0;
4230: while (nblocks < llen) {
4231: uint64_t reqblocks = DMIN64(wblocks, (llen - nblocks));
1.1.1.2 misho 4232: rc = spec->write(spec, conn->workbuf, (reqblocks * nbytes));
4233: if (rc < 0 || (uint64_t) rc != (reqblocks * nbytes)) {
1.1 misho 4234: ISTGT_ERRLOG("lu_disk_write() failed\n");
4235: return -1;
4236: }
4237: nblocks += reqblocks;
4238: }
4239: #endif
4240: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
4241: (nblocks * nbytes), (llen * nbytes));
4242:
4243: lu_cmd->data_len = nbytes;
4244:
4245: return 0;
4246: }
4247:
4248: static int
4249: istgt_lu_disk_lbwrite_ats(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
4250: {
4251: uint8_t *data;
4252: uint64_t maxlba;
4253: uint64_t llen;
4254: uint64_t blen;
4255: uint64_t offset;
4256: uint64_t nbytes;
4257: int64_t rc;
4258: uint8_t *sense_data;
1.1.1.2 misho 4259: size_t *sense_len;
1.1 misho 4260:
4261: if (len == 0) {
4262: lu_cmd->data_len = 0;
4263: return 0;
4264: }
4265:
4266: sense_data = lu_cmd->sense_data;
4267: sense_len = &lu_cmd->sense_data_len;
4268: *sense_len = 0;
4269:
4270: maxlba = spec->blockcnt;
4271: llen = (uint64_t) len;
4272: blen = spec->blocklen;
4273: offset = lba * blen;
4274: nbytes = llen * blen;
4275:
4276: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4277: "Write ATS: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
4278: maxlba, lba, len);
4279:
4280: if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
4281: ISTGT_ERRLOG("end of media\n");
4282: return -1;
4283: }
4284:
4285: if (nbytes > lu_cmd->iobufsize) {
1.1.1.2 misho 4286: ISTGT_ERRLOG("nbytes(%zu) > iobufsize(%zu)\n",
4287: (size_t) nbytes, lu_cmd->iobufsize);
1.1 misho 4288: return -1;
4289: }
4290: data = lu_cmd->iobuf;
4291:
4292: rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
4293: lu_cmd->iobufsize, nbytes * 2);
4294: if (rc < 0) {
4295: ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
4296: return -1;
4297: }
4298:
4299: if (spec->lu->readonly) {
4300: ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
4301: return -1;
4302: }
4303:
1.1.1.2 misho 4304: if (spec->watsbuf == NULL) {
4305: spec->watssize = ISTGT_LU_WORK_ATS_BLOCK_SIZE;
4306: spec->watsbuf = xmalloc(spec->watssize);
4307: }
4308: if (nbytes > (uint64_t) spec->watssize) {
4309: ISTGT_ERRLOG("nbytes(%zu) > watssize(%zu)\n",
4310: (size_t) nbytes, (size_t) spec->watssize);
4311: return -1;
4312: }
4313:
1.1 misho 4314: spec->req_write_cache = 0;
4315: /* start atomic test and set */
4316: MTX_LOCK(&spec->ats_mutex);
4317:
1.1.1.2 misho 4318: rc = spec->seek(spec, offset);
1.1 misho 4319: if (rc < 0) {
4320: MTX_UNLOCK(&spec->ats_mutex);
4321: ISTGT_ERRLOG("lu_disk_seek() failed\n");
4322: return -1;
4323: }
4324:
1.1.1.2 misho 4325: rc = spec->read(spec, spec->watsbuf, nbytes);
4326: if (rc < 0 || (uint64_t) rc != nbytes) {
1.1 misho 4327: MTX_UNLOCK(&spec->ats_mutex);
4328: ISTGT_ERRLOG("lu_disk_read() failed\n");
4329: return -1;
4330: }
4331:
4332: #if 0
4333: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS VERIFY", data, nbytes);
4334: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS WRITE", data + nbytes, nbytes);
1.1.1.2 misho 4335: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS DATA", spec->watsbuf, nbytes);
1.1 misho 4336: #endif
1.1.1.2 misho 4337: if (memcmp(spec->watsbuf, data, nbytes) != 0) {
1.1 misho 4338: MTX_UNLOCK(&spec->ats_mutex);
4339: //ISTGT_ERRLOG("compare failed\n");
4340: /* MISCOMPARE DURING VERIFY OPERATION */
4341: BUILD_SENSE(MISCOMPARE, 0x1d, 0x00);
4342: return -1;
4343: }
4344:
1.1.1.2 misho 4345: rc = spec->seek(spec, offset);
1.1 misho 4346: if (rc < 0) {
4347: MTX_UNLOCK(&spec->ats_mutex);
4348: ISTGT_ERRLOG("lu_disk_seek() failed\n");
4349: return -1;
4350: }
1.1.1.2 misho 4351: rc = spec->write(spec, data + nbytes, nbytes);
4352: if (rc < 0 || (uint64_t) rc != nbytes) {
1.1 misho 4353: MTX_UNLOCK(&spec->ats_mutex);
4354: ISTGT_ERRLOG("lu_disk_write() failed\n");
4355: return -1;
4356: }
4357: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
4358: rc, nbytes);
4359:
4360: MTX_UNLOCK(&spec->ats_mutex);
4361: /* end atomic test and set */
4362:
4363: lu_cmd->data_len = nbytes * 2;
4364:
4365: return 0;
4366: }
4367:
4368: static int
1.1.1.2 misho 4369: 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 4370: {
4371: uint64_t maxlba;
4372: uint64_t llen;
4373: uint64_t blen;
4374: uint64_t offset;
4375: uint64_t nbytes;
4376: int64_t rc;
4377:
4378: if (len == 0) {
4379: return 0;
4380: }
4381:
4382: maxlba = spec->blockcnt;
4383: llen = (uint64_t) len;
4384: blen = spec->blocklen;
4385: offset = lba * blen;
4386: nbytes = llen * blen;
4387:
4388: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4389: "Sync: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
4390: maxlba, lba, len);
4391:
4392: if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
4393: ISTGT_ERRLOG("end of media\n");
4394: return -1;
4395: }
4396:
1.1.1.2 misho 4397: rc = spec->sync(spec, offset, nbytes);
1.1 misho 4398: if (rc < 0) {
4399: ISTGT_ERRLOG("lu_disk_sync() failed\n");
4400: return -1;
4401: }
4402:
4403: return 0;
4404: }
4405:
4406: int
4407: istgt_lu_scsi_build_sense_data(uint8_t *data, int sk, int asc, int ascq)
4408: {
4409: uint8_t *cp;
4410: int resp_code;
4411: int hlen = 0, len = 0, plen;
4412: int total;
4413:
4414: resp_code = 0x70; /* Current + Fixed format */
4415:
4416: /* SenseLength */
4417: DSET16(&data[0], 0);
4418: hlen = 2;
4419:
4420: /* Sense Data */
4421: cp = &data[hlen + len];
4422:
4423: /* VALID(7) RESPONSE CODE(6-0) */
4424: BDSET8(&cp[0], 1, 7);
4425: BDADD8W(&cp[0], resp_code, 6, 7);
4426: /* Obsolete */
4427: cp[1] = 0;
4428: /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
4429: BDSET8W(&cp[2], sk, 3, 4);
4430: /* INFORMATION */
4431: memset(&cp[3], 0, 4);
4432: /* ADDITIONAL SENSE LENGTH */
4433: cp[7] = 0;
4434: len = 8;
4435:
4436: /* COMMAND-SPECIFIC INFORMATION */
4437: memset(&cp[8], 0, 4);
4438: /* ADDITIONAL SENSE CODE */
4439: cp[12] = asc;
4440: /* ADDITIONAL SENSE CODE QUALIFIER */
4441: cp[13] = ascq;
4442: /* FIELD REPLACEABLE UNIT CODE */
4443: cp[14] = 0;
4444: /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
4445: cp[15] = 0;
4446: cp[16] = 0;
4447: cp[17] = 0;
4448: /* Additional sense bytes */
4449: //data[18] = 0;
4450: plen = 18 - len;
4451:
4452: /* ADDITIONAL SENSE LENGTH */
4453: cp[7] = plen;
4454:
4455: total = hlen + len + plen;
4456:
4457: /* SenseLength */
4458: DSET16(&data[0], total - 2);
4459:
4460: return total;
4461: }
4462:
4463: static int
1.1.1.2 misho 4464: istgt_lu_disk_build_sense_data(ISTGT_LU_DISK *spec __attribute__((__unused__)), uint8_t *data, int sk, int asc, int ascq)
1.1 misho 4465: {
4466: int rc;
4467:
4468: rc = istgt_lu_scsi_build_sense_data(data, sk, asc, ascq);
4469: if (rc < 0) {
4470: return -1;
4471: }
4472: return rc;
4473: }
4474:
4475: int
4476: istgt_lu_scsi_build_sense_data2(uint8_t *data, int sk, int asc, int ascq)
4477: {
4478: uint8_t *cp;
4479: int resp_code;
4480: int hlen = 0, len = 0, plen;
4481: int total;
4482:
4483: resp_code = 0x71; /* Deferred + Fixed format */
4484:
4485: /* SenseLength */
4486: DSET16(&data[0], 0);
4487: hlen = 2;
4488:
4489: /* Sense Data */
4490: cp = &data[hlen + len];
4491:
4492: /* VALID(7) RESPONSE CODE(6-0) */
4493: BDSET8(&cp[0], 1, 7);
4494: BDADD8W(&cp[0], resp_code, 6, 7);
4495: /* Obsolete */
4496: cp[1] = 0;
4497: /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
4498: BDSET8W(&cp[2], sk, 3, 4);
4499: /* INFORMATION */
4500: memset(&cp[3], 0, 4);
4501: /* ADDITIONAL SENSE LENGTH */
4502: cp[7] = 0;
4503: len = 8;
4504:
4505: /* COMMAND-SPECIFIC INFORMATION */
4506: memset(&cp[8], 0, 4);
4507: /* ADDITIONAL SENSE CODE */
4508: cp[12] = asc;
4509: /* ADDITIONAL SENSE CODE QUALIFIER */
4510: cp[13] = ascq;
4511: /* FIELD REPLACEABLE UNIT CODE */
4512: cp[14] = 0;
4513: /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
4514: cp[15] = 0;
4515: cp[16] = 0;
4516: cp[17] = 0;
4517: /* Additional sense bytes */
4518: //data[18] = 0;
4519: plen = 18 - len;
4520:
4521: /* ADDITIONAL SENSE LENGTH */
4522: cp[7] = plen;
4523:
4524: total = hlen + len + plen;
4525:
4526: /* SenseLength */
4527: DSET16(&data[0], total - 2);
4528:
4529: return total;
4530: }
4531:
4532: static int
1.1.1.2 misho 4533: istgt_lu_disk_build_sense_data2(ISTGT_LU_DISK *spec __attribute__((__unused__)), uint8_t *data, int sk, int asc, int ascq)
1.1 misho 4534: {
4535: int rc;
4536:
4537: rc = istgt_lu_scsi_build_sense_data2(data, sk, asc, ascq);
4538: if (rc < 0) {
4539: return -1;
4540: }
4541: return rc;
4542: }
4543:
4544: int
4545: istgt_lu_disk_reset(ISTGT_LU_Ptr lu, int lun)
4546: {
4547: ISTGT_LU_DISK *spec;
4548: int flags;
4549: int rc;
4550:
4551: if (lu == NULL) {
4552: return -1;
4553: }
4554: if (lun >= lu->maxlun) {
4555: return -1;
4556: }
4557: if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
4558: return -1;
4559: }
4560: if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) {
4561: return -1;
4562: }
4563: spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
4564:
4565: #if 0
4566: if (spec->lock) {
4567: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "unlock by reset\n");
4568: spec->lock = 0;
4569: }
4570: #endif
4571:
4572: if (lu->queue_depth != 0) {
4573: rc = istgt_lu_disk_queue_clear_all(lu, lun);
4574: if (rc < 0) {
4575: ISTGT_ERRLOG("lu_disk_queue_clear_all() failed\n");
4576: return -1;
4577: }
4578: }
4579:
4580: /* re-open file */
4581: if (!spec->lu->readonly) {
1.1.1.2 misho 4582: rc = spec->sync(spec, 0, spec->size);
1.1 misho 4583: if (rc < 0) {
4584: ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_sync() failed\n",
4585: lu->num, lun);
4586: /* ignore error */
4587: }
4588: }
1.1.1.2 misho 4589: rc = spec->close(spec);
1.1 misho 4590: if (rc < 0) {
4591: ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_close() failed\n",
4592: lu->num, lun);
4593: /* ignore error */
4594: }
4595: flags = lu->readonly ? O_RDONLY : O_RDWR;
1.1.1.2 misho 4596: rc = spec->open(spec, flags, 0666);
1.1 misho 4597: if (rc < 0) {
4598: ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_open() failed\n",
4599: lu->num, lun);
4600: return -1;
4601: }
4602:
4603: return 0;
4604: }
4605:
4606: static int
4607: istgt_lu_disk_queue_clear_internal(ISTGT_LU_DISK *spec, const char *initiator_port, int all_cmds, uint32_t CmdSN)
4608: {
4609: ISTGT_LU_TASK_Ptr lu_task;
4610: ISTGT_QUEUE saved_queue;
4611: time_t now;
4612: int rc;
4613:
4614: if (spec == NULL)
4615: return -1;
4616:
4617: if (all_cmds != 0) {
4618: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by port=%s\n",
4619: initiator_port);
4620: } else {
4621: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by port=%s, CmdSN=%u\n",
4622: initiator_port, CmdSN);
4623: }
4624:
4625: istgt_queue_init(&saved_queue);
4626:
4627: now = time(NULL);
4628: MTX_LOCK(&spec->cmd_queue_mutex);
4629: while (1) {
4630: lu_task = istgt_queue_dequeue(&spec->cmd_queue);
4631: if (lu_task == NULL)
4632: break;
4633: if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN))
4634: && (strcasecmp(lu_task->initiator_port,
4635: initiator_port) == 0)) {
1.1.1.2 misho 4636: ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%lu cleared\n",
1.1 misho 4637: lu_task->lu_cmd.CmdSN,
4638: lu_task->lu_cmd.cdb[0],
1.1.1.2 misho 4639: (unsigned long) (now - lu_task->create_time));
1.1 misho 4640: rc = istgt_lu_destroy_task(lu_task);
4641: if (rc < 0) {
4642: MTX_UNLOCK(&spec->cmd_queue_mutex);
4643: ISTGT_ERRLOG("lu_destory_task() failed\n");
4644: goto error_return;
4645: }
4646: continue;
4647: }
4648: rc = istgt_queue_enqueue(&saved_queue, lu_task);
4649: if (rc < 0) {
4650: MTX_UNLOCK(&spec->cmd_queue_mutex);
4651: ISTGT_ERRLOG("queue_enqueue() failed\n");
4652: goto error_return;
4653: }
4654: }
4655: while (1) {
4656: lu_task = istgt_queue_dequeue(&saved_queue);
4657: if (lu_task == NULL)
4658: break;
4659: rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
4660: if (rc < 0) {
4661: MTX_UNLOCK(&spec->cmd_queue_mutex);
4662: ISTGT_ERRLOG("queue_enqueue() failed\n");
4663: goto error_return;
4664: }
4665: }
4666: MTX_UNLOCK(&spec->cmd_queue_mutex);
4667:
4668: /* check wait task */
4669: MTX_LOCK(&spec->wait_lu_task_mutex);
4670: lu_task = spec->wait_lu_task;
4671: if (lu_task != NULL) {
4672: if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN))
4673: && (strcasecmp(lu_task->initiator_port,
4674: initiator_port) == 0)) {
4675: /* conn had gone? */
4676: rc = pthread_mutex_trylock(&lu_task->trans_mutex);
4677: if (rc == 0) {
1.1.1.2 misho 4678: ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%lu aborted\n",
1.1 misho 4679: lu_task->lu_cmd.CmdSN,
4680: lu_task->lu_cmd.cdb[0],
1.1.1.2 misho 4681: (unsigned long) (now - lu_task->create_time));
1.1 misho 4682: /* force error */
4683: lu_task->error = 1;
4684: lu_task->abort = 1;
4685: rc = pthread_cond_broadcast(&lu_task->trans_cond);
4686: if (rc != 0) {
4687: /* ignore error */
4688: }
4689: MTX_UNLOCK(&lu_task->trans_mutex);
4690: }
4691: }
4692: }
4693: MTX_UNLOCK(&spec->wait_lu_task_mutex);
4694:
4695: rc = istgt_queue_count(&saved_queue);
4696: if (rc != 0) {
4697: ISTGT_ERRLOG("temporary queue is not empty\n");
4698: goto error_return;
4699: }
4700:
4701: istgt_queue_destroy(&saved_queue);
4702: return 0;
4703:
4704: error_return:
4705: istgt_queue_destroy(&saved_queue);
4706: return -1;
4707: }
4708:
4709: static int
4710: istgt_lu_disk_queue_abort_ITL(ISTGT_LU_DISK *spec, const char *initiator_port)
4711: {
4712: int rc;
4713:
4714: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue abort by port=%s\n",
4715: initiator_port);
4716:
4717: rc = istgt_lu_disk_queue_clear_internal(spec, initiator_port,
4718: 1, 0U); /* ALL, CmdSN=0 */
4719: return rc;
4720: }
4721:
4722: int
4723: istgt_lu_disk_queue_clear_IT(CONN_Ptr conn, ISTGT_LU_Ptr lu)
4724: {
4725: ISTGT_LU_DISK *spec;
4726: int rc;
4727: int i;
4728:
4729: if (lu == NULL)
4730: return -1;
4731:
4732: for (i = 0; i < lu->maxlun; i++) {
4733: if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
4734: #if 0
4735: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
4736: lu->num, i);
4737: #endif
4738: continue;
4739: }
4740: if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) {
4741: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
4742: return -1;
4743: }
4744: spec = (ISTGT_LU_DISK *) lu->lun[i].spec;
4745: if (spec == NULL) {
4746: continue;
4747: }
4748:
4749: rc = istgt_lu_disk_queue_clear_ITL(conn, lu, i);
4750: if (rc < 0) {
4751: return -1;
4752: }
4753: }
4754:
4755: return 0;
4756: }
4757:
4758: int
4759: istgt_lu_disk_queue_clear_ITL(CONN_Ptr conn, ISTGT_LU_Ptr lu, int lun)
4760: {
4761: ISTGT_LU_DISK *spec;
4762: int rc;
4763:
4764: if (lu == NULL)
4765: return -1;
4766: if (lun >= lu->maxlun)
4767: return -1;
4768:
4769: spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
4770: if (spec == NULL)
4771: return -1;
4772:
4773: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by name=%s, port=%s\n",
4774: conn->initiator_name, conn->initiator_port);
4775:
4776: rc = istgt_lu_disk_queue_clear_internal(spec, conn->initiator_port,
4777: 1, 0U); /* ALL, CmdSN=0 */
4778: return rc;
4779: }
4780:
4781: int
4782: istgt_lu_disk_queue_clear_ITLQ(CONN_Ptr conn, ISTGT_LU_Ptr lu, int lun, uint32_t CmdSN)
4783: {
4784: ISTGT_LU_DISK *spec;
4785: int rc;
4786:
4787: if (lu == NULL)
4788: return -1;
4789: if (lun >= lu->maxlun)
4790: return -1;
4791:
4792: spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
4793: if (spec == NULL)
4794: return -1;
4795:
4796: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by name=%s, port=%s\n",
4797: conn->initiator_name, conn->initiator_port);
4798:
4799: rc = istgt_lu_disk_queue_clear_internal(spec, conn->initiator_port,
4800: 0, CmdSN);
4801: return rc;
4802: }
4803:
4804: int
4805: istgt_lu_disk_queue_clear_all(ISTGT_LU_Ptr lu, int lun)
4806: {
4807: ISTGT_LU_TASK_Ptr lu_task;
4808: ISTGT_LU_DISK *spec;
4809: time_t now;
4810: int rc;
4811:
4812: if (lu == NULL)
4813: return -1;
4814: if (lun >= lu->maxlun)
4815: return -1;
4816:
4817: if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
4818: return -1;
4819: }
4820: if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) {
4821: return -1;
4822: }
4823: spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
4824: if (spec == NULL)
4825: return -1;
4826:
4827: now = time(NULL);
4828: MTX_LOCK(&spec->cmd_queue_mutex);
4829: while (1) {
4830: lu_task = istgt_queue_dequeue(&spec->cmd_queue);
4831: if (lu_task == NULL)
4832: break;
1.1.1.2 misho 4833: ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%lu cleared\n",
1.1 misho 4834: lu_task->lu_cmd.CmdSN,
4835: lu_task->lu_cmd.cdb[0],
1.1.1.2 misho 4836: (unsigned long) (now - lu_task->create_time));
1.1 misho 4837: rc = istgt_lu_destroy_task(lu_task);
4838: if (rc < 0) {
4839: MTX_UNLOCK(&spec->cmd_queue_mutex);
4840: ISTGT_ERRLOG("lu_destory_task() failed\n");
4841: return -1;
4842: }
4843: }
4844: MTX_UNLOCK(&spec->cmd_queue_mutex);
4845:
4846: /* check wait task */
4847: MTX_LOCK(&spec->wait_lu_task_mutex);
4848: lu_task = spec->wait_lu_task;
4849: if (lu_task != NULL) {
4850: /* conn had gone? */
4851: rc = pthread_mutex_trylock(&lu_task->trans_mutex);
4852: if (rc == 0) {
1.1.1.2 misho 4853: ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%lu aborted\n",
1.1 misho 4854: lu_task->lu_cmd.CmdSN,
4855: lu_task->lu_cmd.cdb[0],
1.1.1.2 misho 4856: (unsigned long) (now - lu_task->create_time));
1.1 misho 4857: /* force error */
4858: lu_task->error = 1;
4859: lu_task->abort = 1;
4860: rc = pthread_cond_broadcast(&lu_task->trans_cond);
4861: if (rc != 0) {
4862: /* ignore error */
4863: }
4864: MTX_UNLOCK(&lu_task->trans_mutex);
4865: }
4866: }
4867: MTX_UNLOCK(&spec->wait_lu_task_mutex);
4868:
4869: MTX_LOCK(&spec->cmd_queue_mutex);
4870: rc = istgt_queue_count(&spec->cmd_queue);
4871: MTX_UNLOCK(&spec->cmd_queue_mutex);
4872: if (rc != 0) {
4873: ISTGT_ERRLOG("cmd queue is not empty\n");
4874: return -1;
4875: }
4876:
4877: return 0;
4878: }
4879:
4880: int
4881: istgt_lu_disk_queue(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
4882: {
4883: ISTGT_LU_TASK_Ptr lu_task;
4884: ISTGT_LU_Ptr lu;
4885: ISTGT_LU_DISK *spec;
4886: uint8_t *data;
4887: uint8_t *cdb;
4888: uint32_t allocation_len;
4889: int data_len;
4890: int data_alloc_len;
4891: uint8_t *sense_data;
1.1.1.2 misho 4892: size_t *sense_len;
1.1 misho 4893: int lun_i;
4894: int maxq;
4895: int qcnt;
4896: int rc;
4897:
4898: if (lu_cmd == NULL)
4899: return -1;
4900: lu = lu_cmd->lu;
4901: if (lu == NULL) {
4902: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4903: return -1;
4904: }
4905: spec = NULL;
4906: cdb = lu_cmd->cdb;
4907: data = lu_cmd->data;
4908: data_alloc_len = lu_cmd->alloc_len;
4909: sense_data = lu_cmd->sense_data;
4910: sense_len = &lu_cmd->sense_data_len;
4911: *sense_len = 0;
4912:
4913: lun_i = istgt_lu_islun2lun(lu_cmd->lun);
4914: if (lun_i >= lu->maxlun) {
4915: #ifdef ISTGT_TRACE_DISK
4916: ISTGT_ERRLOG("LU%d: LUN%4.4"PRIx64" invalid\n",
4917: lu->num, lun_i);
4918: #endif /* ISTGT_TRACE_DISK */
4919: if (cdb[0] == SPC_INQUIRY) {
4920: allocation_len = DGET16(&cdb[3]);
1.1.1.2 misho 4921: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 4922: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
4923: data_alloc_len);
4924: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4925: return -1;
4926: }
4927: memset(data, 0, allocation_len);
4928: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
4929: BDSET8W(&data[0], 0x03, 7, 3);
4930: BDADD8W(&data[0], 0x1f, 4, 5);
4931: data_len = 96;
4932: memset(&data[1], 0, data_len - 1);
4933: /* ADDITIONAL LENGTH */
4934: data[4] = data_len - 5;
1.1.1.2 misho 4935: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 4936: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
4937: return ISTGT_LU_TASK_RESULT_IMMEDIATE;
4938: } else {
4939: /* LOGICAL UNIT NOT SUPPORTED */
4940: BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
4941: lu_cmd->data_len = 0;
4942: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4943: return ISTGT_LU_TASK_RESULT_IMMEDIATE;
4944: }
4945: }
4946: spec = (ISTGT_LU_DISK *) lu->lun[lun_i].spec;
4947: if (spec == NULL) {
4948: /* LOGICAL UNIT NOT SUPPORTED */
4949: BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
4950: lu_cmd->data_len = 0;
4951: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
4952: return ISTGT_LU_TASK_RESULT_IMMEDIATE;
4953: }
4954: /* ready to enqueue, spec is valid for LUN access */
4955:
4956: /* allocate task and copy LU_CMD(PDU) */
4957: lu_task = xmalloc(sizeof *lu_task);
4958: memset(lu_task, 0, sizeof *lu_task);
4959: rc = istgt_lu_create_task(conn, lu_cmd, lu_task, lun_i);
4960: if (rc < 0) {
4961: ISTGT_ERRLOG("lu_create_task() failed\n");
4962: xfree(lu_task);
4963: return -1;
4964: }
4965:
4966: /* enqueue SCSI command */
4967: MTX_LOCK(&spec->cmd_queue_mutex);
4968: rc = istgt_queue_count(&spec->cmd_queue);
4969: maxq = spec->queue_depth * lu->istgt->MaxSessions;
4970: if (rc > maxq) {
4971: MTX_UNLOCK(&spec->cmd_queue_mutex);
4972: lu_cmd->data_len = 0;
4973: lu_cmd->status = ISTGT_SCSI_STATUS_TASK_SET_FULL;
4974: rc = istgt_lu_destroy_task(lu_task);
4975: if (rc < 0) {
4976: ISTGT_ERRLOG("lu_destroy_task() failed\n");
4977: return -1;
4978: }
4979: return ISTGT_LU_TASK_RESULT_QUEUE_FULL;
4980: }
4981: qcnt = rc;
4982: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
4983: "Queue(%d), CmdSN=%u, OP=0x%x, LUN=0x%16.16"PRIx64"\n",
4984: qcnt, lu_cmd->CmdSN, lu_cmd->cdb[0], lu_cmd->lun);
4985:
4986: /* enqueue task to LUN */
4987: switch (lu_cmd->Attr_bit) {
4988: case 0x03: /* Head of Queue */
4989: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Head of Queue\n");
4990: rc = istgt_queue_enqueue_first(&spec->cmd_queue, lu_task);
4991: break;
4992: case 0x00: /* Untagged */
4993: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Untagged\n");
4994: rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
4995: break;
4996: case 0x01: /* Simple */
4997: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Simple\n");
4998: rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
4999: break;
5000: case 0x02: /* Ordered */
5001: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Ordered\n");
5002: rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
5003: break;
5004: case 0x04: /* ACA */
5005: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert ACA\n");
5006: rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
5007: break;
5008: default: /* Reserved */
5009: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Reserved Attribute\n");
5010: rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
5011: break;
5012: }
5013: MTX_UNLOCK(&spec->cmd_queue_mutex);
5014: if (rc < 0) {
5015: ISTGT_ERRLOG("queue_enqueue() failed\n");
5016: error_return:
5017: rc = istgt_lu_destroy_task(lu_task);
5018: if (rc < 0) {
5019: ISTGT_ERRLOG("lu_destroy_task() failed\n");
5020: return -1;
5021: }
5022: return -1;
5023: }
5024:
5025: /* notify LUN thread */
1.1.1.2 misho 5026: MTX_LOCK(&lu->queue_mutex);
5027: lu->queue_check = 1;
1.1 misho 5028: rc = pthread_cond_broadcast(&lu->queue_cond);
5029: MTX_UNLOCK(&lu->queue_mutex);
5030: if (rc != 0) {
5031: ISTGT_ERRLOG("LU%d: cond_broadcast() failed\n", lu->num);
5032: goto error_return;
5033: }
5034:
5035: return ISTGT_LU_TASK_RESULT_QUEUE_OK;
5036: }
5037:
5038: int
5039: istgt_lu_disk_queue_count(ISTGT_LU_Ptr lu, int *lun)
5040: {
5041: ISTGT_LU_DISK *spec;
5042: int qcnt;
5043: int luns;
5044: int i;
5045:
5046: if (lun == NULL)
5047: return -1;
5048:
5049: i = *lun;
5050: if (i >= lu->maxlun) {
5051: *lun = 0;
5052: i = 0;
5053: }
5054:
5055: qcnt = 0;
5056: for (luns = lu->maxlun; luns >= 0 ; luns--) {
5057: if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
5058: goto next_lun;
5059: }
5060: if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) {
5061: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
5062: goto next_lun;
5063: }
5064: spec = (ISTGT_LU_DISK *) lu->lun[i].spec;
5065: if (spec == NULL) {
5066: goto next_lun;
5067: }
5068:
5069: MTX_LOCK(&spec->cmd_queue_mutex);
5070: qcnt = istgt_queue_count(&spec->cmd_queue);
5071: MTX_UNLOCK(&spec->cmd_queue_mutex);
5072: if (qcnt > 0) {
5073: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5074: "LU%d: LUN%d queue(%d)\n",
5075: lu->num, i, qcnt);
5076: *lun = spec->lun;
5077: break;
5078: }
5079:
5080: next_lun:
5081: i++;
5082: if (i >= lu->maxlun) {
5083: i = 0;
5084: }
5085: }
5086: return qcnt;
5087: }
5088:
5089: int
5090: istgt_lu_disk_queue_start(ISTGT_LU_Ptr lu, int lun)
5091: {
5092: ISTGT_Ptr istgt;
5093: ISTGT_LU_DISK *spec;
5094: ISTGT_LU_TASK_Ptr lu_task;
5095: CONN_Ptr conn;
5096: ISTGT_LU_CMD_Ptr lu_cmd;
5097: struct timespec abstime;
1.1.1.3 ! misho 5098: time_t start, now;
1.1 misho 5099: uint8_t *iobuf;
5100: char tmp[1];
5101: int abort_task = 0;
5102: int rc;
5103:
5104: if (lun < 0 || lun >= lu->maxlun) {
5105: return -1;
5106: }
5107:
5108: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LU%d: LUN%d queue start\n",
5109: lu->num, lun);
5110: spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
5111: if (spec == NULL)
5112: return -1;
5113:
5114: MTX_LOCK(&spec->cmd_queue_mutex);
5115: lu_task = istgt_queue_dequeue(&spec->cmd_queue);
5116: MTX_UNLOCK(&spec->cmd_queue_mutex);
5117: if (lu_task == NULL) {
5118: /* cleared or empty queue */
5119: return 0;
5120: }
5121: lu_task->thread = pthread_self();
5122: conn = lu_task->conn;
5123: istgt = conn->istgt;
5124: lu_cmd = &lu_task->lu_cmd;
5125:
5126: /* XXX need pre-allocate? */
5127: #if 0
5128: /* allocated in istgt_lu_create_task() */
5129: lu_task->data = xmalloc(lu_cmd->alloc_len);
5130: lu_task->sense_data = xmalloc(lu_cmd->sense_alloc_len);
5131: lu_task->iobuf = NULL;
5132: #endif
5133: lu_cmd->data = lu_task->data;
5134: lu_cmd->data_len = 0;
5135: lu_cmd->sense_data = lu_task->sense_data;
5136: lu_cmd->sense_data_len = 0;
5137:
5138: tmp[0] = 'Q';
5139: if (lu_cmd->W_bit) {
5140: if (lu_cmd->pdu->data_segment_len >= lu_cmd->transfer_len) {
5141: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5142: "LU%d: LUN%d Task Write Immediate Start\n",
5143: lu->num, lun);
5144: #if 0
5145: iobuf = xmalloc(lu_cmd->pdu->data_segment_len);
5146: memcpy(iobuf, lu_cmd->pdu->data,
5147: lu_cmd->pdu->data_segment_len);
5148: lu_task->iobuf = iobuf;
5149: #else
5150: iobuf = lu_cmd->pdu->data;
5151: lu_task->dup_iobuf = 1;
5152: #endif
5153: lu_cmd->iobuf = iobuf;
5154:
5155: MTX_LOCK(&lu_cmd->lu->mutex);
5156: rc = istgt_lu_disk_execute(conn, lu_cmd);
5157: MTX_UNLOCK(&lu_cmd->lu->mutex);
5158: if (rc < 0) {
5159: ISTGT_ERRLOG("lu_disk_execute() failed\n");
5160: error_return:
5161: rc = istgt_lu_destroy_task(lu_task);
5162: if (rc < 0) {
5163: ISTGT_ERRLOG("lu_destroy_task() failed\n");
5164: return -1;
5165: }
5166: return -1;
5167: }
5168: lu_task->execute = 1;
5169:
5170: /* response */
5171: if (conn->use_sender == 0) {
5172: MTX_LOCK(&conn->task_queue_mutex);
5173: rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
5174: MTX_UNLOCK(&conn->task_queue_mutex);
5175: if (rc < 0) {
5176: ISTGT_ERRLOG("queue_enqueue() failed\n");
5177: goto error_return;
5178: }
5179: rc = write(conn->task_pipe[1], tmp, 1);
5180: if(rc < 0 || rc != 1) {
5181: ISTGT_ERRLOG("write() failed\n");
5182: goto error_return;
5183: }
5184: } else {
5185: MTX_LOCK(&conn->result_queue_mutex);
5186: rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
5187: if (rc < 0) {
5188: MTX_UNLOCK(&conn->result_queue_mutex);
5189: ISTGT_ERRLOG("queue_enqueue() failed\n");
5190: goto error_return;
5191: }
5192: rc = pthread_cond_broadcast(&conn->result_queue_cond);
5193: MTX_UNLOCK(&conn->result_queue_mutex);
5194: if (rc != 0) {
5195: ISTGT_ERRLOG("cond_broadcast() failed\n");
5196: goto error_return;
5197: }
5198: }
5199:
5200: #if 0
5201: /* write cache */
5202: if (spec->req_write_cache) {
5203: MTX_LOCK(&lu->mutex);
5204: rc = istgt_lu_disk_write_cache(spec, conn);
5205: MTX_UNLOCK(&lu->mutex);
5206: if (rc < 0) {
5207: ISTGT_ERRLOG("disk_write_cache() failed\n");
5208: return -1;
5209: }
5210: }
5211: #endif
5212: } else {
5213: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5214: "LU%d: LUN%d Task Write Start\n",
5215: lu->num, lun);
5216:
5217: #if 0
5218: MTX_LOCK(&spec->wait_lu_task_mutex);
5219: spec->wait_lu_task = NULL;
5220: MTX_UNLOCK(&spec->wait_lu_task_mutex);
5221: #endif
5222: rc = pthread_mutex_init(&lu_task->trans_mutex, NULL);
5223: if (rc != 0) {
5224: ISTGT_ERRLOG("mutex_init() failed\n");
5225: goto error_return;
5226: }
5227: rc = pthread_cond_init(&lu_task->trans_cond, NULL);
5228: if (rc != 0) {
5229: ISTGT_ERRLOG("cond_init() failed\n");
5230: goto error_return;
5231: }
5232: rc = pthread_cond_init(&lu_task->exec_cond, NULL);
5233: if (rc != 0) {
5234: ISTGT_ERRLOG("cond_init() failed\n");
5235: goto error_return;
5236: }
5237: lu_task->use_cond = 1;
5238: #if 0
5239: lu_cmd->iobufsize = lu_cmd->transfer_len + 65536;
5240: iobuf = xmalloc(lu_cmd->iobufsize);
5241: lu_task->iobuf = iobuf;
5242: #else
5243: lu_cmd->iobufsize = lu_task->lu_cmd.iobufsize;
5244: iobuf = lu_task->iobuf;
5245: #endif
5246: lu_cmd->iobuf = iobuf;
5247: lu_task->req_transfer_out = 1;
5248: memset(&abstime, 0, sizeof abstime);
5249: abstime.tv_sec = 0;
5250: abstime.tv_nsec = 0;
5251:
5252: MTX_LOCK(&conn->task_queue_mutex);
5253: rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
5254: MTX_UNLOCK(&conn->task_queue_mutex);
5255: if (rc < 0) {
5256: MTX_UNLOCK(&lu_task->trans_mutex);
5257: ISTGT_ERRLOG("queue_enqueue() failed\n");
5258: goto error_return;
5259: }
5260: rc = write(conn->task_pipe[1], tmp, 1);
5261: if(rc < 0 || rc != 1) {
5262: MTX_UNLOCK(&lu_task->trans_mutex);
5263: ISTGT_ERRLOG("write() failed\n");
5264: goto error_return;
5265: }
5266:
1.1.1.3 ! misho 5267: start = now = time(NULL);
1.1 misho 5268: abstime.tv_sec = now + (lu_task->condwait / 1000);
5269: abstime.tv_nsec = (lu_task->condwait % 1000) * 1000000;
5270: #if 0
5271: ISTGT_LOG("wait CmdSN=%u\n", lu_task->lu_cmd.CmdSN);
5272: #endif
1.1.1.2 misho 5273: MTX_LOCK(&lu_task->trans_mutex);
1.1 misho 5274: MTX_LOCK(&spec->wait_lu_task_mutex);
5275: spec->wait_lu_task = lu_task;
5276: MTX_UNLOCK(&spec->wait_lu_task_mutex);
1.1.1.2 misho 5277: rc = 0;
1.1 misho 5278: while (lu_task->req_transfer_out == 1) {
5279: rc = pthread_cond_timedwait(&lu_task->trans_cond,
5280: &lu_task->trans_mutex,
5281: &abstime);
5282: if (rc == ETIMEDOUT) {
5283: if (lu_task->req_transfer_out == 1) {
5284: lu_task->error = 1;
5285: MTX_LOCK(&spec->wait_lu_task_mutex);
5286: spec->wait_lu_task = NULL;
5287: MTX_UNLOCK(&spec->wait_lu_task_mutex);
5288: MTX_UNLOCK(&lu_task->trans_mutex);
1.1.1.3 ! misho 5289: now = time(NULL);
! 5290: ISTGT_ERRLOG("timeout trans_cond CmdSN=%u "
! 5291: "(time=%d)\n",
! 5292: lu_task->lu_cmd.CmdSN,
! 5293: (int)difftime(now, start));
1.1 misho 5294: /* timeout */
5295: return -1;
5296: }
5297: /* OK cond */
5298: rc = 0;
5299: break;
5300: }
5301: if (lu_task->error != 0) {
5302: rc = -1;
5303: break;
5304: }
5305: if (rc != 0) {
5306: break;
5307: }
5308: }
5309: MTX_LOCK(&spec->wait_lu_task_mutex);
5310: spec->wait_lu_task = NULL;
5311: MTX_UNLOCK(&spec->wait_lu_task_mutex);
5312: MTX_UNLOCK(&lu_task->trans_mutex);
5313: if (rc != 0) {
5314: if (rc < 0) {
5315: lu_task->error = 1;
5316: if (lu_task->abort) {
5317: ISTGT_WARNLOG("transfer abort CmdSN=%u\n",
5318: lu_task->lu_cmd.CmdSN);
5319: return -2;
5320: } else {
5321: ISTGT_ERRLOG("transfer error CmdSN=%u\n",
5322: lu_task->lu_cmd.CmdSN);
5323: return -1;
5324: }
5325: }
5326: if (rc == ETIMEDOUT) {
5327: lu_task->error = 1;
1.1.1.3 ! misho 5328: now = time(NULL);
! 5329: ISTGT_ERRLOG("timeout trans_cond CmdSN=%u (time=%d)\n",
! 5330: lu_task->lu_cmd.CmdSN, (int)difftime(now, start));
1.1 misho 5331: return -1;
5332: }
5333: lu_task->error = 1;
5334: ISTGT_ERRLOG("cond_timedwait rc=%d\n", rc);
5335: return -1;
5336: }
5337:
5338: if (lu_task->req_execute == 0) {
5339: ISTGT_ERRLOG("wrong request\n");
5340: goto error_return;
5341: }
5342: MTX_LOCK(&lu_cmd->lu->mutex);
5343: rc = istgt_lu_disk_execute(conn, lu_cmd);
5344: MTX_UNLOCK(&lu_cmd->lu->mutex);
5345: if (rc < 0) {
5346: lu_task->error = 1;
5347: ISTGT_ERRLOG("lu_disk_execute() failed\n");
5348: goto error_return;
5349: }
5350: lu_task->execute = 1;
5351:
5352: /* response */
5353: if (conn->use_sender == 0) {
5354: MTX_LOCK(&conn->task_queue_mutex);
5355: rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
5356: MTX_UNLOCK(&conn->task_queue_mutex);
5357: if (rc < 0) {
5358: ISTGT_ERRLOG("queue_enqueue() failed\n");
5359: goto error_return;
5360: }
5361: rc = write(conn->task_pipe[1], tmp, 1);
5362: if(rc < 0 || rc != 1) {
5363: ISTGT_ERRLOG("write() failed\n");
5364: goto error_return;
5365: }
5366: } else {
5367: MTX_LOCK(&conn->result_queue_mutex);
5368: rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
5369: if (rc < 0) {
5370: MTX_UNLOCK(&conn->result_queue_mutex);
5371: ISTGT_ERRLOG("queue_enqueue() failed\n");
5372: goto error_return;
5373: }
5374: rc = pthread_cond_broadcast(&conn->result_queue_cond);
5375: MTX_UNLOCK(&conn->result_queue_mutex);
5376: if (rc != 0) {
5377: ISTGT_ERRLOG("cond_broadcast() failed\n");
5378: goto error_return;
5379: }
5380: }
5381:
5382: #if 0
5383: /* write cache */
5384: if (spec->req_write_cache) {
5385: MTX_LOCK(&lu->mutex);
5386: rc = istgt_lu_disk_write_cache(spec, conn);
5387: MTX_UNLOCK(&lu->mutex);
5388: if (rc < 0) {
5389: ISTGT_ERRLOG("disk_write_cache() failed\n");
5390: return -1;
5391: }
5392: }
5393: #endif
5394: }
5395: } else {
5396: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5397: "LU%d: LUN%d Task Read Start\n",
5398: lu->num, lun);
5399: #if 0
5400: lu_cmd->iobufsize = lu_cmd->transfer_len + 65536;
5401: iobuf = xmalloc(lu_cmd->iobufsize);
5402: lu_task->iobuf = iobuf;
5403: #else
5404: lu_cmd->iobufsize = lu_task->lu_cmd.iobufsize;
5405: iobuf = lu_task->iobuf;
5406: #endif
5407: lu_cmd->iobuf = iobuf;
5408: MTX_LOCK(&lu_cmd->lu->mutex);
5409: rc = istgt_lu_disk_execute(conn, lu_cmd);
5410: MTX_UNLOCK(&lu_cmd->lu->mutex);
5411: if (rc < 0) {
5412: ISTGT_ERRLOG("lu_disk_execute() failed\n");
5413: goto error_return;
5414: }
5415: lu_task->execute = 1;
5416:
5417: /* response */
5418: if (conn->use_sender == 0) {
5419: MTX_LOCK(&conn->task_queue_mutex);
5420: rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
5421: MTX_UNLOCK(&conn->task_queue_mutex);
5422: if (rc < 0) {
5423: ISTGT_ERRLOG("queue_enqueue() failed\n");
5424: goto error_return;
5425: }
5426: rc = write(conn->task_pipe[1], tmp, 1);
5427: if(rc < 0 || rc != 1) {
5428: ISTGT_ERRLOG("write() failed\n");
5429: goto error_return;
5430: }
5431: } else {
5432: MTX_LOCK(&conn->result_queue_mutex);
5433: rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
5434: if (rc < 0) {
5435: MTX_UNLOCK(&conn->result_queue_mutex);
5436: ISTGT_ERRLOG("queue_enqueue() failed\n");
5437: goto error_return;
5438: }
5439: rc = pthread_cond_broadcast(&conn->result_queue_cond);
5440: MTX_UNLOCK(&conn->result_queue_mutex);
5441: if (rc != 0) {
5442: ISTGT_ERRLOG("cond_broadcast() failed\n");
5443: goto error_return;
5444: }
5445: }
5446: }
5447:
5448: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LU%d: LUN%d queue end\n",
5449: lu->num, lun);
5450:
5451: if (abort_task) {
5452: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Abort Task\n");
5453: return -1;
5454: }
5455: return 0;
5456: }
5457:
5458: int
5459: istgt_lu_disk_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
5460: {
5461: ISTGT_LU_Ptr lu;
5462: ISTGT_LU_DISK *spec;
5463: uint8_t *data;
5464: uint8_t *cdb;
5465: uint32_t allocation_len;
5466: int data_len;
5467: int data_alloc_len;
5468: uint64_t lba;
5469: uint32_t len;
5470: uint32_t transfer_len;
5471: uint32_t parameter_len;
5472: uint8_t *sense_data;
1.1.1.2 misho 5473: size_t *sense_len;
1.1 misho 5474: int lun_i;
5475: int rc;
5476:
5477: if (lu_cmd == NULL)
5478: return -1;
5479: lu = lu_cmd->lu;
5480: if (lu == NULL) {
5481: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5482: return -1;
5483: }
5484: spec = NULL;
5485: cdb = lu_cmd->cdb;
5486: data = lu_cmd->data;
5487: data_alloc_len = lu_cmd->alloc_len;
5488: sense_data = lu_cmd->sense_data;
5489: sense_len = &lu_cmd->sense_data_len;
5490: *sense_len = 0;
5491:
5492: lun_i = istgt_lu_islun2lun(lu_cmd->lun);
5493: if (lun_i >= lu->maxlun) {
5494: #ifdef ISTGT_TRACE_DISK
5495: ISTGT_ERRLOG("LU%d: LUN%4.4"PRIx64" invalid\n",
5496: lu->num, lun_i);
5497: #endif /* ISTGT_TRACE_DISK */
5498: if (cdb[0] == SPC_INQUIRY) {
5499: allocation_len = DGET16(&cdb[3]);
1.1.1.2 misho 5500: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 5501: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5502: data_alloc_len);
5503: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5504: return -1;
5505: }
5506: memset(data, 0, allocation_len);
5507: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
5508: BDSET8W(&data[0], 0x03, 7, 3);
5509: BDADD8W(&data[0], 0x1f, 4, 5);
5510: data_len = 96;
5511: memset(&data[1], 0, data_len - 1);
5512: /* ADDITIONAL LENGTH */
5513: data[4] = data_len - 5;
1.1.1.2 misho 5514: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 5515: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5516: return 0;
5517: } else {
5518: /* LOGICAL UNIT NOT SUPPORTED */
5519: BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
5520: lu_cmd->data_len = 0;
5521: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5522: return 0;
5523: }
5524: }
5525: spec = (ISTGT_LU_DISK *) lu->lun[lun_i].spec;
5526: if (spec == NULL) {
5527: /* LOGICAL UNIT NOT SUPPORTED */
5528: BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
5529: lu_cmd->data_len = 0;
5530: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5531: return 0;
5532: }
5533:
5534: if (spec->sense != 0) {
5535: int sk, asc, ascq;
5536: if (cdb[0] != SPC_INQUIRY
5537: && cdb[0] != SPC_REPORT_LUNS) {
5538: sk = (spec->sense >> 16) & 0xffU;
5539: asc = (spec->sense >> 8) & 0xffU;
5540: ascq = (spec->sense >> 0) & 0xffU;
5541: spec->sense = 0;
5542: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5543: "Generate sk=0x%x, asc=0x%x, ascq=0x%x\n",
5544: sk, asc, ascq);
5545: *sense_len
5546: = istgt_lu_disk_build_sense_data(spec, sense_data,
5547: sk, asc, ascq);
5548: lu_cmd->data_len = 0;
5549: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5550: return 0;
5551: }
5552: }
5553:
5554: if (spec->err_write_cache) {
5555: /* WRITE ERROR - AUTO REALLOCATION FAILED */
5556: BUILD_SENSE2(MEDIUM_ERROR, 0x0c, 0x02);
5557: #if 0
5558: /* WRITE ERROR - RECOMMEND REASSIGNMENT */
5559: BUILD_SENSE2(MEDIUM_ERROR, 0x0c, 0x03);
5560: #endif
5561: spec->err_write_cache = 0;
5562: lba = spec->woffset / spec->blocklen;
5563: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
5564: "Deferred error (write cache) at %"PRIu64"\n", lba);
5565: if (lba > 0xffffffffULL) {
5566: ISTGT_WARNLOG("lba > 0xffffffff\n");
5567: }
5568: /* COMMAND-SPECIFIC INFORMATION */
5569: DSET32(&sense_data[8], (uint32_t)(lba & 0xffffffffULL));
5570: lu_cmd->data_len = 0;
5571: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5572: return 0;
5573: }
5574:
5575: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
5576: "SCSI OP=0x%x, LUN=0x%16.16"PRIx64"\n",
5577: cdb[0], lu_cmd->lun);
5578: #ifdef ISTGT_TRACE_DISK
5579: if (cdb[0] != SPC_TEST_UNIT_READY) {
5580: istgt_scsi_dump_cdb(cdb);
5581: }
5582: #endif /* ISTGT_TRACE_DISK */
5583: switch (cdb[0]) {
5584: case SPC_INQUIRY:
5585: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "INQUIRY\n");
5586: if (lu_cmd->R_bit == 0) {
5587: ISTGT_ERRLOG("R_bit == 0\n");
5588: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5589: return -1;
5590: }
5591: allocation_len = DGET16(&cdb[3]);
1.1.1.2 misho 5592: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 5593: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5594: data_alloc_len);
5595: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5596: return -1;
5597: }
5598: memset(data, 0, allocation_len);
5599: data_len = istgt_lu_disk_scsi_inquiry(spec, conn, cdb,
5600: data, data_alloc_len);
5601: if (data_len < 0) {
5602: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5603: break;
5604: }
5605: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "INQUIRY", data, data_len);
1.1.1.2 misho 5606: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 5607: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5608: break;
5609:
5610: case SPC_REPORT_LUNS:
5611: {
5612: int sel;
5613:
5614: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT LUNS\n");
5615: if (lu_cmd->R_bit == 0) {
5616: ISTGT_ERRLOG("R_bit == 0\n");
5617: return -1;
5618: }
5619:
5620: sel = cdb[2];
5621: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sel=%x\n", sel);
5622:
5623: allocation_len = DGET32(&cdb[6]);
1.1.1.2 misho 5624: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 5625: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 5626: data_alloc_len);
1.1 misho 5627: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5628: return -1;
5629: }
5630: if (allocation_len < 16) {
5631: /* INVALID FIELD IN CDB */
5632: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
5633: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5634: break;
5635: }
5636: memset(data, 0, allocation_len);
5637: data_len = istgt_lu_disk_scsi_report_luns(lu, conn, cdb, sel,
5638: data, data_alloc_len);
5639: if (data_len < 0) {
5640: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5641: break;
5642: }
5643: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "REPORT LUNS", data, data_len);
1.1.1.2 misho 5644: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 5645: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5646: }
5647: break;
5648:
5649: case SPC_TEST_UNIT_READY:
5650: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "TEST_UNIT_READY\n");
5651: lu_cmd->data_len = 0;
5652: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5653: break;
5654:
5655: case SBC_START_STOP_UNIT:
5656: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "START_STOP_UNIT\n");
5657: {
5658: int pc, loej, start;
5659:
5660: pc = BGET8W(&cdb[4], 7, 4);
5661: loej = BGET8(&cdb[4], 1);
5662: start = BGET8(&cdb[4], 0);
5663:
5664: if (start != 0 || pc != 0) {
5665: if (spec->rsv_key) {
5666: rc = istgt_lu_disk_check_pr(spec, conn,
5667: PR_ALLOW(0,0,1,0,0));
5668: if (rc != 0) {
5669: lu_cmd->status
5670: = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
5671: break;
5672: }
5673: }
5674: }
5675:
5676: lu_cmd->data_len = 0;
5677: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5678: }
5679: break;
5680:
5681: case SBC_READ_CAPACITY_10:
5682: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_CAPACITY_10\n");
5683: if (lu_cmd->R_bit == 0) {
5684: ISTGT_ERRLOG("R_bit == 0\n");
5685: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5686: return -1;
5687: }
5688: if (spec->blockcnt - 1 > 0xffffffffULL) {
5689: DSET32(&data[0], 0xffffffffUL);
5690: } else {
5691: DSET32(&data[0], (uint32_t) (spec->blockcnt - 1));
5692: }
5693: DSET32(&data[4], (uint32_t) spec->blocklen);
5694: data_len = 8;
5695: lu_cmd->data_len = data_len;
5696: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5697: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
5698: "SBC_READ_CAPACITY_10", data, data_len);
5699: break;
5700:
5701: case SPC_SERVICE_ACTION_IN_16:
5702: switch (BGET8W(&cdb[1], 4, 5)) { /* SERVICE ACTION */
5703: case SBC_SAI_READ_CAPACITY_16:
5704: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_CAPACITY_16\n");
5705: if (lu_cmd->R_bit == 0) {
5706: ISTGT_ERRLOG("R_bit == 0\n");
5707: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5708: return -1;
5709: }
5710: allocation_len = DGET32(&cdb[10]);
1.1.1.2 misho 5711: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 5712: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5713: data_alloc_len);
5714: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5715: return -1;
5716: }
5717: memset(data, 0, allocation_len);
5718: DSET64(&data[0], spec->blockcnt - 1);
5719: DSET32(&data[8], (uint32_t) spec->blocklen);
5720: data[12] = 0; /* RTO_EN(1) PROT_EN(0) */
5721: memset(&data[13], 0, 32 - (8 + 4 + 1)); /* Reserved */
5722: data_len = 32;
1.1.1.2 misho 5723: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 5724: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5725: break;
5726: case SBC_SAI_READ_LONG_16:
5727: default:
5728: /* INVALID COMMAND OPERATION CODE */
5729: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
5730: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5731: break;
5732: }
5733: break;
5734:
5735: case SPC_MODE_SELECT_6:
5736: #if 0
5737: istgt_scsi_dump_cdb(cdb);
5738: #endif
5739: {
5740: int pf, sp, pllen;
5741: int mdlen, mt, dsp, bdlen;
5742:
5743: if (spec->rsv_key) {
5744: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
5745: if (rc != 0) {
5746: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
5747: break;
5748: }
5749: }
5750:
5751: pf = BGET8(&cdb[1], 4);
5752: sp = BGET8(&cdb[1], 0);
5753: pllen = cdb[4]; /* Parameter List Length */
5754:
5755: if (pllen == 0) {
5756: lu_cmd->data_len = 0;
5757: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5758: break;
5759: }
5760: /* Data-Out */
5761: rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
5762: lu_cmd->iobufsize, pllen);
5763: if (rc < 0) {
5764: ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
5765: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5766: break;
5767: }
5768: if (pllen < 4) {
5769: /* INVALID FIELD IN CDB */
5770: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
5771: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5772: break;
5773: }
5774: #if 0
5775: istgt_dump("MODE SELECT(6)", lu_cmd->iobuf, pllen);
5776: #endif
5777: data = lu_cmd->iobuf;
5778: mdlen = data[0]; /* Mode Data Length */
5779: mt = data[1]; /* Medium Type */
5780: dsp = data[2]; /* Device-Specific Parameter */
5781: bdlen = data[3]; /* Block Descriptor Length */
5782:
5783: /* Short LBA mode parameter block descriptor */
5784: /* data[4]-data[7] Number of Blocks */
5785: /* data[8]-data[11] Block Length */
5786:
5787: /* page data */
5788: data_len = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[4 + bdlen], pllen - (4 + bdlen));
5789: if (data_len != 0) {
5790: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5791: break;
5792: }
5793: lu_cmd->data_len = pllen;
5794: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5795: break;
5796: }
5797:
5798: case SPC_MODE_SELECT_10:
5799: #if 0
5800: istgt_scsi_dump_cdb(cdb);
5801: #endif
5802: {
5803: int pf, sp, pllen;
5804: int mdlen, mt, dsp, bdlen;
5805: int llba;
5806:
5807: if (spec->rsv_key) {
5808: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
5809: if (rc != 0) {
5810: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
5811: break;
5812: }
5813: }
5814:
5815: pf = BGET8(&cdb[1], 4);
5816: sp = BGET8(&cdb[1], 0);
5817: pllen = DGET16(&cdb[7]); /* Parameter List Length */
5818:
5819: if (pllen == 0) {
5820: lu_cmd->data_len = 0;
5821: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5822: break;
5823: }
5824: /* Data-Out */
5825: rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
5826: lu_cmd->iobufsize, pllen);
5827: if (rc < 0) {
5828: ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
5829: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5830: break;
5831: }
5832: if (pllen < 4) {
5833: /* INVALID FIELD IN CDB */
5834: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
5835: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5836: break;
5837: }
5838: #if 0
5839: istgt_dump("MODE SELECT(10)", lu_cmd->iobuf, pllen);
5840: #endif
5841: data = lu_cmd->iobuf;
5842: mdlen = DGET16(&data[0]); /* Mode Data Length */
5843: mt = data[2]; /* Medium Type */
5844: dsp = data[3]; /* Device-Specific Parameter */
5845: llba = BGET8(&data[4], 0); /* Long LBA */
5846: bdlen = DGET16(&data[6]); /* Block Descriptor Length */
5847:
5848: if (llba) {
5849: /* Long LBA mode parameter block descriptor */
5850: /* data[8]-data[15] Number of Blocks */
5851: /* data[16]-data[19] Reserved */
5852: /* data[20]-data[23] Block Length */
5853: } else {
5854: /* Short LBA mode parameter block descriptor */
5855: /* data[8]-data[11] Number of Blocks */
5856: /* data[12]-data[15] Block Length */
5857: }
5858:
5859: /* page data */
5860: data_len = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[8 + bdlen], pllen - (8 + bdlen));
5861: if (data_len != 0) {
5862: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5863: break;
5864: }
5865: lu_cmd->data_len = pllen;
5866: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5867: break;
5868: }
5869:
5870: case SPC_MODE_SENSE_6:
5871: #if 0
5872: istgt_scsi_dump_cdb(cdb);
5873: #endif
5874: {
5875: int dbd, pc, page, subpage;
5876:
5877: if (spec->rsv_key) {
5878: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
5879: if (rc != 0) {
5880: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
5881: break;
5882: }
5883: }
5884:
5885: if (lu_cmd->R_bit == 0) {
5886: ISTGT_ERRLOG("R_bit == 0\n");
5887: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5888: return -1;
5889: }
5890:
5891: dbd = BGET8(&cdb[1], 3);
5892: pc = BGET8W(&cdb[2], 7, 2);
5893: page = BGET8W(&cdb[2], 5, 6);
5894: subpage = cdb[3];
5895:
5896: allocation_len = cdb[4];
1.1.1.2 misho 5897: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 5898: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5899: data_alloc_len);
5900: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5901: return -1;
5902: }
5903: memset(data, 0, allocation_len);
5904:
5905: data_len = istgt_lu_disk_scsi_mode_sense6(spec, conn, cdb, dbd, pc, page, subpage, data, data_alloc_len);
5906: if (data_len < 0) {
1.1.1.2 misho 5907: /* INVALID FIELD IN CDB */
5908: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
1.1 misho 5909: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5910: break;
5911: }
5912: #if 0
5913: istgt_dump("MODE SENSE(6)", data, data_len);
5914: #endif
1.1.1.2 misho 5915: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 5916: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5917: break;
5918: }
5919:
5920: case SPC_MODE_SENSE_10:
5921: #if 0
5922: istgt_scsi_dump_cdb(cdb);
5923: #endif
5924: {
5925: int dbd, pc, page, subpage;
5926: int llbaa;
5927:
5928: if (spec->rsv_key) {
5929: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
5930: if (rc != 0) {
5931: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
5932: break;
5933: }
5934: }
5935:
5936: if (lu_cmd->R_bit == 0) {
5937: ISTGT_ERRLOG("R_bit == 0\n");
5938: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5939: return -1;
5940: }
5941:
5942: llbaa = BGET8(&cdb[1], 4);
5943: dbd = BGET8(&cdb[1], 3);
5944: pc = BGET8W(&cdb[2], 7, 2);
5945: page = BGET8W(&cdb[2], 5, 6);
5946: subpage = cdb[3];
5947:
5948: allocation_len = DGET16(&cdb[7]);
1.1.1.2 misho 5949: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 5950: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5951: data_alloc_len);
5952: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5953: return -1;
5954: }
5955: memset(data, 0, allocation_len);
5956:
5957: data_len = istgt_lu_disk_scsi_mode_sense10(spec, conn, cdb, llbaa, dbd, pc, page, subpage, data, data_alloc_len);
5958: if (data_len < 0) {
1.1.1.2 misho 5959: /* INVALID FIELD IN CDB */
5960: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
1.1 misho 5961: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5962: break;
5963: }
5964: #if 0
5965: istgt_dump("MODE SENSE(10)", data, data_len);
5966: #endif
1.1.1.2 misho 5967: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 5968: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
5969: break;
5970: }
5971:
5972: case SPC_LOG_SELECT:
5973: case SPC_LOG_SENSE:
5974: /* INVALID COMMAND OPERATION CODE */
5975: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
5976: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5977: break;
5978:
5979: case SPC_REQUEST_SENSE:
5980: {
5981: int desc;
5982: int sk, asc, ascq;
5983:
5984: if (lu_cmd->R_bit == 0) {
5985: ISTGT_ERRLOG("R_bit == 0\n");
5986: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5987: return -1;
5988: }
5989:
5990: desc = BGET8(&cdb[1], 0);
5991: if (desc != 0) {
5992: /* INVALID FIELD IN CDB */
5993: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
5994: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
5995: break;
5996: }
5997:
5998: allocation_len = cdb[4];
1.1.1.2 misho 5999: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 6000: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
6001: data_alloc_len);
6002: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6003: return -1;
6004: }
6005: memset(data, 0, allocation_len);
6006:
6007: if (!spec->sense) {
6008: /* NO ADDITIONAL SENSE INFORMATION */
6009: sk = ISTGT_SCSI_SENSE_NO_SENSE;
6010: asc = 0x00;
6011: ascq = 0x00;
6012: } else {
6013: sk = (spec->sense >> 16) & 0xffU;
6014: asc = (spec->sense >> 8) & 0xffU;
6015: ascq = spec->sense & 0xffU;
6016: }
6017: data_len = istgt_lu_disk_build_sense_data(spec, sense_data,
6018: sk, asc, ascq);
6019: if (data_len < 0 || data_len < 2) {
6020: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6021: break;
6022: }
6023: /* omit SenseLength */
6024: data_len -= 2;
6025: memcpy(data, sense_data + 2, data_len);
6026: #if 0
6027: istgt_dump("REQUEST SENSE", data, data_len);
6028: #endif
1.1.1.2 misho 6029: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 6030: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6031: break;
6032: }
6033:
6034: case SBC_READ_6:
6035: {
6036: if (spec->rsv_key) {
6037: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6038: if (rc != 0) {
6039: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6040: break;
6041: }
6042: }
6043:
6044: if (lu_cmd->R_bit == 0) {
6045: ISTGT_ERRLOG("R_bit == 0\n");
6046: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6047: return -1;
6048: }
6049:
6050: lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU);
6051: transfer_len = (uint32_t) DGET8(&cdb[4]);
6052: if (transfer_len == 0) {
6053: transfer_len = 256;
6054: }
6055: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6056: "READ_6(lba %"PRIu64", len %u blocks)\n",
6057: lba, transfer_len);
6058: rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
6059: if (rc < 0) {
6060: ISTGT_ERRLOG("lu_disk_lbread() failed\n");
6061: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6062: break;
6063: }
6064: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6065: break;
6066: }
6067:
6068: case SBC_READ_10:
6069: {
6070: int dpo, fua, fua_nv;
6071:
6072: if (spec->rsv_key) {
6073: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6074: if (rc != 0) {
6075: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6076: break;
6077: }
6078: }
6079:
6080: if (lu_cmd->R_bit == 0) {
6081: ISTGT_ERRLOG("R_bit == 0\n");
6082: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6083: return -1;
6084: }
6085:
6086: dpo = BGET8(&cdb[1], 4);
6087: fua = BGET8(&cdb[1], 3);
6088: fua_nv = BGET8(&cdb[1], 1);
6089: lba = (uint64_t) DGET32(&cdb[2]);
6090: transfer_len = (uint32_t) DGET16(&cdb[7]);
6091: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6092: "READ_10(lba %"PRIu64", len %u blocks)\n",
6093: lba, transfer_len);
6094: rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
6095: if (rc < 0) {
6096: ISTGT_ERRLOG("lu_disk_lbread() failed\n");
6097: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6098: break;
6099: }
6100: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6101: break;
6102: }
6103:
6104: case SBC_READ_12:
6105: {
6106: int dpo, fua, fua_nv;
6107:
6108: if (spec->rsv_key) {
6109: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6110: if (rc != 0) {
6111: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6112: break;
6113: }
6114: }
6115:
6116: if (lu_cmd->R_bit == 0) {
6117: ISTGT_ERRLOG("R_bit == 0\n");
6118: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6119: return -1;
6120: }
6121:
6122: dpo = BGET8(&cdb[1], 4);
6123: fua = BGET8(&cdb[1], 3);
6124: fua_nv = BGET8(&cdb[1], 1);
6125: lba = (uint64_t) DGET32(&cdb[2]);
6126: transfer_len = (uint32_t) DGET32(&cdb[6]);
6127: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6128: "READ_12(lba %"PRIu64", len %u blocks)\n",
6129: lba, transfer_len);
6130: rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
6131: if (rc < 0) {
6132: ISTGT_ERRLOG("lu_disk_lbread() failed\n");
6133: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6134: break;
6135: }
6136: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6137: break;
6138: }
6139:
6140: case SBC_READ_16:
6141: {
6142: int dpo, fua, fua_nv;
6143:
6144: if (spec->rsv_key) {
6145: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6146: if (rc != 0) {
6147: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6148: break;
6149: }
6150: }
6151:
6152: if (lu_cmd->R_bit == 0) {
6153: ISTGT_ERRLOG("R_bit == 0\n");
6154: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6155: return -1;
6156: }
6157:
6158: dpo = BGET8(&cdb[1], 4);
6159: fua = BGET8(&cdb[1], 3);
6160: fua_nv = BGET8(&cdb[1], 1);
6161: lba = (uint64_t) DGET64(&cdb[2]);
6162: transfer_len = (uint32_t) DGET32(&cdb[10]);
6163: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6164: "READ_16(lba %"PRIu64", len %u blocks)\n",
6165: lba, transfer_len);
6166: rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
6167: if (rc < 0) {
6168: ISTGT_ERRLOG("lu_disk_lbread() failed\n");
6169: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6170: break;
6171: }
6172: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6173: break;
6174: }
6175:
6176: case SBC_WRITE_6:
6177: {
6178: if (spec->rsv_key) {
6179: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6180: if (rc != 0) {
6181: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6182: break;
6183: }
6184: }
6185:
6186: if (lu_cmd->W_bit == 0) {
6187: ISTGT_ERRLOG("W_bit == 0\n");
6188: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6189: return -1;
6190: }
6191:
6192: lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU);
6193: transfer_len = (uint32_t) DGET8(&cdb[4]);
6194: if (transfer_len == 0) {
6195: transfer_len = 256;
6196: }
6197: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6198: "WRITE_6(lba %"PRIu64", len %u blocks)\n",
6199: lba, transfer_len);
6200: rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
6201: if (rc < 0) {
6202: ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
6203: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6204: break;
6205: }
6206: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6207: break;
6208: }
6209:
6210: case SBC_WRITE_10:
6211: case SBC_WRITE_AND_VERIFY_10:
6212: {
6213: int dpo, fua, fua_nv;
6214:
6215: if (spec->rsv_key) {
6216: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6217: if (rc != 0) {
6218: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6219: break;
6220: }
6221: }
6222:
6223: if (lu_cmd->W_bit == 0) {
6224: ISTGT_ERRLOG("W_bit == 0\n");
6225: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6226: return -1;
6227: }
6228:
6229: dpo = BGET8(&cdb[1], 4);
6230: fua = BGET8(&cdb[1], 3);
6231: fua_nv = BGET8(&cdb[1], 1);
6232: lba = (uint64_t) DGET32(&cdb[2]);
6233: transfer_len = (uint32_t) DGET16(&cdb[7]);
6234: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6235: "WRITE_10(lba %"PRIu64", len %u blocks)\n",
6236: lba, transfer_len);
6237: rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
6238: if (rc < 0) {
6239: ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
6240: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6241: break;
6242: }
6243: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6244: break;
6245: }
6246:
6247: case SBC_WRITE_12:
6248: case SBC_WRITE_AND_VERIFY_12:
6249: {
6250: int dpo, fua, fua_nv;
6251:
6252: if (spec->rsv_key) {
6253: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6254: if (rc != 0) {
6255: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6256: break;
6257: }
6258: }
6259:
6260: if (lu_cmd->W_bit == 0) {
6261: ISTGT_ERRLOG("W_bit == 0\n");
6262: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6263: return -1;
6264: }
6265:
6266: dpo = BGET8(&cdb[1], 4);
6267: fua = BGET8(&cdb[1], 3);
6268: fua_nv = BGET8(&cdb[1], 1);
6269: lba = (uint64_t) DGET32(&cdb[2]);
6270: transfer_len = (uint32_t) DGET32(&cdb[6]);
6271: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6272: "WRITE_12(lba %"PRIu64", len %u blocks)\n",
6273: lba, transfer_len);
6274: rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
6275: if (rc < 0) {
6276: ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
6277: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6278: break;
6279: }
6280: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6281: break;
6282: }
6283:
6284: case SBC_WRITE_16:
6285: case SBC_WRITE_AND_VERIFY_16:
6286: {
6287: int dpo, fua, fua_nv;
6288:
6289: if (spec->rsv_key) {
6290: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6291: if (rc != 0) {
6292: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6293: break;
6294: }
6295: }
6296:
6297: if (lu_cmd->W_bit == 0) {
6298: ISTGT_ERRLOG("W_bit == 0\n");
6299: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6300: return -1;
6301: }
6302:
6303: dpo = BGET8(&cdb[1], 4);
6304: fua = BGET8(&cdb[1], 3);
6305: fua_nv = BGET8(&cdb[1], 1);
6306: lba = (uint64_t) DGET64(&cdb[2]);
6307: transfer_len = (uint32_t) DGET32(&cdb[10]);
6308: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6309: "WRITE_16(lba %"PRIu64", len %u blocks)\n",
6310: lba, transfer_len);
6311: rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
6312: if (rc < 0) {
6313: ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
6314: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6315: break;
6316: }
6317: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6318: break;
6319: }
6320:
6321: case SBC_VERIFY_10:
6322: {
6323: int dpo, bytchk;
6324:
6325: if (spec->rsv_key) {
6326: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6327: if (rc != 0) {
6328: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6329: break;
6330: }
6331: }
6332:
6333: dpo = BGET8(&cdb[1], 4);
6334: bytchk = BGET8(&cdb[1], 1);
6335: lba = (uint64_t) DGET32(&cdb[2]);
6336: len = (uint32_t) DGET16(&cdb[7]);
6337: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6338: "VERIFY_10(lba %"PRIu64", len %u blocks)\n",
6339: lba, len);
6340: lu_cmd->data_len = 0;
6341: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6342: break;
6343: }
6344:
6345: case SBC_VERIFY_12:
6346: {
6347: int dpo, bytchk;
6348:
6349: if (spec->rsv_key) {
6350: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6351: if (rc != 0) {
6352: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6353: break;
6354: }
6355: }
6356:
6357: dpo = BGET8(&cdb[1], 4);
6358: bytchk = BGET8(&cdb[1], 1);
6359: lba = (uint64_t) DGET32(&cdb[2]);
6360: len = (uint32_t) DGET32(&cdb[6]);
6361: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6362: "VERIFY_12(lba %"PRIu64", len %u blocks)\n",
6363: lba, len);
6364: lu_cmd->data_len = 0;
6365: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6366: break;
6367: }
6368:
6369: case SBC_VERIFY_16:
6370: {
6371: int dpo, bytchk;
6372:
6373: if (spec->rsv_key) {
6374: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
6375: if (rc != 0) {
6376: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6377: break;
6378: }
6379: }
6380:
6381: dpo = BGET8(&cdb[1], 4);
6382: bytchk = BGET8(&cdb[1], 1);
6383: lba = (uint64_t) DGET64(&cdb[2]);
6384: len = (uint32_t) DGET32(&cdb[10]);
6385: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6386: "VERIFY_16(lba %"PRIu64", len %u blocks)\n",
6387: lba, len);
6388: lu_cmd->data_len = 0;
6389: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6390: break;
6391: }
6392:
6393: case SBC_WRITE_SAME_10:
6394: {
6395: int wprotect, pbdata, lbdata, group_no;
6396:
6397: if (spec->rsv_key) {
6398: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6399: if (rc != 0) {
6400: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6401: break;
6402: }
6403: }
6404:
6405: if (lu_cmd->W_bit == 0) {
6406: ISTGT_ERRLOG("W_bit == 0\n");
6407: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6408: return -1;
6409: }
6410:
6411: wprotect = BGET8W(&cdb[1], 7, 3);
6412: pbdata = BGET8(&cdb[1], 2);
6413: lbdata = BGET8(&cdb[1], 1);
6414: lba = (uint64_t) DGET32(&cdb[2]);
6415: transfer_len = (uint32_t) DGET16(&cdb[7]);
6416: group_no = BGET8W(&cdb[6], 4, 5);
6417:
6418: /* only PBDATA=0 and LBDATA=0 support */
6419: if (pbdata || lbdata) {
6420: /* INVALID FIELD IN CDB */
6421: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6422: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6423: break;
6424: }
6425:
6426: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6427: "WRITE_SAME_10(lba %"PRIu64", len %u blocks)\n",
6428: lba, transfer_len);
6429: rc = istgt_lu_disk_lbwrite_same(spec, conn, lu_cmd, lba, transfer_len);
6430: if (rc < 0) {
6431: ISTGT_ERRLOG("lu_disk_lbwrite_same() failed\n");
6432: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6433: break;
6434: }
6435: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6436: break;
6437: }
6438:
6439: case SBC_WRITE_SAME_16:
6440: {
6441: int wprotect, anchor, unmap, pbdata, lbdata, group_no;
6442:
6443: #if 0
6444: istgt_scsi_dump_cdb(cdb);
6445: #endif
6446: if (spec->rsv_key) {
6447: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6448: if (rc != 0) {
6449: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6450: break;
6451: }
6452: }
6453:
6454: if (lu_cmd->W_bit == 0) {
6455: ISTGT_ERRLOG("W_bit == 0\n");
6456: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6457: return -1;
6458: }
6459:
6460: wprotect = BGET8W(&cdb[1], 7, 3);
6461: anchor = BGET8(&cdb[1], 4);
6462: unmap = BGET8(&cdb[1], 3);
6463: pbdata = BGET8(&cdb[1], 2);
6464: lbdata = BGET8(&cdb[1], 1);
6465: lba = (uint64_t) DGET64(&cdb[2]);
6466: transfer_len = (uint32_t) DGET32(&cdb[10]);
6467: group_no = BGET8W(&cdb[14], 4, 5);
6468:
6469: /* only PBDATA=0 and LBDATA=0 support */
6470: if (pbdata || lbdata) {
6471: /* INVALID FIELD IN CDB */
6472: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6473: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6474: break;
6475: }
6476: if (anchor) {
6477: /* INVALID FIELD IN CDB */
6478: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6479: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6480: break;
6481: }
6482:
6483: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6484: "WRITE_SAME_16(lba %"PRIu64", len %u blocks)\n",
6485: lba, transfer_len);
6486: rc = istgt_lu_disk_lbwrite_same(spec, conn, lu_cmd, lba, transfer_len);
6487: if (rc < 0) {
6488: ISTGT_ERRLOG("lu_disk_lbwrite_same() failed\n");
6489: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6490: break;
6491: }
6492: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6493: break;
6494: }
6495:
6496: case SBC_COMPARE_AND_WRITE:
6497: {
6498: int64_t maxlen;
6499: int wprotect, dpo, fua, fua_nv, group_no;
6500:
6501: #if 0
6502: istgt_scsi_dump_cdb(cdb);
6503: #endif
6504: if (spec->lu->istgt->swmode == ISTGT_SWMODE_TRADITIONAL) {
6505: /* INVALID COMMAND OPERATION CODE */
6506: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6507: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6508: break;
6509: }
6510: if (spec->rsv_key) {
6511: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6512: if (rc != 0) {
6513: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6514: break;
6515: }
6516: }
6517:
6518: if (lu_cmd->W_bit == 0) {
6519: ISTGT_ERRLOG("W_bit == 0\n");
6520: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6521: return -1;
6522: }
6523:
6524: wprotect = BGET8W(&cdb[1], 7, 3);
6525: dpo = BGET8(&cdb[1], 4);
6526: fua = BGET8(&cdb[1], 3);
6527: fua_nv = BGET8(&cdb[1], 1);
6528: lba = (uint64_t) DGET64(&cdb[2]);
6529: transfer_len = (uint32_t) DGET8(&cdb[13]);
6530: group_no = BGET8W(&cdb[14], 4, 5);
6531:
1.1.1.2 misho 6532: maxlen = ISTGT_LU_WORK_ATS_BLOCK_SIZE / spec->blocklen;
1.1 misho 6533: if (maxlen > 0xff) {
6534: maxlen = 0xff;
6535: }
6536: if (transfer_len > maxlen) {
6537: /* INVALID FIELD IN CDB */
6538: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6539: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6540: break;
6541: }
6542:
6543: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6544: "COMPARE_AND_WRITE(lba %"PRIu64", len %u blocks)\n",
6545: lba, transfer_len);
6546: rc = istgt_lu_disk_lbwrite_ats(spec, conn, lu_cmd, lba, transfer_len);
6547: if (rc < 0) {
6548: //ISTGT_ERRLOG("lu_disk_lbwrite_ats() failed\n");
6549: /* sense data build by function */
6550: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6551: break;
6552: }
6553: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6554: break;
6555: }
6556:
6557: case SBC_SYNCHRONIZE_CACHE_10:
6558: {
6559: int sync_nv, immed;
6560:
6561: if (spec->rsv_key) {
6562: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6563: if (rc != 0) {
6564: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6565: break;
6566: }
6567: }
6568:
6569: sync_nv = BGET8(&cdb[1], 2);
6570: immed = BGET8(&cdb[1], 1);
6571: lba = (uint64_t) DGET32(&cdb[2]);
6572: len = (uint32_t) DGET16(&cdb[7]);
6573: if (len == 0) {
6574: len = spec->blockcnt;
6575: }
6576: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6577: "SYNCHRONIZE_CACHE_10(lba %"PRIu64
6578: ", len %u blocks)\n",
6579: lba, len);
6580: rc = istgt_lu_disk_lbsync(spec, conn, lu_cmd, lba, len);
6581: if (rc < 0) {
6582: ISTGT_ERRLOG("lu_disk_lbsync() failed\n");
6583: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6584: break;
6585: }
6586: lu_cmd->data_len = 0;
6587: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6588: break;
6589: }
6590:
6591: case SBC_SYNCHRONIZE_CACHE_16:
6592: {
6593: int sync_nv, immed;
6594:
6595: if (spec->rsv_key) {
6596: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6597: if (rc != 0) {
6598: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6599: break;
6600: }
6601: }
6602:
6603: sync_nv = BGET8(&cdb[1], 2);
6604: immed = BGET8(&cdb[1], 1);
6605: lba = (uint64_t) DGET64(&cdb[2]);
6606: len = (uint32_t) DGET32(&cdb[10]);
6607: if (len == 0) {
6608: len = spec->blockcnt;
6609: }
6610: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6611: "SYNCHRONIZE_CACHE_10(lba %"PRIu64
6612: ", len %u blocks)\n",
6613: lba, len);
6614: rc = istgt_lu_disk_lbsync(spec, conn, lu_cmd, lba, len);
6615: if (rc < 0) {
6616: ISTGT_ERRLOG("lu_disk_lbsync() failed\n");
6617: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6618: break;
6619: }
6620: lu_cmd->data_len = 0;
6621: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6622: break;
6623: }
6624:
1.1.1.2 misho 6625: case SBC_READ_DEFECT_DATA_10:
6626: {
6627: int req_plist, req_glist, list_format;
6628:
6629: if (lu_cmd->R_bit == 0) {
6630: ISTGT_ERRLOG("R_bit == 0\n");
6631: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6632: return -1;
6633: }
6634:
6635: req_plist = BGET8(&cdb[2], 4);
6636: req_glist = BGET8(&cdb[2], 3);
6637: list_format = BGET8W(&cdb[2], 2, 3);
6638:
6639: allocation_len = (uint32_t) DGET16(&cdb[7]);
6640: if (allocation_len > (size_t) data_alloc_len) {
6641: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
6642: data_alloc_len);
6643: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6644: return -1;
6645: }
6646: memset(data, 0, allocation_len);
6647:
6648: data_len = istgt_lu_disk_scsi_read_defect10(spec, conn, cdb,
6649: req_plist, req_glist, list_format, data, data_alloc_len);
6650: if (data_len < 0) {
6651: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6652: break;
6653: }
6654: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
6655: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6656: break;
6657: }
6658:
6659: case SBC_READ_DEFECT_DATA_12:
6660: {
6661: int req_plist, req_glist, list_format;
6662:
6663: if (lu_cmd->R_bit == 0) {
6664: ISTGT_ERRLOG("R_bit == 0\n");
6665: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6666: return -1;
6667: }
6668:
6669: req_plist = BGET8(&cdb[2], 4);
6670: req_glist = BGET8(&cdb[2], 3);
6671: list_format = BGET8W(&cdb[2], 2, 3);
6672:
6673: allocation_len = DGET32(&cdb[6]);
6674: if (allocation_len > (size_t) data_alloc_len) {
6675: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
6676: data_alloc_len);
6677: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6678: return -1;
6679: }
6680: memset(data, 0, allocation_len);
6681:
6682: data_len = istgt_lu_disk_scsi_read_defect12(spec, conn, cdb,
6683: req_plist, req_glist, list_format, data, data_alloc_len);
6684: if (data_len < 0) {
6685: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6686: break;
6687: }
6688: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
6689: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6690: break;
6691: }
6692:
1.1 misho 6693: case SCC_MAINTENANCE_IN:
6694: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MAINTENANCE_IN\n");
6695: switch (BGET8W(&cdb[1], 4, 5)) { /* SERVICE ACTION */
6696: case SPC_MI_REPORT_TARGET_PORT_GROUPS:
6697: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT_TARGET_PORT_GROUPS\n");
6698: if (lu_cmd->R_bit == 0) {
6699: ISTGT_ERRLOG("R_bit == 0\n");
6700: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6701: return -1;
6702: }
6703: allocation_len = DGET32(&cdb[6]);
1.1.1.2 misho 6704: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 6705: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
6706: data_alloc_len);
6707: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6708: return -1;
6709: }
6710: memset(data, 0, allocation_len);
6711: data_len = istgt_lu_disk_scsi_report_target_port_groups(spec, conn, cdb, data, data_alloc_len);
6712: if (data_len < 0) {
6713: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6714: break;
6715: }
6716: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
6717: "REPORT_TARGET_PORT_GROUPS", data, data_len);
1.1.1.2 misho 6718: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 6719: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6720: break;
6721: default:
6722: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "SA=0x%2.2x\n",
6723: BGET8W(&cdb[1], 4, 5));
6724: /* INVALID COMMAND OPERATION CODE */
6725: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6726: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6727: break;
6728: }
6729: break;
6730:
6731: case SCC_MAINTENANCE_OUT:
6732: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MAINTENANCE_OUT\n");
6733: switch (BGET8W(&cdb[1], 4, 5)) { /* SERVICE ACTION */
6734: case SPC_MO_SET_TARGET_PORT_GROUPS:
6735: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SET_TARGET_PORT_GROUPS\n");
6736: if (spec->rsv_key) {
6737: rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
6738: if (rc != 0) {
6739: lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
6740: break;
6741: }
6742: }
6743: if (lu_cmd->W_bit == 0) {
6744: ISTGT_ERRLOG("W_bit == 0\n");
6745: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6746: return -1;
6747: }
6748: parameter_len = DGET32(&cdb[6]);
6749: if (parameter_len == 0) {
6750: lu_cmd->data_len = 0;
6751: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6752: break;
6753: }
6754: /* Data-Out */
6755: rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
6756: lu_cmd->iobufsize, parameter_len);
6757: if (rc < 0) {
6758: ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
6759: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6760: break;
6761: }
6762: if (parameter_len < 4) {
6763: /* INVALID FIELD IN CDB */
6764: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6765: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6766: break;
6767: }
6768: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
6769: "SET_TARGET_PORT_GROUPS",
6770: lu_cmd->iobuf, parameter_len);
6771: data = lu_cmd->iobuf;
6772: /* data[0]-data[3] Reserved */
6773: /* Set target port group descriptor(s) */
6774: data_len = istgt_lu_disk_scsi_set_target_port_groups(spec, conn, cdb, &data[4], parameter_len - 4);
6775: if (data_len < 0) {
6776: /* INVALID FIELD IN PARAMETER LIST */
6777: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
6778: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6779: break;
6780: }
6781: lu_cmd->data_len = parameter_len;
6782: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6783: break;
6784: default:
6785: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "SA=0x%2.2x\n",
6786: BGET8W(&cdb[1], 4, 5));
6787: /* INVALID COMMAND OPERATION CODE */
6788: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6789: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6790: break;
6791: }
6792: break;
6793:
6794: case SPC_PERSISTENT_RESERVE_IN:
6795: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PERSISTENT_RESERVE_IN\n");
6796: {
6797: int sa;
6798:
6799: if (lu_cmd->R_bit == 0) {
6800: ISTGT_ERRLOG("R_bit == 0\n");
6801: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6802: return -1;
6803: }
6804:
6805: sa = BGET8W(&cdb[1], 4, 5);
6806: allocation_len = DGET16(&cdb[7]);
1.1.1.2 misho 6807: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 6808: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
6809: data_alloc_len);
6810: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6811: return -1;
6812: }
6813: memset(data, 0, allocation_len);
6814:
6815: data_len = istgt_lu_disk_scsi_persistent_reserve_in(spec, conn, lu_cmd, sa, data, allocation_len);
6816: if (data_len < 0) {
6817: /* status build by function */
6818: break;
6819: }
6820: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
6821: "PERSISTENT_RESERVE_IN", data, data_len);
1.1.1.2 misho 6822: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 6823: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6824: }
6825: break;
6826:
6827: case SPC_PERSISTENT_RESERVE_OUT:
6828: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PERSISTENT_RESERVE_OUT\n");
6829: {
6830: int sa, scope, type;
6831:
6832: if (lu_cmd->W_bit == 0) {
6833: ISTGT_ERRLOG("W_bit == 0\n");
6834: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6835: return -1;
6836: }
6837:
6838: sa = BGET8W(&cdb[1], 4, 5);
6839: scope = BGET8W(&cdb[2], 7, 4);
6840: type = BGET8W(&cdb[2], 3, 4);
6841: parameter_len = DGET32(&cdb[5]);
6842:
6843: /* Data-Out */
6844: rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
6845: lu_cmd->iobufsize, parameter_len);
6846: if (rc < 0) {
6847: ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
6848: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6849: break;
6850: }
6851: if (parameter_len < 24) {
6852: /* INVALID FIELD IN CDB */
6853: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
6854: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6855: break;
6856: }
6857:
6858: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
6859: "PERSISTENT_RESERVE_OUT",
6860: lu_cmd->iobuf, parameter_len);
6861: data = lu_cmd->iobuf;
6862:
6863: data_len = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, lu_cmd, sa, scope, type, &data[0], parameter_len);
6864: if (data_len < 0) {
6865: /* status build by function */
6866: break;
6867: }
6868: lu_cmd->data_len = parameter_len;
6869: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6870: }
6871: break;
6872:
6873: /* XXX TODO: fix */
1.1.1.2 misho 6874: case 0x85: /* ATA PASS-THROUGH(16) */
6875: case 0xA1: /* ATA PASS-THROUGH(12) */
6876: /* INVALID COMMAND OPERATION CODE */
6877: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6878: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6879: break;
1.1 misho 6880: case SPC_EXTENDED_COPY:
6881: /* INVALID COMMAND OPERATION CODE */
6882: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6883: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6884: break;
6885: case SPC2_RELEASE_6:
6886: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_6\n");
6887: rc = istgt_lu_disk_scsi_release(spec, conn, lu_cmd);
6888: if (rc < 0) {
6889: /* build by function */
6890: break;
6891: }
6892: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6893: break;
6894: case SPC2_RELEASE_10:
6895: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_10\n");
6896: rc = istgt_lu_disk_scsi_release(spec, conn, lu_cmd);
6897: if (rc < 0) {
6898: /* build by function */
6899: break;
6900: }
6901: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6902: break;
6903: case SPC2_RESERVE_6:
6904: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_6\n");
6905: rc = istgt_lu_disk_scsi_reserve(spec, conn, lu_cmd);
6906: if (rc < 0) {
6907: /* build by function */
6908: break;
6909: }
6910: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6911: break;
6912: case SPC2_RESERVE_10:
6913: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_10\n");
6914: rc = istgt_lu_disk_scsi_reserve(spec, conn, lu_cmd);
6915: if (rc < 0) {
6916: /* build by function */
6917: break;
6918: }
6919: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
6920: break;
6921:
6922: default:
6923: ISTGT_ERRLOG("unsupported SCSI OP=0x%x\n", cdb[0]);
6924: /* INVALID COMMAND OPERATION CODE */
6925: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
6926: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
6927: break;
6928: }
6929:
6930: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
6931: "SCSI OP=0x%x, LUN=0x%16.16"PRIx64" status=0x%x,"
6932: " complete\n",
6933: cdb[0], lu_cmd->lun, lu_cmd->status);
6934: return 0;
6935: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>