Annotation of embedaddon/istgt/src/istgt_lu.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 <ctype.h>
36: #include <errno.h>
37: #include <signal.h>
38: #include <stdio.h>
39: #include <stdlib.h>
40: #include <string.h>
41: #include <limits.h>
42: #include <pthread.h>
43: #ifdef HAVE_PTHREAD_NP_H
44: #include <pthread_np.h>
45: #endif
46: #include <time.h>
47: #include <sys/types.h>
48: #include <sys/stat.h>
49: #include <netinet/in.h>
50: #include <arpa/inet.h>
51:
52: #include <fcntl.h>
53: #include <unistd.h>
54: #include <sys/ioctl.h>
55: #ifdef HAVE_SYS_DISK_H
56: #include <sys/disk.h>
57: #endif
58: #ifdef HAVE_SYS_DISKLABEL_H
59: #include <sys/disklabel.h>
60: #endif
61: #ifdef __linux__
62: #include <linux/fs.h>
63: #endif
64:
65: #include "istgt.h"
66: #include "istgt_ver.h"
67: #include "istgt_log.h"
68: #include "istgt_conf.h"
69: #include "istgt_sock.h"
70: #include "istgt_misc.h"
71: #include "istgt_md5.h"
72: #include "istgt_iscsi.h"
73: #include "istgt_lu.h"
74: #include "istgt_proto.h"
75: #include "istgt_scsi.h"
76:
77: #define MAX_MASKBUF 128
78: static int
79: istgt_lu_allow_ipv6(const char *netmask, const char *addr)
80: {
81: struct in6_addr in6_mask;
82: struct in6_addr in6_addr;
83: char mask[MAX_MASKBUF];
84: const char *p;
85: int bits, bmask;
86: int n;
87: int i;
88:
89: if (netmask[0] != '[')
90: return 0;
91: p = strchr(netmask, ']');
92: if (p == NULL)
93: return 0;
94: n = p - (netmask + 1);
95: if (n + 1 > sizeof mask)
96: return 0;
97:
98: memcpy(mask, netmask + 1, n);
99: mask[n] = '\0';
100: p++;
101:
102: if (p[0] == '/') {
103: bits = (int) strtol(p + 1, NULL, 10);
104: if (bits < 0 || bits > 128)
105: return 0;
106: } else {
107: bits = 128;
108: }
109:
110: #if 0
111: printf("input %s\n", addr);
112: printf("mask %s / %d\n", mask, bits);
113: #endif
114:
115: /* presentation to network order binary */
116: if (inet_pton(AF_INET6, mask, &in6_mask) <= 0
117: || inet_pton(AF_INET6, addr, &in6_addr) <= 0) {
118: return 0;
119: }
120:
121: /* check 128bits */
122: for (i = 0; i < (bits / 8); i++) {
123: if (in6_mask.s6_addr[i] != in6_addr.s6_addr[i])
124: return 0;
125: }
126: if (bits % 8) {
127: bmask = (0xffU << (8 - (bits % 8))) & 0xffU;
128: if ((in6_mask.s6_addr[i] & bmask) != (in6_addr.s6_addr[i] & bmask))
129: return 0;
130: }
131:
132: /* match */
133: return 1;
134: }
135:
136: static int
137: istgt_lu_allow_ipv4(const char *netmask, const char *addr)
138: {
139: struct in_addr in4_mask;
140: struct in_addr in4_addr;
141: char mask[MAX_MASKBUF];
142: const char *p;
143: uint32_t bmask;
144: int bits;
145: int n;
146:
147: p = strchr(netmask, '/');
148: if (p == NULL) {
149: p = netmask + strlen(netmask);
150: }
151: n = p - netmask;
152: if (n + 1 > sizeof mask)
153: return 0;
154:
155: memcpy(mask, netmask, n);
156: mask[n] = '\0';
157:
158: if (p[0] == '/') {
159: bits = (int) strtol(p + 1, NULL, 10);
160: if (bits < 0 || bits > 32)
161: return 0;
162: } else {
163: bits = 32;
164: }
165:
166: #if 0
167: printf("input %s\n", addr);
168: printf("mask %s / %d\n", mask, bits);
169: #endif
170:
171: /* presentation to network order binary */
172: if (inet_pton(AF_INET, mask, &in4_mask) <= 0
173: || inet_pton(AF_INET, addr, &in4_addr) <= 0) {
174: return 0;
175: }
176:
177: /* check 32bits */
178: bmask = (0xffffffffU << (32 - bits)) & 0xffffffffU;
179: if ((ntohl(in4_mask.s_addr) & bmask) != (ntohl(in4_addr.s_addr) & bmask))
180: return 0;
181:
182: /* match */
183: return 1;
184: }
185:
186: int
187: istgt_lu_allow_netmask(const char *netmask, const char *addr)
188: {
189: if (netmask == NULL || addr == NULL)
190: return 0;
191: if (strcasecmp(netmask, "ALL") == 0)
192: return 1;
193: if (netmask[0] == '[') {
194: /* IPv6 */
195: if (istgt_lu_allow_ipv6(netmask, addr))
196: return 1;
197: } else {
198: /* IPv4 */
199: if (istgt_lu_allow_ipv4(netmask, addr))
200: return 1;
201: }
202: return 0;
203: }
204:
205: int
206: istgt_lu_access(CONN_Ptr conn, ISTGT_LU_Ptr lu, const char *iqn, const char *addr)
207: {
208: ISTGT_Ptr istgt;
209: INITIATOR_GROUP *igp;
210: int pg_tag;
211: int ig_tag;
212: int rc;
213: int i, j, k;
214:
215: if (conn == NULL || lu == NULL || iqn == NULL || addr == NULL)
216: return 0;
217: istgt = conn->istgt;
218: pg_tag = conn->portal.tag;
219:
220: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "pg=%d, iqn=%s, addr=%s\n",
221: pg_tag, iqn, addr);
222: for (i = 0; i < lu->maxmap; i++) {
223: /* skip excluding self portal group tag */
224: if (pg_tag != lu->map[i].pg_tag)
225: continue;
226: /* iqn is initiator group? */
227: ig_tag = lu->map[i].ig_tag;
228: igp = istgt_lu_find_initiatorgroup(istgt, ig_tag);
229: if (igp == NULL) {
230: ISTGT_ERRLOG("LU%d: ig_tag not found\n", lu->num);
231: continue;
232: }
233: for (j = 0; j < igp->ninitiators; j++) {
234: /* deny initiators */
235: if (igp->initiators[j][0] == '!'
236: && (strcasecmp(&igp->initiators[j][1], "ALL") == 0
237: || strcasecmp(&igp->initiators[j][1], iqn) == 0)) {
238: /* NG */
239: ISTGT_WARNLOG("access denied from %s (%s) to %s (%s:%s,%d)\n",
240: iqn, addr, conn->target_name, conn->portal.host,
241: conn->portal.port, conn->portal.tag);
242: return 0;
243: }
244: /* allow initiators */
245: if (strcasecmp(igp->initiators[j], "ALL") == 0
246: || strcasecmp(igp->initiators[j], iqn) == 0) {
247: /* OK iqn, check netmask */
248: if (igp->nnetmasks == 0) {
249: /* OK, empty netmask as ALL */
250: return 1;
251: }
252: for (k = 0; k < igp->nnetmasks; k++) {
253: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
254: "netmask=%s, addr=%s\n",
255: igp->netmasks[k], addr);
256: rc = istgt_lu_allow_netmask(igp->netmasks[k], addr);
257: if (rc > 0) {
258: /* OK netmask */
259: return 1;
260: }
261: }
262: /* NG netmask in this group */
263: }
264: }
265: }
266:
267: /* NG */
268: ISTGT_WARNLOG("access denied from %s (%s) to %s (%s:%s,%d)\n",
269: iqn, addr, conn->target_name, conn->portal.host,
270: conn->portal.port, conn->portal.tag);
271: return 0;
272: }
273:
274: int
275: istgt_lu_visible(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu, const char *iqn, int pg_tag)
276: {
277: INITIATOR_GROUP *igp;
278: int match_pg_tag;
279: int ig_tag;
280: int i, j;
281:
282: if (istgt == NULL || lu == NULL || iqn == NULL)
283: return 0;
284: /* pg_tag exist map? */
285: match_pg_tag = 0;
286: for (i = 0; i < lu->maxmap; i++) {
287: if (lu->map[i].pg_tag == pg_tag) {
288: match_pg_tag = 1;
289: break;
290: }
291: }
292: if (match_pg_tag == 0) {
293: /* cat't access from pg_tag */
294: return 0;
295: }
296: for (i = 0; i < lu->maxmap; i++) {
297: /* iqn is initiator group? */
298: ig_tag = lu->map[i].ig_tag;
299: igp = istgt_lu_find_initiatorgroup(istgt, ig_tag);
300: if (igp == NULL) {
301: ISTGT_ERRLOG("LU%d: ig_tag not found\n", lu->num);
302: continue;
303: }
304: for (j = 0; j < igp->ninitiators; j++) {
305: if (igp->initiators[j][0] == '!'
306: && (strcasecmp(&igp->initiators[j][1], "ALL") == 0
307: || strcasecmp(&igp->initiators[j][1], iqn) == 0)) {
308: /* NG */
309: return 0;
310: }
311: if (strcasecmp(igp->initiators[j], "ALL") == 0
312: || strcasecmp(igp->initiators[j], iqn) == 0) {
313: /* OK iqn, no check addr */
314: return 1;
315: }
316: }
317: }
318:
319: /* NG */
320: return 0;
321: }
322:
323: int
324: istgt_lu_sendtargets(CONN_Ptr conn, const char *iiqn, const char *iaddr, const char *tiqn, uint8_t *data, int alloc_len, int data_len)
325: {
326: char buf[MAX_TMPBUF];
327: ISTGT_Ptr istgt;
328: ISTGT_LU_Ptr lu;
329: char *host;
330: int total;
331: int len;
332: int rc;
333: int pg_tag;
334: int i, j, k;
335:
336: if (conn == NULL)
337: return 0;
338: istgt = conn->istgt;
339:
340: total = data_len;
341: if (alloc_len < 1) {
342: return 0;
343: }
344: if (total > alloc_len) {
345: total = alloc_len;
346: data[total - 1] = '\0';
347: return total;
348: }
349:
350: if (alloc_len - total < 1) {
351: ISTGT_ERRLOG("data space small %d\n", alloc_len);
352: return total;
353: }
354:
355: MTX_LOCK(&istgt->mutex);
356: for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
357: lu = istgt->logical_unit[i];
358: if (lu == NULL)
359: continue;
360: if (strcasecmp(tiqn, "ALL") != 0
361: && strcasecmp(tiqn, lu->name) != 0) {
362: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
363: "SKIP iqn=%s for %s from %s (%s)\n",
364: tiqn, lu->name, iiqn, iaddr);
365: continue;
366: }
367: rc = istgt_lu_visible(istgt, lu, iiqn, conn->portal.tag);
368: if (rc == 0) {
369: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
370: "SKIP iqn=%s for %s from %s (%s)\n",
371: tiqn, lu->name, iiqn, iaddr);
372: continue;
373: }
374:
375: /* DO SENDTARGETS */
376: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
377: "OK iqn=%s for %s from %s (%s)\n",
378: tiqn, lu->name, iiqn, iaddr);
379:
380: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
381: "TargetName=%s\n", lu->name);
382: len = snprintf((char *) data + total, alloc_len - total,
383: "TargetName=%s", lu->name);
384: total += len + 1;
385:
386: for (j = 0; j < lu->maxmap; j++) {
387: pg_tag = lu->map[j].pg_tag;
388: /* skip same pg_tag */
389: for (k = 0; k < j; k++) {
390: if (lu->map[k].pg_tag == pg_tag) {
391: goto skip_pg_tag;
392: }
393: }
394: /* write to data */
395: for (k = 0; k < istgt->nportal; k++) {
396: if (istgt->portal[k].tag == pg_tag) {
397: if (alloc_len - total < 1) {
398: MTX_UNLOCK(&istgt->mutex);
399: ISTGT_ERRLOG("data space small %d\n", alloc_len);
400: return total;
401: }
402: host = istgt->portal[k].host;
403: /* wildcard? */
404: if (strcasecmp(host, "[::]") == 0
405: || strcasecmp(host, "[*]") == 0
406: || strcasecmp(host, "0.0.0.0") == 0
407: || strcasecmp(host, "*") == 0) {
408: if ((strcasecmp(host, "[::]") == 0
409: || strcasecmp(host, "[*]") == 0)
410: && conn->initiator_family == AF_INET6) {
411: snprintf(buf, sizeof buf, "[%s]",
412: conn->target_addr);
413: host = buf;
414: } else if ((strcasecmp(host, "0.0.0.0") == 0
415: || strcasecmp(host, "*") == 0)
416: && conn->initiator_family == AF_INET) {
417: snprintf(buf, sizeof buf, "%s",
418: conn->target_addr);
419: host = buf;
420: } else {
421: /* skip portal for the family */
422: continue;
423: }
424: }
425: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
426: "TargetAddress=%s:%s,%d\n",
427: host,
428: istgt->portal[k].port,
429: istgt->portal[k].tag);
430: len = snprintf((char *) data + total,
431: alloc_len - total,
432: "TargetAddress=%s:%s,%d",
433: host,
434: istgt->portal[k].port,
435: istgt->portal[k].tag);
436: total += len + 1;
437: }
438: }
439: skip_pg_tag:
440: ;
441: }
442: }
443: MTX_UNLOCK(&istgt->mutex);
444:
445: return total;
446: }
447:
448: ISTGT_LU_Ptr
449: istgt_lu_find_target(ISTGT_Ptr istgt, const char *target_name)
450: {
451: ISTGT_LU_Ptr lu;
452: int i;
453:
454: if (istgt == NULL || target_name == NULL)
455: return NULL;
456: for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
457: lu = istgt->logical_unit[i];
458: if (lu == NULL)
459: continue;
460: if (strcasecmp(target_name, lu->name) == 0) {
461: return lu;
462: }
463: }
464: ISTGT_WARNLOG("can't find target %s\n",
465: target_name);
466: return NULL;
467: }
468:
469: uint16_t
470: istgt_lu_allocate_tsih(ISTGT_LU_Ptr lu, const char *initiator_port, int tag)
471: {
472: uint16_t tsih;
473: int retry = 10;
474: int i;
475:
476: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_allocate_tsih\n");
477: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "initiator_port=%s, tag=%d\n",
478: initiator_port, tag);
479: if (lu == NULL || initiator_port == NULL || tag == 0)
480: return 0;
481: /* tsih 0 is reserved */
482: tsih = 0;
483: MTX_LOCK(&lu->mutex);
484: #if 0
485: for (i = 1; i < MAX_LU_TSIH; i++) {
486: if (lu->tsih[i].initiator_port == NULL)
487: continue;
488: if (tag != lu->tsih[i].tag)
489: continue;
490: if (strcasecmp(initiator_port, lu->tsih[i].initiator_port) == 0) {
491: tsih = lu->tsih[i].tsih;
492: break;
493: }
494: }
495: #endif
496: if (tsih == 0) {
497: if (lu->maxtsih >= MAX_LU_TSIH) {
498: ISTGT_ERRLOG("LU%d: tsih is maximum\n", lu->num);
499: MTX_UNLOCK(&lu->mutex);
500: return 0;
501: }
502: retry:
503: lu->last_tsih++;
504: tsih = lu->last_tsih;
505: if (tsih == 0) {
506: if (retry > 0) {
507: retry--;
508: goto retry;
509: }
510: ISTGT_ERRLOG("LU%d: retry error\n", lu->num);
511: MTX_UNLOCK(&lu->mutex);
512: return 0;
513: }
514: for (i = 1; i < MAX_LU_TSIH; i++) {
515: if (lu->tsih[i].initiator_port != NULL
516: && lu->tsih[i].tsih == tsih) {
517: ISTGT_ERRLOG("tsih is found in list\n");
518: if (retry > 0) {
519: retry--;
520: goto retry;
521: }
522: ISTGT_ERRLOG("LU%d: retry error\n", lu->num);
523: MTX_UNLOCK(&lu->mutex);
524: return 0;
525: }
526: }
527: for (i = 1; i < MAX_LU_TSIH; i++) {
528: if (lu->tsih[i].initiator_port == NULL) {
529: lu->tsih[i].tag = tag;
530: lu->tsih[i].tsih = tsih;
531: lu->tsih[i].initiator_port = xstrdup(initiator_port);
532: lu->maxtsih++;
533: break;
534: }
535: }
536: }
537: MTX_UNLOCK(&lu->mutex);
538: return tsih;
539: }
540:
541: void
542: istgt_lu_free_tsih(ISTGT_LU_Ptr lu, uint16_t tsih, char *initiator_port)
543: {
544: int i;
545:
546: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_free_tsih\n");
547: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "tsih=%u, initiator_port=%s\n",
548: tsih, initiator_port);
549: if (lu == NULL || initiator_port == NULL)
550: return;
551: if (tsih == 0)
552: return;
553:
554: MTX_LOCK(&lu->mutex);
555: for (i = 1; i < MAX_LU_TSIH; i++) {
556: if (lu->tsih[i].initiator_port == NULL)
557: continue;
558: if (lu->tsih[i].tsih != tsih)
559: continue;
560:
561: if (strcasecmp(initiator_port, lu->tsih[i].initiator_port) == 0) {
562: lu->tsih[i].tag = 0;
563: lu->tsih[i].tsih = 0;
564: xfree(lu->tsih[i].initiator_port);
565: lu->tsih[i].initiator_port = NULL;
566: lu->maxtsih--;
567: break;
568: }
569: }
570: MTX_UNLOCK(&lu->mutex);
571: return;
572: }
573:
574: char *
575: istgt_lu_get_media_flags_string(int flags, char *buf, size_t len)
576: {
577: char *p;
578: size_t rest;
579:
580: p = buf;
581: rest = len;
582: if (flags & ISTGT_LU_FLAG_MEDIA_READONLY) {
583: snprintf(p, rest, "%s", "ro");
584: } else {
585: snprintf(p, rest, "%s", "rw");
586: }
587: p = buf + strlen(buf);
588: rest = len - strlen(buf);
589: if (flags & ISTGT_LU_FLAG_MEDIA_EXTEND) {
590: snprintf(p, rest, ",%s", "extend");
591: }
592: p = buf + strlen(buf);
593: rest = len - strlen(buf);
594: if (flags & ISTGT_LU_FLAG_MEDIA_DYNAMIC) {
595: snprintf(p, rest, ",%s", "dynamic");
596: }
597: return buf;
598: }
599:
600: uint64_t
601: istgt_lu_get_devsize(const char *file)
602: {
603: uint64_t val;
604: struct stat st;
605: int fd;
606: int rc;
607:
608: val = 0ULL;
609: rc = lstat(file, &st);
610: if (rc != 0)
611: return val;
612: if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
613: return val;
614:
615: fd = open(file, O_RDONLY, 0);
616: if (fd >= 0) {
617: #ifdef DIOCGMEDIASIZE
618: if (val == 0) {
619: off_t offset;
620: rc = ioctl(fd, DIOCGMEDIASIZE, &offset);
621: if (rc != -1) {
622: val = (uint64_t) offset;
623: }
624: }
625: #endif /* DIOCGMEDIASIZE */
626: #ifdef DIOCGDINFO
627: if (val == 0) {
628: struct disklabel dl;
629: rc = ioctl(fd, DIOCGDINFO, &dl);
630: if (rc != -1) {
631: val = (uint64_t) dl.d_secperunit;
632: val *= (uint64_t) dl.d_secsize;
633: }
634: }
635: #endif /* DIOCGDINFO */
636: #if defined(DKIOCGETBLOCKSIZE) && defined(DKIOCGETBLOCKCOUNT)
637: if (val == 0) {
638: uint32_t blocklen;
639: uint64_t blockcnt;
640: rc = ioctl(fd, DKIOCGETBLOCKSIZE, &blocklen);
641: if (rc != -1) {
642: rc = ioctl(fd, DKIOCGETBLOCKCOUNT, &blockcnt);
643: if (rc != -1) {
644: val = (uint64_t) blocklen;
645: val *= (uint64_t) blockcnt;
646: }
647: }
648: }
649: #endif /* DKIOCGETBLOCKSIZE && DKIOCGETBLOCKCOUNT */
650: #ifdef __linux__
651: #ifdef BLKGETSIZE64
652: if (val == 0) {
653: uint64_t blocksize;
654: rc = ioctl(fd, BLKGETSIZE64, &blocksize);
655: if (rc != -1) {
656: val = (uint64_t) blocksize;
657: }
658: }
659: #endif /* BLKGETSIZE64 */
660: #ifdef BLKGETSIZE
661: if (val == 0) {
662: uint32_t blocksize;
663: rc = ioctl(fd, BLKGETSIZE, &blocksize);
664: if (rc != -1) {
665: val = (uint64_t) 512;
666: val *= (uint64_t) blocksize;
667: }
668: }
669: #endif /* BLKGETSIZE */
670: #endif /* __linux__ */
671: if (val == 0) {
672: ISTGT_ERRLOG("unknown device size\n");
673: }
674: (void) close(fd);
675: } else {
676: if (g_trace_flag) {
677: ISTGT_WARNLOG("open error %s (errno=%d)\n", file, errno);
678: }
679: val = 0ULL;
680: }
681: return val;
682: }
683:
684: uint64_t
685: istgt_lu_get_filesize(const char *file)
686: {
687: uint64_t val;
688: struct stat st;
689: int rc;
690:
691: val = 0ULL;
692: rc = lstat(file, &st);
693: if (rc < 0)
694: return val;
695: if (S_ISLNK(st.st_mode))
696: return val;
697:
698: if (S_ISCHR(st.st_mode)) {
699: val = istgt_lu_get_devsize(file);
700: } else if (S_ISBLK(st.st_mode)) {
701: val = istgt_lu_get_devsize(file);
702: } else if (S_ISREG(st.st_mode)) {
703: val = st.st_size;
704: } else {
705: ISTGT_ERRLOG("lstat is neither REG, CHR nor BLK\n");
706: val = 0ULL;
707: }
708: return val;
709: }
710:
711: uint64_t
712: istgt_lu_parse_size(const char *size)
713: {
714: uint64_t val, val1, val2;
715: char *endp, *p;
716: size_t idx;
717: int sign;
718:
719: val1 = (uint64_t) strtoull(size, &endp, 10);
720: val = val1;
721: val2 = 0;
722: if (endp != NULL) {
723: p = endp;
724: switch (toupper((int) *p)) {
725: case 'Z': val1 *= (uint64_t) 1024ULL;
726: case 'E': val1 *= (uint64_t) 1024ULL;
727: case 'P': val1 *= (uint64_t) 1024ULL;
728: case 'T': val1 *= (uint64_t) 1024ULL;
729: case 'G': val1 *= (uint64_t) 1024ULL;
730: case 'M': val1 *= (uint64_t) 1024ULL;
731: case 'K': val1 *= (uint64_t) 1024ULL;
732: break;
733: }
734: val = val1;
735: p++;
736: idx = strspn(p, "Bb \t");
737: p += idx;
738: if (*p == '-' || *p == '+') {
739: sign = (int) *p++;
740: idx = strspn(p, " \t");
741: p += idx;
742: val2 = (uint64_t) strtoull(p, &endp, 10);
743: if (endp != NULL) {
744: p = endp;
745: switch (toupper((int) *p)) {
746: case 'Z': val2 *= (uint64_t) 1024ULL;
747: case 'E': val2 *= (uint64_t) 1024ULL;
748: case 'P': val2 *= (uint64_t) 1024ULL;
749: case 'T': val2 *= (uint64_t) 1024ULL;
750: case 'G': val2 *= (uint64_t) 1024ULL;
751: case 'M': val2 *= (uint64_t) 1024ULL;
752: case 'K': val2 *= (uint64_t) 1024ULL;
753: break;
754: }
755: }
756: if (sign == '-') {
757: if (val2 > val1) {
758: /* underflow */
759: val = (uint64_t) 0ULL;
760: } else {
761: val = val1 - val2;
762: }
763: } else {
764: if (val2 > (UINT64_MAX - val1)) {
765: /* overflow */
766: val = UINT64_MAX;
767: } else {
768: val = val1 + val2;
769: }
770: }
771: }
772: }
773: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
774: "size=%s, val=%"PRIu64", val1=%"PRIu64", val2=%"PRIu64"\n",
775: size, val, val1, val2);
776: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
777: "size=%s, val=%"PRIx64", val1=%"PRIx64", val2=%"PRIx64"\n",
778: size, val, val1, val2);
779:
780: return val;
781: }
782:
783: int
784: istgt_lu_parse_media_flags(const char *flags)
785: {
786: char buf[MAX_TMPBUF];
787: const char *delim = ",";
788: char *next_p;
789: char *p;
790: int mflags;
791:
792: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "mflags=%s\n", flags);
793: mflags = 0;
794: strlcpy(buf, flags, MAX_TMPBUF);
795: next_p = buf;
796: while ((p = strsep(&next_p, delim)) != NULL) {
797: if (strcasecmp(p, "ro") == 0) {
798: mflags |= ISTGT_LU_FLAG_MEDIA_READONLY;
799: } else if (strcasecmp(p, "rw") == 0) {
800: mflags &= ~ISTGT_LU_FLAG_MEDIA_READONLY;
801: } else if (strcasecmp(p, "extend") == 0) {
802: mflags |= ISTGT_LU_FLAG_MEDIA_EXTEND;
803: } else if (strcasecmp(p, "dynamic") == 0) {
804: mflags |= ISTGT_LU_FLAG_MEDIA_DYNAMIC;
805: } else {
806: ISTGT_ERRLOG("unknown media flag %.64s\n", p);
807: }
808: }
809:
810: return mflags;
811: }
812:
813: uint64_t
814: istgt_lu_parse_media_size(const char *file, const char *size, int *flags)
815: {
816: uint64_t msize, fsize;
817:
818: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "msize=%s\n", size);
819: if (strcasecmp(file, "/dev/null") == 0) {
820: return 0;
821: }
822: if (strcasecmp(size, "Auto") == 0
823: || strcasecmp(size, "Size") == 0) {
824: msize = istgt_lu_get_filesize(file);
825: if (msize == 0) {
826: msize = ISTGT_LU_MEDIA_SIZE_MIN;
827: }
828: *flags |= ISTGT_LU_FLAG_MEDIA_AUTOSIZE;
829: } else {
830: msize = istgt_lu_parse_size(size);
831: if (*flags & ISTGT_LU_FLAG_MEDIA_EXTEND) {
832: fsize = istgt_lu_get_filesize(file);
833: if (fsize > msize) {
834: msize = fsize;
835: }
836: }
837: }
838:
839: if (*flags & ISTGT_LU_FLAG_MEDIA_DYNAMIC) {
840: if (msize < ISTGT_LU_MEDIA_SIZE_MIN) {
841: msize = ISTGT_LU_MEDIA_SIZE_MIN;
842: }
843: } else {
844: if (msize < ISTGT_LU_MEDIA_SIZE_MIN) {
845: ISTGT_ERRLOG("media size too small\n");
846: return 0ULL;
847: }
848: }
849:
850: return msize;
851: }
852:
853: PORTAL *
854: istgt_lu_find_portalgroup(ISTGT_Ptr istgt, int tag)
855: {
856: PORTAL *pp;
857: int i;
858:
859: for (i = 0; i < istgt->nportal; i++) {
860: if (istgt->portal[i].tag == tag) {
861: pp = &istgt->portal[i];
862: return pp;
863: }
864: }
865: return NULL;
866: }
867:
868: INITIATOR_GROUP *
869: istgt_lu_find_initiatorgroup(ISTGT_Ptr istgt, int tag)
870: {
871: INITIATOR_GROUP *igp;
872: int i;
873:
874: for (i = 0; i < istgt->ninitiator_group; i++) {
875: if (istgt->initiator_group[i].tag == tag) {
876: igp = &istgt->initiator_group[i];
877: return igp;
878: }
879: }
880: return NULL;
881: }
882:
883: static int
884: istgt_lu_check_iscsi_name(const char *name)
885: {
886: const unsigned char *up = (const unsigned char *) name;
887: size_t n;
888:
889: /* valid iSCSI name? */
890: for (n = 0; up[n] != 0; n++) {
891: if (up[n] > 0x00U && up[n] <= 0x2cU)
892: return -1;
893: if (up[n] == 0x2fU)
894: return -1;
895: if (up[n] >= 0x3bU && up[n] <= 0x40U)
896: return -1;
897: if (up[n] >= 0x5bU && up[n] <= 0x60U)
898: return -1;
899: if (up[n] >= 0x7bU && up[n] <= 0x7fU)
900: return -1;
901: if (isspace(up[n]))
902: return -1;
903: }
904: /* valid format? */
905: if (strncasecmp(name, "iqn.", 4) == 0) {
906: /* iqn.YYYY-MM.reversed.domain.name */
907: if (!isdigit(up[4]) || !isdigit(up[5]) || !isdigit(up[6])
908: || !isdigit(up[7]) || up[8] != '-' || !isdigit(up[9])
909: || !isdigit(up[10]) || up[11] != '.') {
910: ISTGT_ERRLOG("invalid iqn format. "
911: "expect \"iqn.YYYY-MM.reversed.domain.name\"\n");
912: return -1;
913: }
914: } else if (strncasecmp(name, "eui.", 4) == 0) {
915: /* EUI-64 -> 16bytes */
916: /* XXX */
917: } else if (strncasecmp(name, "naa.", 4) == 0) {
918: /* 64bit -> 16bytes, 128bit -> 32bytes */
919: /* XXX */
920: }
921: /* OK */
922: return 0;
923: }
924:
925: static uint64_t
926: istgt_lu_get_nbserial(const char *nodebase)
927: {
928: ISTGT_MD5CTX md5ctx;
929: uint8_t nbsmd5[ISTGT_MD5DIGEST_LEN];
930: char buf[MAX_TMPBUF];
931: uint64_t nbs;
932: int idx;
933: int i;
934:
935: snprintf(buf, sizeof buf, "%s", nodebase);
936: if (strcasecmp(buf, "iqn.2007-09.jp.ne.peach.istgt") == 0
937: || strcasecmp(buf, "iqn.2007-09.jp.ne.peach") == 0) {
938: /* always zero */
939: return 0;
940: }
941:
942: istgt_md5init(&md5ctx);
943: istgt_md5update(&md5ctx, buf, strlen(buf));
944: istgt_md5final(nbsmd5, &md5ctx);
945:
946: nbs = 0U;
947: idx = ISTGT_MD5DIGEST_LEN - 8;
948: if (idx < 0) {
949: ISTGT_WARNLOG("missing MD5 length\n");
950: idx = 0;
951: }
952: for (i = idx; i < ISTGT_MD5DIGEST_LEN; i++) {
953: nbs |= (uint64_t) nbsmd5[i];
954: nbs = nbs << 8;
955: }
956: return nbs;
957: }
958:
959: static int
960: istgt_lu_set_local_settings(ISTGT_Ptr istgt, CF_SECTION *sp, ISTGT_LU_Ptr lu)
961: {
962: const char *val;
963:
964: val = istgt_get_val(sp, "MaxOutstandingR2T");
965: if (val == NULL) {
966: lu->MaxOutstandingR2T = lu->istgt->MaxOutstandingR2T;
967: } else {
968: lu->MaxOutstandingR2T = (int)strtol(val, NULL, 10);
969: if (lu->MaxOutstandingR2T < 1) {
970: lu->MaxOutstandingR2T = DEFAULT_MAXOUTSTANDINGR2T;
971: }
972: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxOutstandingR2T %d\n",
973: lu->MaxOutstandingR2T);
974: }
975:
976: val = istgt_get_val(sp, "DefaultTime2Wait");
977: if (val == NULL) {
978: lu->DefaultTime2Wait = lu->istgt->DefaultTime2Wait;
979: } else {
980: lu->DefaultTime2Wait = (int)strtol(val, NULL, 10);
981: if (lu->DefaultTime2Wait < 0) {
982: lu->DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
983: }
984: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Wait %d\n",
985: lu->DefaultTime2Wait);
986: }
987:
988: val = istgt_get_val(sp, "DefaultTime2Retain");
989: if (val == NULL) {
990: lu->DefaultTime2Retain = lu->istgt->DefaultTime2Retain;
991: } else {
992: lu->DefaultTime2Retain = (int)strtol(val, NULL, 10);
993: if (lu->DefaultTime2Retain < 0) {
994: lu->DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
995: }
996: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Retain %d\n",
997: lu->DefaultTime2Retain);
998: }
999:
1000: /* check size limit - RFC3720(12.15, 12.16, 12.17) */
1001: if (lu->MaxOutstandingR2T > 65535) {
1002: ISTGT_ERRLOG("MaxOutstandingR2T(%d) > 65535\n",
1003: lu->MaxOutstandingR2T);
1004: return -1;
1005: }
1006: if (lu->DefaultTime2Wait > 3600) {
1007: ISTGT_ERRLOG("DefaultTime2Wait(%d) > 3600\n",
1008: lu->DefaultTime2Wait);
1009: return -1;
1010: }
1011: if (lu->DefaultTime2Retain > 3600) {
1012: ISTGT_ERRLOG("DefaultTime2Retain(%d) > 3600\n",
1013: lu->DefaultTime2Retain);
1014: return -1;
1015: }
1016:
1017: val = istgt_get_val(sp, "FirstBurstLength");
1018: if (val == NULL) {
1019: lu->FirstBurstLength = lu->istgt->FirstBurstLength;
1020: } else {
1021: lu->FirstBurstLength = (int)strtol(val, NULL, 10);
1022: if (lu->FirstBurstLength < 0) {
1023: lu->FirstBurstLength = DEFAULT_FIRSTBURSTLENGTH;
1024: }
1025: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "FirstBurstLength %d\n",
1026: lu->FirstBurstLength);
1027: }
1028:
1029: val = istgt_get_val(sp, "MaxBurstLength");
1030: if (val == NULL) {
1031: lu->MaxBurstLength = lu->istgt->MaxBurstLength;
1032: } else {
1033: lu->MaxBurstLength = (int)strtol(val, NULL, 10);
1034: if (lu->MaxBurstLength < 0) {
1035: lu->MaxBurstLength = DEFAULT_MAXBURSTLENGTH;
1036: }
1037: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxBurstLength %d\n",
1038: lu->MaxBurstLength);
1039: }
1040:
1041: val = istgt_get_val(sp, "MaxRecvDataSegmentLength");
1042: if (val == NULL) {
1043: lu->MaxRecvDataSegmentLength
1044: = lu->istgt->MaxRecvDataSegmentLength;
1045: } else {
1046: lu->MaxRecvDataSegmentLength = (int)strtol(val, NULL, 10);
1047: if (lu->MaxRecvDataSegmentLength < 0) {
1048: lu->MaxRecvDataSegmentLength
1049: = DEFAULT_MAXRECVDATASEGMENTLENGTH;
1050: }
1051: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1052: "MaxRecvDataSegmentLength %d\n",
1053: lu->MaxRecvDataSegmentLength);
1054: }
1055:
1056: /* check size limit (up to 24bits - RFC3720(12.12)) */
1057: if (lu->MaxBurstLength < 512) {
1058: ISTGT_ERRLOG("MaxBurstLength(%d) < 512\n",
1059: lu->MaxBurstLength);
1060: return -1;
1061: }
1062: if (lu->FirstBurstLength < 512) {
1063: ISTGT_ERRLOG("FirstBurstLength(%d) < 512\n",
1064: lu->FirstBurstLength);
1065: return -1;
1066: }
1067: if (lu->FirstBurstLength > lu->MaxBurstLength) {
1068: ISTGT_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
1069: lu->FirstBurstLength, istgt->MaxBurstLength);
1070: return -1;
1071: }
1072: if (lu->MaxBurstLength > 0x00ffffff) {
1073: ISTGT_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n",
1074: lu->MaxBurstLength);
1075: return -1;
1076: }
1077: if (lu->MaxRecvDataSegmentLength < 512) {
1078: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
1079: lu->MaxRecvDataSegmentLength);
1080: return -1;
1081: }
1082: if (lu->MaxRecvDataSegmentLength > 0x00ffffff) {
1083: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
1084: lu->MaxRecvDataSegmentLength);
1085: return -1;
1086: }
1087:
1088: val = istgt_get_val(sp, "InitialR2T");
1089: if (val == NULL) {
1090: lu->InitialR2T = lu->istgt->InitialR2T;
1091: } else {
1092: if (strcasecmp(val, "Yes") == 0) {
1093: lu->InitialR2T = 1;
1094: } else if (strcasecmp(val, "No") == 0) {
1095: #if 0
1096: lu->InitialR2T = 0;
1097: #else
1098: ISTGT_ERRLOG("not supported value %s\n", val);
1099: return -1;
1100: #endif
1101: } else {
1102: ISTGT_ERRLOG("unknown value %s\n", val);
1103: return -1;
1104: }
1105: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "InitialR2T %s\n",
1106: lu->InitialR2T ? "Yes" : "No");
1107: }
1108:
1109: val = istgt_get_val(sp, "ImmediateData");
1110: if (val == NULL) {
1111: lu->ImmediateData = lu->istgt->ImmediateData;
1112: } else {
1113: if (strcasecmp(val, "Yes") == 0) {
1114: lu->ImmediateData = 1;
1115: } else if (strcasecmp(val, "No") == 0) {
1116: lu->ImmediateData = 0;
1117: } else {
1118: ISTGT_ERRLOG("unknown value %s\n", val);
1119: return -1;
1120: }
1121: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ImmediateData %s\n",
1122: lu->ImmediateData ? "Yes" : "No");
1123: }
1124:
1125: val = istgt_get_val(sp, "DataPDUInOrder");
1126: if (val == NULL) {
1127: lu->DataPDUInOrder = lu->istgt->DataPDUInOrder;
1128: } else {
1129: if (strcasecmp(val, "Yes") == 0) {
1130: lu->DataPDUInOrder = 1;
1131: } else if (strcasecmp(val, "No") == 0) {
1132: #if 0
1133: lu->DataPDUInOrder = 0;
1134: #else
1135: ISTGT_ERRLOG("not supported value %s\n", val);
1136: return -1;
1137: #endif
1138: } else {
1139: ISTGT_ERRLOG("unknown value %s\n", val);
1140: return -1;
1141: }
1142: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataPDUInOrder %s\n",
1143: lu->DataPDUInOrder ? "Yes" : "No");
1144: }
1145:
1146: val = istgt_get_val(sp, "DataSequenceInOrder");
1147: if (val == NULL) {
1148: lu->DataSequenceInOrder = lu->istgt->DataSequenceInOrder;
1149: } else {
1150: if (strcasecmp(val, "Yes") == 0) {
1151: lu->DataSequenceInOrder = 1;
1152: } else if (strcasecmp(val, "No") == 0) {
1153: #if 0
1154: lu->DataSequenceInOrder = 0;
1155: #else
1156: ISTGT_ERRLOG("not supported value %s\n", val);
1157: return -1;
1158: #endif
1159: } else {
1160: ISTGT_ERRLOG("unknown value %s\n", val);
1161: return -1;
1162: }
1163: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataSequenceInOrder %s\n",
1164: lu->DataSequenceInOrder ? "Yes" : "No");
1165: }
1166:
1167: val = istgt_get_val(sp, "ErrorRecoveryLevel");
1168: if (val == NULL) {
1169: lu->ErrorRecoveryLevel = lu->istgt->ErrorRecoveryLevel;
1170: } else {
1171: lu->ErrorRecoveryLevel = (int)strtol(val, NULL, 10);
1172: if (lu->ErrorRecoveryLevel < 0) {
1173: lu->ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
1174: } else if (lu->ErrorRecoveryLevel == 0) {
1175: lu->ErrorRecoveryLevel = 0;
1176: } else if (lu->ErrorRecoveryLevel == 1) {
1177: #if 0
1178: lu->ErrorRecoveryLevel = 1;
1179: #else
1180: ISTGT_ERRLOG("not supported value %d\n",
1181: lu->ErrorRecoveryLevel);
1182: return -1;
1183: #endif
1184: } else if (lu->ErrorRecoveryLevel == 2) {
1185: #if 0
1186: lu->ErrorRecoveryLevel = 2;
1187: #else
1188: ISTGT_ERRLOG("not supported value %d\n",
1189: lu->ErrorRecoveryLevel);
1190: return -1;
1191: #endif
1192: } else {
1193: ISTGT_ERRLOG("not supported value %d\n",
1194: lu->ErrorRecoveryLevel);
1195: return -1;
1196: }
1197: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ErrorRecoveryLevel %d\n",
1198: istgt->ErrorRecoveryLevel);
1199: }
1200:
1201: return 0;
1202: }
1203:
1204: static int
1205: istgt_lu_add_unit(ISTGT_Ptr istgt, CF_SECTION *sp)
1206: {
1207: char buf[MAX_TMPBUF], buf2[MAX_TMPBUF];
1208: ISTGT_LU_Ptr lu;
1209: const char *vendor, *product, *revision, *serial;
1210: const char *pg_tag, *ig_tag;
1211: const char *ag_tag;
1212: const char *flags, *file, *size;
1213: const char *key, *val;
1214: uint64_t msize;
1215: uint64_t nbs64;
1216: int pg_tag_i, ig_tag_i;
1217: int ag_tag_i;
1218: int rpm, formfactor;
1219: int mflags;
1220: int slot;
1221: int nbs;
1222: int i, j, k;
1223: int rc;
1224:
1225: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add unit %d\n", sp->num);
1226:
1227: if (sp->num >= MAX_LOGICAL_UNIT) {
1228: ISTGT_ERRLOG("LU%d: over maximum unit number\n", sp->num);
1229: return -1;
1230: }
1231: if (istgt->logical_unit[sp->num] != NULL) {
1232: ISTGT_ERRLOG("LU%d: duplicate unit\n", sp->num);
1233: return -1;
1234: }
1235:
1236: lu = xmalloc(sizeof *lu);
1237: memset(lu, 0, sizeof *lu);
1238: lu->num = sp->num;
1239: lu->istgt = istgt;
1240: istgt_lu_set_state(lu, ISTGT_STATE_INVALID);
1241: nbs64 = istgt_lu_get_nbserial(istgt->nodebase);
1242: #if 0
1243: /* disabled now */
1244: nbs = (int) (nbs64 % 900) * 100000;
1245: #else
1246: nbs = 0;
1247: #endif
1248:
1249: val = istgt_get_val(sp, "Comment");
1250: if (val != NULL) {
1251: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
1252: }
1253:
1254: val = istgt_get_val(sp, "TargetName");
1255: if (val == NULL) {
1256: ISTGT_ERRLOG("LU%d: TargetName not found\n", lu->num);
1257: goto error_return;
1258: }
1259: if (strncasecmp(val, "iqn.", 4) != 0
1260: && strncasecmp(val, "eui.", 4) != 0
1261: && strncasecmp(val, "naa.", 4) != 0) {
1262: snprintf(buf, sizeof buf, "%s:%s", istgt->nodebase, val);
1263: } else {
1264: snprintf(buf, sizeof buf, "%s", val);
1265: }
1266: if (istgt_lu_check_iscsi_name(buf) != 0) {
1267: ISTGT_ERRLOG("TargetName %s contains an invalid character or format.\n",
1268: buf);
1269: #if 0
1270: goto error_return;
1271: #endif
1272: }
1273: lu->name = xstrdup(buf);
1274: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "TargetName %s\n",
1275: lu->name);
1276:
1277: val = istgt_get_val(sp, "TargetAlias");
1278: if (val == NULL) {
1279: lu->alias = NULL;
1280: } else {
1281: lu->alias = xstrdup(val);
1282: }
1283: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "TargetAlias %s\n",
1284: lu->alias);
1285:
1286: val = istgt_get_val(sp, "Mapping");
1287: if (val == NULL) {
1288: /* no map */
1289: lu->maxmap = 0;
1290: } else {
1291: lu->maxmap = 0;
1292: for (i = 0; ; i++) {
1293: val = istgt_get_nmval(sp, "Mapping", i, 0);
1294: if (val == NULL)
1295: break;
1296: if (lu->maxmap >= MAX_LU_MAP) {
1297: ISTGT_ERRLOG("LU%d: too many mapping\n", lu->num);
1298: goto error_return;
1299: }
1300: pg_tag = istgt_get_nmval(sp, "Mapping", i, 0);
1301: ig_tag = istgt_get_nmval(sp, "Mapping", i, 1);
1302: if (pg_tag == NULL || ig_tag == NULL) {
1303: ISTGT_ERRLOG("LU%d: mapping error\n", lu->num);
1304: goto error_return;
1305: }
1306: if (strncasecmp(pg_tag, "PortalGroup",
1307: strlen("PortalGroup")) != 0
1308: || sscanf(pg_tag, "%*[^0-9]%d", &pg_tag_i) != 1) {
1309: ISTGT_ERRLOG("LU%d: mapping portal error\n", lu->num);
1310: goto error_return;
1311: }
1312: if (strncasecmp(ig_tag, "InitiatorGroup",
1313: strlen("InitiatorGroup")) != 0
1314: || sscanf(ig_tag, "%*[^0-9]%d", &ig_tag_i) != 1) {
1315: ISTGT_ERRLOG("LU%d: mapping initiator error\n", lu->num);
1316: goto error_return;
1317: }
1318: if (pg_tag_i < 1 || ig_tag_i < 1) {
1319: ISTGT_ERRLOG("LU%d: invalid group tag\n", lu->num);
1320: goto error_return;
1321: }
1322: if (istgt_lu_find_portalgroup(istgt, pg_tag_i) == NULL) {
1323: ISTGT_ERRLOG("LU%d: PortalGroup%d not found\n",
1324: lu->num, pg_tag_i);
1325: goto error_return;
1326: }
1327: if (istgt_lu_find_initiatorgroup(istgt, ig_tag_i) == NULL) {
1328: ISTGT_ERRLOG("LU%d: InitiatorGroup%d not found\n",
1329: lu->num, ig_tag_i);
1330: goto error_return;
1331: }
1332: lu->map[i].pg_tag = pg_tag_i;
1333: lu->map[i].pg_aas = AAS_ACTIVE_OPTIMIZED;
1334: //lu->map[i].pg_aas = AAS_ACTIVE_NON_OPTIMIZED;
1335: lu->map[i].pg_aas |= AAS_STATUS_IMPLICIT;
1336: lu->map[i].ig_tag = ig_tag_i;
1337: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1338: "Mapping PortalGroup%d InitiatorGroup%d\n",
1339: lu->map[i].pg_tag, lu->map[i].ig_tag);
1340: lu->maxmap = i + 1;
1341: }
1342: }
1343: if (lu->maxmap == 0) {
1344: ISTGT_ERRLOG("LU%d: no Mapping\n", lu->num);
1345: goto error_return;
1346: }
1347:
1348: val = istgt_get_val(sp, "AuthMethod");
1349: if (val == NULL) {
1350: /* none */
1351: lu->no_auth_chap = 0;
1352: lu->auth_chap = 0;
1353: lu->auth_chap_mutual = 0;
1354: } else {
1355: lu->no_auth_chap = 0;
1356: for (i = 0; ; i++) {
1357: val = istgt_get_nmval(sp, "AuthMethod", 0, i);
1358: if (val == NULL)
1359: break;
1360: if (strcasecmp(val, "CHAP") == 0) {
1361: lu->auth_chap = 1;
1362: } else if (strcasecmp(val, "Mutual") == 0) {
1363: lu->auth_chap_mutual = 1;
1364: } else if (strcasecmp(val, "Auto") == 0) {
1365: lu->auth_chap = 0;
1366: lu->auth_chap_mutual = 0;
1367: } else if (strcasecmp(val, "None") == 0) {
1368: lu->no_auth_chap = 1;
1369: lu->auth_chap = 0;
1370: lu->auth_chap_mutual = 0;
1371: } else {
1372: ISTGT_ERRLOG("LU%d: unknown auth\n", lu->num);
1373: goto error_return;
1374: }
1375: }
1376: if (lu->auth_chap_mutual && !lu->auth_chap) {
1377: ISTGT_ERRLOG("LU%d: Mutual but not CHAP\n", lu->num);
1378: goto error_return;
1379: }
1380: }
1381: if (lu->no_auth_chap != 0) {
1382: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod None\n");
1383: } else if (lu->auth_chap == 0) {
1384: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod Auto\n");
1385: } else {
1386: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod %s %s\n",
1387: lu->auth_chap ? "CHAP" : "",
1388: lu->auth_chap_mutual ? "Mutual" : "");
1389: }
1390:
1391: val = istgt_get_val(sp, "AuthGroup");
1392: if (val == NULL) {
1393: lu->auth_group = 0;
1394: } else {
1395: ag_tag = val;
1396: if (strcasecmp(ag_tag, "None") == 0) {
1397: ag_tag_i = 0;
1398: } else {
1399: if (strncasecmp(ag_tag, "AuthGroup",
1400: strlen("AuthGroup")) != 0
1401: || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) {
1402: ISTGT_ERRLOG("LU%d: auth group error\n", lu->num);
1403: goto error_return;
1404: }
1405: if (ag_tag_i == 0) {
1406: ISTGT_ERRLOG("LU%d: invalid auth group %d\n", ag_tag_i);
1407: goto error_return;
1408: }
1409: }
1410: lu->auth_group = ag_tag_i;
1411: }
1412: if (lu->auth_group == 0) {
1413: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthGroup None\n");
1414: } else {
1415: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthGroup AuthGroup%d\n",
1416: lu->auth_group);
1417: }
1418:
1419: val = istgt_get_val(sp, "UseDigest");
1420: if (val != NULL) {
1421: for (i = 0; ; i++) {
1422: val = istgt_get_nmval(sp, "UseDigest", 0, i);
1423: if (val == NULL)
1424: break;
1425: if (strcasecmp(val, "Header") == 0) {
1426: lu->header_digest = 1;
1427: } else if (strcasecmp(val, "Data") == 0) {
1428: lu->data_digest = 1;
1429: } else if (strcasecmp(val, "Auto") == 0) {
1430: lu->header_digest = 0;
1431: lu->data_digest = 0;
1432: } else {
1433: ISTGT_ERRLOG("LU%d: unknown digest\n", lu->num);
1434: goto error_return;
1435: }
1436: }
1437: }
1438: if (lu->header_digest == 0 && lu->data_digest == 0) {
1439: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UseDigest Auto\n");
1440: } else {
1441: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UseDigest %s %s\n",
1442: lu->header_digest ? "Header" : "",
1443: lu->data_digest ? "Data" : "");
1444: }
1445:
1446: val = istgt_get_val(sp, "ReadOnly");
1447: if (val == NULL) {
1448: lu->readonly = 0;
1449: } else if (strcasecmp(val, "Yes") == 0) {
1450: lu->readonly = 1;
1451: }
1452: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ReadOnly %s\n",
1453: lu->readonly ? "Yes" : "No");
1454:
1455: val = istgt_get_val(sp, "UnitType");
1456: if (val == NULL) {
1457: ISTGT_ERRLOG("LU%d: unknown unit type\n", lu->num);
1458: goto error_return;
1459: }
1460: if (strcasecmp(val, "Pass") == 0) {
1461: lu->type = ISTGT_LU_TYPE_PASS;
1462: } else if (strcasecmp(val, "Disk") == 0) {
1463: lu->type = ISTGT_LU_TYPE_DISK;
1464: } else if (strcasecmp(val, "DVD") == 0) {
1465: lu->type = ISTGT_LU_TYPE_DVD;
1466: } else if (strcasecmp(val, "Tape") == 0) {
1467: lu->type = ISTGT_LU_TYPE_TAPE;
1468: } else {
1469: ISTGT_ERRLOG("LU%d: unknown unit type\n", lu->num);
1470: goto error_return;
1471: }
1472: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UnitType %d (%s)\n",
1473: lu->type, val);
1474:
1475: val = istgt_get_val(sp, "UnitOnline");
1476: if (val == NULL) {
1477: lu->online = 1;
1478: } else if (strcasecmp(val, "Yes") == 0) {
1479: lu->online = 1;
1480: }
1481: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UnitOnline %s\n",
1482: lu->online ? "Yes" : "No");
1483:
1484: vendor = istgt_get_nmval(sp, "UnitInquiry", 0, 0);
1485: product = istgt_get_nmval(sp, "UnitInquiry", 0, 1);
1486: revision = istgt_get_nmval(sp, "UnitInquiry", 0, 2);
1487: serial = istgt_get_nmval(sp, "UnitInquiry", 0, 3);
1488: switch (lu->type) {
1489: case ISTGT_LU_TYPE_DISK:
1490: if (vendor == NULL || strlen(vendor) == 0)
1491: vendor = DEFAULT_LU_VENDOR_DISK;
1492: if (product == NULL || strlen(product) == 0)
1493: product = DEFAULT_LU_PRODUCT_DISK;
1494: if (revision == NULL || strlen(revision) == 0)
1495: revision = DEFAULT_LU_REVISION_DISK;
1496: if (serial == NULL || strlen(serial) == 0) {
1497: snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num);
1498: serial = (const char *) &buf[0];
1499: }
1500: break;
1501: case ISTGT_LU_TYPE_DVD:
1502: if (vendor == NULL || strlen(vendor) == 0)
1503: vendor = DEFAULT_LU_VENDOR_DVD;
1504: if (product == NULL || strlen(product) == 0)
1505: product = DEFAULT_LU_PRODUCT_DVD;
1506: if (revision == NULL || strlen(revision) == 0)
1507: revision = DEFAULT_LU_REVISION_DVD;
1508: if (serial == NULL || strlen(serial) == 0) {
1509: snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num);
1510: serial = (const char *) &buf[0];
1511: }
1512: break;
1513: case ISTGT_LU_TYPE_TAPE:
1514: if (vendor == NULL || strlen(vendor) == 0)
1515: vendor = DEFAULT_LU_VENDOR_TAPE;
1516: if (product == NULL || strlen(product) == 0)
1517: product = DEFAULT_LU_PRODUCT_TAPE;
1518: if (revision == NULL || strlen(revision) == 0)
1519: revision = DEFAULT_LU_REVISION_TAPE;
1520: if (serial == NULL || strlen(serial) == 0) {
1521: #ifdef USE_LU_TAPE_DLT8000
1522: snprintf(buf, sizeof buf, "CX%.8d", 10000000 + nbs + lu->num);
1523: #else
1524: snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num);
1525: #endif /* USE_LU_TAPE_DLT8000 */
1526: serial = (const char *) &buf[0];
1527: }
1528: break;
1529: default:
1530: if (vendor == NULL || strlen(vendor) == 0)
1531: vendor = DEFAULT_LU_VENDOR;
1532: if (product == NULL || strlen(product) == 0)
1533: product = DEFAULT_LU_PRODUCT;
1534: if (revision == NULL || strlen(revision) == 0)
1535: revision = DEFAULT_LU_REVISION;
1536: if (serial == NULL || strlen(serial) == 0) {
1537: snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num);
1538: serial = (const char *) &buf[0];
1539: }
1540: break;
1541: }
1542: lu->inq_vendor = xstrdup(vendor);
1543: lu->inq_product = xstrdup(product);
1544: lu->inq_revision = xstrdup(revision);
1545: lu->inq_serial = xstrdup(serial);
1546: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UnitInquiry %s %s %s %s\n",
1547: lu->inq_vendor, lu->inq_product, lu->inq_revision,
1548: lu->inq_serial);
1549:
1550: val = istgt_get_val(sp, "BlockLength");
1551: if (val == NULL) {
1552: switch (lu->type) {
1553: case ISTGT_LU_TYPE_DISK:
1554: lu->blocklen = DEFAULT_LU_BLOCKLEN_DISK;
1555: break;
1556: case ISTGT_LU_TYPE_DVD:
1557: lu->blocklen = DEFAULT_LU_BLOCKLEN_DVD;
1558: break;
1559: case ISTGT_LU_TYPE_TAPE:
1560: lu->blocklen = DEFAULT_LU_BLOCKLEN_TAPE;
1561: break;
1562: default:
1563: lu->blocklen = DEFAULT_LU_BLOCKLEN;
1564: break;
1565: }
1566: } else {
1567: lu->blocklen = (int) strtol(val, NULL, 10);
1568: }
1569: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "BlockLength %d\n",
1570: lu->blocklen);
1571:
1572: val = istgt_get_val(sp, "QueueDepth");
1573: if (val == NULL) {
1574: switch (lu->type) {
1575: case ISTGT_LU_TYPE_DISK:
1576: lu->queue_depth = DEFAULT_LU_QUEUE_DEPTH;
1577: //lu->queue_depth = 0;
1578: break;
1579: case ISTGT_LU_TYPE_DVD:
1580: case ISTGT_LU_TYPE_TAPE:
1581: default:
1582: lu->queue_depth = 0;
1583: break;
1584: }
1585: } else {
1586: lu->queue_depth = (int) strtol(val, NULL, 10);
1587: }
1588: if (lu->queue_depth < 0 || lu->queue_depth >= MAX_LU_QUEUE_DEPTH) {
1589: ISTGT_ERRLOG("LU%d: queue depth range error\n");
1590: goto error_return;
1591: }
1592: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "QueueDepth %d\n",
1593: lu->queue_depth);
1594:
1595: lu->maxlun = 0;
1596: for (i = 0; i < MAX_LU_LUN; i++) {
1597: lu->lun[i].type = ISTGT_LU_LUN_TYPE_NONE;
1598: lu->lun[i].rotationrate = DEFAULT_LU_ROTATIONRATE;
1599: lu->lun[i].formfactor = DEFAULT_LU_FORMFACTOR;
1600: lu->lun[i].readcache = 1;
1601: lu->lun[i].writecache = 1;
1602: lu->lun[i].serial = NULL;
1603: lu->lun[i].spec = NULL;
1604: snprintf(buf, sizeof buf, "LUN%d", i);
1605: val = istgt_get_val(sp, buf);
1606: if (val == NULL)
1607: continue;
1608: if (i != 0) {
1609: /* default LUN serial (except LUN0) */
1610: snprintf(buf2, sizeof buf2, "%sL%d", lu->inq_serial, i);
1611: lu->lun[i].serial = xstrdup(buf2);
1612: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d Serial %s (default)\n",
1613: i, buf2);
1614: }
1615: for (j = 0; ; j++) {
1616: val = istgt_get_nmval(sp, buf, j, 0);
1617: if (val == NULL)
1618: break;
1619: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d\n", i);
1620: if (strcasecmp(val, "Device") == 0) {
1621: if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_NONE) {
1622: ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i);
1623: goto error_return;
1624: }
1625: lu->lun[i].type = ISTGT_LU_LUN_TYPE_DEVICE;
1626:
1627: file = istgt_get_nmval(sp, buf, j, 1);
1628: if (file == NULL) {
1629: ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
1630: goto error_return;
1631: }
1632: lu->lun[i].u.device.file = xstrdup(file);
1633: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Device file=%s\n",
1634: lu->lun[i].u.device.file);
1635: } else if (strcasecmp(val, "Storage") == 0) {
1636: if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_NONE) {
1637: ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i);
1638: goto error_return;
1639: }
1640: lu->lun[i].type = ISTGT_LU_LUN_TYPE_STORAGE;
1641:
1642: file = istgt_get_nmval(sp, buf, j, 1);
1643: size = istgt_get_nmval(sp, buf, j, 2);
1644: if (file == NULL || size == NULL) {
1645: ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
1646: goto error_return;
1647: }
1648: if (strcasecmp(size, "Auto") == 0
1649: || strcasecmp(size, "Size") == 0) {
1650: lu->lun[i].u.storage.size = istgt_lu_get_filesize(file);
1651: } else {
1652: lu->lun[i].u.storage.size = istgt_lu_parse_size(size);
1653: }
1654: if (lu->lun[i].u.storage.size == 0) {
1655: ISTGT_ERRLOG("LU%d: LUN%d: Auto size error (%s)\n", lu->num, i, file);
1656: goto error_return;
1657: }
1658: lu->lun[i].u.storage.fd = -1;
1659: lu->lun[i].u.storage.file = xstrdup(file);
1660: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1661: "Storage file=%s, size=%"PRIu64"\n",
1662: lu->lun[i].u.storage.file,
1663: lu->lun[i].u.storage.size);
1664: } else if (strcasecmp(val, "Removable") == 0) {
1665: if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_NONE) {
1666: ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i);
1667: goto error_return;
1668: }
1669: lu->lun[i].type = ISTGT_LU_LUN_TYPE_REMOVABLE;
1670:
1671: flags = istgt_get_nmval(sp, buf, j, 1);
1672: file = istgt_get_nmval(sp, buf, j, 2);
1673: size = istgt_get_nmval(sp, buf, j, 3);
1674: if (flags == NULL || file == NULL || size == NULL) {
1675: ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
1676: goto error_return;
1677: }
1678: mflags = istgt_lu_parse_media_flags(flags);
1679: msize = istgt_lu_parse_media_size(file, size, &mflags);
1680: if (msize == 0 && strcasecmp(file, "/dev/null") == 0) {
1681: /* empty media */
1682: } else if (msize == 0) {
1683: ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
1684: goto error_return;
1685: }
1686: lu->lun[i].u.removable.type = 0;
1687: lu->lun[i].u.removable.id = 0;
1688: lu->lun[i].u.removable.fd = -1;
1689: lu->lun[i].u.removable.flags = mflags;
1690: lu->lun[i].u.removable.file = xstrdup(file);
1691: lu->lun[i].u.removable.size = msize;
1692: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1693: "Removable file=%s, size=%"PRIu64", flags=%x\n",
1694: lu->lun[i].u.removable.file,
1695: lu->lun[i].u.removable.size,
1696: lu->lun[i].u.removable.flags);
1697: } else if (strncasecmp(val, "Slot", 4) == 0) {
1698: if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
1699: lu->lun[i].u.slot.maxslot = 0;
1700: for (k = 0; k < MAX_LU_LUN_SLOT; k++) {
1701: lu->lun[i].u.slot.present[k] = 0;
1702: lu->lun[i].u.slot.flags[k] = 0;
1703: lu->lun[i].u.slot.file[k] = NULL;
1704: lu->lun[i].u.slot.size[k] = 0;
1705: }
1706: } else if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_SLOT) {
1707: ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i);
1708: goto error_return;
1709: }
1710: lu->lun[i].type = ISTGT_LU_LUN_TYPE_SLOT;
1711: if (sscanf(val, "%*[^0-9]%d", &slot) != 1) {
1712: ISTGT_ERRLOG("LU%d: slot number error\n", lu->num);
1713: goto error_return;
1714: }
1715: if (slot < 0 || slot >= MAX_LU_LUN_SLOT) {
1716: ISTGT_ERRLOG("LU%d: slot number range error\n", lu->num);
1717: goto error_return;
1718: }
1719: if (lu->lun[i].u.slot.present[slot]) {
1720: ISTGT_ERRLOG("LU%d: duplicate slot %d\n", lu->num, slot);
1721: goto error_return;
1722: }
1723: lu->lun[i].u.slot.present[slot] = 1;
1724: if (slot + 1 > lu->lun[i].u.slot.maxslot) {
1725: lu->lun[i].u.slot.maxslot = slot + 1;
1726: }
1727:
1728: flags = istgt_get_nmval(sp, buf, j, 1);
1729: file = istgt_get_nmval(sp, buf, j, 2);
1730: size = istgt_get_nmval(sp, buf, j, 3);
1731: if (flags == NULL || file == NULL || size == NULL) {
1732: ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
1733: goto error_return;
1734: }
1735: mflags = istgt_lu_parse_media_flags(flags);
1736: msize = istgt_lu_parse_media_size(file, size, &mflags);
1737: if (msize == 0) {
1738: ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
1739: goto error_return;
1740: }
1741: lu->lun[i].u.slot.flags[slot] = mflags;
1742: lu->lun[i].u.slot.file[slot] = xstrdup(file);
1743: lu->lun[i].u.slot.size[slot] = msize;
1744: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1745: "Slot%d file=%s, size=%"PRIu64", flags=%x\n",
1746: slot,
1747: lu->lun[i].u.slot.file[slot],
1748: lu->lun[i].u.slot.size[slot],
1749: lu->lun[i].u.slot.flags[slot]);
1750: } else if (strncasecmp(val, "Option", 6) == 0) {
1751: key = istgt_get_nmval(sp, buf, j, 1);
1752: val = istgt_get_nmval(sp, buf, j, 2);
1753: if (key == NULL || val == NULL) {
1754: ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
1755: goto error_return;
1756: }
1757: if (strcasecmp(key, "Serial") == 0) {
1758: /* set LUN serial */
1759: if (strlen(val) == 0) {
1760: ISTGT_ERRLOG("LU%d: LUN%d: no serial\n",
1761: lu->num, i);
1762: goto error_return;
1763: }
1764: xfree(lu->lun[i].serial);
1765: lu->lun[i].serial = xstrdup(val);
1766: } else if (strcasecmp(key, "RPM") == 0) {
1767: rpm = (int)strtol(val, NULL, 10);
1768: if (rpm < 0) {
1769: rpm = 0;
1770: } else if (rpm > 0xfffe) {
1771: rpm = 0xfffe;
1772: }
1773: lu->lun[i].rotationrate = rpm;
1774: } else if (strcasecmp(key, "FormFactor") == 0) {
1775: formfactor = (int)strtol(val, NULL, 10);
1776: if (formfactor < 0) {
1777: formfactor = 0;
1778: } else if (formfactor > 0x0f) {
1779: formfactor = 0xf;
1780: }
1781: lu->lun[i].formfactor = formfactor;
1782: } else if (strcasecmp(key, "ReadCache") == 0) {
1783: if (strcasecmp(val, "Enable") == 0) {
1784: lu->lun[i].readcache = 1;
1785: } else if (strcasecmp(val, "Disable") == 0) {
1786: lu->lun[i].readcache = 0;
1787: } else {
1788: ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n",
1789: lu->num, i, val);
1790: }
1791: } else if (strcasecmp(key, "WriteCache") == 0) {
1792: if (strcasecmp(val, "Enable") == 0) {
1793: lu->lun[i].writecache = 1;
1794: } else if (strcasecmp(val, "Disable") == 0) {
1795: lu->lun[i].writecache = 0;
1796: } else {
1797: ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n",
1798: lu->num, i, val);
1799: }
1800: } else {
1801: ISTGT_WARNLOG("LU%d: LUN%d: unknown key(%s)\n",
1802: lu->num, i, key);
1803: continue;
1804: }
1805: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d Option %s => %s\n",
1806: i, key, val);
1807: continue;
1808: } else {
1809: ISTGT_ERRLOG("LU%d: unknown lun type\n", lu->num);
1810: goto error_return;
1811: }
1812: }
1813: if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_SLOT) {
1814: if (lu->lun[i].u.slot.maxslot == 0) {
1815: ISTGT_ERRLOG("LU%d: no slot\n", lu->num);
1816: goto error_return;
1817: }
1818: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "maxslot=%d\n",
1819: lu->lun[i].u.slot.maxslot);
1820: }
1821: lu->maxlun = i + 1;
1822: }
1823: if (lu->maxlun == 0) {
1824: ISTGT_ERRLOG("LU%d: no LUN\n", lu->num);
1825: goto error_return;
1826: }
1827: if (lu->lun[0].type == ISTGT_LU_LUN_TYPE_NONE) {
1828: ISTGT_ERRLOG("LU%d: no LUN0\n", lu->num);
1829: goto error_return;
1830: }
1831:
1832: /* set local values if any */
1833: rc = istgt_lu_set_local_settings(istgt, sp, lu);
1834: if (rc < 0) {
1835: ISTGT_ERRLOG("LU%d: local setting error\n", lu->num);
1836: goto error_return;
1837: }
1838:
1839: /* tsih 0 is reserved */
1840: for (i = 0; i < MAX_LU_TSIH; i++) {
1841: lu->tsih[i].tag = 0;
1842: lu->tsih[i].tsih = 0;
1843: lu->tsih[i].initiator_port = NULL;
1844: }
1845: lu->maxtsih = 1;
1846: lu->last_tsih = 0;
1847:
1848: MTX_LOCK(&istgt->mutex);
1849: istgt->nlogical_unit++;
1850: istgt->logical_unit[lu->num] = lu;
1851: MTX_UNLOCK(&istgt->mutex);
1852: return 0;
1853:
1854: error_return:
1855: xfree(lu->name);
1856: xfree(lu->alias);
1857: xfree(lu->inq_vendor);
1858: xfree(lu->inq_product);
1859: xfree(lu->inq_revision);
1860: for (i = 0; i < MAX_LU_LUN; i++) {
1861: switch (lu->lun[i].type) {
1862: case ISTGT_LU_LUN_TYPE_DEVICE:
1863: xfree(lu->lun[i].u.device.file);
1864: break;
1865: case ISTGT_LU_LUN_TYPE_STORAGE:
1866: xfree(lu->lun[i].u.storage.file);
1867: break;
1868: case ISTGT_LU_LUN_TYPE_REMOVABLE:
1869: xfree(lu->lun[i].u.removable.file);
1870: break;
1871: case ISTGT_LU_LUN_TYPE_SLOT:
1872: for (j = 0; j < lu->lun[i].u.slot.maxslot; j++) {
1873: xfree(lu->lun[i].u.slot.file[j]);
1874: }
1875: break;
1876: case ISTGT_LU_LUN_TYPE_NONE:
1877: default:
1878: break;
1879: }
1880: }
1881: for (i = 0; i < MAX_LU_TSIH; i++) {
1882: xfree(lu->tsih[i].initiator_port);
1883: }
1884: for (i = 0; i < lu->maxmap; i++) {
1885: /* nothing */
1886: }
1887:
1888: xfree(lu);
1889: return -1;
1890: }
1891:
1892: static int
1893: istgt_lu_del_unit(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu)
1894: {
1895: int i, j;
1896:
1897: if (lu ==NULL)
1898: return 0;
1899: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "del unit %d\n", lu->num);
1900:
1901: MTX_LOCK(&istgt->mutex);
1902: istgt->nlogical_unit--;
1903: istgt->logical_unit[lu->num] = NULL;
1904: MTX_UNLOCK(&istgt->mutex);
1905:
1906: xfree(lu->name);
1907: xfree(lu->alias);
1908: xfree(lu->inq_vendor);
1909: xfree(lu->inq_product);
1910: xfree(lu->inq_revision);
1911: xfree(lu->inq_serial);
1912: for (i = 0; i < MAX_LU_LUN; i++) {
1913: xfree(lu->lun[i].serial);
1914: switch (lu->lun[i].type) {
1915: case ISTGT_LU_LUN_TYPE_DEVICE:
1916: xfree(lu->lun[i].u.device.file);
1917: break;
1918: case ISTGT_LU_LUN_TYPE_STORAGE:
1919: xfree(lu->lun[i].u.storage.file);
1920: break;
1921: case ISTGT_LU_LUN_TYPE_REMOVABLE:
1922: xfree(lu->lun[i].u.removable.file);
1923: break;
1924: case ISTGT_LU_LUN_TYPE_SLOT:
1925: for (j = 0; j < lu->lun[i].u.slot.maxslot; j++) {
1926: xfree(lu->lun[i].u.slot.file[j]);
1927: }
1928: break;
1929: case ISTGT_LU_LUN_TYPE_NONE:
1930: default:
1931: break;
1932: }
1933: }
1934: for (i = 0; i < MAX_LU_TSIH; i++) {
1935: xfree(lu->tsih[i].initiator_port);
1936: }
1937: for (i = 0; i < lu->maxmap; i++) {
1938: /* nothing */
1939: }
1940:
1941: return 0;
1942: }
1943:
1944: static void *luworker(void *arg);
1945:
1946: int
1947: istgt_lu_init(ISTGT_Ptr istgt)
1948: {
1949: ISTGT_LU_Ptr lu;
1950: CF_SECTION *sp;
1951: int rc;
1952: int i;
1953:
1954: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_init\n");
1955: sp = istgt_find_cf_section(istgt->config, "Global");
1956: if (sp == NULL) {
1957: ISTGT_ERRLOG("find_cf_section failed()\n");
1958: return -1;
1959: }
1960:
1961: sp = istgt->config->section;
1962: while (sp != NULL) {
1963: if (sp->type == ST_LOGICAL_UNIT) {
1964: if (sp->num == 0) {
1965: ISTGT_ERRLOG("Unit 0 is invalid\n");
1966: return -1;
1967: }
1968: if (sp->num > ISTGT_LU_TAG_MAX) {
1969: ISTGT_ERRLOG("tag %d is invalid\n", sp->num);
1970: return -1;
1971: }
1972: rc = istgt_lu_add_unit(istgt, sp);
1973: if (rc < 0) {
1974: ISTGT_ERRLOG("lu_add_unit() failed\n");
1975: return -1;
1976: }
1977: }
1978: sp = sp->next;
1979: }
1980:
1981: for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
1982: lu = istgt->logical_unit[i];
1983: if (lu == NULL)
1984: continue;
1985:
1986: rc = pthread_mutex_init(&lu->mutex, NULL);
1987: if (rc != 0) {
1988: ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
1989: return -1;
1990: }
1991: rc = pthread_mutex_init(&lu->state_mutex, NULL);
1992: if (rc != 0) {
1993: ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
1994: return -1;
1995: }
1996: rc = pthread_mutex_init(&lu->queue_mutex, NULL);
1997: if (rc != 0) {
1998: ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
1999: return -1;
2000: }
2001: rc = pthread_cond_init(&lu->queue_cond, NULL);
2002: if (rc != 0) {
2003: ISTGT_ERRLOG("LU%d: cond_init() failed\n", lu->num);
2004: return -1;
2005: }
2006:
2007: switch (lu->type) {
2008: case ISTGT_LU_TYPE_PASS:
2009: rc = istgt_lu_pass_init(istgt, lu);
2010: if (rc < 0) {
2011: ISTGT_ERRLOG("LU%d: lu_pass_init() failed\n", lu->num);
2012: return -1;
2013: }
2014: break;
2015:
2016: case ISTGT_LU_TYPE_DISK:
2017: rc = istgt_lu_disk_init(istgt, lu);
2018: if (rc < 0) {
2019: ISTGT_ERRLOG("LU%d: lu_disk_init() failed\n", lu->num);
2020: return -1;
2021: }
2022: break;
2023:
2024: case ISTGT_LU_TYPE_DVD:
2025: rc = istgt_lu_dvd_init(istgt, lu);
2026: if (rc < 0) {
2027: ISTGT_ERRLOG("LU%d: lu_dvd_init() failed\n", lu->num);
2028: return -1;
2029: }
2030: break;
2031:
2032: case ISTGT_LU_TYPE_TAPE:
2033: rc = istgt_lu_tape_init(istgt, lu);
2034: if (rc < 0) {
2035: ISTGT_ERRLOG("LU%d: lu_tape_init() failed\n", lu->num);
2036: return -1;
2037: }
2038: break;
2039:
2040: case ISTGT_LU_TYPE_NONE:
2041: //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num);
2042: break;
2043: default:
2044: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
2045: return -1;
2046: }
2047:
2048: istgt_lu_set_state(lu, ISTGT_STATE_INITIALIZED);
2049: }
2050:
2051: return 0;
2052: }
2053:
2054: int
2055: istgt_lu_set_all_state(ISTGT_Ptr istgt, ISTGT_STATE state)
2056: {
2057: ISTGT_LU_Ptr lu;
2058: int i;
2059:
2060: for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
2061: lu = istgt->logical_unit[i];
2062: if (lu == NULL)
2063: continue;
2064:
2065: istgt_lu_set_state(lu, state);
2066: }
2067:
2068: return 0;
2069: }
2070:
2071: int
2072: istgt_lu_create_threads(ISTGT_Ptr istgt)
2073: {
2074: #ifdef HAVE_PTHREAD_SET_NAME_NP
2075: char buf[MAX_TMPBUF];
2076: #endif
2077: ISTGT_LU_Ptr lu;
2078: int rc;
2079: int i;
2080:
2081: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_create_threads\n");
2082:
2083: for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
2084: lu = istgt->logical_unit[i];
2085: if (lu == NULL)
2086: continue;
2087:
2088: if (lu->queue_depth != 0) {
2089: /* create LU thread */
2090: #ifdef ISTGT_STACKSIZE
2091: rc = pthread_create(&lu->thread, &istgt->attr, &luworker, (void *)lu);
2092: #else
2093: rc = pthread_create(&lu->thread, NULL, &luworker, (void *)lu);
2094: #endif
2095: if (rc != 0) {
2096: ISTGT_ERRLOG("pthread_create() failed\n");
2097: return -1;
2098: }
2099: #if 0
2100: rc = pthread_detach(lu->thread);
2101: if (rc != 0) {
2102: ISTGT_ERRLOG("pthread_detach() failed\n");
2103: return -1;
2104: }
2105: #endif
2106: #ifdef HAVE_PTHREAD_SET_NAME_NP
2107: snprintf(buf, sizeof buf, "luthread #%d", i);
2108: pthread_set_name_np(lu->thread, buf);
2109: #endif
2110: }
2111: }
2112:
2113: return 0;
2114: }
2115:
2116: int
2117: istgt_lu_shutdown(ISTGT_Ptr istgt)
2118: {
2119: ISTGT_LU_Ptr lu;
2120: int rc;
2121: int i;
2122:
2123: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_shutdown\n");
2124:
2125: for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
2126: lu = istgt->logical_unit[i];
2127: if (lu == NULL)
2128: continue;
2129: istgt_lu_set_state(lu, ISTGT_STATE_SHUTDOWN);
2130:
2131: switch (lu->type) {
2132: case ISTGT_LU_TYPE_PASS:
2133: rc = istgt_lu_pass_shutdown(istgt, lu);
2134: if (rc < 0) {
2135: ISTGT_ERRLOG("LU%d: lu_pass_shutdown() failed\n", lu->num);
2136: /* ignore error */
2137: }
2138: break;
2139:
2140: case ISTGT_LU_TYPE_DISK:
2141: rc = istgt_lu_disk_shutdown(istgt, lu);
2142: if (rc < 0) {
2143: ISTGT_ERRLOG("LU%d: lu_disk_shutdown() failed\n", lu->num);
2144: /* ignore error */
2145: }
2146: break;
2147:
2148: case ISTGT_LU_TYPE_DVD:
2149: rc = istgt_lu_dvd_shutdown(istgt, lu);
2150: if (rc < 0) {
2151: ISTGT_ERRLOG("LU%d: lu_dvd_shutdown() failed\n", lu->num);
2152: /* ignore error */
2153: }
2154: break;
2155:
2156: case ISTGT_LU_TYPE_TAPE:
2157: rc = istgt_lu_tape_shutdown(istgt, lu);
2158: if (rc < 0) {
2159: ISTGT_ERRLOG("LU%d: lu_tape_shutdown() failed\n", lu->num);
2160: /* ignore error */
2161: }
2162: break;
2163:
2164: case ISTGT_LU_TYPE_NONE:
2165: //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num);
2166: break;
2167: default:
2168: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
2169: return -1;
2170: }
2171:
2172: rc = istgt_lu_del_unit(istgt, lu);
2173: if (rc < 0) {
2174: ISTGT_ERRLOG("LU%d: lu_del_unit() failed\n", lu->num);
2175: /* ignore error */
2176: }
2177:
2178: if (lu->queue_depth != 0) {
2179: rc = pthread_cond_broadcast(&lu->queue_cond);
2180: if (rc != 0) {
2181: ISTGT_ERRLOG("LU%d: cond_broadcast() failed\n", lu->num);
2182: }
2183: rc = pthread_join(lu->thread, NULL);
2184: if (rc != 0) {
2185: ISTGT_ERRLOG("LU%d: pthread_join() failed\n", lu->num);
2186: }
2187: }
2188: rc = pthread_cond_destroy(&lu->queue_cond);
2189: if (rc != 0) {
2190: ISTGT_ERRLOG("LU%d: cond_destroy() failed\n", lu->num);
2191: /* ignore error */
2192: }
2193: rc = pthread_mutex_destroy(&lu->queue_mutex);
2194: if (rc != 0) {
2195: ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
2196: /* ignore error */
2197: }
2198: rc = pthread_mutex_destroy(&lu->state_mutex);
2199: if (rc != 0) {
2200: ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
2201: /* ignore error */
2202: }
2203: rc = pthread_mutex_destroy(&lu->mutex);
2204: if (rc != 0) {
2205: ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
2206: /* ignore error */
2207: }
2208: xfree(lu);
2209: istgt->logical_unit[i] = NULL;
2210: }
2211:
2212: return 0;
2213: }
2214:
2215: int
2216: istgt_lu_islun2lun(uint64_t islun)
2217: {
2218: uint64_t fmt_lun;
2219: uint64_t method;
2220: int lun_i;
2221:
2222: fmt_lun = islun;
2223: method = (fmt_lun >> 62) & 0x03U;
2224: fmt_lun = fmt_lun >> 48;
2225: if (method == 0x00U) {
2226: lun_i = (int) (fmt_lun & 0x00ffU);
2227: } else if (method == 0x01U) {
2228: lun_i = (int) (fmt_lun & 0x3fffU);
2229: } else {
2230: lun_i = 0xffffU;
2231: }
2232: return lun_i;
2233: }
2234:
2235: uint64_t
2236: istgt_lu_lun2islun(int lun, int maxlun)
2237: {
2238: uint64_t fmt_lun;
2239: uint64_t method;
2240: uint64_t islun;
2241:
2242: islun = (uint64_t) lun;
2243: if (maxlun <= 0x0100) {
2244: /* below 256 */
2245: method = 0x00U;
2246: fmt_lun = (method & 0x03U) << 62;
2247: fmt_lun |= (islun & 0x00ffU) << 48;
2248: } else if (maxlun <= 0x4000U) {
2249: /* below 16384 */
2250: method = 0x01U;
2251: fmt_lun = (method & 0x03U) << 62;
2252: fmt_lun |= (islun & 0x3fffU) << 48;
2253: } else {
2254: /* XXX */
2255: fmt_lun = ~((uint64_t) 0);
2256: }
2257: return fmt_lun;
2258: }
2259:
2260: int
2261: istgt_lu_reset(ISTGT_LU_Ptr lu, uint64_t lun)
2262: {
2263: int lun_i;
2264: int rc;
2265:
2266: if (lu == NULL)
2267: return -1;
2268:
2269: lun_i = istgt_lu_islun2lun(lun);
2270:
2271: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: Name=%s, LUN=%d\n",
2272: lu->num, lu->name, lun_i);
2273:
2274: switch (lu->type) {
2275: case ISTGT_LU_TYPE_PASS:
2276: MTX_LOCK(&lu->mutex);
2277: rc = istgt_lu_pass_reset(lu, lun_i);
2278: MTX_UNLOCK(&lu->mutex);
2279: if (rc < 0) {
2280: ISTGT_ERRLOG("LU%d: lu_pass_reset() failed\n", lu->num);
2281: return -1;
2282: }
2283: break;
2284:
2285: case ISTGT_LU_TYPE_DISK:
2286: MTX_LOCK(&lu->mutex);
2287: rc = istgt_lu_disk_reset(lu, lun_i);
2288: MTX_UNLOCK(&lu->mutex);
2289: if (rc < 0) {
2290: ISTGT_ERRLOG("LU%d: lu_disk_reset() failed\n", lu->num);
2291: return -1;
2292: }
2293: break;
2294:
2295: case ISTGT_LU_TYPE_DVD:
2296: MTX_LOCK(&lu->mutex);
2297: rc = istgt_lu_dvd_reset(lu, lun_i);
2298: MTX_UNLOCK(&lu->mutex);
2299: if (rc < 0) {
2300: ISTGT_ERRLOG("LU%d: lu_dvd_reset() failed\n", lu->num);
2301: return -1;
2302: }
2303: break;
2304:
2305: case ISTGT_LU_TYPE_TAPE:
2306: MTX_LOCK(&lu->mutex);
2307: rc = istgt_lu_tape_reset(lu, lun_i);
2308: MTX_UNLOCK(&lu->mutex);
2309: if (rc < 0) {
2310: ISTGT_ERRLOG("LU%d: lu_tape_reset() failed\n", lu->num);
2311: return -1;
2312: }
2313: break;
2314:
2315: case ISTGT_LU_TYPE_NONE:
2316: //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num);
2317: break;
2318: default:
2319: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
2320: return -1;
2321: }
2322:
2323: return 0;
2324: }
2325:
2326: int
2327: istgt_lu_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
2328: {
2329: ISTGT_LU_Ptr lu;
2330: int rc;
2331:
2332: if (lu_cmd == NULL)
2333: return -1;
2334: lu = lu_cmd->lu;
2335: if (lu == NULL)
2336: return -1;
2337:
2338: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2339: "LU%d: PG=0x%4.4x, Name=%s, LUN=0x%16.16"PRIx64"\n",
2340: lu->num, conn->portal.tag, lu->name, lu_cmd->lun);
2341:
2342: if (lu->online == 0) {
2343: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LU%d: offline\n", lu->num);
2344: /* LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE */
2345: lu_cmd->sense_data_len
2346: = istgt_lu_scsi_build_sense_data(lu_cmd->sense_data,
2347: ISTGT_SCSI_SENSE_NOT_READY,
2348: 0x04, 0x00);
2349: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
2350: return 0;
2351: }
2352:
2353: rc = 0;
2354: switch (lu->type) {
2355: case ISTGT_LU_TYPE_PASS:
2356: MTX_LOCK(&lu->mutex);
2357: rc = istgt_lu_pass_execute(conn, lu_cmd);
2358: MTX_UNLOCK(&lu->mutex);
2359: if (rc < 0) {
2360: ISTGT_ERRLOG("LU%d: lu_pass_execute() failed\n",
2361: lu->num);
2362: return -1;
2363: }
2364: break;
2365:
2366: case ISTGT_LU_TYPE_DISK:
2367: if (lu->queue_depth != 0) {
2368: //MTX_LOCK(&lu->queue_mutex);
2369: rc = istgt_lu_disk_queue(conn, lu_cmd);
2370: //MTX_UNLOCK(&lu->queue_mutex);
2371: if (rc < 0) {
2372: ISTGT_ERRLOG("LU%d: lu_disk_queue() failed\n",
2373: lu->num);
2374: return -1;
2375: }
2376: } else {
2377: MTX_LOCK(&lu->mutex);
2378: rc = istgt_lu_disk_execute(conn, lu_cmd);
2379: MTX_UNLOCK(&lu->mutex);
2380: if (rc < 0) {
2381: ISTGT_ERRLOG("LU%d: lu_disk_execute() failed\n",
2382: lu->num);
2383: return -1;
2384: }
2385: }
2386: break;
2387:
2388: case ISTGT_LU_TYPE_DVD:
2389: MTX_LOCK(&lu->mutex);
2390: rc = istgt_lu_dvd_execute(conn, lu_cmd);
2391: MTX_UNLOCK(&lu->mutex);
2392: if (rc < 0) {
2393: ISTGT_ERRLOG("LU%d: lu_dvd_execute() failed\n",
2394: lu->num);
2395: return -1;
2396: }
2397: break;
2398:
2399: case ISTGT_LU_TYPE_TAPE:
2400: MTX_LOCK(&lu->mutex);
2401: rc = istgt_lu_tape_execute(conn, lu_cmd);
2402: MTX_UNLOCK(&lu->mutex);
2403: if (rc < 0) {
2404: ISTGT_ERRLOG("LU%d: lu_tape_execute() failed\n",
2405: lu->num);
2406: return -1;
2407: }
2408: break;
2409:
2410: case ISTGT_LU_TYPE_NONE:
2411: //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num);
2412: break;
2413: default:
2414: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
2415: return -1;
2416: }
2417:
2418: return rc;
2419: }
2420:
2421: int
2422: istgt_lu_create_task(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, ISTGT_LU_TASK_Ptr lu_task, int lun)
2423: {
2424: ISCSI_PDU_Ptr dst_pdu, src_pdu;
2425: uint8_t *cdb;
2426: int alloc_len;
2427: #if 0
2428: int rc;
2429: #endif
2430:
2431: if (lu_task == NULL)
2432: return -1;
2433:
2434: lu_task->type = ISTGT_LU_TASK_RESPONSE;
2435: lu_task->conn = conn;
2436: strncpy(lu_task->initiator_name, conn->initiator_name,
2437: sizeof lu_task->initiator_name);
2438: strncpy(lu_task->initiator_port, conn->initiator_port,
2439: sizeof lu_task->initiator_port);
2440:
2441: lu_task->lun = (int) lun;
2442: lu_task->use_cond = 0;
2443: lu_task->dup_iobuf = 0;
2444: lu_task->iobuf = NULL;
2445: lu_task->data = NULL;
2446: lu_task->sense_data = NULL;
2447: lu_task->create_time = 0;
2448: lu_task->condwait = 0;
2449: lu_task->offset = 0;
2450: lu_task->req_execute = 0;
2451: lu_task->req_transfer_out = 0;
2452: lu_task->error = 0;
2453: lu_task->abort = 0;
2454: lu_task->execute = 0;
2455: lu_task->complete = 0;
2456: lu_task->lock = 0;
2457:
2458: #if 0
2459: rc = pthread_mutex_init(&lu_task->trans_mutex, NULL);
2460: if (rc != 0) {
2461: ISTGT_ERRLOG("mutex_init() failed\n");
2462: return -1;
2463: }
2464: rc = pthread_cond_init(&lu_task->trans_cond, NULL);
2465: if (rc != 0) {
2466: ISTGT_ERRLOG("cond_init() failed\n");
2467: return -1;
2468: }
2469: rc = pthread_cond_init(&lu_task->exec_cond, NULL);
2470: if (rc != 0) {
2471: ISTGT_ERRLOG("cond_init() failed\n");
2472: return -1;
2473: }
2474: #endif
2475:
2476: lu_task->lu_cmd.pdu = xmalloc(sizeof *lu_task->lu_cmd.pdu);
2477: memset(lu_task->lu_cmd.pdu, 0, sizeof *lu_task->lu_cmd.pdu);
2478:
2479: /* copy PDU */
2480: dst_pdu = lu_task->lu_cmd.pdu;
2481: src_pdu = lu_cmd->pdu;
2482: memcpy(&dst_pdu->bhs, &src_pdu->bhs, ISCSI_BHS_LEN);
2483: dst_pdu->ahs = src_pdu->ahs;
2484: memcpy(dst_pdu->header_digest, src_pdu->header_digest, ISCSI_DIGEST_LEN);
2485: if (src_pdu->data == src_pdu->shortdata) {
2486: memcpy(dst_pdu->shortdata, src_pdu->shortdata,
2487: sizeof src_pdu->shortdata);
2488: dst_pdu->data = dst_pdu->shortdata;
2489: } else {
2490: dst_pdu->data = src_pdu->data;
2491: }
2492: memcpy(dst_pdu->data_digest, src_pdu->data_digest, ISCSI_DIGEST_LEN);
2493: dst_pdu->total_ahs_len = src_pdu->total_ahs_len;
2494: dst_pdu->data_segment_len = src_pdu->data_segment_len;
2495: dst_pdu->copy_pdu = 0;
2496: src_pdu->copy_pdu = 1;
2497:
2498: /* copy other lu_cmd */
2499: lu_task->lu_cmd.lu = lu_cmd->lu;
2500: cdb = ((uint8_t *) &lu_task->lu_cmd.pdu->bhs) + 32;
2501: lu_task->lu_cmd.I_bit = lu_cmd->I_bit;
2502: lu_task->lu_cmd.F_bit = lu_cmd->F_bit;
2503: lu_task->lu_cmd.R_bit = lu_cmd->R_bit;
2504: lu_task->lu_cmd.W_bit = lu_cmd->W_bit;
2505: lu_task->lu_cmd.Attr_bit = lu_cmd->Attr_bit;
2506: lu_task->lu_cmd.lun = lu_cmd->lun;
2507: lu_task->lu_cmd.task_tag = lu_cmd->task_tag;
2508: lu_task->lu_cmd.transfer_len = lu_cmd->transfer_len;
2509: //lu_task->lu_cmd.cdb = lu_cmd->cdb;
2510: lu_task->lu_cmd.cdb = cdb;
2511: lu_task->lu_cmd.CmdSN = lu_cmd->CmdSN;
2512:
2513: //lu_task->lu_cmd.iobuf = lu_cmd->iobuf;
2514: lu_task->lu_cmd.iobuf = NULL;
2515: lu_task->lu_cmd.iobufsize = lu_cmd->iobufsize;
2516: lu_task->lu_cmd.data = lu_cmd->data;
2517: lu_task->lu_cmd.data_len = lu_cmd->data_len;
2518: lu_task->lu_cmd.alloc_len = lu_cmd->alloc_len;
2519:
2520: lu_task->lu_cmd.status = lu_cmd->status;
2521: lu_task->lu_cmd.sense_data = lu_cmd->sense_data;
2522: lu_task->lu_cmd.sense_data_len = lu_cmd->sense_data_len;
2523: lu_task->lu_cmd.sense_alloc_len = lu_cmd->sense_alloc_len;
2524:
2525: /* pre allocate buffer */
2526: lu_task->lu_cmd.iobufsize = lu_cmd->transfer_len + 65536;
2527: #if 0
2528: lu_task->data = xmalloc(lu_cmd->alloc_len);
2529: lu_task->sense_data = xmalloc(lu_cmd->sense_alloc_len);
2530: lu_task->iobuf = xmalloc(lu_task->lu_cmd.iobufsize);
2531: #else
2532: alloc_len = ISCSI_ALIGN(lu_cmd->alloc_len);
2533: alloc_len += ISCSI_ALIGN(lu_cmd->sense_alloc_len);
2534: alloc_len += ISCSI_ALIGN(lu_task->lu_cmd.iobufsize);
2535: lu_task->data = xmalloc(alloc_len);
2536: lu_task->sense_data = lu_task->data + ISCSI_ALIGN(lu_cmd->alloc_len);
2537: lu_task->iobuf = lu_task->sense_data + ISCSI_ALIGN(lu_cmd->sense_alloc_len);
2538: #endif
2539:
2540: /* creation time */
2541: lu_task->create_time = time(NULL);
2542: /* wait time */
2543: lu_task->condwait = conn->timeout * 1000;
2544: if (lu_task->condwait < ISTGT_CONDWAIT_MIN) {
2545: lu_task->condwait = ISTGT_CONDWAIT_MIN;
2546: }
2547:
2548: return 0;
2549: }
2550:
2551: int
2552: istgt_lu_destroy_task(ISTGT_LU_TASK_Ptr lu_task)
2553: {
2554: int rc;
2555:
2556: if (lu_task == NULL)
2557: return -1;
2558:
2559: if (lu_task->use_cond != 0) {
2560: rc = pthread_mutex_destroy(&lu_task->trans_mutex);
2561: if (rc != 0) {
2562: ISTGT_ERRLOG("mutex_destroy() failed\n");
2563: return -1;
2564: }
2565: rc = pthread_cond_destroy(&lu_task->trans_cond);
2566: if (rc != 0) {
2567: ISTGT_ERRLOG("cond_destroy() failed\n");
2568: return -1;
2569: }
2570: rc = pthread_cond_destroy(&lu_task->exec_cond);
2571: if (rc != 0) {
2572: ISTGT_ERRLOG("cond_destroy() failed\n");
2573: return -1;
2574: }
2575: }
2576: if (lu_task->lu_cmd.pdu != NULL) {
2577: if (lu_task->lu_cmd.pdu->copy_pdu == 0) {
2578: xfree(lu_task->lu_cmd.pdu->ahs);
2579: if (lu_task->lu_cmd.pdu->data
2580: != lu_task->lu_cmd.pdu->shortdata) {
2581: xfree(lu_task->lu_cmd.pdu->data);
2582: }
2583: }
2584: xfree(lu_task->lu_cmd.pdu);
2585: }
2586: #if 0
2587: if (lu_task->dup_iobuf == 0) {
2588: xfree(lu_task->iobuf);
2589: }
2590: xfree(lu_task->data);
2591: xfree(lu_task->sense_data);
2592: #else
2593: xfree(lu_task->data);
2594: #endif
2595: xfree(lu_task);
2596: return 0;
2597: }
2598:
2599: int
2600: istgt_lu_clear_task_IT(CONN_Ptr conn, ISTGT_LU_Ptr lu)
2601: {
2602: int rc;
2603:
2604: if (lu == NULL)
2605: return -1;
2606:
2607: if (lu->queue_depth == 0)
2608: return 0;
2609:
2610: rc = 0;
2611: switch (lu->type) {
2612: case ISTGT_LU_TYPE_DISK:
2613: MTX_LOCK(&lu->mutex);
2614: rc = istgt_lu_disk_queue_clear_IT(conn, lu);
2615: MTX_UNLOCK(&lu->mutex);
2616: if (rc < 0) {
2617: ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_IT() failed\n", lu->num);
2618: return -1;
2619: }
2620: break;
2621:
2622: case ISTGT_LU_TYPE_DVD:
2623: case ISTGT_LU_TYPE_TAPE:
2624: case ISTGT_LU_TYPE_NONE:
2625: default:
2626: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
2627: return -1;
2628: }
2629:
2630: return 0;
2631: }
2632:
2633: int
2634: istgt_lu_clear_task_ITL(CONN_Ptr conn, ISTGT_LU_Ptr lu, uint64_t lun)
2635: {
2636: int lun_i;
2637: int rc;
2638:
2639: if (lu == NULL)
2640: return -1;
2641:
2642: if (lu->queue_depth == 0)
2643: return 0;
2644:
2645: lun_i = istgt_lu_islun2lun(lun);
2646:
2647: rc = 0;
2648: switch (lu->type) {
2649: case ISTGT_LU_TYPE_DISK:
2650: MTX_LOCK(&lu->mutex);
2651: rc = istgt_lu_disk_queue_clear_ITL(conn, lu, lun_i);
2652: MTX_UNLOCK(&lu->mutex);
2653: if (rc < 0) {
2654: ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_ITL() failed\n", lu->num);
2655: return -1;
2656: }
2657: break;
2658:
2659: case ISTGT_LU_TYPE_DVD:
2660: case ISTGT_LU_TYPE_TAPE:
2661: case ISTGT_LU_TYPE_NONE:
2662: default:
2663: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
2664: return -1;
2665: }
2666:
2667: return 0;
2668: }
2669:
2670: int
2671: istgt_lu_clear_task_ITLQ(CONN_Ptr conn, ISTGT_LU_Ptr lu, uint64_t lun, uint32_t CmdSN)
2672: {
2673: int lun_i;
2674: int rc;
2675:
2676: if (lu == NULL)
2677: return -1;
2678:
2679: if (lu->queue_depth == 0)
2680: return 0;
2681:
2682: lun_i = istgt_lu_islun2lun(lun);
2683:
2684: rc = 0;
2685: switch (lu->type) {
2686: case ISTGT_LU_TYPE_DISK:
2687: MTX_LOCK(&lu->mutex);
2688: rc = istgt_lu_disk_queue_clear_ITLQ(conn, lu, lun_i, CmdSN);
2689: MTX_UNLOCK(&lu->mutex);
2690: if (rc < 0) {
2691: ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_ITLQ() failed\n", lu->num);
2692: return -1;
2693: }
2694: break;
2695:
2696: case ISTGT_LU_TYPE_DVD:
2697: case ISTGT_LU_TYPE_TAPE:
2698: case ISTGT_LU_TYPE_NONE:
2699: default:
2700: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
2701: return -1;
2702: }
2703:
2704: return 0;
2705: }
2706:
2707: int
2708: istgt_lu_clear_all_task(ISTGT_LU_Ptr lu, uint64_t lun)
2709: {
2710: int rc;
2711:
2712: if (lu == NULL)
2713: return -1;
2714:
2715: if (lu->queue_depth == 0)
2716: return 0;
2717:
2718: rc = 0;
2719: switch (lu->type) {
2720: case ISTGT_LU_TYPE_DISK:
2721: MTX_LOCK(&lu->mutex);
2722: rc = istgt_lu_disk_queue_clear_all(lu, lun);
2723: MTX_UNLOCK(&lu->mutex);
2724: if (rc < 0) {
2725: ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_all() failed\n", lu->num);
2726: return -1;
2727: }
2728: break;
2729:
2730: case ISTGT_LU_TYPE_DVD:
2731: case ISTGT_LU_TYPE_TAPE:
2732: case ISTGT_LU_TYPE_NONE:
2733: default:
2734: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
2735: return -1;
2736: }
2737:
2738: return 0;
2739: }
2740:
2741: static void *
2742: luworker(void *arg)
2743: {
2744: ISTGT_LU_Ptr lu = (ISTGT_LU_Ptr) arg;
2745: sigset_t signew, sigold;
2746: #if 0
2747: struct timespec abstime;
2748: time_t now;
2749: int timeout = 20; /* XXX */
2750: #endif
2751: int qcnt;
2752: int lun;
2753: int rc;
2754:
2755: sigemptyset(&signew);
2756: sigemptyset(&sigold);
2757: sigaddset(&signew, ISTGT_SIGWAKEUP);
2758: pthread_sigmask(SIG_UNBLOCK, &signew, &sigold);
2759:
2760: while (istgt_get_state(lu->istgt) != ISTGT_STATE_RUNNING) {
2761: if (istgt_get_state(lu->istgt) == ISTGT_STATE_EXITING
2762: || istgt_get_state(lu->istgt) == ISTGT_STATE_SHUTDOWN) {
2763: ISTGT_ERRLOG("exit before running\n");
2764: return NULL;
2765: }
2766: //ISTGT_WARNLOG("Wait for running\n");
2767: sleep(1);
2768: continue;
2769: }
2770:
2771: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d loop start\n", lu->num);
2772: lun = 0;
2773: qcnt = 0;
2774: #if 0
2775: memset(&abstime, 0, sizeof abstime);
2776: #endif
2777: while (1) {
2778: switch (lu->type) {
2779: case ISTGT_LU_TYPE_DISK:
2780: while (1) {
2781: if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) {
2782: goto loop_exit;
2783: }
2784: MTX_LOCK(&lu->queue_mutex);
2785: qcnt = istgt_lu_disk_queue_count(lu, &lun);
2786: if (qcnt == 0) {
2787: #if 0
2788: now = time(NULL);
2789: abstime.tv_sec = now + timeout;
2790: abstime.tv_nsec = 0;
2791: rc = pthread_cond_timedwait(&lu->queue_cond,
2792: &lu->queue_mutex, &abstime);
2793: if (rc == ETIMEDOUT) {
2794: /* nothing */
2795: }
2796: #else
2797: pthread_cond_wait(&lu->queue_cond,
2798: &lu->queue_mutex);
2799: #endif
2800: qcnt = istgt_lu_disk_queue_count(lu, &lun);
2801: if (qcnt == 0) {
2802: MTX_UNLOCK(&lu->queue_mutex);
2803: continue;
2804: }
2805: }
2806: MTX_UNLOCK(&lu->queue_mutex);
2807: break;
2808: }
2809: if (qcnt < 0) {
2810: ISTGT_ERRLOG("LU%d: lu_disk_queue_count() failed\n",
2811: lu->num);
2812: break;
2813: }
2814: rc = istgt_lu_disk_queue_start(lu, lun);
2815: lun++;
2816: if (rc == -2) {
2817: ISTGT_WARNLOG("LU%d: lu_disk_queue_start() aborted\n",
2818: lu->num);
2819: break;
2820: }
2821: if (rc < 0) {
2822: ISTGT_ERRLOG("LU%d: lu_disk_queue_start() failed\n",
2823: lu->num);
2824: break;
2825: }
2826: break;
2827:
2828: case ISTGT_LU_TYPE_DVD:
2829: case ISTGT_LU_TYPE_TAPE:
2830: case ISTGT_LU_TYPE_NONE:
2831: default:
2832: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
2833: return NULL;
2834: }
2835:
2836: #if 0
2837: /* still running? */
2838: if (qcnt <= 1) {
2839: if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) {
2840: goto loop_exit;
2841: }
2842: }
2843: #endif
2844: }
2845: loop_exit:
2846: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d loop ended\n", lu->num);
2847:
2848: return NULL;
2849: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>