No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / iscsi / dist / src / osd / osd.c
blob6856696ac90ba946a3082f69e4fa6a6b589bbd58
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.
6 * Intel License Agreement
8 * Copyright (c) 2000, Intel Corporation
9 * All rights reserved.
11 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
12 * the following conditions are met:
14 * -Redistributions of source code must retain the above copyright notice, this list of conditions and the
15 * following disclaimer.
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.
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.
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.
32 #include "config.h"
34 #include <sys/types.h>
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
38 #endif
40 #ifdef HAVE_SYS_MMAN_H
41 #include <sys/mman.h>
42 #endif
44 #ifdef HAVE_SYS_UIO_H
45 #include <sys/uio.h>
46 #endif
48 #ifdef HAVE_SYS_TIME_H
49 #include <sys/time.h>
50 #endif
52 #ifdef HAVE_SYS_STAT_H
53 #include <sys/stat.h>
54 #endif
56 #ifdef HAVE_SYS_VFS_H
57 #include <sys/vfs.h>
58 #endif
60 #include <stdio.h>
61 #include <stdlib.h>
63 #ifdef HAVE_STRING_H
64 #include <string.h>
65 #endif
67 #include <unistd.h>
69 #ifdef HAVE_ERRNO_H
70 #include <errno.h>
71 #endif
73 #include <unistd.h>
75 #ifdef HAVE_FCNTL_H
76 #include <fcntl.h>
77 #endif
79 #ifdef HAVE_UTIME_H
80 #include <utime.h>
81 #endif
83 #include "scsi_cmd_codes.h"
85 #include "iscsi.h"
86 #include "iscsiutil.h"
87 #include "device.h"
88 #include "osd.h"
91 * Globals
94 static int osd_luns = CONFIG_OSD_LUNS_DFLT;
95 static uint64_t osd_capacity = CONFIG_OSD_CAPACITY_DFLT * 1048576;
96 static char base_dir[64] = CONFIG_OSD_BASEDIR_DFLT;
98 #ifndef __KERNEL__
99 void
100 device_set_var(const char *var, char *arg)
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);
112 #endif
114 int
115 device_init(globals_t *gp, char *dev)
117 struct stat st;
118 char FileName[1024];
119 int i;
121 if (stat(base_dir, &st) < 0) {
123 /* Create directory for OSD */
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;
131 /* Create directory for LU */
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;
143 /* Display LU info */
145 return 0;
148 int
149 osd_read_callback(void *arg)
151 struct iovec *sg = (struct iovec *) arg;
152 int i = 0;
154 while (sg[i].iov_base != NULL) {
155 iscsi_free_atomic(sg[i].iov_base);
156 i++;
158 return 0;
161 int
162 device_command(target_session_t * sess, target_cmd_t * cmd)
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;
183 iscsi_trace(TRACE_SCSI_CMD, "SCSI op 0x%x (lun %llu)\n", args->cdb[0], args->lun);
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;
190 args->status = 1;
192 switch (args->cdb[0]) {
194 case TEST_UNIT_READY:
196 iscsi_trace(TRACE_SCSI_CMD, "TEST_UNIT_READY(lun %llu)\n", args->lun);
197 args->status = 0;
198 args->length = 0;
199 break;
201 case INQUIRY:
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 */
214 * data[7] |= 0x80; // Relative
215 * addressing
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 */
223 * data[7] |= 0x02; // Tagged Command
224 * Queueing
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;
235 break;
237 case 0x7F:
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;
245 * Transfer all data
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;
253 sg[sg_len].iov_base = set_list;
254 sg[sg_len].iov_len = osd_args.set_attributes_list_length;
255 sg_len++;
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;
262 sg[sg_len].iov_base = get_list;
263 sg[sg_len].iov_len = osd_args.get_attributes_list_length;
264 sg_len++;
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;
271 sg[sg_len].iov_base = write_data;
272 sg[sg_len].iov_len = osd_args.length;
273 sg_len++;
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;
282 * Set any attributes
285 if (osd_args.set_attributes_list_length) {
286 uint32_t page, attr;
287 uint16_t len;
288 int i;
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;
304 if (write(rc, set_list + i, len) != len) {
305 iscsi_err(__FILE__, __LINE__, "write() failed\n");
307 close(rc);
308 i += len;
309 iscsi_trace(TRACE_OSD, "SET(0x%x,%u,%u>\n", page, attr, len);
312 args->send_sg_len = 0;
313 sg_len = 0;
315 switch (osd_args.service_action) {
317 case OSD_CREATE_GROUP:
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;
328 case OSD_REMOVE_GROUP:
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;
336 args->status = 0;
337 break;
339 case OSD_CREATE:
341 UserID = rand() % 1048576 * 1024 + 1;
342 create_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;
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;
354 break;
356 case OSD_REMOVE:
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;
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;
370 args->status = 0;
371 break;
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;
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;
386 if (write(rc, write_data, osd_args.length) != osd_args.length) {
387 iscsi_err(__FILE__, __LINE__, "write() failed\n");
388 goto write_done;
390 close(rc);
391 args->status = 0;
392 write_done:
393 break;
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;
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;
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;
412 if (read(rc, read_data, osd_args.length) != osd_args.length) {
413 iscsi_err(__FILE__, __LINE__, "read() failed\n");
414 goto read_done;
416 close(rc);
417 args->status = 0;
418 read_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.. */
436 break;
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;
444 case OSD_SET_ATTR:
445 args->status = 0;
446 break;
449 if (args->status)
450 goto done;
453 * Send back requested attributes
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;
462 if (osd_args.get_attributes_list_length) {
463 int i;
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);
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;
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;
516 break;
518 /* Vendor-specific */
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);
534 if (read(rc, get_data + attr_len, 480) != 480) {
535 iscsi_err(__FILE__, __LINE__, "read() failed\n");
536 goto done;
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;
545 break;
547 default:
548 iscsi_err(__FILE__, __LINE__, "unknown page 0x%x\n", page);
549 goto done;
553 if (osd_args.get_attributes_page) {
556 * Right now, if we get a request for an entire page,
557 * we return only one attribute.
560 page = osd_args.get_attributes_page;
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;
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;
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);
600 if (read(rc, get_data + attr_len, 480) != 480) {
601 iscsi_err(__FILE__, __LINE__, "read() failed\n");
602 goto done;
604 close(rc);
605 attr_len += 480;
606 break;
607 default:
608 iscsi_err(__FILE__, __LINE__, "page not yet supported\n");
609 goto done;
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;
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);
634 break;
636 default:
637 iscsi_err(__FILE__, __LINE__, "UNKNOWN OPCODE 0x%x\n", args->cdb[0]);
638 args->status = 0x01;
639 break;
643 done:
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);
648 if (get_list) {
649 iscsi_free_atomic(get_list);
651 if (write_data) {
652 iscsi_free_atomic(write_data);
654 return 0;
657 /* ARGSUSED */
658 int
659 device_shutdown(target_session_t *sess)
661 return 0;