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