xref: /netbsd-src/external/bsd/iscsi/dist/src/osd/osd.c (revision 5e01dafb5c1f3a68ee2f80136c3b6043ad89a0f3)
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