1 /*- 2 * Copyright (c) 2007,2009 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Alistair Crooks (agc@netbsd.org) 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 #include <sys/types.h> 30 31 #define FUSE_USE_VERSION 26 32 33 #include <err.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <fuse.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include "scsi_cmd_codes.h" 43 #include "iscsi.h" 44 #include "initiator.h" 45 #include "tests.h" 46 47 #include "virtdir.h" 48 49 #if defined(__NetBSD__) && defined(USE_LIBKMOD) 50 #include "libkmod.h" 51 #endif 52 53 #include "defs.h" 54 55 static int verbose; /* how chatty are we? */ 56 57 static virtdir_t iscsi; 58 59 enum { 60 VendorLen = 8, 61 ProductLen = 16, 62 VersionLen = 4, 63 64 SGsize = 131072 65 }; 66 67 68 /* this struct keeps information on the target */ 69 typedef struct targetinfo_t { 70 char *host; /* resolvable host name */ 71 char *ip; /* textual IP address */ 72 char *targetname; /* name of iSCSI target prog */ 73 char *stargetname; /* short name of the target */ 74 uint64_t target; /* target number */ 75 uint32_t lun; /* LUN number */ 76 uint32_t lbac; /* number of LBAs */ 77 uint32_t blocksize; /* size of device blocks */ 78 uint32_t devicetype; /* SCSI device type */ 79 char vendor[VendorLen + 1]; 80 /* device vendor information */ 81 char product[ProductLen + 1]; 82 /* device product information */ 83 char version[VersionLen + 1]; 84 /* device version information */ 85 char *serial; /* unit serial number */ 86 } targetinfo_t; 87 88 DEFINE_ARRAY(targetv_t, targetinfo_t); 89 90 static targetv_t tv; /* target vector of targetinfo_t structs */ 91 92 /* iqns and target addresses are returned as pairs in this dynamic array */ 93 static strv_t all_targets; 94 95 /* Small Target Info... */ 96 typedef struct sti_t { 97 struct stat st; /* normal stat info */ 98 uint64_t target; /* cached target number, so we don't have an expensive pathname-based lookup */ 99 } sti_t; 100 101 #ifndef __UNCONST 102 #define __UNCONST(x) (x) 103 #endif 104 105 static void 106 lba2cdb(uint8_t *cdb, uint32_t *lba, uint16_t *len) 107 { 108 /* Some platforms (like strongarm) aligns on */ 109 /* word boundaries. So HTONL and NTOHL won't */ 110 /* work here. */ 111 int little_endian = 1; 112 113 if (*(char *) (void *) &little_endian) { 114 /* little endian */ 115 cdb[2] = ((uint8_t *) (void *)lba)[3]; 116 cdb[3] = ((uint8_t *) (void *)lba)[2]; 117 cdb[4] = ((uint8_t *) (void *)lba)[1]; 118 cdb[5] = ((uint8_t *) (void *)lba)[0]; 119 cdb[7] = ((uint8_t *) (void *)len)[1]; 120 cdb[8] = ((uint8_t *) (void *)len)[0]; 121 } else { 122 /* big endian */ 123 cdb[2] = ((uint8_t *) (void *)lba)[2]; 124 cdb[3] = ((uint8_t *) (void *)lba)[3]; 125 cdb[4] = ((uint8_t *) (void *)lba)[0]; 126 cdb[5] = ((uint8_t *) (void *)lba)[1]; 127 cdb[7] = ((uint8_t *) (void *)len)[0]; 128 cdb[8] = ((uint8_t *) (void *)len)[1]; 129 } 130 } 131 132 /* read the capacity (maximum LBA and blocksize) from the target */ 133 int 134 read_capacity(uint64_t target, uint32_t lun, uint32_t *maxlba, uint32_t *blocklen) 135 { 136 iscsi_scsi_cmd_args_t args; 137 initiator_cmd_t cmd; 138 uint8_t data[8]; 139 uint8_t cdb[16]; 140 141 (void) memset(cdb, 0x0, sizeof(cdb)); 142 cdb[0] = READ_CAPACITY; 143 cdb[1] = lun << 5; 144 145 (void) memset(&args, 0x0, sizeof(args)); 146 args.recv_data = data; 147 args.input = 1; 148 args.lun = lun; 149 args.trans_len = 8; 150 args.cdb = cdb; 151 152 (void) memset(&cmd, 0, sizeof(initiator_cmd_t)); 153 154 cmd.isid = target; 155 cmd.type = ISCSI_SCSI_CMD; 156 cmd.ptr = &args; 157 158 if (initiator_command(&cmd) != 0) { 159 iscsi_err(__FILE__, __LINE__, "initiator_command() failed\n"); 160 return -1; 161 } 162 if (args.status) { 163 iscsi_err(__FILE__, __LINE__, "READ_CAPACITY failed (status %#x)\n", args.status); 164 return -1; 165 } 166 memcpy(maxlba, data, sizeof(*maxlba)); 167 *maxlba = ISCSI_NTOHL(*maxlba); 168 if (*maxlba == 0) { 169 iscsi_err(__FILE__, __LINE__, "Device returned Maximum LBA of zero\n"); 170 return -1; 171 } 172 memcpy(blocklen, data + 4, sizeof(*blocklen)); 173 *blocklen = ISCSI_NTOHL(*blocklen); 174 if (*blocklen % 2) { 175 iscsi_err(__FILE__, __LINE__, "Device returned strange block len: %u\n", *blocklen); 176 return -1; 177 } 178 return 0; 179 } 180 181 /* send inquiry command to the target, to get it to identify itself */ 182 static int 183 inquiry(uint64_t target, uint32_t lun, uint8_t type, uint8_t inquire, uint8_t *data) 184 { 185 iscsi_scsi_cmd_args_t args; 186 initiator_cmd_t cmd; 187 uint8_t cdb[16]; 188 189 (void) memset(cdb, 0x0, sizeof(cdb)); 190 cdb[0] = INQUIRY; 191 cdb[1] = type | (lun << 5); 192 cdb[2] = inquire; 193 cdb[4] = 256 - 1; 194 195 (void) memset(&args, 0x0, sizeof(args)); 196 args.input = 1; 197 args.trans_len = 256; 198 args.cdb = cdb; 199 args.lun = lun; 200 args.recv_data = data; 201 (void) memset(&cmd, 0x0, sizeof(cmd)); 202 cmd.isid = target; 203 cmd.type = ISCSI_SCSI_CMD; 204 cmd.ptr = &args; 205 206 if (initiator_command(&cmd) != 0) { 207 iscsi_err(__FILE__, __LINE__, "initiator_command() failed\n"); 208 return -1; 209 } 210 if (args.status) { 211 iscsi_err(__FILE__, __LINE__, "INQUIRY failed (status %#x)\n", args.status); 212 return -1; 213 } 214 215 return 0; 216 } 217 218 /* read or write a single block of information */ 219 static int 220 blockop(uint64_t target, uint32_t lun, uint32_t lba, uint32_t len, 221 uint32_t blocklen, uint8_t *data, int writing) 222 { 223 iscsi_scsi_cmd_args_t args; 224 initiator_cmd_t cmd; 225 uint16_t readlen; 226 uint8_t cdb[16]; 227 228 /* Build CDB */ 229 (void) memset(cdb, 0, 16); 230 cdb[0] = (writing) ? WRITE_10 : READ_10; 231 cdb[1] = lun << 5; 232 readlen = (uint16_t) len; 233 lba2cdb(cdb, &lba, &readlen); 234 235 /* Build SCSI command */ 236 (void) memset(&args, 0x0, sizeof(args)); 237 if (writing) { 238 args.send_data = data; 239 args.output = 1; 240 } else { 241 args.recv_data = data; 242 args.input = 1; 243 } 244 args.lun = lun; 245 args.trans_len = len*blocklen; 246 args.length = len*blocklen; 247 args.cdb = cdb; 248 (void) memset(&cmd, 0, sizeof(initiator_cmd_t)); 249 cmd.isid = target; 250 cmd.type = ISCSI_SCSI_CMD; 251 cmd.ptr = &args; 252 /* Execute iSCSI command */ 253 if (initiator_command(&cmd) != 0) { 254 iscsi_err(__FILE__, __LINE__, "initiator_command() failed\n"); 255 return -1; 256 } 257 258 if (args.status) { 259 iscsi_err(__FILE__, __LINE__, "scsi_command() failed (status %#x)\n", args.status); 260 return -1; 261 } 262 return 0; 263 } 264 265 /* perform a scatter/gather block operation */ 266 static int 267 sgblockop(uint64_t target, uint32_t lun, uint32_t lba, uint32_t len, 268 uint32_t blocklen, uint8_t *data, int sglen, int writing) 269 { 270 iscsi_scsi_cmd_args_t args; 271 initiator_cmd_t cmd; 272 uint16_t readlen; 273 uint8_t cdb[16]; 274 275 /* Build CDB */ 276 277 (void) memset(cdb, 0, 16); 278 cdb[0] = (writing) ? WRITE_10 : READ_10; 279 cdb[1] = lun << 5; 280 readlen = (uint16_t) len; 281 lba2cdb(cdb, &lba, &readlen); 282 283 /* Build iSCSI command */ 284 (void) memset(&args, 0x0, sizeof(args)); 285 args.lun = lun; 286 args.output = (writing) ? 1 : 0; 287 args.input = (writing) ? 0 : 1; 288 args.trans_len = len * blocklen; 289 args.length = len * blocklen; 290 args.send_data = (writing) ? data : NULL; 291 args.send_sg_len = (writing) ? sglen : 0; 292 args.recv_data = (writing) ? NULL : data; 293 args.recv_sg_len = (writing) ? 0 : sglen; 294 args.cdb = cdb; 295 memset(&cmd, 0, sizeof(initiator_cmd_t)); 296 cmd.isid = target; 297 cmd.ptr = &args; 298 cmd.type = ISCSI_SCSI_CMD; 299 300 /* Execute iSCSI command */ 301 302 if (initiator_command(&cmd) != 0) { 303 iscsi_err(__FILE__, __LINE__, "initiator_command() failed\n"); 304 return -1; 305 } 306 if (args.status) { 307 iscsi_err(__FILE__, __LINE__, "scsi_command() failed (status %#x)\n", args.status); 308 return -1; 309 } 310 return 0; 311 } 312 313 /* read info from the target - method depends on size of data being read */ 314 static int 315 targetop(uint32_t t, uint64_t offset, uint32_t length, uint32_t request, char *buf, int writing) 316 { 317 struct iovec *iov; 318 uint32_t ioc; 319 uint32_t i; 320 int req_len; 321 322 if (request > SGsize) { 323 /* split up request into blocksize chunks */ 324 ioc = request / SGsize; 325 if ((ioc * SGsize) < request) 326 ioc++; 327 if ((iov = iscsi_malloc(ioc * sizeof(*iov))) == NULL) { 328 iscsi_err(__FILE__, __LINE__, "out of memory\n"); 329 return -1; 330 } 331 332 for (i = 0 ; i < ioc ; i++) { 333 iov[i].iov_base = &buf[i * SGsize]; 334 if (i == (ioc - 1)) { /* last one */ 335 iov[i].iov_len = request - (i * SGsize); 336 } else { 337 iov[i].iov_len = SGsize; 338 } 339 } 340 341 if (sgblockop(tv.v[t].target, tv.v[t].lun, offset / tv.v[t].blocksize, (length / tv.v[t].blocksize), tv.v[t].blocksize, (uint8_t *) iov, ioc, writing) != 0) { 342 iscsi_free(iov); 343 iscsi_err(__FILE__, __LINE__, "read_10() failed\n"); 344 return -1; 345 } 346 iscsi_free(iov); 347 } else { 348 req_len = length / tv.v[t].blocksize; 349 if ((req_len * tv.v[t].blocksize) < length) 350 req_len++; 351 if (blockop(tv.v[t].target, tv.v[t].lun, offset / tv.v[t].blocksize, 352 req_len, tv.v[t].blocksize, (uint8_t *) buf, writing) != 0) { 353 iscsi_err(__FILE__, __LINE__, "read_10() failed\n"); 354 return -1; 355 } 356 } 357 return 0; 358 } 359 360 361 /****************************************************************************/ 362 363 /* perform the stat operation */ 364 /* if this is the root, then just synthesise the data */ 365 /* otherwise, retrieve the data, and be sure to fill in the size */ 366 static int 367 iscsifs_getattr(const char *path, struct stat *st) 368 { 369 virt_dirent_t *ep; 370 sti_t *p; 371 372 if (strcmp(path, "/") == 0) { 373 (void) memset(st, 0x0, sizeof(*st)); 374 st->st_mode = S_IFDIR | 0755; 375 st->st_nlink = 2; 376 return 0; 377 } 378 if ((ep = virtdir_find(&iscsi, path, strlen(path))) == NULL) { 379 return -ENOENT; 380 } 381 switch(ep->type) { 382 case 'b': 383 (void) memcpy(st, &iscsi.file, sizeof(*st)); 384 st->st_mode = (S_IFBLK | 0644); 385 break; 386 case 'c': 387 (void) memcpy(st, &iscsi.file, sizeof(*st)); 388 st->st_mode = (S_IFCHR | 0644); 389 break; 390 case 'd': 391 (void) memcpy(st, &iscsi.dir, sizeof(*st)); 392 break; 393 case 'f': 394 (void) memcpy(st, &iscsi.file, sizeof(*st)); 395 p = (sti_t *) ep->tgt; 396 st->st_size = p->st.st_size; 397 break; 398 case 'l': 399 (void) memcpy(st, &iscsi.lnk, sizeof(*st)); 400 st->st_size = ep->tgtlen; 401 break; 402 default: 403 warn("unknown directory type `%c'", ep->type); 404 return -ENOENT; 405 } 406 st->st_ino = ep->ino; 407 return 0; 408 } 409 410 /* readdir operation */ 411 static int 412 iscsifs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 413 off_t offset, struct fuse_file_info * fi) 414 { 415 virt_dirent_t *dp; 416 VIRTDIR *dirp; 417 418 if ((dirp = openvirtdir(&iscsi, path)) == NULL) { 419 return 0; 420 } 421 filler(buf, ".", NULL, 0); 422 filler(buf, "..", NULL, 0); 423 while ((dp = readvirtdir(dirp)) != NULL) { 424 filler(buf, dp->d_name, NULL, 0); 425 } 426 closevirtdir(dirp); 427 return 0; 428 } 429 430 /* open the file in the file system */ 431 static int 432 iscsifs_open(const char *path, struct fuse_file_info *fi) 433 { 434 virt_dirent_t *ep; 435 const char *slash; 436 437 if ((ep = virtdir_find(&iscsi, path, strlen(path))) == NULL) { 438 return -ENOENT; 439 } 440 /* check path is the correct one */ 441 if ((slash = strrchr(path, '/')) == NULL) { 442 slash = path; 443 } else { 444 slash += 1; 445 } 446 if (strcmp(slash, "storage") != 0) { 447 return -ENOENT; 448 } 449 return 0; 450 } 451 452 /* read the storage from the iSCSI target */ 453 static int 454 iscsifs_read(const char *path, char *buf, size_t size, off_t offset, 455 struct fuse_file_info * fi) 456 { 457 virt_dirent_t *ep; 458 uint64_t target; 459 sti_t *p; 460 461 if ((ep = virtdir_find(&iscsi, path, strlen(path))) == NULL) { 462 return -ENOENT; 463 } 464 465 p = (sti_t *)ep->tgt; 466 target = p->target; 467 468 if (targetop(target, offset, size, size, buf, 0) < 0) { 469 return -EPERM; 470 } 471 return size; 472 } 473 474 /* write the file's contents to the file system */ 475 static int 476 iscsifs_write(const char *path, const char *buf, size_t size, off_t offset, 477 struct fuse_file_info * fi) 478 { 479 virt_dirent_t *ep; 480 uint64_t target; 481 sti_t *p; 482 483 if ((ep = virtdir_find(&iscsi, path, strlen(path))) == NULL) { 484 return -ENOENT; 485 } 486 487 p = (sti_t *)ep->tgt; 488 target = p->target; 489 490 if (targetop(target, offset, size, size, __UNCONST(buf), 1) < 0) { 491 return -EPERM; 492 } 493 return size; 494 } 495 496 /* fill in the statvfs struct */ 497 static int 498 iscsifs_statfs(const char *path, struct statvfs *st) 499 { 500 (void) memset(st, 0x0, sizeof(*st)); 501 return 0; 502 } 503 504 /* read the symbolic link */ 505 static int 506 iscsifs_readlink(const char *path, char *buf, size_t size) 507 { 508 virt_dirent_t *ep; 509 510 if ((ep = virtdir_find(&iscsi, path, strlen(path))) == NULL) { 511 return -ENOENT; 512 } 513 if (ep->tgt == NULL) { 514 return -ENOENT; 515 } 516 (void) strlcpy(buf, ep->tgt, size); 517 return 0; 518 } 519 520 /* operations struct */ 521 static struct fuse_operations iscsiops = { 522 .getattr = iscsifs_getattr, 523 .readlink = iscsifs_readlink, 524 .readdir = iscsifs_readdir, 525 .open = iscsifs_open, 526 .read = iscsifs_read, 527 .write = iscsifs_write, 528 .statfs = iscsifs_statfs 529 }; 530 531 int 532 main(int argc, char **argv) 533 { 534 iscsi_initiator_t ini; 535 initiator_target_t tinfo; 536 unsigned u; 537 uint32_t lbac; 538 uint32_t blocksize; 539 uint8_t data[256]; 540 sti_t sti; 541 char hostname[1024]; 542 char name[1024]; 543 char *colon; 544 char *host; 545 char buf[32]; 546 char devtype; 547 int discover; 548 int cc; 549 int i; 550 uint32_t max_targets; 551 552 (void) memset(&tinfo, 0x0, sizeof(tinfo)); 553 iscsi_initiator_set_defaults(&ini); 554 (void) gethostname(host = hostname, sizeof(hostname)); 555 discover = 0; 556 (void) stat("/etc/hosts", &sti.st); 557 devtype = 'f'; 558 iscsi_initiator_setvar(&ini, "address family", "4"); 559 max_targets = iscsi_initiator_get_max_targets(); 560 561 while ((i = getopt(argc, argv, "46a:bcd:Dfh:p:t:u:v:V")) != -1) { 562 switch(i) { 563 case '4': 564 case '6': 565 buf[0] = i; 566 buf[1] = 0x0; 567 iscsi_initiator_setvar(&ini, "address family", buf); 568 break; 569 case 'a': 570 iscsi_initiator_setvar(&ini, "auth type", optarg); 571 break; 572 case 'b': 573 devtype = 'b'; 574 break; 575 case 'c': 576 devtype = 'c'; 577 break; 578 case 'd': 579 iscsi_initiator_setvar(&ini, "digest type", optarg); 580 break; 581 case 'D': 582 discover = 1; 583 break; 584 case 'f': 585 devtype = 'f'; 586 break; 587 case 'h': 588 iscsi_initiator_setvar(&ini, "target hostname", optarg); 589 break; 590 case 'p': 591 iscsi_initiator_setvar(&ini, "target port", optarg); 592 break; 593 case 't': 594 iscsi_initiator_setvar(&ini, "target instance", optarg); 595 break; 596 case 'u': 597 iscsi_initiator_setvar(&ini, "user", optarg); 598 break; 599 case 'V': 600 (void) printf("\"%s\" %s\nPlease send all bug reports " 601 "to %s\n", 602 PACKAGE_NAME, 603 PACKAGE_VERSION, 604 PACKAGE_BUGREPORT); 605 exit(EXIT_SUCCESS); 606 /* NOTREACHED */ 607 case 'v': 608 verbose += 1; 609 if (strcmp(optarg, "net") == 0) { 610 iscsi_initiator_setvar(&ini, "debug", "net"); 611 } else if (strcmp(optarg, "iscsi") == 0) { 612 iscsi_initiator_setvar(&ini, "debug", "iscsi"); 613 } else if (strcmp(optarg, "scsi") == 0) { 614 iscsi_initiator_setvar(&ini, "debug", "scsi"); 615 } else if (strcmp(optarg, "all") == 0) { 616 iscsi_initiator_setvar(&ini, "debug", "all"); 617 } 618 break; 619 default: 620 (void) fprintf(stderr, "%s: unknown option `%c'", 621 *argv, i); 622 } 623 } 624 if (!strcmp(iscsi_initiator_getvar(&ini, "auth type"), "chap") && 625 iscsi_initiator_getvar(&ini, "user") == NULL) { 626 iscsi_err(__FILE__, __LINE__, "user must be specified with " 627 "-u if using CHAP authentication\n"); 628 exit(EXIT_FAILURE); 629 } 630 631 if (strcmp(iscsi_initiator_getvar(&ini, "auth type"), "none") && 632 iscsi_initiator_getvar(&ini, "user") != NULL) { 633 /* 634 * For backwards compatibility, default to using CHAP 635 * if username given 636 */ 637 iscsi_initiator_setvar(&ini, "auth type", "chap"); 638 } 639 640 if (iscsi_initiator_start(&ini) == -1) { 641 iscsi_err(__FILE__, __LINE__, "initiator_init() failed\n"); 642 exit(EXIT_FAILURE); 643 } 644 645 if (iscsi_initiator_discover(host, 0, 0) < 0) { 646 printf("initiator_discover() in discover failed\n"); 647 exit(EXIT_FAILURE); 648 } 649 650 if (iscsi_initiator_get_targets(0,&all_targets) == -1) { 651 iscsi_err(__FILE__, __LINE__, 652 "initiator_get_targets() failed\n"); 653 exit(EXIT_FAILURE); 654 } 655 656 657 if (discover) { 658 printf("Targets available from host %s:\n",host); 659 for (u = 0; u < all_targets.c ; u += 2) { 660 printf("%s at %s\n", all_targets.v[u], 661 all_targets.v[u + 1]); 662 } 663 664 exit(EXIT_SUCCESS); 665 } 666 667 if (all_targets.c/2 > max_targets) { 668 (void) fprintf(stderr, 669 "CONFIG_INITIATOR_NUM_TARGETS in initiator.h " 670 "is too small. %d targets available, " 671 "only %d configurable.\n", 672 all_targets.c/2, max_targets); 673 (void) fprintf(stderr, 674 "To increase this value, libiscsi will have be " 675 "recompiled.\n"); 676 (void) fprintf(stderr, 677 "Truncating number of targets to %d.\n", 678 max_targets); 679 all_targets.c = 2 * max_targets; 680 } 681 682 sti.st.st_ino = 0x15c51; 683 684 #if defined(__NetBSD__) && defined(USE_LIBKMOD) 685 /* check that the puffs module is loaded on NetBSD */ 686 if (kmodstat("puffs", NULL) == 0 && !kmodload("puffs")) { 687 (void) fprintf(stderr, "initiator: can't load puffs module\n"); 688 } 689 #endif 690 691 for (u = 0 ; u < all_targets.c / 2 ; u++) { 692 ALLOC(targetinfo_t, tv.v, tv.size, tv.c, 10, 10, "iscsifs", 693 exit(EXIT_FAILURE)); 694 695 initiator_set_target_name(u, all_targets.v[u * 2]); 696 697 if (iscsi_initiator_discover(host, u, 0) < 0) { 698 printf("iscsi_initiator_discover() failed\n"); 699 break; 700 } 701 702 get_target_info(u, &tinfo); 703 if ((colon = strrchr(tinfo.TargetName, ':')) == NULL) { 704 colon = tinfo.TargetName; 705 } else { 706 colon += 1; 707 } 708 709 /* stuff size into st.st_size */ 710 { 711 int retry = 5; 712 while (retry > 0) { 713 if (read_capacity(u, 0, &lbac, &blocksize) == 0) 714 break; 715 retry--; 716 iscsi_warn(__FILE__, __LINE__, 717 "read_capacity failed - retrying %d\n", retry); 718 sleep(1); 719 } 720 if (retry == 0) { 721 iscsi_err(__FILE__, __LINE__, "read_capacity failed - giving up\n"); 722 break; 723 } 724 } 725 sti.st.st_size = (off_t)(((uint64_t)lbac + 1) * blocksize); 726 sti.target = u; 727 728 tv.v[tv.c].host = strdup(tinfo.name); 729 tv.v[tv.c].ip = strdup(tinfo.ip); 730 tv.v[tv.c].targetname = strdup(tinfo.TargetName); 731 tv.v[tv.c].stargetname = strdup(colon); 732 tv.v[tv.c].target = u; 733 tv.v[tv.c].lun = 0; 734 tv.v[tv.c].lbac = lbac; 735 tv.v[tv.c].blocksize = blocksize; 736 737 /* get iSCSI target information */ 738 (void) memset(data, 0x0, sizeof(data)); 739 inquiry(u, 0, 0, 0, data); 740 tv.v[tv.c].devicetype = (data[0] & 0x1f); 741 (void) memcpy(tv.v[tv.c].vendor, &data[8], VendorLen); 742 (void) memcpy(tv.v[tv.c].product, &data[8 + VendorLen], 743 ProductLen); 744 (void) memcpy(tv.v[tv.c].version, 745 &data[8 + VendorLen + ProductLen], VersionLen); 746 (void) memset(data, 0x0, sizeof(data)); 747 inquiry(u, 0, INQUIRY_EVPD_BIT, INQUIRY_UNIT_SERIAL_NUMBER_VPD, 748 data); 749 tv.v[tv.c].serial = strdup((char *)&data[4]); 750 751 /* create the tree using virtdir routines */ 752 cc = snprintf(name, sizeof(name), "/%s", colon); 753 virtdir_add(&iscsi, name, cc, 'd', name, cc); 754 cc = snprintf(name, sizeof(name), "/%s/storage", colon); 755 virtdir_add(&iscsi, name, cc, devtype, (void *)&sti, 756 sizeof(sti)); 757 cc = snprintf(name, sizeof(name), "/%s/hostname", colon); 758 virtdir_add(&iscsi, name, cc, 'l', tinfo.name, 759 strlen(tinfo.name)); 760 cc = snprintf(name, sizeof(name), "/%s/ip", colon); 761 virtdir_add(&iscsi, name, cc, 'l', tinfo.ip, strlen(tinfo.ip)); 762 cc = snprintf(name, sizeof(name), "/%s/targetname", colon); 763 virtdir_add(&iscsi, name, cc, 'l', tinfo.TargetName, 764 strlen(tinfo.TargetName)); 765 cc = snprintf(name, sizeof(name), "/%s/vendor", colon); 766 virtdir_add(&iscsi, name, cc, 'l', tv.v[tv.c].vendor, 767 strlen(tv.v[tv.c].vendor)); 768 cc = snprintf(name, sizeof(name), "/%s/product", colon); 769 virtdir_add(&iscsi, name, cc, 'l', tv.v[tv.c].product, 770 strlen(tv.v[tv.c].product)); 771 cc = snprintf(name, sizeof(name), "/%s/version", colon); 772 virtdir_add(&iscsi, name, cc, 'l', tv.v[tv.c].version, 773 strlen(tv.v[tv.c].version)); 774 if (tv.v[tv.c].serial[0] && tv.v[tv.c].serial[0] != ' ') { 775 cc = snprintf(name, sizeof(name), "/%s/serial", 776 colon); 777 virtdir_add(&iscsi, name, cc, 'l', tv.v[tv.c].serial, 778 strlen(tv.v[tv.c].serial)); 779 } 780 tv.c += 1; 781 } 782 return fuse_main(argc - optind, argv + optind, &iscsiops, NULL); 783 } 784