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
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.
34 #include <sys/types.h>
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
40 #ifdef HAVE_SYS_MMAN_H
48 #ifdef HAVE_SYS_TIME_H
52 #ifdef HAVE_SYS_STAT_H
83 #include "scsi_cmd_codes.h"
86 #include "iscsiutil.h"
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
;
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
));
109 (void) fprintf(stderr
, "Unrecognised variable: `%s'\n", var
);
115 device_init(globals_t
*gp
, char *dev
)
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
);
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
);
143 /* Display LU info */
149 osd_read_callback(void *arg
)
151 struct iovec
*sg
= (struct iovec
*) arg
;
154 while (sg
[i
].iov_base
!= NULL
) {
155 iscsi_free_atomic(sg
[i
].iov_base
);
162 device_command(target_session_t
* sess
, target_cmd_t
* cmd
)
164 iscsi_scsi_cmd_args_t
*args
= cmd
->scsi_cmd
;
167 uint8_t *write_data
= NULL
;
168 uint8_t *read_data
= NULL
;
169 uint8_t *set_list
= NULL
;
170 uint8_t *get_list
= NULL
;
175 uint32_t GroupID
= 0;
178 uint8_t *get_data
= NULL
;
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
);
192 switch (args
->cdb
[0]) {
194 case TEST_UNIT_READY
:
196 iscsi_trace(TRACE_SCSI_CMD
, "TEST_UNIT_READY(lun %llu)\n", args
->lun
);
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
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
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 */
232 args
->length
= args
->cdb
[4] + 1;
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
;
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");
253 sg
[sg_len
].iov_base
= set_list
;
254 sg
[sg_len
].iov_len
= osd_args
.set_attributes_list_length
;
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");
262 sg
[sg_len
].iov_base
= get_list
;
263 sg
[sg_len
].iov_len
= osd_args
.get_attributes_list_length
;
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");
271 sg
[sg_len
].iov_base
= write_data
;
272 sg
[sg_len
].iov_len
= osd_args
.length
;
276 if (target_transfer_data(sess
, args
, sg
, sg_len
) != 0) {
277 iscsi_err(__FILE__
, __LINE__
, "target_transfer_data() failed\n");
285 if (osd_args
.set_attributes_list_length
) {
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
]))));
294 attr
= ISCSI_NTOHL(*((uint32_t *) (&(set_list
[i
]))));
296 len
= ISCSI_NTOHS(*((uint16_t *) (&(set_list
[i
]))));
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
);
304 if (write(rc
, set_list
+ i
, len
) != len
) {
305 iscsi_err(__FILE__
, __LINE__
, "write() failed\n");
309 iscsi_trace(TRACE_OSD
, "SET(0x%x,%u,%u>\n", page
, attr
, len
);
312 args
->send_sg_len
= 0;
315 switch (osd_args
.service_action
) {
317 case OSD_CREATE_GROUP
:
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
);
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
);
341 UserID
= rand() % 1048576 * 1024 + 1;
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
;
351 iscsi_trace(TRACE_OSD
, "OSD_CREATE(lun %llu, GroupID 0x%x) --> 0x%llx\n", args
->lun
, osd_args
.GroupID
, UserID
);
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
);
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
);
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
);
382 if (lseek(rc
, osd_args
.offset
, SEEK_SET
) == -1) {
383 iscsi_err(__FILE__
, __LINE__
, "error seeking \"%s\": errno %d\n", FileName
, errno
);
386 if (write(rc
, write_data
, osd_args
.length
) != osd_args
.length
) {
387 iscsi_err(__FILE__
, __LINE__
, "write() failed\n");
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
);
404 if ((read_data
= iscsi_malloc_atomic(osd_args
.length
)) == NULL
) {
405 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc_atomic() failed\n");
408 if (lseek(rc
, osd_args
.offset
, SEEK_SET
) == -1) {
409 iscsi_err(__FILE__
, __LINE__
, "error seeking \"%s\": errno %d\n", FileName
, errno
);
412 if (read(rc
, read_data
, osd_args
.length
) != osd_args
.length
) {
413 iscsi_err(__FILE__
, __LINE__
, "read() failed\n");
419 if (args
->status
== 0) {
421 sg
[0].iov_base
= read_data
;
422 sg
[0].iov_len
= osd_args
.length
;
423 sg
[1].iov_base
= NULL
;
425 args
->send_data
= (void *) sg
;
426 args
->send_sg_len
= 1;
428 cmd
->callback
= osd_read_callback
;
429 cmd
->callback_arg
= sg
;
432 iscsi_free_atomic(read_data
);
433 args
->length
= 0; /* Need a better way of
434 * specifying an error.. */
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
);
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");
462 if (osd_args
.get_attributes_list_length
) {
465 for (i
= 0; i
< osd_args
.get_attributes_list_length
;) {
466 page
= ISCSI_NTOHL(*((uint32_t *) (&(get_list
[i
]))));
468 index
= ISCSI_NTOHL(*((uint32_t *) (&(get_list
[i
]))));
470 iscsi_trace(TRACE_OSD
, "GET(0x%x,%u)\n", page
, index
);
476 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(page
);
478 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(index
);
480 *((uint16_t *) & get_data
[attr_len
]) = ISCSI_HTONS(4);
482 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(GroupID
);
486 iscsi_err(__FILE__
, __LINE__
, "unknown attr index %u\n", index
);
493 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(page
);
495 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(index
);
497 *((uint16_t *) & get_data
[attr_len
]) = ISCSI_HTONS(4);
499 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(GroupID
);
503 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(page
);
505 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(index
);
507 *((uint16_t *) & get_data
[attr_len
]) = ISCSI_HTONS(8);
509 *((uint64_t *) & get_data
[attr_len
]) = ISCSI_HTONLL(UserID
);
513 iscsi_err(__FILE__
, __LINE__
, "unknown attr index %u\n", index
);
518 /* Vendor-specific */
523 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(page
);
525 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(index
);
527 *((uint16_t *) & get_data
[attr_len
]) = ISCSI_HTONS(480);
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");
542 iscsi_err(__FILE__
, __LINE__
, "unknown vendor attr index %u\n", index
);
548 iscsi_err(__FILE__
, __LINE__
, "unknown page 0x%x\n", page
);
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
) {
565 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(page
);
567 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(index
);
569 *((uint16_t *) & get_data
[attr_len
]) = ISCSI_HTONS(4);
571 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(GroupID
);
577 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(page
);
579 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(index
);
581 *((uint16_t *) & get_data
[attr_len
]) = ISCSI_HTONS(8);
583 *((uint64_t *) & get_data
[attr_len
]) = ISCSI_HTONLL(UserID
);
589 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(page
);
591 *((uint32_t *) & get_data
[attr_len
]) = ISCSI_HTONL(index
);
593 *((uint16_t *) & get_data
[attr_len
]) = ISCSI_HTONS(480);
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");
608 iscsi_err(__FILE__
, __LINE__
, "page not yet supported\n");
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
);
620 sg
[sg_len
].iov_base
= get_data
;
621 sg
[sg_len
].iov_len
= osd_args
.get_attributes_allocation_length
;
623 sg
[sg_len
].iov_base
= NULL
;
624 sg
[sg_len
].iov_len
= 0;
625 args
->send_data
= (void *) sg
;
627 cmd
->callback
= osd_read_callback
;
628 cmd
->callback_arg
= sg
;
631 iscsi_free_atomic(get_data
);
637 iscsi_err(__FILE__
, __LINE__
, "UNKNOWN OPCODE 0x%x\n", args
->cdb
[0]);
644 iscsi_trace(TRACE_SCSI_DEBUG
, "SCSI op 0x%x: done (status 0x%x)\n", args
->cdb
[0], args
->status
);
646 iscsi_free_atomic(set_list
);
649 iscsi_free_atomic(get_list
);
652 iscsi_free_atomic(write_data
);
659 device_shutdown(target_session_t
*sess
)