1/* 2 * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or 3 * using the software you agree to this license. If you do not agree to this license, do not download, install, 4 * copy or use the software. 5 * 6 * Intel License Agreement 7 * 8 * Copyright (c) 2000, Intel Corporation 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that 12 * the following conditions are met: 13 * 14 * -Redistributions of source code must retain the above copyright notice, this list of conditions and the 15 * following disclaimer. 16 * 17 * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 18 * following disclaimer in the documentation and/or other materials provided with the distribution. 19 * 20 * -The name of Intel Corporation may not be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32#include "config.h" 33 34#include <sys/types.h> 35 36#ifdef HAVE_NETINET_IN_H 37#include <netinet/in.h> 38#endif 39 40#ifdef HAVE_SYS_MMAN_H 41#include <sys/mman.h> 42#endif 43 44#ifdef HAVE_SYS_UIO_H 45#include <sys/uio.h> 46#endif 47 48#ifdef HAVE_SYS_TIME_H 49#include <sys/time.h> 50#endif 51 52#ifdef HAVE_SYS_STAT_H 53#include <sys/stat.h> 54#endif 55 56#ifdef HAVE_SYS_VFS_H 57#include <sys/vfs.h> 58#endif 59 60#include <stdio.h> 61#include <stdlib.h> 62 63#ifdef HAVE_STRING_H 64#include <string.h> 65#endif 66 67#include <unistd.h> 68 69#ifdef HAVE_ERRNO_H 70#include <errno.h> 71#endif 72 73#include <unistd.h> 74 75#ifdef HAVE_FCNTL_H 76#include <fcntl.h> 77#endif 78 79#ifdef HAVE_UTIME_H 80#include <utime.h> 81#endif 82 83#include "scsi_cmd_codes.h" 84 85#include "iscsi.h" 86#include "iscsiutil.h" 87#include "device.h" 88#include "osd.h" 89 90/* 91 * Globals 92 */ 93 94static int osd_luns = CONFIG_OSD_LUNS_DFLT; 95static uint64_t osd_capacity = CONFIG_OSD_CAPACITY_DFLT * 1048576; 96static char base_dir[64] = CONFIG_OSD_BASEDIR_DFLT; 97 98#ifndef __KERNEL__ 99void 100device_set_var(const char *var, char *arg) 101{ 102 if (strcmp(var, "capacity") == 0) { 103 osd_capacity = strtoll(arg, (char **) NULL, 10) * 1048576; 104 } else if (strcmp(var, "luns") == 0) { 105 osd_luns = atoi(arg); 106 } else if (strcmp(var, "directory") == 0) { 107 (void) strlcpy(base_dir, arg, sizeof(base_dir)); 108 } else { 109 (void) fprintf(stderr, "Unrecognised variable: `%s'\n", var); 110 } 111} 112#endif 113 114int 115device_init(globals_t *gp, char *dev) 116{ 117 struct stat st; 118 char FileName[1024]; 119 int i; 120 121 if (stat(base_dir, &st) < 0) { 122 123 /* Create directory for OSD */ 124 125 if (mkdir(base_dir, 0755) != 0) { 126 if (errno != EEXIST) { 127 iscsi_err(__FILE__, __LINE__, "error creating directory \"%s\" for OSD: errno %d\n", base_dir, errno); 128 return -1; 129 } 130 } 131 /* Create directory for LU */ 132 133 for (i = 0; i < osd_luns; i++) { 134 sprintf(FileName, "%s/lun_%d", base_dir, i); 135 if (mkdir(FileName, 0755) != 0) { 136 if (errno != EEXIST) { 137 iscsi_err(__FILE__, __LINE__, "error creating \"%s\" for LU %d: errno %d\n", FileName, i, errno); 138 return -1; 139 } 140 } 141 } 142 } 143 /* Display LU info */ 144 145 return 0; 146} 147 148int 149osd_read_callback(void *arg) 150{ 151 struct iovec *sg = (struct iovec *) arg; 152 int i = 0; 153 154 while (sg[i].iov_base != NULL) { 155 iscsi_free_atomic(sg[i].iov_base); 156 i++; 157 } 158 return 0; 159} 160 161int 162device_command(target_session_t * sess, target_cmd_t * cmd) 163{ 164 iscsi_scsi_cmd_args_t *args = cmd->scsi_cmd; 165 uint8_t *data; 166 char FileName[1024]; 167 uint8_t *write_data = NULL; 168 uint8_t *read_data = NULL; 169 uint8_t *set_list = NULL; 170 uint8_t *get_list = NULL; 171 struct iovec sg[3]; 172 int sg_len = 0; 173 int rc; 174 osd_args_t osd_args; 175 uint32_t GroupID = 0; 176 uint64_t UserID = 0; 177 char string[1024]; 178 uint8_t *get_data = NULL; 179 uint32_t page = 0; 180 uint32_t index = 0; 181 int attr_len = 0; 182 183 iscsi_trace(TRACE_SCSI_CMD, "SCSI op 0x%x (lun %llu)\n", args->cdb[0], args->lun); 184 185 if (args->lun >= osd_luns) { 186 iscsi_trace(TRACE_SCSI_DEBUG, "invalid lun: %llu\n", args->lun); 187 args->status = 0x01; 188 return 0; 189 } 190 args->status = 1; 191 192 switch (args->cdb[0]) { 193 194 case TEST_UNIT_READY: 195 196 iscsi_trace(TRACE_SCSI_CMD, "TEST_UNIT_READY(lun %llu)\n", args->lun); 197 args->status = 0; 198 args->length = 0; 199 break; 200 201 case INQUIRY: 202 203 iscsi_trace(TRACE_SCSI_CMD, "INQUIRY(lun %llu)\n", args->lun); 204 data = args->send_data; 205 memset(data, 0, args->cdb[4]); /* Clear allocated buffer */ 206 data[0] = 0x0e; /* Peripheral Device Type */ 207 /* data[1] |= 0x80; // Removable Bit */ 208 data[2] |= 0x02;/* ANSI-approved version */ 209 /* data[3] |= 0x80; // AENC */ 210 /* data[3] |= 0x40; // TrmIOP */ 211 /* data[3] |= 0x20; // NormACA */ 212 data[4] = args->cdb[4] - 4; /* Additional length */ 213 /* 214 * data[7] |= 0x80; // Relative 215 * addressing 216 */ 217 data[7] |= 0x40;/* WBus32 */ 218 data[7] |= 0x20;/* WBus16 */ 219 /* data[7] |= 0x10; // Sync */ 220 /* data[7] |= 0x08; // Linked Commands */ 221 /* data[7] |= 0x04; // TransDis */ 222 /* 223 * data[7] |= 0x02; // Tagged Command 224 * Queueing 225 */ 226 /* data[7] |= 0x01; // SftRe */ 227 (void) memset(data + 8, 0x0, 32); 228 strlcpy(data + 8, OSD_VENDOR, 8); /* Vendor */ 229 strlcpy(data + 16, OSD_PRODUCT, 16); /* Product ID */ 230 (void) snprintf(data + 32, 8, "%d", OSD_VERSION); /* Product Revision */ 231 args->input = 1; 232 args->length = args->cdb[4] + 1; 233 args->status = 0; 234 235 break; 236 237 case 0x7F: 238 239 OSD_DECAP_CDB(args->cdb, args->ext_cdb, &osd_args); 240 /* OSD_PRINT_CDB(args->cdb, args->ext_cdb); */ 241 GroupID = osd_args.GroupID; 242 UserID = osd_args.UserID; 243 244 /* 245 * Transfer all data 246 */ 247 248 if (osd_args.set_attributes_list_length) { 249 if ((set_list = iscsi_malloc_atomic(osd_args.set_attributes_list_length)) == NULL) { 250 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); 251 goto done; 252 } 253 sg[sg_len].iov_base = set_list; 254 sg[sg_len].iov_len = osd_args.set_attributes_list_length; 255 sg_len++; 256 } 257 if (osd_args.get_attributes_list_length) { 258 if ((get_list = iscsi_malloc_atomic(osd_args.get_attributes_list_length)) == NULL) { 259 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); 260 goto done; 261 } 262 sg[sg_len].iov_base = get_list; 263 sg[sg_len].iov_len = osd_args.get_attributes_list_length; 264 sg_len++; 265 } 266 if (osd_args.service_action == OSD_WRITE) { 267 if ((write_data = iscsi_malloc_atomic(osd_args.length)) == NULL) { 268 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); 269 goto done; 270 } 271 sg[sg_len].iov_base = write_data; 272 sg[sg_len].iov_len = osd_args.length; 273 sg_len++; 274 } 275 if (sg_len) { 276 if (target_transfer_data(sess, args, sg, sg_len) != 0) { 277 iscsi_err(__FILE__, __LINE__, "target_transfer_data() failed\n"); 278 goto done; 279 } 280 } 281 /* 282 * Set any attributes 283 */ 284 285 if (osd_args.set_attributes_list_length) { 286 uint32_t page, attr; 287 uint16_t len; 288 int i; 289 290 iscsi_trace(TRACE_OSD, "OSD_SET_ATTR(lun %llu, GroupID 0x%x, UserID 0x%llx)\n", args->lun, osd_args.GroupID, osd_args.UserID); 291 for (i = 0; i < osd_args.set_attributes_list_length;) { 292 page = ISCSI_NTOHL(*((uint32_t *) (&(set_list[i])))); 293 i += 4; 294 attr = ISCSI_NTOHL(*((uint32_t *) (&(set_list[i])))); 295 i += 4; 296 len = ISCSI_NTOHS(*((uint16_t *) (&(set_list[i])))); 297 i += 2; 298 sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u", 299 base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, attr); 300 if ((rc = open(FileName, O_WRONLY | O_CREAT, 0644)) == -1) { 301 iscsi_err(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); 302 goto done; 303 } 304 if (write(rc, set_list + i, len) != len) { 305 iscsi_err(__FILE__, __LINE__, "write() failed\n"); 306 } 307 close(rc); 308 i += len; 309 iscsi_trace(TRACE_OSD, "SET(0x%x,%u,%u>\n", page, attr, len); 310 } 311 } 312 args->send_sg_len = 0; 313 sg_len = 0; 314 315 switch (osd_args.service_action) { 316 317 case OSD_CREATE_GROUP: 318 319 do { 320 GroupID = rand() % 1048576 * 1024 + 1; 321 sprintf(FileName, "%s/lun_%llu/0x%x", base_dir, args->lun, GroupID); 322 rc = mkdir(FileName, 0755); 323 } while (rc == -1 && errno == EEXIST); 324 iscsi_trace(TRACE_OSD, "OSD_CREATE_GROUP(lun %llu) --> 0x%x\n", args->lun, GroupID); 325 args->status = 0; 326 break; 327 328 case OSD_REMOVE_GROUP: 329 330 iscsi_trace(TRACE_OSD, "OSD_REMOVE_GROUP(lun %llu, 0x%x)\n", args->lun, osd_args.GroupID); 331 sprintf(FileName, "%s/lun_%llu/0x%x", base_dir, args->lun, osd_args.GroupID); 332 if ((rc = rmdir(FileName)) == -1) { 333 iscsi_err(__FILE__, __LINE__, "rmdir(\"%s\") failed: errno %d\n", FileName, errno); 334 goto done; 335 } 336 args->status = 0; 337 break; 338 339 case OSD_CREATE: 340 341 UserID = rand() % 1048576 * 1024 + 1; 342create_user_again: 343 sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", 344 base_dir, args->lun, osd_args.GroupID, UserID); 345 rc = open(FileName, O_CREAT | O_EXCL | O_RDWR, 0644); 346 if ((rc == -1) && (errno == EEXIST)) { 347 UserID = rand() % 1048576 * 1024 + 1; 348 goto create_user_again; 349 } 350 close(rc); 351 iscsi_trace(TRACE_OSD, "OSD_CREATE(lun %llu, GroupID 0x%x) --> 0x%llx\n", args->lun, osd_args.GroupID, UserID); 352 args->status = 0; 353 354 break; 355 356 case OSD_REMOVE: 357 358 iscsi_trace(TRACE_OSD, "OSD_REMOVE(lun %llu, 0x%llx)\n", args->lun, osd_args.UserID); 359 sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", 360 base_dir, args->lun, osd_args.GroupID, osd_args.UserID); 361 if ((rc = unlink(FileName)) == -1) { 362 iscsi_err(__FILE__, __LINE__, "unlink(\"%s\") failed: errno %d\n", FileName, errno); 363 goto done; 364 } 365 sprintf(string, "rm -f %s/lun_%llu/0x%x/0x%llx.*", base_dir, args->lun, osd_args.GroupID, osd_args.UserID); 366 if (system(string) != 0) { 367 iscsi_err(__FILE__, __LINE__, "\"%s\" failed\n", string); 368 return -1; 369 } 370 args->status = 0; 371 break; 372 373 case OSD_WRITE: 374 iscsi_trace(TRACE_OSD, "OSD_WRITE(lun %llu, GroupID 0x%x, UserID 0x%llx, length %llu, offset %llu)\n", 375 args->lun, osd_args.GroupID, osd_args.UserID, osd_args.length, osd_args.offset); 376 sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", 377 base_dir, args->lun, osd_args.GroupID, osd_args.UserID); 378 if ((rc = open(FileName, O_WRONLY, 0644)) == -1) { 379 iscsi_err(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); 380 goto write_done; 381 } 382 if (lseek(rc, osd_args.offset, SEEK_SET) == -1) { 383 iscsi_err(__FILE__, __LINE__, "error seeking \"%s\": errno %d\n", FileName, errno); 384 goto write_done; 385 } 386 if (write(rc, write_data, osd_args.length) != osd_args.length) { 387 iscsi_err(__FILE__, __LINE__, "write() failed\n"); 388 goto write_done; 389 } 390 close(rc); 391 args->status = 0; 392write_done: 393 break; 394 395 case OSD_READ: 396 iscsi_trace(TRACE_OSD, "OSD_READ(lun %llu, GroupID 0x%x, UserID 0x%llx, length %llu, offset %llu)\n", 397 args->lun, osd_args.GroupID, osd_args.UserID, osd_args.length, osd_args.offset); 398 sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", 399 base_dir, args->lun, osd_args.GroupID, osd_args.UserID); 400 if ((rc = open(FileName, O_RDONLY, 0644)) == -1) { 401 iscsi_err(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); 402 goto read_done; 403 } 404 if ((read_data = iscsi_malloc_atomic(osd_args.length)) == NULL) { 405 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); 406 goto read_done; 407 } 408 if (lseek(rc, osd_args.offset, SEEK_SET) == -1) { 409 iscsi_err(__FILE__, __LINE__, "error seeking \"%s\": errno %d\n", FileName, errno); 410 goto read_done; 411 } 412 if (read(rc, read_data, osd_args.length) != osd_args.length) { 413 iscsi_err(__FILE__, __LINE__, "read() failed\n"); 414 goto read_done; 415 } 416 close(rc); 417 args->status = 0; 418read_done: 419 if (args->status == 0) { 420 args->input = 1; 421 sg[0].iov_base = read_data; 422 sg[0].iov_len = osd_args.length; 423 sg[1].iov_base = NULL; 424 sg[1].iov_len = 0; 425 args->send_data = (void *) sg; 426 args->send_sg_len = 1; 427 sg_len++; 428 cmd->callback = osd_read_callback; 429 cmd->callback_arg = sg; 430 } else { 431 if (read_data) 432 iscsi_free_atomic(read_data); 433 args->length = 0; /* Need a better way of 434 * specifying an error.. */ 435 } 436 break; 437 438 case OSD_GET_ATTR: 439 iscsi_trace(TRACE_OSD, "OSD_GET_ATTR(lun %llu, GroupID 0x%x, UserID 0x%llx)\n", 440 args->lun, osd_args.GroupID, osd_args.UserID); 441 args->status = 0; 442 break; 443 444 case OSD_SET_ATTR: 445 args->status = 0; 446 break; 447 } 448 449 if (args->status) 450 goto done; 451 452 /* 453 * Send back requested attributes 454 */ 455 456 if (osd_args.get_attributes_list_length || osd_args.get_attributes_page) { 457 if ((get_data = iscsi_malloc_atomic(osd_args.get_attributes_allocation_length)) == NULL) { 458 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); 459 goto done; 460 } 461 } 462 if (osd_args.get_attributes_list_length) { 463 int i; 464 465 for (i = 0; i < osd_args.get_attributes_list_length;) { 466 page = ISCSI_NTOHL(*((uint32_t *) (&(get_list[i])))); 467 i += 4; 468 index = ISCSI_NTOHL(*((uint32_t *) (&(get_list[i])))); 469 i += 4; 470 iscsi_trace(TRACE_OSD, "GET(0x%x,%u)\n", page, index); 471 472 switch (page) { 473 case 0x40000001: 474 switch (index) { 475 case 0x1: 476 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); 477 attr_len += 4; 478 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); 479 attr_len += 4; 480 *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4); 481 attr_len += 2; 482 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID); 483 attr_len += 4; 484 break; 485 default: 486 iscsi_err(__FILE__, __LINE__, "unknown attr index %u\n", index); 487 goto done; 488 } 489 break; 490 case 0x00000001: 491 switch (index) { 492 case 0x1: 493 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); 494 attr_len += 4; 495 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); 496 attr_len += 4; 497 *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4); 498 attr_len += 2; 499 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID); 500 attr_len += 4; 501 break; 502 case 0x2: 503 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); 504 attr_len += 4; 505 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); 506 attr_len += 4; 507 *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(8); 508 attr_len += 2; 509 *((uint64_t *) & get_data[attr_len]) = ISCSI_HTONLL(UserID); 510 attr_len += 8; 511 break; 512 default: 513 iscsi_err(__FILE__, __LINE__, "unknown attr index %u\n", index); 514 goto done; 515 } 516 break; 517 518 /* Vendor-specific */ 519 520 case 0x30000000: 521 switch (index) { 522 case 0x1: 523 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); 524 attr_len += 4; 525 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); 526 attr_len += 4; 527 *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(480); 528 attr_len += 2; 529 sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u", 530 base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, index); 531 if ((rc = open(FileName, O_RDONLY, 0644)) == -1) { 532 iscsi_err(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); 533 } 534 if (read(rc, get_data + attr_len, 480) != 480) { 535 iscsi_err(__FILE__, __LINE__, "read() failed\n"); 536 goto done; 537 } 538 close(rc); 539 attr_len += 480; 540 break; 541 default: 542 iscsi_err(__FILE__, __LINE__, "unknown vendor attr index %u\n", index); 543 goto done; 544 } 545 break; 546 547 default: 548 iscsi_err(__FILE__, __LINE__, "unknown page 0x%x\n", page); 549 goto done; 550 } 551 } 552 } 553 if (osd_args.get_attributes_page) { 554 555 /* 556 * Right now, if we get a request for an entire page, 557 * we return only one attribute. 558 */ 559 560 page = osd_args.get_attributes_page; 561 562 switch (osd_args.get_attributes_page) { 563 case 0x40000001: 564 index = 1; 565 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); 566 attr_len += 4; 567 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); 568 attr_len += 4; 569 *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4); 570 attr_len += 2; 571 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID); 572 attr_len += 4; 573 break; 574 575 case 0x00000001: 576 index = 2; 577 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); 578 attr_len += 4; 579 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); 580 attr_len += 4; 581 *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(8); 582 attr_len += 2; 583 *((uint64_t *) & get_data[attr_len]) = ISCSI_HTONLL(UserID); 584 attr_len += 8; 585 break; 586 587 case 0x30000000: 588 index = 1; 589 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); 590 attr_len += 4; 591 *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); 592 attr_len += 4; 593 *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(480); 594 attr_len += 2; 595 sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u", 596 base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, index); 597 if ((rc = open(FileName, O_RDONLY, 0644)) == -1) { 598 iscsi_err(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); 599 } 600 if (read(rc, get_data + attr_len, 480) != 480) { 601 iscsi_err(__FILE__, __LINE__, "read() failed\n"); 602 goto done; 603 } 604 close(rc); 605 attr_len += 480; 606 break; 607 default: 608 iscsi_err(__FILE__, __LINE__, "page not yet supported\n"); 609 goto done; 610 } 611 } 612 if (attr_len) { 613 if (attr_len != osd_args.get_attributes_allocation_length) { 614 iscsi_err(__FILE__, __LINE__, "allocation lengths differ: got %u, expected %u\n", 615 osd_args.get_attributes_allocation_length, attr_len); 616 goto done; 617 } 618 if (!args->status) { 619 args->input = 1; 620 sg[sg_len].iov_base = get_data; 621 sg[sg_len].iov_len = osd_args.get_attributes_allocation_length; 622 sg_len++; 623 sg[sg_len].iov_base = NULL; 624 sg[sg_len].iov_len = 0; 625 args->send_data = (void *) sg; 626 args->send_sg_len++; 627 cmd->callback = osd_read_callback; 628 cmd->callback_arg = sg; 629 } else { 630 if (get_data) 631 iscsi_free_atomic(get_data); 632 } 633 } 634 break; 635 636 default: 637 iscsi_err(__FILE__, __LINE__, "UNKNOWN OPCODE 0x%x\n", args->cdb[0]); 638 args->status = 0x01; 639 break; 640 } 641 642 643done: 644 iscsi_trace(TRACE_SCSI_DEBUG, "SCSI op 0x%x: done (status 0x%x)\n", args->cdb[0], args->status); 645 if (set_list) { 646 iscsi_free_atomic(set_list); 647 } 648 if (get_list) { 649 iscsi_free_atomic(get_list); 650 } 651 if (write_data) { 652 iscsi_free_atomic(write_data); 653 } 654 return 0; 655} 656 657/* ARGSUSED */ 658int 659device_shutdown(target_session_t *sess) 660{ 661 return 0; 662} 663