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