1534fa804Sagc /*
2534fa804Sagc * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or
3534fa804Sagc * using the software you agree to this license. If you do not agree to this license, do not download, install,
4534fa804Sagc * copy or use the software.
5534fa804Sagc *
6534fa804Sagc * Intel License Agreement
7534fa804Sagc *
8534fa804Sagc * Copyright (c) 2000, Intel Corporation
9534fa804Sagc * All rights reserved.
10534fa804Sagc *
11534fa804Sagc * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
12534fa804Sagc * the following conditions are met:
13534fa804Sagc *
14534fa804Sagc * -Redistributions of source code must retain the above copyright notice, this list of conditions and the
15534fa804Sagc * following disclaimer.
16534fa804Sagc *
17534fa804Sagc * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
18534fa804Sagc * following disclaimer in the documentation and/or other materials provided with the distribution.
19534fa804Sagc *
20534fa804Sagc * -The name of Intel Corporation may not be used to endorse or promote products derived from this software
21534fa804Sagc * without specific prior written permission.
22534fa804Sagc *
23534fa804Sagc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
24534fa804Sagc * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25534fa804Sagc * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26534fa804Sagc * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27534fa804Sagc * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28534fa804Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29534fa804Sagc * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30534fa804Sagc * POSSIBILITY OF SUCH DAMAGE.
31534fa804Sagc */
32534fa804Sagc #include "config.h"
33534fa804Sagc
34534fa804Sagc #include <sys/types.h>
35534fa804Sagc
36534fa804Sagc #ifdef HAVE_NETINET_IN_H
37534fa804Sagc #include <netinet/in.h>
38534fa804Sagc #endif
39534fa804Sagc
40534fa804Sagc #ifdef HAVE_SYS_MMAN_H
41534fa804Sagc #include <sys/mman.h>
42534fa804Sagc #endif
43534fa804Sagc
44534fa804Sagc #ifdef HAVE_SYS_UIO_H
45534fa804Sagc #include <sys/uio.h>
46534fa804Sagc #endif
47534fa804Sagc
48534fa804Sagc #ifdef HAVE_SYS_TIME_H
49534fa804Sagc #include <sys/time.h>
50534fa804Sagc #endif
51534fa804Sagc
52534fa804Sagc #ifdef HAVE_SYS_STAT_H
53534fa804Sagc #include <sys/stat.h>
54534fa804Sagc #endif
55534fa804Sagc
56534fa804Sagc #ifdef HAVE_SYS_VFS_H
57534fa804Sagc #include <sys/vfs.h>
58534fa804Sagc #endif
59534fa804Sagc
60534fa804Sagc #include <stdio.h>
61534fa804Sagc #include <stdlib.h>
62534fa804Sagc
63534fa804Sagc #ifdef HAVE_STRING_H
64534fa804Sagc #include <string.h>
65534fa804Sagc #endif
66534fa804Sagc
67534fa804Sagc #include <unistd.h>
68534fa804Sagc
69534fa804Sagc #ifdef HAVE_ERRNO_H
70534fa804Sagc #include <errno.h>
71534fa804Sagc #endif
72534fa804Sagc
73534fa804Sagc #include <unistd.h>
74534fa804Sagc
75534fa804Sagc #ifdef HAVE_FCNTL_H
76534fa804Sagc #include <fcntl.h>
77534fa804Sagc #endif
78534fa804Sagc
79534fa804Sagc #ifdef HAVE_UTIME_H
80534fa804Sagc #include <utime.h>
81534fa804Sagc #endif
82534fa804Sagc
83534fa804Sagc #include "scsi_cmd_codes.h"
84534fa804Sagc
85534fa804Sagc #include "iscsi.h"
86534fa804Sagc #include "iscsiutil.h"
87534fa804Sagc #include "device.h"
88534fa804Sagc #include "osd.h"
89534fa804Sagc
90534fa804Sagc /*
91534fa804Sagc * Globals
92534fa804Sagc */
93534fa804Sagc
94534fa804Sagc static int osd_luns = CONFIG_OSD_LUNS_DFLT;
95534fa804Sagc static uint64_t osd_capacity = CONFIG_OSD_CAPACITY_DFLT * 1048576;
96534fa804Sagc static char base_dir[64] = CONFIG_OSD_BASEDIR_DFLT;
97534fa804Sagc
98534fa804Sagc #ifndef __KERNEL__
99534fa804Sagc void
device_set_var(const char * var,char * arg)100534fa804Sagc device_set_var(const char *var, char *arg)
101534fa804Sagc {
102534fa804Sagc if (strcmp(var, "capacity") == 0) {
103534fa804Sagc osd_capacity = strtoll(arg, (char **) NULL, 10) * 1048576;
104534fa804Sagc } else if (strcmp(var, "luns") == 0) {
105534fa804Sagc osd_luns = atoi(arg);
106534fa804Sagc } else if (strcmp(var, "directory") == 0) {
107534fa804Sagc (void) strlcpy(base_dir, arg, sizeof(base_dir));
108534fa804Sagc } else {
109534fa804Sagc (void) fprintf(stderr, "Unrecognised variable: `%s'\n", var);
110534fa804Sagc }
111534fa804Sagc }
112534fa804Sagc #endif
113534fa804Sagc
114534fa804Sagc int
device_init(globals_t * gp,char * dev)115534fa804Sagc device_init(globals_t *gp, char *dev)
116534fa804Sagc {
117534fa804Sagc struct stat st;
118534fa804Sagc char FileName[1024];
119534fa804Sagc int i;
120534fa804Sagc
121534fa804Sagc if (stat(base_dir, &st) < 0) {
122534fa804Sagc
123534fa804Sagc /* Create directory for OSD */
124534fa804Sagc
125534fa804Sagc if (mkdir(base_dir, 0755) != 0) {
126534fa804Sagc if (errno != EEXIST) {
127*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "error creating directory \"%s\" for OSD: errno %d\n", base_dir, errno);
128534fa804Sagc return -1;
129534fa804Sagc }
130534fa804Sagc }
131534fa804Sagc /* Create directory for LU */
132534fa804Sagc
133534fa804Sagc for (i = 0; i < osd_luns; i++) {
134534fa804Sagc sprintf(FileName, "%s/lun_%d", base_dir, i);
135534fa804Sagc if (mkdir(FileName, 0755) != 0) {
136534fa804Sagc if (errno != EEXIST) {
137*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "error creating \"%s\" for LU %d: errno %d\n", FileName, i, errno);
138534fa804Sagc return -1;
139534fa804Sagc }
140534fa804Sagc }
141534fa804Sagc }
142534fa804Sagc }
143534fa804Sagc /* Display LU info */
144534fa804Sagc
145534fa804Sagc return 0;
146534fa804Sagc }
147534fa804Sagc
148534fa804Sagc int
osd_read_callback(void * arg)149534fa804Sagc osd_read_callback(void *arg)
150534fa804Sagc {
151534fa804Sagc struct iovec *sg = (struct iovec *) arg;
152534fa804Sagc int i = 0;
153534fa804Sagc
154534fa804Sagc while (sg[i].iov_base != NULL) {
155534fa804Sagc iscsi_free_atomic(sg[i].iov_base);
156534fa804Sagc i++;
157534fa804Sagc }
158534fa804Sagc return 0;
159534fa804Sagc }
160534fa804Sagc
161534fa804Sagc int
device_command(target_session_t * sess,target_cmd_t * cmd)162534fa804Sagc device_command(target_session_t * sess, target_cmd_t * cmd)
163534fa804Sagc {
164534fa804Sagc iscsi_scsi_cmd_args_t *args = cmd->scsi_cmd;
165534fa804Sagc uint8_t *data;
166534fa804Sagc char FileName[1024];
167534fa804Sagc uint8_t *write_data = NULL;
168534fa804Sagc uint8_t *read_data = NULL;
169534fa804Sagc uint8_t *set_list = NULL;
170534fa804Sagc uint8_t *get_list = NULL;
171534fa804Sagc struct iovec sg[3];
172534fa804Sagc int sg_len = 0;
173534fa804Sagc int rc;
174534fa804Sagc osd_args_t osd_args;
175534fa804Sagc uint32_t GroupID = 0;
176534fa804Sagc uint64_t UserID = 0;
177534fa804Sagc char string[1024];
178534fa804Sagc uint8_t *get_data = NULL;
179534fa804Sagc uint32_t page = 0;
180534fa804Sagc uint32_t index = 0;
181534fa804Sagc int attr_len = 0;
182534fa804Sagc
183*5e01dafbSagc iscsi_trace(TRACE_SCSI_CMD, "SCSI op 0x%x (lun %llu)\n", args->cdb[0], args->lun);
184534fa804Sagc
185534fa804Sagc if (args->lun >= osd_luns) {
186*5e01dafbSagc iscsi_trace(TRACE_SCSI_DEBUG, "invalid lun: %llu\n", args->lun);
187534fa804Sagc args->status = 0x01;
188534fa804Sagc return 0;
189534fa804Sagc }
190534fa804Sagc args->status = 1;
191534fa804Sagc
192534fa804Sagc switch (args->cdb[0]) {
193534fa804Sagc
194534fa804Sagc case TEST_UNIT_READY:
195534fa804Sagc
196*5e01dafbSagc iscsi_trace(TRACE_SCSI_CMD, "TEST_UNIT_READY(lun %llu)\n", args->lun);
197534fa804Sagc args->status = 0;
198534fa804Sagc args->length = 0;
199534fa804Sagc break;
200534fa804Sagc
201534fa804Sagc case INQUIRY:
202534fa804Sagc
203*5e01dafbSagc iscsi_trace(TRACE_SCSI_CMD, "INQUIRY(lun %llu)\n", args->lun);
204534fa804Sagc data = args->send_data;
205534fa804Sagc memset(data, 0, args->cdb[4]); /* Clear allocated buffer */
206534fa804Sagc data[0] = 0x0e; /* Peripheral Device Type */
207534fa804Sagc /* data[1] |= 0x80; // Removable Bit */
208534fa804Sagc data[2] |= 0x02;/* ANSI-approved version */
209534fa804Sagc /* data[3] |= 0x80; // AENC */
210534fa804Sagc /* data[3] |= 0x40; // TrmIOP */
211534fa804Sagc /* data[3] |= 0x20; // NormACA */
212534fa804Sagc data[4] = args->cdb[4] - 4; /* Additional length */
213534fa804Sagc /*
214534fa804Sagc * data[7] |= 0x80; // Relative
215534fa804Sagc * addressing
216534fa804Sagc */
217534fa804Sagc data[7] |= 0x40;/* WBus32 */
218534fa804Sagc data[7] |= 0x20;/* WBus16 */
219534fa804Sagc /* data[7] |= 0x10; // Sync */
220534fa804Sagc /* data[7] |= 0x08; // Linked Commands */
221534fa804Sagc /* data[7] |= 0x04; // TransDis */
222534fa804Sagc /*
223534fa804Sagc * data[7] |= 0x02; // Tagged Command
224534fa804Sagc * Queueing
225534fa804Sagc */
226534fa804Sagc /* data[7] |= 0x01; // SftRe */
227534fa804Sagc (void) memset(data + 8, 0x0, 32);
228534fa804Sagc strlcpy(data + 8, OSD_VENDOR, 8); /* Vendor */
229534fa804Sagc strlcpy(data + 16, OSD_PRODUCT, 16); /* Product ID */
230534fa804Sagc (void) snprintf(data + 32, 8, "%d", OSD_VERSION); /* Product Revision */
231534fa804Sagc args->input = 1;
232534fa804Sagc args->length = args->cdb[4] + 1;
233534fa804Sagc args->status = 0;
234534fa804Sagc
235534fa804Sagc break;
236534fa804Sagc
237534fa804Sagc case 0x7F:
238534fa804Sagc
239534fa804Sagc OSD_DECAP_CDB(args->cdb, args->ext_cdb, &osd_args);
240534fa804Sagc /* OSD_PRINT_CDB(args->cdb, args->ext_cdb); */
241534fa804Sagc GroupID = osd_args.GroupID;
242534fa804Sagc UserID = osd_args.UserID;
243534fa804Sagc
244534fa804Sagc /*
245534fa804Sagc * Transfer all data
246534fa804Sagc */
247534fa804Sagc
248534fa804Sagc if (osd_args.set_attributes_list_length) {
249534fa804Sagc if ((set_list = iscsi_malloc_atomic(osd_args.set_attributes_list_length)) == NULL) {
250*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
251534fa804Sagc goto done;
252534fa804Sagc }
253534fa804Sagc sg[sg_len].iov_base = set_list;
254534fa804Sagc sg[sg_len].iov_len = osd_args.set_attributes_list_length;
255534fa804Sagc sg_len++;
256534fa804Sagc }
257534fa804Sagc if (osd_args.get_attributes_list_length) {
258534fa804Sagc if ((get_list = iscsi_malloc_atomic(osd_args.get_attributes_list_length)) == NULL) {
259*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
260534fa804Sagc goto done;
261534fa804Sagc }
262534fa804Sagc sg[sg_len].iov_base = get_list;
263534fa804Sagc sg[sg_len].iov_len = osd_args.get_attributes_list_length;
264534fa804Sagc sg_len++;
265534fa804Sagc }
266534fa804Sagc if (osd_args.service_action == OSD_WRITE) {
267534fa804Sagc if ((write_data = iscsi_malloc_atomic(osd_args.length)) == NULL) {
268*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
269534fa804Sagc goto done;
270534fa804Sagc }
271534fa804Sagc sg[sg_len].iov_base = write_data;
272534fa804Sagc sg[sg_len].iov_len = osd_args.length;
273534fa804Sagc sg_len++;
274534fa804Sagc }
275534fa804Sagc if (sg_len) {
276534fa804Sagc if (target_transfer_data(sess, args, sg, sg_len) != 0) {
277*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "target_transfer_data() failed\n");
278534fa804Sagc goto done;
279534fa804Sagc }
280534fa804Sagc }
281534fa804Sagc /*
282534fa804Sagc * Set any attributes
283534fa804Sagc */
284534fa804Sagc
285534fa804Sagc if (osd_args.set_attributes_list_length) {
286534fa804Sagc uint32_t page, attr;
287534fa804Sagc uint16_t len;
288534fa804Sagc int i;
289534fa804Sagc
290*5e01dafbSagc iscsi_trace(TRACE_OSD, "OSD_SET_ATTR(lun %llu, GroupID 0x%x, UserID 0x%llx)\n", args->lun, osd_args.GroupID, osd_args.UserID);
291534fa804Sagc for (i = 0; i < osd_args.set_attributes_list_length;) {
292534fa804Sagc page = ISCSI_NTOHL(*((uint32_t *) (&(set_list[i]))));
293534fa804Sagc i += 4;
294534fa804Sagc attr = ISCSI_NTOHL(*((uint32_t *) (&(set_list[i]))));
295534fa804Sagc i += 4;
296534fa804Sagc len = ISCSI_NTOHS(*((uint16_t *) (&(set_list[i]))));
297534fa804Sagc i += 2;
298534fa804Sagc sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u",
299534fa804Sagc base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, attr);
300534fa804Sagc if ((rc = open(FileName, O_WRONLY | O_CREAT, 0644)) == -1) {
301*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno);
302534fa804Sagc goto done;
303534fa804Sagc }
304534fa804Sagc if (write(rc, set_list + i, len) != len) {
305*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "write() failed\n");
306534fa804Sagc }
307534fa804Sagc close(rc);
308534fa804Sagc i += len;
309*5e01dafbSagc iscsi_trace(TRACE_OSD, "SET(0x%x,%u,%u>\n", page, attr, len);
310534fa804Sagc }
311534fa804Sagc }
312534fa804Sagc args->send_sg_len = 0;
313534fa804Sagc sg_len = 0;
314534fa804Sagc
315534fa804Sagc switch (osd_args.service_action) {
316534fa804Sagc
317534fa804Sagc case OSD_CREATE_GROUP:
318534fa804Sagc
319534fa804Sagc do {
320534fa804Sagc GroupID = rand() % 1048576 * 1024 + 1;
321534fa804Sagc sprintf(FileName, "%s/lun_%llu/0x%x", base_dir, args->lun, GroupID);
322534fa804Sagc rc = mkdir(FileName, 0755);
323534fa804Sagc } while (rc == -1 && errno == EEXIST);
324*5e01dafbSagc iscsi_trace(TRACE_OSD, "OSD_CREATE_GROUP(lun %llu) --> 0x%x\n", args->lun, GroupID);
325534fa804Sagc args->status = 0;
326534fa804Sagc break;
327534fa804Sagc
328534fa804Sagc case OSD_REMOVE_GROUP:
329534fa804Sagc
330*5e01dafbSagc iscsi_trace(TRACE_OSD, "OSD_REMOVE_GROUP(lun %llu, 0x%x)\n", args->lun, osd_args.GroupID);
331534fa804Sagc sprintf(FileName, "%s/lun_%llu/0x%x", base_dir, args->lun, osd_args.GroupID);
332534fa804Sagc if ((rc = rmdir(FileName)) == -1) {
333*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "rmdir(\"%s\") failed: errno %d\n", FileName, errno);
334534fa804Sagc goto done;
335534fa804Sagc }
336534fa804Sagc args->status = 0;
337534fa804Sagc break;
338534fa804Sagc
339534fa804Sagc case OSD_CREATE:
340534fa804Sagc
341534fa804Sagc UserID = rand() % 1048576 * 1024 + 1;
342534fa804Sagc create_user_again:
343534fa804Sagc sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx",
344534fa804Sagc base_dir, args->lun, osd_args.GroupID, UserID);
345534fa804Sagc rc = open(FileName, O_CREAT | O_EXCL | O_RDWR, 0644);
346534fa804Sagc if ((rc == -1) && (errno == EEXIST)) {
347534fa804Sagc UserID = rand() % 1048576 * 1024 + 1;
348534fa804Sagc goto create_user_again;
349534fa804Sagc }
350534fa804Sagc close(rc);
351*5e01dafbSagc iscsi_trace(TRACE_OSD, "OSD_CREATE(lun %llu, GroupID 0x%x) --> 0x%llx\n", args->lun, osd_args.GroupID, UserID);
352534fa804Sagc args->status = 0;
353534fa804Sagc
354534fa804Sagc break;
355534fa804Sagc
356534fa804Sagc case OSD_REMOVE:
357534fa804Sagc
358*5e01dafbSagc iscsi_trace(TRACE_OSD, "OSD_REMOVE(lun %llu, 0x%llx)\n", args->lun, osd_args.UserID);
359534fa804Sagc sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx",
360534fa804Sagc base_dir, args->lun, osd_args.GroupID, osd_args.UserID);
361534fa804Sagc if ((rc = unlink(FileName)) == -1) {
362*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "unlink(\"%s\") failed: errno %d\n", FileName, errno);
363534fa804Sagc goto done;
364534fa804Sagc }
365534fa804Sagc sprintf(string, "rm -f %s/lun_%llu/0x%x/0x%llx.*", base_dir, args->lun, osd_args.GroupID, osd_args.UserID);
366534fa804Sagc if (system(string) != 0) {
367*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "\"%s\" failed\n", string);
368534fa804Sagc return -1;
369534fa804Sagc }
370534fa804Sagc args->status = 0;
371534fa804Sagc break;
372534fa804Sagc
373534fa804Sagc case OSD_WRITE:
374*5e01dafbSagc iscsi_trace(TRACE_OSD, "OSD_WRITE(lun %llu, GroupID 0x%x, UserID 0x%llx, length %llu, offset %llu)\n",
375534fa804Sagc args->lun, osd_args.GroupID, osd_args.UserID, osd_args.length, osd_args.offset);
376534fa804Sagc sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx",
377534fa804Sagc base_dir, args->lun, osd_args.GroupID, osd_args.UserID);
378534fa804Sagc if ((rc = open(FileName, O_WRONLY, 0644)) == -1) {
379*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno);
380534fa804Sagc goto write_done;
381534fa804Sagc }
382534fa804Sagc if (lseek(rc, osd_args.offset, SEEK_SET) == -1) {
383*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "error seeking \"%s\": errno %d\n", FileName, errno);
384534fa804Sagc goto write_done;
385534fa804Sagc }
386534fa804Sagc if (write(rc, write_data, osd_args.length) != osd_args.length) {
387*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "write() failed\n");
388534fa804Sagc goto write_done;
389534fa804Sagc }
390534fa804Sagc close(rc);
391534fa804Sagc args->status = 0;
392534fa804Sagc write_done:
393534fa804Sagc break;
394534fa804Sagc
395534fa804Sagc case OSD_READ:
396*5e01dafbSagc iscsi_trace(TRACE_OSD, "OSD_READ(lun %llu, GroupID 0x%x, UserID 0x%llx, length %llu, offset %llu)\n",
397534fa804Sagc args->lun, osd_args.GroupID, osd_args.UserID, osd_args.length, osd_args.offset);
398534fa804Sagc sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx",
399534fa804Sagc base_dir, args->lun, osd_args.GroupID, osd_args.UserID);
400534fa804Sagc if ((rc = open(FileName, O_RDONLY, 0644)) == -1) {
401*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno);
402534fa804Sagc goto read_done;
403534fa804Sagc }
404534fa804Sagc if ((read_data = iscsi_malloc_atomic(osd_args.length)) == NULL) {
405*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
406534fa804Sagc goto read_done;
407534fa804Sagc }
408534fa804Sagc if (lseek(rc, osd_args.offset, SEEK_SET) == -1) {
409*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "error seeking \"%s\": errno %d\n", FileName, errno);
410534fa804Sagc goto read_done;
411534fa804Sagc }
412534fa804Sagc if (read(rc, read_data, osd_args.length) != osd_args.length) {
413*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "read() failed\n");
414534fa804Sagc goto read_done;
415534fa804Sagc }
416534fa804Sagc close(rc);
417534fa804Sagc args->status = 0;
418534fa804Sagc read_done:
419534fa804Sagc if (args->status == 0) {
420534fa804Sagc args->input = 1;
421534fa804Sagc sg[0].iov_base = read_data;
422534fa804Sagc sg[0].iov_len = osd_args.length;
423534fa804Sagc sg[1].iov_base = NULL;
424534fa804Sagc sg[1].iov_len = 0;
425534fa804Sagc args->send_data = (void *) sg;
426534fa804Sagc args->send_sg_len = 1;
427534fa804Sagc sg_len++;
428534fa804Sagc cmd->callback = osd_read_callback;
429534fa804Sagc cmd->callback_arg = sg;
430534fa804Sagc } else {
431534fa804Sagc if (read_data)
432534fa804Sagc iscsi_free_atomic(read_data);
433534fa804Sagc args->length = 0; /* Need a better way of
434534fa804Sagc * specifying an error.. */
435534fa804Sagc }
436534fa804Sagc break;
437534fa804Sagc
438534fa804Sagc case OSD_GET_ATTR:
439*5e01dafbSagc iscsi_trace(TRACE_OSD, "OSD_GET_ATTR(lun %llu, GroupID 0x%x, UserID 0x%llx)\n",
440534fa804Sagc args->lun, osd_args.GroupID, osd_args.UserID);
441534fa804Sagc args->status = 0;
442534fa804Sagc break;
443534fa804Sagc
444534fa804Sagc case OSD_SET_ATTR:
445534fa804Sagc args->status = 0;
446534fa804Sagc break;
447534fa804Sagc }
448534fa804Sagc
449534fa804Sagc if (args->status)
450534fa804Sagc goto done;
451534fa804Sagc
452534fa804Sagc /*
453534fa804Sagc * Send back requested attributes
454534fa804Sagc */
455534fa804Sagc
456534fa804Sagc if (osd_args.get_attributes_list_length || osd_args.get_attributes_page) {
457534fa804Sagc if ((get_data = iscsi_malloc_atomic(osd_args.get_attributes_allocation_length)) == NULL) {
458*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
459534fa804Sagc goto done;
460534fa804Sagc }
461534fa804Sagc }
462534fa804Sagc if (osd_args.get_attributes_list_length) {
463534fa804Sagc int i;
464534fa804Sagc
465534fa804Sagc for (i = 0; i < osd_args.get_attributes_list_length;) {
466534fa804Sagc page = ISCSI_NTOHL(*((uint32_t *) (&(get_list[i]))));
467534fa804Sagc i += 4;
468534fa804Sagc index = ISCSI_NTOHL(*((uint32_t *) (&(get_list[i]))));
469534fa804Sagc i += 4;
470*5e01dafbSagc iscsi_trace(TRACE_OSD, "GET(0x%x,%u)\n", page, index);
471534fa804Sagc
472534fa804Sagc switch (page) {
473534fa804Sagc case 0x40000001:
474534fa804Sagc switch (index) {
475534fa804Sagc case 0x1:
476534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page);
477534fa804Sagc attr_len += 4;
478534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index);
479534fa804Sagc attr_len += 4;
480534fa804Sagc *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4);
481534fa804Sagc attr_len += 2;
482534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID);
483534fa804Sagc attr_len += 4;
484534fa804Sagc break;
485534fa804Sagc default:
486*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "unknown attr index %u\n", index);
487534fa804Sagc goto done;
488534fa804Sagc }
489534fa804Sagc break;
490534fa804Sagc case 0x00000001:
491534fa804Sagc switch (index) {
492534fa804Sagc case 0x1:
493534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page);
494534fa804Sagc attr_len += 4;
495534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index);
496534fa804Sagc attr_len += 4;
497534fa804Sagc *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4);
498534fa804Sagc attr_len += 2;
499534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID);
500534fa804Sagc attr_len += 4;
501534fa804Sagc break;
502534fa804Sagc case 0x2:
503534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page);
504534fa804Sagc attr_len += 4;
505534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index);
506534fa804Sagc attr_len += 4;
507534fa804Sagc *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(8);
508534fa804Sagc attr_len += 2;
509534fa804Sagc *((uint64_t *) & get_data[attr_len]) = ISCSI_HTONLL(UserID);
510534fa804Sagc attr_len += 8;
511534fa804Sagc break;
512534fa804Sagc default:
513*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "unknown attr index %u\n", index);
514534fa804Sagc goto done;
515534fa804Sagc }
516534fa804Sagc break;
517534fa804Sagc
518534fa804Sagc /* Vendor-specific */
519534fa804Sagc
520534fa804Sagc case 0x30000000:
521534fa804Sagc switch (index) {
522534fa804Sagc case 0x1:
523534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page);
524534fa804Sagc attr_len += 4;
525534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index);
526534fa804Sagc attr_len += 4;
527534fa804Sagc *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(480);
528534fa804Sagc attr_len += 2;
529534fa804Sagc sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u",
530534fa804Sagc base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, index);
531534fa804Sagc if ((rc = open(FileName, O_RDONLY, 0644)) == -1) {
532*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno);
533534fa804Sagc }
534534fa804Sagc if (read(rc, get_data + attr_len, 480) != 480) {
535*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "read() failed\n");
536534fa804Sagc goto done;
537534fa804Sagc }
538534fa804Sagc close(rc);
539534fa804Sagc attr_len += 480;
540534fa804Sagc break;
541534fa804Sagc default:
542*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "unknown vendor attr index %u\n", index);
543534fa804Sagc goto done;
544534fa804Sagc }
545534fa804Sagc break;
546534fa804Sagc
547534fa804Sagc default:
548*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "unknown page 0x%x\n", page);
549534fa804Sagc goto done;
550534fa804Sagc }
551534fa804Sagc }
552534fa804Sagc }
553534fa804Sagc if (osd_args.get_attributes_page) {
554534fa804Sagc
555534fa804Sagc /*
556534fa804Sagc * Right now, if we get a request for an entire page,
557534fa804Sagc * we return only one attribute.
558534fa804Sagc */
559534fa804Sagc
560534fa804Sagc page = osd_args.get_attributes_page;
561534fa804Sagc
562534fa804Sagc switch (osd_args.get_attributes_page) {
563534fa804Sagc case 0x40000001:
564534fa804Sagc index = 1;
565534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page);
566534fa804Sagc attr_len += 4;
567534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index);
568534fa804Sagc attr_len += 4;
569534fa804Sagc *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4);
570534fa804Sagc attr_len += 2;
571534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID);
572534fa804Sagc attr_len += 4;
573534fa804Sagc break;
574534fa804Sagc
575534fa804Sagc case 0x00000001:
576534fa804Sagc index = 2;
577534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page);
578534fa804Sagc attr_len += 4;
579534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index);
580534fa804Sagc attr_len += 4;
581534fa804Sagc *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(8);
582534fa804Sagc attr_len += 2;
583534fa804Sagc *((uint64_t *) & get_data[attr_len]) = ISCSI_HTONLL(UserID);
584534fa804Sagc attr_len += 8;
585534fa804Sagc break;
586534fa804Sagc
587534fa804Sagc case 0x30000000:
588534fa804Sagc index = 1;
589534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page);
590534fa804Sagc attr_len += 4;
591534fa804Sagc *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index);
592534fa804Sagc attr_len += 4;
593534fa804Sagc *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(480);
594534fa804Sagc attr_len += 2;
595534fa804Sagc sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u",
596534fa804Sagc base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, index);
597534fa804Sagc if ((rc = open(FileName, O_RDONLY, 0644)) == -1) {
598*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno);
599534fa804Sagc }
600534fa804Sagc if (read(rc, get_data + attr_len, 480) != 480) {
601*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "read() failed\n");
602534fa804Sagc goto done;
603534fa804Sagc }
604534fa804Sagc close(rc);
605534fa804Sagc attr_len += 480;
606534fa804Sagc break;
607534fa804Sagc default:
608*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "page not yet supported\n");
609534fa804Sagc goto done;
610534fa804Sagc }
611534fa804Sagc }
612534fa804Sagc if (attr_len) {
613534fa804Sagc if (attr_len != osd_args.get_attributes_allocation_length) {
614*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "allocation lengths differ: got %u, expected %u\n",
615534fa804Sagc osd_args.get_attributes_allocation_length, attr_len);
616534fa804Sagc goto done;
617534fa804Sagc }
618534fa804Sagc if (!args->status) {
619534fa804Sagc args->input = 1;
620534fa804Sagc sg[sg_len].iov_base = get_data;
621534fa804Sagc sg[sg_len].iov_len = osd_args.get_attributes_allocation_length;
622534fa804Sagc sg_len++;
623534fa804Sagc sg[sg_len].iov_base = NULL;
624534fa804Sagc sg[sg_len].iov_len = 0;
625534fa804Sagc args->send_data = (void *) sg;
626534fa804Sagc args->send_sg_len++;
627534fa804Sagc cmd->callback = osd_read_callback;
628534fa804Sagc cmd->callback_arg = sg;
629534fa804Sagc } else {
630534fa804Sagc if (get_data)
631534fa804Sagc iscsi_free_atomic(get_data);
632534fa804Sagc }
633534fa804Sagc }
634534fa804Sagc break;
635534fa804Sagc
636534fa804Sagc default:
637*5e01dafbSagc iscsi_err(__FILE__, __LINE__, "UNKNOWN OPCODE 0x%x\n", args->cdb[0]);
638534fa804Sagc args->status = 0x01;
639534fa804Sagc break;
640534fa804Sagc }
641534fa804Sagc
642534fa804Sagc
643534fa804Sagc done:
644*5e01dafbSagc iscsi_trace(TRACE_SCSI_DEBUG, "SCSI op 0x%x: done (status 0x%x)\n", args->cdb[0], args->status);
645534fa804Sagc if (set_list) {
646534fa804Sagc iscsi_free_atomic(set_list);
647534fa804Sagc }
648534fa804Sagc if (get_list) {
649534fa804Sagc iscsi_free_atomic(get_list);
650534fa804Sagc }
651534fa804Sagc if (write_data) {
652534fa804Sagc iscsi_free_atomic(write_data);
653534fa804Sagc }
654534fa804Sagc return 0;
655534fa804Sagc }
656534fa804Sagc
657534fa804Sagc /* ARGSUSED */
658534fa804Sagc int
device_shutdown(target_session_t * sess)659534fa804Sagc device_shutdown(target_session_t *sess)
660534fa804Sagc {
661534fa804Sagc return 0;
662534fa804Sagc }
663