1 /*
2    Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as published by
6    the Free Software Foundation; either version 2.1 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public License
15    along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17 /*
18  * would be nice if this could grow into a full blown library to
19  * 1, build and unmarshall a CDB
20  * 2, check how big a complete data-in structure needs to be
21  * 3, unmarshall data-in into a real structure
22  * 4, marshall a real structure into a data-out blob
23  */
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 
32 #ifdef HAVE_ARPA_INET_H
33 #include <arpa/inet.h>
34 #endif
35 
36 #ifdef AROS
37 #include "aros/aros_compat.h"
38 #endif
39 
40 #if defined(_WIN32)
41 #include <winsock2.h>
42 #include "win32/win32_compat.h"
43 #else
44 #include <strings.h>
45 #endif
46 
47 #ifdef HAVE_SYS_SOCKET_H
48 #include <sys/socket.h>
49 #endif
50 
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <stddef.h>
54 #include <string.h>
55 #include <stdint.h>
56 #include <errno.h>
57 #include "slist.h"
58 #include "scsi-lowlevel.h"
59 
60 void scsi_task_set_iov_out(struct scsi_task *task, struct scsi_iovec *iov, int niov);
61 
62 struct scsi_allocated_memory {
63 	struct scsi_allocated_memory *next;
64 	char buf[0];
65 };
66 
67 void
scsi_free_scsi_task(struct scsi_task * task)68 scsi_free_scsi_task(struct scsi_task *task)
69 {
70 	struct scsi_allocated_memory *mem;
71 
72 	if (!task)
73 		return;
74 
75 	while ((mem = task->mem)) {
76 		   ISCSI_LIST_REMOVE(&task->mem, mem);
77 		   free(mem);
78 	}
79 
80 	free(task->datain.data);
81 	free(task);
82 }
83 
84 struct scsi_task *
scsi_create_task(int cdb_size,unsigned char * cdb,int xfer_dir,int expxferlen)85 scsi_create_task(int cdb_size, unsigned char *cdb, int xfer_dir, int expxferlen)
86 {
87 	struct scsi_task *task;
88 
89 	task = malloc(sizeof(struct scsi_task));
90 	if (task == NULL) {
91 		return NULL;
92 	}
93 
94 	memset(task, 0, sizeof(struct scsi_task));
95 
96 	memcpy(&task->cdb[0], cdb, cdb_size);
97 	task->cdb_size   = cdb_size;
98 	task->xfer_dir   = xfer_dir;
99 	task->expxferlen = expxferlen;
100 
101 	return task;
102 }
103 
104 
105 void *
scsi_malloc(struct scsi_task * task,size_t size)106 scsi_malloc(struct scsi_task *task, size_t size)
107 {
108 	struct scsi_allocated_memory *mem;
109 
110 	mem = malloc(sizeof(struct scsi_allocated_memory) + size);
111 	if (mem == NULL) {
112 		return NULL;
113 	}
114 	memset(mem, 0, sizeof(struct scsi_allocated_memory) + size);
115 	ISCSI_LIST_ADD(&task->mem, mem);
116 	return &mem->buf[0];
117 }
118 
119 struct value_string {
120    int value;
121    const char *string;
122 };
123 
124 static const char *
value_string_find(struct value_string * values,int value)125 value_string_find(struct value_string *values, int value)
126 {
127 	for (; values->string; values++) {
128 		if (value == values->value) {
129 			return values->string;
130 		}
131 	}
132 	return NULL;
133 }
134 
135 const char *
scsi_sense_key_str(int key)136 scsi_sense_key_str(int key)
137 {
138 	struct value_string keys[] = {
139 		{SCSI_SENSE_NO_SENSE,
140 		 "NO SENSE"},
141 		{SCSI_SENSE_RECOVERED_ERROR,
142 		 "RECOVERED ERROR"},
143 		{SCSI_SENSE_NOT_READY,
144 		 "NOT READY"},
145 		{SCSI_SENSE_HARDWARE_ERROR,
146 		 "HARDWARE_ERROR"},
147 		{SCSI_SENSE_ILLEGAL_REQUEST,
148 		 "ILLEGAL_REQUEST"},
149 		{SCSI_SENSE_UNIT_ATTENTION,
150 		 "UNIT_ATTENTION"},
151 		{SCSI_SENSE_DATA_PROTECTION,
152 		 "DATA PROTECTION"},
153 		{SCSI_SENSE_BLANK_CHECK,
154 		 "BLANK CHECK"},
155 		{SCSI_SENSE_VENDOR_SPECIFIC,
156 		 "VENDOR SPECIFIC"},
157 		{SCSI_SENSE_COPY_ABORTED,
158 		 "COPY ABORTED"},
159 		{SCSI_SENSE_COMMAND_ABORTED,
160 		 "COMMAND ABORTED"},
161 		{SCSI_SENSE_OBSOLETE_ERROR_CODE,
162 		 "OBSOLETE_ERROR_CODE"},
163 		{SCSI_SENSE_OVERFLOW_COMMAND,
164 		 "OVERFLOW_COMMAND"},
165 		{SCSI_SENSE_MISCOMPARE,
166 		 "MISCOMPARE"},
167 	       {0, NULL}
168 	};
169 
170 	return value_string_find(keys, key);
171 }
172 
173 const char *
scsi_sense_ascq_str(int ascq)174 scsi_sense_ascq_str(int ascq)
175 {
176 	struct value_string ascqs[] = {
177 		{SCSI_SENSE_ASCQ_SANITIZE_IN_PROGRESS,
178 		 "SANITIZE_IN_PROGRESS"},
179 		{SCSI_SENSE_ASCQ_WRITE_AFTER_SANITIZE_REQUIRED,
180 		 "WRITE_AFTER_SANITIZE_REQUIRED"},
181 		{SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE,
182 		 "INVALID_OPERATION_CODE"},
183 		{SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE,
184 		 "LBA_OUT_OF_RANGE"},
185 		{SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB,
186 		 "INVALID_FIELD_IN_CDB"},
187 		{SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED,
188 		 "LOGICAL_UNIT_NOT_SUPPORTED"},
189 		{SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR,
190 		 "PARAMETER_LIST_LENGTH_ERROR"},
191 		{SCSI_SENSE_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST,
192 		 "INVALID_FIELD_IN_PARAMETER_LIST"},
193 		{SCSI_SENSE_ASCQ_WRITE_PROTECTED,
194 		 "WRITE_PROTECTED"},
195 		{SCSI_SENSE_ASCQ_WRITE_PROTECTED,
196 		 "WRITE_PROTECTED"},
197 		{SCSI_SENSE_ASCQ_HARDWARE_WRITE_PROTECTED,
198 		 "HARDWARE_WRITE_PROTECTED"},
199 		{SCSI_SENSE_ASCQ_SOFTWARE_WRITE_PROTECTED,
200 		 "SOFTWARE_WRITE_PROTECTED"},
201 		{SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT,
202 		 "MEDIUM_NOT_PRESENT"},
203 		{SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED,
204 		 "MEDIUM_NOT_PRESENT-TRAY_CLOSED"},
205 		{SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN,
206 		 "MEDIUM_NOT_PRESENT-TRAY_OPEN"},
207 		{SCSI_SENSE_ASCQ_BUS_RESET,
208 		 "BUS_RESET"},
209 		{SCSI_SENSE_ASCQ_POWER_ON_OCCURED,
210 		 "POWER_ON_OCCURED"},
211 		{SCSI_SENSE_ASCQ_SCSI_BUS_RESET_OCCURED,
212 		 "SCSI_BUS_RESET_OCCURED"},
213 		{SCSI_SENSE_ASCQ_BUS_DEVICE_RESET_FUNCTION_OCCURED,
214 		 "BUS_DEVICE_RESET_FUNCTION_OCCURED"},
215 		{SCSI_SENSE_ASCQ_DEVICE_INTERNAL_RESET,
216 		 "DEVICE_INTERNAL_RESET"},
217 		{SCSI_SENSE_ASCQ_TRANSCEIVER_MODE_CHANGED_TO_SINGLE_ENDED,
218 		 "TRANSCEIVER_MODE_CHANGED_TO_SINGLE_ENDED"},
219 		{SCSI_SENSE_ASCQ_TRANSCEIVER_MODE_CHANGED_TO_LVD,
220 		 "TRANSCEIVER_MODE_CHANGED_TO_LVD"},
221 		{SCSI_SENSE_ASCQ_MODE_PARAMETERS_CHANGED,
222 		 "MODE PARAMETERS CHANGED"},
223 		{SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED,
224 		 "CAPACITY_DATA_HAS_CHANGED"},
225 		{SCSI_SENSE_ASCQ_THIN_PROVISION_SOFT_THRES_REACHED,
226 		 "THIN PROVISIONING SOFT THRESHOLD REACHED"},
227 		{SCSI_SENSE_ASCQ_INQUIRY_DATA_HAS_CHANGED,
228 		 "INQUIRY DATA HAS CHANGED"},
229 		{SCSI_SENSE_ASCQ_INTERNAL_TARGET_FAILURE,
230 		 "INTERNAL_TARGET_FAILURE"},
231 		{SCSI_SENSE_ASCQ_MISCOMPARE_DURING_VERIFY,
232 		 "MISCOMPARE_DURING_VERIFY"},
233 		{SCSI_SENSE_ASCQ_MISCOMPARE_VERIFY_OF_UNMAPPED_LBA,
234 		 "MISCOMPARE_VERIFY_OF_UNMAPPED_LBA"},
235 		{ SCSI_SENSE_ASCQ_MEDIUM_LOAD_OR_EJECT_FAILED,
236 		  "MEDIUM_LOAD_OR_EJECT_FAILED" },
237 		{SCSI_SENSE_ASCQ_MEDIUM_REMOVAL_PREVENTED,
238 		 "SCSI_SENSE_ASCQ_MEDIUM_REMOVAL_PREVENTED"},
239 	       {0, NULL}
240 	};
241 
242 	return value_string_find(ascqs, ascq);
243 }
244 
245 const char *
scsi_pr_type_str(enum scsi_persistent_out_type pr_type)246 scsi_pr_type_str(enum scsi_persistent_out_type pr_type)
247 {
248 	struct value_string pr_type_strings[] = {
249 		{SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE,
250 		 "Write Exclusive"},
251 		{SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS,
252 		 "Exclusive Access"},
253 		{SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY,
254 		 "Write Exclusive, Registrants Only"},
255 		{SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY,
256 		 "Exclusive Access Registrants Only"},
257 		{SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS,
258 		 "Write Exclusive, All Registrants"},
259 		{SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS,
260 		 "Exclusive Access, All Registrants"},
261 		{0, NULL}
262 	};
263 
264 	return value_string_find(pr_type_strings, pr_type);
265 }
266 
267 uint64_t
scsi_get_uint64(const unsigned char * c)268 scsi_get_uint64(const unsigned char *c)
269 {
270 	uint64_t val;
271 
272 	val = scsi_get_uint32(c);
273 	val <<= 32;
274 	c += 4;
275 	val |= scsi_get_uint32(c);
276 
277 	return val;
278 }
279 
280 uint32_t
scsi_get_uint32(const unsigned char * c)281 scsi_get_uint32(const unsigned char *c)
282 {
283 	uint32_t val;
284 	val = c[0];
285 	val = (val << 8) | c[1];
286 	val = (val << 8) | c[2];
287 	val = (val << 8) | c[3];
288 	return val;
289 }
290 
291 uint16_t
scsi_get_uint16(const unsigned char * c)292 scsi_get_uint16(const unsigned char *c)
293 {
294 	uint16_t val;
295 	val = c[0];
296 	val = (val << 8) | c[1];
297 	return val;
298 }
299 
300 static inline uint64_t
task_get_uint64(struct scsi_task * task,int offset)301 task_get_uint64(struct scsi_task *task, int offset)
302 {
303 	if (offset <= task->datain.size - 8) {
304 		const unsigned char *c = &task->datain.data[offset];
305 
306 		return scsi_get_uint64(c);
307 	} else {
308 		return 0;
309 	}
310 }
311 
312 static inline uint32_t
task_get_uint32(struct scsi_task * task,int offset)313 task_get_uint32(struct scsi_task *task, int offset)
314 {
315 	if (offset <= task->datain.size - 4) {
316 		const unsigned char *c = &task->datain.data[offset];
317 
318 		return scsi_get_uint32(c);
319 	} else {
320 		return 0;
321 	}
322 }
323 
324 static inline uint16_t
task_get_uint16(struct scsi_task * task,int offset)325 task_get_uint16(struct scsi_task *task, int offset)
326 {
327 	if (offset <= task->datain.size - 2) {
328 		const unsigned char *c = &task->datain.data[offset];
329 
330 		return scsi_get_uint16(c);
331 	} else {
332 		return 0;
333 	}
334 }
335 
336 static inline uint8_t
task_get_uint8(struct scsi_task * task,int offset)337 task_get_uint8(struct scsi_task *task, int offset)
338 {
339 	if (offset <= task->datain.size - 1) {
340 		return task->datain.data[offset];
341 	} else {
342 		return 0;
343 	}
344 }
345 
346 void
scsi_set_uint64(unsigned char * c,uint64_t v)347 scsi_set_uint64(unsigned char *c, uint64_t v)
348 {
349 	uint32_t val;
350 
351 	val = (v >> 32) & 0xffffffff;
352 	scsi_set_uint32(c, val);
353 
354 	c += 4;
355 	val = v & 0xffffffff;
356 	scsi_set_uint32(c, val);
357 }
358 
359 void
scsi_set_uint32(unsigned char * c,uint32_t val)360 scsi_set_uint32(unsigned char *c, uint32_t val)
361 {
362 	c[0] = val >> 24;
363 	c[1] = val >> 16;
364 	c[2] = val >> 8;
365 	c[3] = val;
366 }
367 
368 void
scsi_set_uint16(unsigned char * c,uint16_t val)369 scsi_set_uint16(unsigned char *c, uint16_t val)
370 {
371 	c[0] = val >> 8;
372 	c[1] = val;
373 }
374 
375 /*
376  * TESTUNITREADY
377  */
378 struct scsi_task *
scsi_cdb_testunitready(void)379 scsi_cdb_testunitready(void)
380 {
381 	struct scsi_task *task;
382 
383 	task = malloc(sizeof(struct scsi_task));
384 	if (task == NULL) {
385 		return NULL;
386 	}
387 
388 	memset(task, 0, sizeof(struct scsi_task));
389 	task->cdb[0]   = SCSI_OPCODE_TESTUNITREADY;
390 
391 	task->cdb_size   = 6;
392 	task->xfer_dir   = SCSI_XFER_NONE;
393 	task->expxferlen = 0;
394 
395 	return task;
396 }
397 
398 /*
399  * SANITIZE
400  */
401 struct scsi_task *
scsi_cdb_sanitize(int immed,int ause,int sa,int param_len)402 scsi_cdb_sanitize(int immed, int ause, int sa, int param_len)
403 {
404 	struct scsi_task *task;
405 
406 	task = malloc(sizeof(struct scsi_task));
407 	if (task == NULL) {
408 		return NULL;
409 	}
410 
411 	memset(task, 0, sizeof(struct scsi_task));
412 	task->cdb[0]   = SCSI_OPCODE_SANITIZE;
413 
414 	task->cdb[1] = sa & 0x1f;
415 	if (immed) {
416 		task->cdb[1] |= 0x80;
417 	}
418 	if (ause) {
419 		task->cdb[1] |= 0x20;
420 	}
421 
422 	scsi_set_uint16(&task->cdb[7], param_len);
423 
424 	task->cdb_size   = 10;
425 	if (param_len != 0) {
426 		task->xfer_dir = SCSI_XFER_WRITE;
427 	} else {
428 		task->xfer_dir = SCSI_XFER_NONE;
429 	}
430 	task->expxferlen = (param_len + 3) & 0xfffc;
431 
432 	return task;
433 }
434 
435 /*
436  * REPORTLUNS
437  */
438 struct scsi_task *
scsi_reportluns_cdb(int report_type,int alloc_len)439 scsi_reportluns_cdb(int report_type, int alloc_len)
440 {
441 	struct scsi_task *task;
442 
443 	task = malloc(sizeof(struct scsi_task));
444 	if (task == NULL) {
445 		return NULL;
446 	}
447 
448 	memset(task, 0, sizeof(struct scsi_task));
449 	task->cdb[0]   = SCSI_OPCODE_REPORTLUNS;
450 	task->cdb[2]   = report_type;
451 	scsi_set_uint32(&task->cdb[6], alloc_len);
452 
453 	task->cdb_size = 12;
454 	if (alloc_len != 0) {
455 		task->xfer_dir = SCSI_XFER_READ;
456 	} else {
457 		task->xfer_dir = SCSI_XFER_NONE;
458 	}
459 	task->expxferlen = alloc_len;
460 
461 	return task;
462 }
463 
464 /*
465  * parse the data in blob and calculate the size of a full report luns
466  * datain structure
467  */
468 static int
scsi_reportluns_datain_getfullsize(struct scsi_task * task)469 scsi_reportluns_datain_getfullsize(struct scsi_task *task)
470 {
471 	uint32_t list_size;
472 
473 	list_size = task_get_uint32(task, 0) + 8;
474 
475 	return list_size;
476 }
477 
478 /*
479  * unmarshall the data in blob for reportluns into a structure
480  */
481 static struct scsi_reportluns_list *
scsi_reportluns_datain_unmarshall(struct scsi_task * task)482 scsi_reportluns_datain_unmarshall(struct scsi_task *task)
483 {
484 	struct scsi_reportluns_list *list;
485 	int list_size;
486 	int i, num_luns;
487 
488 	if (task->datain.size < 4) {
489 		return NULL;
490 	}
491 
492 	list_size = task_get_uint32(task, 0) + 8;
493 	if (list_size < task->datain.size) {
494 		return NULL;
495 	}
496 
497 	num_luns = list_size / 8 - 1;
498 	list = scsi_malloc(task, offsetof(struct scsi_reportluns_list, luns)
499 			   + sizeof(uint16_t) * num_luns);
500 	if (list == NULL) {
501 		return NULL;
502 	}
503 
504 	list->num = num_luns;
505 	for (i = 0; i < num_luns; i++) {
506 		list->luns[i] = task_get_uint16(task, i * 8 + 8);
507 	}
508 
509 	return list;
510 }
511 
512 /*
513  * READCAPACITY10
514  */
515 struct scsi_task *
scsi_cdb_readcapacity10(int lba,int pmi)516 scsi_cdb_readcapacity10(int lba, int pmi)
517 {
518 	struct scsi_task *task;
519 
520 	task = malloc(sizeof(struct scsi_task));
521 	if (task == NULL) {
522 		return NULL;
523 	}
524 
525 	memset(task, 0, sizeof(struct scsi_task));
526 	task->cdb[0]   = SCSI_OPCODE_READCAPACITY10;
527 
528 	scsi_set_uint32(&task->cdb[2], lba);
529 
530 	if (pmi) {
531 		task->cdb[8] |= 0x01;
532 	}
533 
534 	task->cdb_size = 10;
535 	task->xfer_dir = SCSI_XFER_READ;
536 	task->expxferlen = 8;
537 
538 	return task;
539 }
540 
541 /*
542  * READDEFECTDATA10
543  */
544 struct scsi_task *
scsi_cdb_readdefectdata10(int req_plist,int req_glist,int defect_list_format,uint16_t alloc_len)545 scsi_cdb_readdefectdata10(int req_plist, int req_glist, int defect_list_format,
546                           uint16_t alloc_len)
547 {
548 	struct scsi_task *task;
549 
550 	task = malloc(sizeof(struct scsi_task));
551 	if (task == NULL) {
552 		return NULL;
553 	}
554 
555 	memset(task, 0, sizeof(struct scsi_task));
556 	task->cdb[0]   = SCSI_OPCODE_READ_DEFECT_DATA10;
557 
558         if (req_plist) {
559                 task->cdb[2] |= 0x10;
560 	}
561         if (req_glist) {
562                 task->cdb[2] |= 0x08;
563 	}
564         task->cdb[2] |= (defect_list_format & 0x07);
565 
566 	scsi_set_uint16(&task->cdb[7], alloc_len);
567 
568 	task->cdb_size = 10;
569 	task->xfer_dir = SCSI_XFER_READ;
570 	task->expxferlen = alloc_len;
571 
572 	return task;
573 }
574 
575 /*
576  * READDEFECTDATA12
577  */
578 struct scsi_task *
scsi_cdb_readdefectdata12(int req_plist,int req_glist,int defect_list_format,uint32_t address_descriptor_index,uint32_t alloc_len)579 scsi_cdb_readdefectdata12(int req_plist, int req_glist, int defect_list_format,
580                           uint32_t address_descriptor_index, uint32_t alloc_len)
581 {
582 	struct scsi_task *task;
583 
584 	task = malloc(sizeof(struct scsi_task));
585 	if (task == NULL) {
586 		return NULL;
587 	}
588 
589 	memset(task, 0, sizeof(struct scsi_task));
590 	task->cdb[0]   = SCSI_OPCODE_READ_DEFECT_DATA12;
591 
592         if (req_plist) {
593                 task->cdb[2] |= 0x10;
594 	}
595         if (req_glist) {
596                 task->cdb[2] |= 0x08;
597 	}
598         task->cdb[2] |= (defect_list_format & 0x07);
599 
600 	scsi_set_uint32(&task->cdb[2], address_descriptor_index);
601 	scsi_set_uint32(&task->cdb[6], alloc_len);
602 
603 	task->cdb_size = 12;
604 	task->xfer_dir = SCSI_XFER_READ;
605 	task->expxferlen = alloc_len;
606 
607 	return task;
608 }
609 
610 /*
611  * READTOC
612  */
613 struct scsi_task *
scsi_cdb_readtoc(int msf,int format,int track_session,uint16_t alloc_len)614 scsi_cdb_readtoc(int msf, int format, int track_session, uint16_t alloc_len)
615 {
616 	struct scsi_task *task;
617 
618 	if (format != SCSI_READ_TOC && format != SCSI_READ_SESSION_INFO
619 	    && format != SCSI_READ_FULL_TOC){
620 		fprintf(stderr, "Read TOC format %d not fully supported yet\n", format);
621 		return NULL;
622 	}
623 
624 	task = malloc(sizeof(struct scsi_task));
625 	if (task == NULL) {
626 		return NULL;
627 	}
628 
629 	memset(task, 0, sizeof(struct scsi_task));
630 	task->cdb[0]   = SCSI_OPCODE_READTOC;
631 
632 	if (msf) {
633 		task->cdb[1] |= 0x02;
634 	}
635 
636 	task->cdb[2] = format & 0xf;
637 
638 	/* Prevent invalid setting of Track/Session Number */
639 	if (format == SCSI_READ_TOC || format == SCSI_READ_FULL_TOC) {
640 		task->cdb[6] = 0xff & track_session;
641 	}
642 
643 	scsi_set_uint16(&task->cdb[7], alloc_len);
644 
645 	task->cdb_size = 10;
646 	if (alloc_len != 0) {
647 		task->xfer_dir = SCSI_XFER_READ;
648 	} else {
649 		task->xfer_dir = SCSI_XFER_NONE;
650 	}
651 	task->expxferlen = alloc_len;
652 
653 	return task;
654 }
655 
656 /*
657  * parse the data in blob and calculate the size of a full read TOC
658  * datain structure
659  */
660 static int
scsi_readtoc_datain_getfullsize(struct scsi_task * task)661 scsi_readtoc_datain_getfullsize(struct scsi_task *task)
662 {
663 	uint16_t toc_data_len;
664 
665 	toc_data_len = task_get_uint16(task, 0) + 2;
666 
667 	return toc_data_len;
668 }
669 
670 static inline enum scsi_readtoc_fmt
scsi_readtoc_format(const struct scsi_task * task)671 scsi_readtoc_format(const struct scsi_task *task)
672 {
673 	return task->cdb[2] & 0xf;
674 }
675 
676 static void
scsi_readtoc_desc_unmarshall(struct scsi_task * task,struct scsi_readtoc_list * list,int i)677 scsi_readtoc_desc_unmarshall(struct scsi_task *task, struct scsi_readtoc_list *list, int i)
678 {
679 	switch(scsi_readtoc_format(task)) {
680 	case SCSI_READ_TOC:
681 		list->desc[i].desc.toc.adr
682 			= task_get_uint8(task, 4 + 8 * i + 1) & 0xf0;
683 		list->desc[i].desc.toc.control
684 			= task_get_uint8(task, 4 + 8 * i + 1) & 0x0f;
685 		list->desc[i].desc.toc.track
686 			= task_get_uint8(task, 4 + 8 * i + 2);
687 		list->desc[i].desc.toc.lba
688 			= task_get_uint32(task, 4 + 8 * i + 4);
689 		break;
690 	case SCSI_READ_SESSION_INFO:
691 		list->desc[i].desc.ses.adr
692 			= task_get_uint8(task, 4 + 8 * i + 1) & 0xf0;
693 		list->desc[i].desc.ses.control
694 			= task_get_uint8(task, 4 + 8 * i + 1) & 0x0f;
695 		list->desc[i].desc.ses.first_in_last
696 			= task_get_uint8(task, 4 + 8 * i + 2);
697 		list->desc[i].desc.ses.lba
698 			= task_get_uint32(task, 4 + 8 * i + 4);
699 		break;
700 	case SCSI_READ_FULL_TOC:
701 		list->desc[i].desc.full.session
702 			= task_get_uint8(task, 4 + 11 * i + 0) & 0xf0;
703 		list->desc[i].desc.full.adr
704 			= task_get_uint8(task, 4 + 11 * i + 1) & 0xf0;
705 		list->desc[i].desc.full.control
706 			= task_get_uint8(task, 4 + 11 * i + 1) & 0x0f;
707 		list->desc[i].desc.full.tno
708 			= task_get_uint8(task, 4 + 11 * i + 2);
709 		list->desc[i].desc.full.point
710 			= task_get_uint8(task, 4 + 11 * i + 3);
711 		list->desc[i].desc.full.min
712 			= task_get_uint8(task, 4 + 11 * i + 4);
713 		list->desc[i].desc.full.sec
714 			= task_get_uint8(task, 4 + 11 * i + 5);
715 		list->desc[i].desc.full.frame
716 			= task_get_uint8(task, 4 + 11 * i + 6);
717 		list->desc[i].desc.full.zero
718 			= task_get_uint8(task, 4 + 11 * i + 7);
719 		list->desc[i].desc.full.pmin
720 			= task_get_uint8(task, 4 + 11 * i + 8);
721 		list->desc[i].desc.full.psec
722 			= task_get_uint8(task, 4 + 11 * i + 9);
723 		list->desc[i].desc.full.pframe
724 			= task_get_uint8(task, 4 + 11 * i + 10);
725 		break;
726 	default:
727 		break;
728 	}
729 }
730 
731 /*
732  * unmarshall the data in blob for read TOC into a structure
733  */
734 static struct scsi_readtoc_list *
scsi_readtoc_datain_unmarshall(struct scsi_task * task)735 scsi_readtoc_datain_unmarshall(struct scsi_task *task)
736 {
737 	struct scsi_readtoc_list *list;
738 	int data_len;
739 	int i, num_desc;
740 
741 	if (task->datain.size < 4) {
742 		return NULL;
743 	}
744 
745 	/* Do we have all data? */
746 	data_len = scsi_readtoc_datain_getfullsize(task) - 2;
747 	if(task->datain.size < data_len) {
748 		return NULL;
749 	}
750 
751 	/* Remove header size (4) to get bytes in descriptor list */
752 	num_desc = (data_len - 4) / 8;
753 
754 	list = scsi_malloc(task, offsetof(struct scsi_readtoc_list, desc)
755 			   + sizeof(struct scsi_readtoc_desc) * num_desc);
756 	if (list == NULL) {
757 		return NULL;
758 	}
759 
760 	list->num = num_desc;
761 	list->first = task_get_uint8(task, 2);
762 	list->last = task_get_uint8(task, 3);
763 
764 	for (i = 0; i < num_desc; i++) {
765 		scsi_readtoc_desc_unmarshall(task, list, i);
766 	}
767 
768 	return list;
769 }
770 
771 /*
772  * RESERVE6
773  */
774 struct scsi_task *
scsi_cdb_reserve6(void)775 scsi_cdb_reserve6(void)
776 {
777 	struct scsi_task *task;
778 
779 	task = malloc(sizeof(struct scsi_task));
780 	if (task == NULL) {
781 		return NULL;
782 	}
783 
784 	memset(task, 0, sizeof(struct scsi_task));
785 	task->cdb[0] = SCSI_OPCODE_RESERVE6;
786 
787 	task->cdb_size = 6;
788 	task->xfer_dir = SCSI_XFER_NONE;
789 
790 	return task;
791 }
792 /*
793  * RELEASE10
794  */
795 struct scsi_task *
scsi_cdb_release6(void)796 scsi_cdb_release6(void)
797 {
798 	struct scsi_task *task;
799 
800 	task = malloc(sizeof(struct scsi_task));
801 	if (task == NULL) {
802 		return NULL;
803 	}
804 
805 	memset(task, 0, sizeof(struct scsi_task));
806 	task->cdb[0] = SCSI_OPCODE_RELEASE6;
807 
808 	task->cdb_size = 6;
809 	task->xfer_dir = SCSI_XFER_NONE;
810 
811 	return task;
812 }
813 
814 static inline uint8_t
scsi_serviceactionin_sa(const struct scsi_task * task)815 scsi_serviceactionin_sa(const struct scsi_task *task)
816 {
817 	return task->cdb[1];
818 }
819 
820 /*
821  * service_action_in unmarshall
822  */
823 static void *
scsi_serviceactionin_datain_unmarshall(struct scsi_task * task)824 scsi_serviceactionin_datain_unmarshall(struct scsi_task *task)
825 {
826 	switch (scsi_serviceactionin_sa(task)) {
827 	case SCSI_READCAPACITY16: {
828 		struct scsi_readcapacity16 *rc16 = scsi_malloc(task,
829 							       sizeof(*rc16));
830 		if (rc16 == NULL) {
831 			return NULL;
832 		}
833 		rc16->returned_lba = task_get_uint32(task, 0);
834 		rc16->returned_lba = (rc16->returned_lba << 32) | task_get_uint32(task, 4);
835 		rc16->block_length = task_get_uint32(task, 8);
836 		rc16->p_type       = (task_get_uint8(task, 12) >> 1) & 0x07;
837 		rc16->prot_en      = task_get_uint8(task, 12) & 0x01;
838 		rc16->p_i_exp      = (task_get_uint8(task, 13) >> 4) & 0x0f;
839 		rc16->lbppbe       = task_get_uint8(task, 13) & 0x0f;
840 		rc16->lbpme        = !!(task_get_uint8(task, 14) & 0x80);
841 		rc16->lbprz        = !!(task_get_uint8(task, 14) & 0x40);
842 		rc16->lalba        = task_get_uint16(task, 14) & 0x3fff;
843 		return rc16;
844 	}
845 	case SCSI_GET_LBA_STATUS: {
846 		struct scsi_get_lba_status *gls = scsi_malloc(task,
847 							      sizeof(*gls));
848 		int32_t len = task_get_uint32(task, 0);
849 		int i;
850 
851 		if (gls == NULL) {
852 			return NULL;
853 		}
854 
855 		if (len > task->datain.size - 4) {
856 			len = task->datain.size - 4;
857 		}
858 		len = len / 16;
859 
860 		gls->num_descriptors = len;
861 		gls->descriptors = scsi_malloc(task,
862 					       sizeof(*gls->descriptors) * len);
863 		if (gls->descriptors == NULL) {
864 			return NULL;
865 		}
866 
867 		for (i = 0; i < (int)gls->num_descriptors; i++) {
868 			gls->descriptors[i].lba  = task_get_uint32(task, 8 + i * sizeof(struct scsi_lba_status_descriptor) + 0);
869 			gls->descriptors[i].lba <<= 32;
870  			gls->descriptors[i].lba |= task_get_uint32(task, 8 + i * sizeof(struct scsi_lba_status_descriptor) + 4);
871 
872 			gls->descriptors[i].num_blocks = task_get_uint32(task, 8 + i * sizeof(struct scsi_lba_status_descriptor) + 8);
873 
874 			gls->descriptors[i].provisioning = task_get_uint8(task, 8 + i * sizeof(struct scsi_lba_status_descriptor) + 12) & 0x0f;
875 		}
876 
877 		return gls;
878 	}
879 	default:
880 		return NULL;
881 	}
882 }
883 
884 /*
885  * persistent_reserve_in unmarshall
886  */
887 static inline uint8_t
scsi_persistentreservein_sa(const struct scsi_task * task)888 scsi_persistentreservein_sa(const struct scsi_task *task)
889 {
890 	return task->cdb[1] & 0x1f;
891 }
892 
893 static int
scsi_persistentreservein_datain_getfullsize(struct scsi_task * task)894 scsi_persistentreservein_datain_getfullsize(struct scsi_task *task)
895 {
896 	switch (scsi_persistentreservein_sa(task)) {
897 	case SCSI_PERSISTENT_RESERVE_READ_KEYS:
898 		return task_get_uint32(task, 4) + 8;
899 	case SCSI_PERSISTENT_RESERVE_READ_RESERVATION:
900 		return 8;
901 	case SCSI_PERSISTENT_RESERVE_REPORT_CAPABILITIES:
902 		return 8;
903 	default:
904 		return -1;
905 	}
906 }
907 
908 static void *
scsi_receivecopyresults_datain_unmarshall(struct scsi_task * task)909 scsi_receivecopyresults_datain_unmarshall(struct scsi_task *task)
910 {
911 	int sa = task->cdb[1] & 0x1f;
912 	int len, i;
913 	struct scsi_copy_results_copy_status *cs;
914 	struct scsi_copy_results_op_params *op;
915 
916 	switch (sa) {
917 	case SCSI_COPY_RESULTS_COPY_STATUS:
918 		len = task_get_uint32(task, 0);
919 		if (len < 8)
920 			return NULL;
921 		cs = scsi_malloc(task, sizeof(*cs));
922 		if (cs == NULL) {
923 			return NULL;
924 		}
925 		cs->available_data = len;
926 		cs->copy_manager_status = task_get_uint8(task, 4) & 0x7F;
927 		cs->hdd = (task_get_uint8(task, 4) & 0x80) >> 7;
928 		cs->segments_processed = task_get_uint16(task, 5);
929 		cs->transfer_count_units = task_get_uint8(task, 7);
930 		cs->transfer_count = task_get_uint32(task, 8);
931 		return cs;
932 
933 	case SCSI_COPY_RESULTS_OP_PARAMS:
934 		len = task_get_uint32(task, 0);
935 		if (len < 40)
936 			return NULL;
937 		op = scsi_malloc(task, sizeof(*op) + task_get_uint8(task, 43));
938 		if (op == NULL) {
939 			return NULL;
940 		}
941 		op->available_data = len;
942 		op->max_target_desc_count = task_get_uint16(task, 8);
943 		op->max_segment_desc_count = task_get_uint16(task, 10);
944 		op->max_desc_list_length = task_get_uint32(task, 12);
945 		op->max_segment_length = task_get_uint32(task, 16);
946 		op->max_inline_data_length = task_get_uint32(task, 20);
947 		op->held_data_limit = task_get_uint32(task, 24);
948 		op->max_stream_device_transfer_size = task_get_uint32(task, 28);
949 		op->total_concurrent_copies = task_get_uint16(task, 34);
950 		op->max_concurrent_copies = task_get_uint8(task, 36);
951 		op->data_segment_granularity = task_get_uint8(task, 37);
952 		op->inline_data_granularity = task_get_uint8(task, 38);
953 		op->held_data_granularity = task_get_uint8(task, 39);
954 		op->impl_desc_list_length = task_get_uint8(task, 43);
955                 for (i = 0; i < (int)op->impl_desc_list_length; i++) {
956                         op->imp_desc_type_codes[i] = task_get_uint8(task, 44+i);
957                 }
958 		return op;
959 	default:
960 		return NULL;
961 	}
962 }
963 
964 #ifndef MIN /* instead of including all of iscsi-private.h */
965 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
966 #endif
967 static void *
scsi_persistentreservein_datain_unmarshall(struct scsi_task * task)968 scsi_persistentreservein_datain_unmarshall(struct scsi_task *task)
969 {
970 	struct scsi_persistent_reserve_in_read_keys *rk;
971 	struct scsi_persistent_reserve_in_read_reservation *rr;
972 	struct scsi_persistent_reserve_in_report_capabilities *rc;
973 	int i;
974 
975 	switch (scsi_persistentreservein_sa(task)) {
976 	case SCSI_PERSISTENT_RESERVE_READ_KEYS: {
977 		uint32_t cdb_keys_len;
978 		uint32_t data_keys_len;
979 		uint32_t keys_len;
980 
981 		if (task->datain.size < 8) {
982 			return NULL;
983 		}
984 
985 		/*
986 		 * SPC5r17: 6.16.2 READ KEYS service action
987 		 * The ADDITIONAL LENGTH field indicates the number of bytes in
988 		 * the Reservation key list. The contents of the ADDITIONAL
989 		 * LENGTH field are not altered based on the allocation length.
990 		 */
991 		cdb_keys_len = task_get_uint32(task, 4);
992 		data_keys_len = task->datain.size - 8;
993 		/*
994 		 * Only process as many keys as permitted by the given
995 		 * ADDITIONAL LENGTH and data-in size limits.
996 		 */
997 		keys_len = MIN(cdb_keys_len, data_keys_len);
998 
999 		rk = scsi_malloc(task,
1000 			offsetof(struct scsi_persistent_reserve_in_read_keys,
1001 				 keys) + keys_len);
1002 		if (rk == NULL) {
1003 			return NULL;
1004 		}
1005 		rk->prgeneration      = task_get_uint32(task, 0);
1006 		rk->additional_length = cdb_keys_len;
1007 
1008 		rk->num_keys = keys_len / 8;
1009 		for (i = 0; i < (int)rk->num_keys; i++) {
1010 			rk->keys[i] = task_get_uint64(task, 8 + i * 8);
1011 		}
1012 		return rk;
1013 	}
1014 	case SCSI_PERSISTENT_RESERVE_READ_RESERVATION: {
1015 		size_t	alloc_sz;
1016 
1017 		i = task_get_uint32(task, 4);
1018 		alloc_sz = sizeof(struct scsi_persistent_reserve_in_read_reservation);
1019 
1020 		rr = scsi_malloc(task, alloc_sz);
1021 		if (rr == NULL) {
1022 			return NULL;
1023 		}
1024 		memset(rr, 0, alloc_sz);
1025 		rr->prgeneration = task_get_uint32(task, 0);
1026 
1027 		if (i > 0) {
1028 			rr->reserved = 1;
1029 			rr->reservation_key =
1030 				task_get_uint64(task, 8);
1031 			rr->pr_scope = task_get_uint8(task, 21) >> 4;
1032 			rr->pr_type = task_get_uint8(task, 21) & 0xf;
1033 		}
1034 
1035 		return rr;
1036 	}
1037 	case SCSI_PERSISTENT_RESERVE_REPORT_CAPABILITIES:
1038 		rc = scsi_malloc(task, sizeof(struct scsi_persistent_reserve_in_report_capabilities));
1039 		if (rc == NULL) {
1040 			return NULL;
1041 		}
1042 		rc->length         = task_get_uint16(task, 0);
1043 		rc->crh            = !!(task_get_uint8(task, 2) & 0x10);
1044 		rc->sip_c          = !!(task_get_uint8(task, 2) & 0x08);
1045 		rc->atp_c          = !!(task_get_uint8(task, 2) & 0x04);
1046 		rc->ptpl_c         = !!(task_get_uint8(task, 2) & 0x01);
1047 		rc->tmv            = !!(task_get_uint8(task, 3) & 0x80);
1048 		rc->allow_commands = (task_get_uint8(task, 3) & 0x70) >> 4;
1049 		rc->persistent_reservation_type_mask = task_get_uint16(task, 4);
1050 
1051 		return rc;
1052 	default:
1053 		return NULL;
1054 	}
1055 }
1056 
1057 static inline uint8_t
scsi_maintenancein_sa(const struct scsi_task * task)1058 scsi_maintenancein_sa(const struct scsi_task *task)
1059 {
1060 	return task->cdb[1];
1061 }
1062 
1063 static inline uint8_t
scsi_report_supported_opcodes_options(const struct scsi_task * task)1064 scsi_report_supported_opcodes_options(const struct scsi_task *task)
1065 {
1066 	return task->cdb[2] & 0x07;
1067 }
1068 
1069 /*
1070  * parse the data in blob and calculate the size of a full maintenancein
1071  * datain structure
1072  */
1073 static int
scsi_maintenancein_datain_getfullsize(struct scsi_task * task)1074 scsi_maintenancein_datain_getfullsize(struct scsi_task *task)
1075 {
1076 
1077 	switch (scsi_maintenancein_sa(task)) {
1078 	case SCSI_REPORT_SUPPORTED_OP_CODES:
1079 		switch (scsi_report_supported_opcodes_options(task)) {
1080 		case SCSI_REPORT_SUPPORTING_OPS_ALL:
1081 			return task_get_uint32(task, 0) + 4;
1082 		case SCSI_REPORT_SUPPORTING_OPCODE:
1083 		case SCSI_REPORT_SUPPORTING_SERVICEACTION:
1084 			return 4 +
1085 				(task_get_uint8(task, 1) & 0x80) ? 12 : 0 +
1086 				task_get_uint16(task, 2);
1087 		}
1088 		return -1;
1089 	default:
1090 		return -1;
1091 	}
1092 }
1093 
1094 /*
1095  * maintenance_in unmarshall
1096  */
1097 static void *
scsi_maintenancein_datain_unmarshall(struct scsi_task * task)1098 scsi_maintenancein_datain_unmarshall(struct scsi_task *task)
1099 {
1100 	struct scsi_report_supported_op_codes *rsoc;
1101 	struct scsi_report_supported_op_codes_one_command *rsoc_one;
1102 	int len, i;
1103 
1104 	switch (scsi_maintenancein_sa(task)) {
1105 	case SCSI_REPORT_SUPPORTED_OP_CODES:
1106 		switch (scsi_report_supported_opcodes_options(task)) {
1107 		case SCSI_REPORT_SUPPORTING_OPS_ALL:
1108 			if (task->datain.size < 4) {
1109 				return NULL;
1110 			}
1111 
1112 			len = task_get_uint32(task, 0);
1113 			/* len / 8 is not always correct since if CTDP==1 then
1114 			 * the descriptor is 20 bytes in size intead of 8.
1115 			 * It doesnt matter here though since it just means
1116 			 * we would allocate more descriptors at the end of
1117 			 * the structure than we strictly need. This avoids
1118 			 * having to traverse the datain buffer twice.
1119 			 */
1120 			rsoc = scsi_malloc(task,
1121 				offsetof(struct scsi_report_supported_op_codes,
1122 					descriptors) +
1123 				len / 8 * sizeof(struct scsi_command_descriptor));
1124 			if (rsoc == NULL) {
1125 				return NULL;
1126 			}
1127 
1128 			rsoc->num_descriptors = 0;
1129 			i = 4;
1130 			while (len >= 8) {
1131 				struct scsi_command_descriptor *desc;
1132 
1133 				desc = &rsoc->descriptors[rsoc->num_descriptors++];
1134 				desc->opcode =
1135 					task_get_uint8(task, i);
1136 				desc->sa =
1137 					task_get_uint16(task, i + 2);
1138 				desc->ctdp =
1139 					!!(task_get_uint8(task, i + 5) & 0x02);
1140 				desc->servactv =
1141 					!!(task_get_uint8(task, i + 5) & 0x01);
1142 				desc->cdb_len =
1143 					task_get_uint16(task, i + 6);
1144 
1145 				len -= 8;
1146 				i += 8;
1147 
1148 				/* No tiemout description */
1149 				if (!desc->ctdp) {
1150 					continue;
1151 				}
1152 
1153 				desc->to.descriptor_length =
1154 					task_get_uint16(task, i);
1155 				desc->to.command_specific =
1156 					task_get_uint8(task, i + 3);
1157 				desc->to.nominal_processing_timeout =
1158 					task_get_uint32(task, i + 4);
1159 				desc->to.recommended_timeout =
1160 					task_get_uint32(task, i + 8);
1161 
1162 				len -= desc->to.descriptor_length + 2;
1163 				i += desc->to.descriptor_length + 2;
1164 			}
1165 			return rsoc;
1166 		case SCSI_REPORT_SUPPORTING_OPCODE:
1167 		case SCSI_REPORT_SUPPORTING_SERVICEACTION:
1168 			rsoc_one = scsi_malloc(task, sizeof(struct scsi_report_supported_op_codes_one_command));
1169 			if (rsoc_one == NULL) {
1170 				return NULL;
1171 			}
1172 
1173 			rsoc_one->ctdp =
1174 				!!(task_get_uint8(task, 1) & 0x80);
1175 			rsoc_one->support =
1176 				task_get_uint8(task, 1) & 0x07;
1177 			rsoc_one->cdb_length =
1178 				task_get_uint16(task, 2);
1179 			if (rsoc_one->cdb_length <=
1180 			    sizeof(rsoc_one->cdb_usage_data)) {
1181 				memcpy(rsoc_one->cdb_usage_data,
1182 					&task->datain.data[4],
1183 					rsoc_one->cdb_length);
1184 			}
1185 
1186 			if (rsoc_one->ctdp) {
1187 				i = 4 + rsoc_one->cdb_length;
1188 
1189 				rsoc_one->to.descriptor_length =
1190 					task_get_uint16(task, i);
1191 				rsoc_one->to.command_specific =
1192 					task_get_uint8(task, i + 3);
1193 				rsoc_one->to.nominal_processing_timeout =
1194 					task_get_uint32(task, i + 4);
1195 				rsoc_one->to.recommended_timeout =
1196 					task_get_uint32(task, i + 8);
1197 			}
1198 			return rsoc_one;
1199 		}
1200 	};
1201 
1202 	return NULL;
1203 }
1204 
1205 /*
1206  * MAINTENANCE In / Read Supported Op Codes
1207  */
1208 struct scsi_task *
scsi_cdb_report_supported_opcodes(int rctd,int options,enum scsi_opcode opcode,int sa,uint32_t alloc_len)1209 scsi_cdb_report_supported_opcodes(int rctd, int options, enum scsi_opcode opcode, int sa, uint32_t alloc_len)
1210 {
1211 	struct scsi_task *task;
1212 
1213 	task = malloc(sizeof(struct scsi_task));
1214 	if (task == NULL) {
1215 		return NULL;
1216 	}
1217 
1218 	memset(task, 0, sizeof(struct scsi_task));
1219 	task->cdb[0]   = SCSI_OPCODE_MAINTENANCE_IN;
1220 	task->cdb[1]   = SCSI_REPORT_SUPPORTED_OP_CODES;
1221 	task->cdb[2]   = options & 0x07;
1222 
1223 	if (rctd) {
1224 		task->cdb[2] |= 0x80;
1225 	}
1226 
1227 	task->cdb[3]   = opcode;
1228 
1229 	scsi_set_uint16(&task->cdb[4], sa);
1230 
1231 	scsi_set_uint32(&task->cdb[6], alloc_len);
1232 
1233 	task->cdb_size = 12;
1234 	if (alloc_len != 0) {
1235 		task->xfer_dir = SCSI_XFER_READ;
1236 	} else {
1237 		task->xfer_dir = SCSI_XFER_NONE;
1238 	}
1239 	task->expxferlen = alloc_len;
1240 
1241 	return task;
1242 }
1243 
1244 /*
1245  * parse the data in blob and calculate the size of a full
1246  * readcapacity10 datain structure
1247  */
1248 static int
scsi_readcapacity10_datain_getfullsize(struct scsi_task * task _U_)1249 scsi_readcapacity10_datain_getfullsize(struct scsi_task *task _U_)
1250 {
1251 	return 8;
1252 }
1253 
1254 /*
1255  * unmarshall the data in blob for readcapacity10 into a structure
1256  */
1257 static struct scsi_readcapacity10 *
scsi_readcapacity10_datain_unmarshall(struct scsi_task * task)1258 scsi_readcapacity10_datain_unmarshall(struct scsi_task *task)
1259 {
1260 	struct scsi_readcapacity10 *rc10;
1261 
1262 	if (task->datain.size < 8) {
1263 		return NULL;
1264 	}
1265 	rc10 = scsi_malloc(task, sizeof(struct scsi_readcapacity10));
1266 	if (rc10 == NULL) {
1267 		return NULL;
1268 	}
1269 
1270 	rc10->lba        = task_get_uint32(task, 0);
1271 	rc10->block_size = task_get_uint32(task, 4);
1272 
1273 	return rc10;
1274 }
1275 
1276 /*
1277  * INQUIRY
1278  */
1279 struct scsi_task *
scsi_cdb_inquiry(int evpd,int page_code,int alloc_len)1280 scsi_cdb_inquiry(int evpd, int page_code, int alloc_len)
1281 {
1282 	struct scsi_task *task;
1283 
1284 	task = malloc(sizeof(struct scsi_task));
1285 	if (task == NULL) {
1286 		return NULL;
1287 	}
1288 
1289 	memset(task, 0, sizeof(struct scsi_task));
1290 	task->cdb[0]   = SCSI_OPCODE_INQUIRY;
1291 
1292 	if (evpd) {
1293 		task->cdb[1] |= 0x01;
1294 	}
1295 
1296 	task->cdb[2] = page_code;
1297 
1298 	scsi_set_uint16(&task->cdb[3], alloc_len);
1299 
1300 	task->cdb_size = 6;
1301 	if (alloc_len != 0) {
1302 		task->xfer_dir = SCSI_XFER_READ;
1303 	} else {
1304 		task->xfer_dir = SCSI_XFER_NONE;
1305 	}
1306 	task->expxferlen = alloc_len;
1307 
1308 	return task;
1309 }
1310 
1311 static inline int
scsi_inquiry_evpd_set(const struct scsi_task * task)1312 scsi_inquiry_evpd_set(const struct scsi_task *task)
1313 {
1314 	return task->cdb[1] & 0x1;
1315 }
1316 
1317 static inline uint8_t
scsi_inquiry_page_code(const struct scsi_task * task)1318 scsi_inquiry_page_code(const struct scsi_task *task)
1319 {
1320 	return task->cdb[2];
1321 }
1322 
1323 /*
1324  * parse the data in blob and calculate the size of a full
1325  * inquiry datain structure
1326  */
1327 static int
scsi_inquiry_datain_getfullsize(struct scsi_task * task)1328 scsi_inquiry_datain_getfullsize(struct scsi_task *task)
1329 {
1330 	if (scsi_inquiry_evpd_set(task) == 0) {
1331 		return task_get_uint8(task, 4) + 5;
1332 	}
1333 
1334 	switch (scsi_inquiry_page_code(task)) {
1335 	case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES:
1336 	case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS:
1337 	case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER:
1338 		return task_get_uint8(task, 3) + 4;
1339 	case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION:
1340 	case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS:
1341 	case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
1342 		return task_get_uint16(task, 2) + 4;
1343 	default:
1344 		return -1;
1345 	}
1346 }
1347 
1348 static struct scsi_inquiry_standard *
scsi_inquiry_unmarshall_standard(struct scsi_task * task)1349 scsi_inquiry_unmarshall_standard(struct scsi_task *task)
1350 {
1351 	int i;
1352 
1353 	struct scsi_inquiry_standard *inq = scsi_malloc(task, sizeof(*inq));
1354 	if (inq == NULL) {
1355 		return NULL;
1356 	}
1357 
1358 	inq->qualifier              = (task_get_uint8(task, 0) >> 5) & 0x07;
1359 	inq->device_type            = task_get_uint8(task, 0) & 0x1f;
1360 	inq->rmb                    = !!(task_get_uint8(task, 1) & 0x80);
1361 	inq->version                = task_get_uint8(task, 2);
1362 	inq->normaca                = !!(task_get_uint8(task, 3) & 0x20);
1363 	inq->hisup                  = !!(task_get_uint8(task, 3) & 0x10);
1364 	inq->response_data_format   = task_get_uint8(task, 3) & 0x0f;
1365 
1366 	inq->additional_length      = task_get_uint8(task, 4);
1367 
1368 	inq->sccs                   = !!(task_get_uint8(task, 5) & 0x80);
1369 	inq->acc                    = !!(task_get_uint8(task, 5) & 0x40);
1370 	inq->tpgs                   = (task_get_uint8(task, 5) >> 4) & 0x03;
1371 	inq->threepc                = !!(task_get_uint8(task, 5) & 0x08);
1372 	inq->protect                = !!(task_get_uint8(task, 5) & 0x01);
1373 
1374 	inq->encserv                = !!(task_get_uint8(task, 6) & 0x40);
1375 	inq->multip                 = !!(task_get_uint8(task, 6) & 0x10);
1376 	inq->addr16                 = !!(task_get_uint8(task, 6) & 0x01);
1377 	inq->wbus16                 = !!(task_get_uint8(task, 7) & 0x20);
1378 	inq->sync                   = !!(task_get_uint8(task, 7) & 0x10);
1379 	inq->cmdque                 = !!(task_get_uint8(task, 7) & 0x02);
1380 
1381 	memcpy(&inq->vendor_identification[0],
1382 	       &task->datain.data[8], 8);
1383 	memcpy(&inq->product_identification[0],
1384 	       &task->datain.data[16], 16);
1385 	memcpy(&inq->product_revision_level[0],
1386 	       &task->datain.data[32], 4);
1387 
1388 	inq->clocking               = (task_get_uint8(task, 56) >> 2) & 0x03;
1389 	inq->qas                    = !!(task_get_uint8(task, 56) & 0x02);
1390 	inq->ius                    = !!(task_get_uint8(task, 56) & 0x01);
1391 
1392 	for (i = 0; i < 8; i++) {
1393 		inq->version_descriptor[i] = task_get_uint16(task, 58 + i * 2);
1394 	}
1395 
1396 	return inq;
1397 }
1398 
1399 static struct scsi_inquiry_supported_pages *
scsi_inquiry_unmarshall_supported_pages(struct scsi_task * task)1400 scsi_inquiry_unmarshall_supported_pages(struct scsi_task *task)
1401 {
1402 	struct scsi_inquiry_supported_pages *inq = scsi_malloc(task,
1403 							       sizeof(*inq));
1404 	if (inq == NULL) {
1405 		return NULL;
1406 	}
1407 	inq->qualifier = (task_get_uint8(task, 0) >> 5) & 0x07;
1408 	inq->device_type = task_get_uint8(task, 0) & 0x1f;
1409 	inq->pagecode = task_get_uint8(task, 1);
1410 
1411 	inq->num_pages = task_get_uint8(task, 3);
1412 	inq->pages = scsi_malloc(task, inq->num_pages);
1413 	if (inq->pages == NULL) {
1414 		return NULL;
1415 	}
1416 	memcpy(inq->pages, &task->datain.data[4], inq->num_pages);
1417 	return inq;
1418 }
1419 
1420 static struct scsi_inquiry_unit_serial_number *
scsi_inquiry_unmarshall_unit_serial_number(struct scsi_task * task)1421 scsi_inquiry_unmarshall_unit_serial_number(struct scsi_task* task)
1422 {
1423 	struct scsi_inquiry_unit_serial_number *inq = scsi_malloc(task,
1424 								  sizeof(*inq));
1425 	if (inq == NULL) {
1426 		return NULL;
1427 	}
1428 	inq->qualifier = (task_get_uint8(task, 0) >> 5) & 0x07;
1429 	inq->device_type = task_get_uint8(task, 0) & 0x1f;
1430 	inq->pagecode = task_get_uint8(task, 1);
1431 
1432 	inq->usn = scsi_malloc(task, task_get_uint8(task, 3) + 1);
1433 	if (inq->usn == NULL) {
1434 		return NULL;
1435 	}
1436 	memcpy(inq->usn, &task->datain.data[4], task_get_uint8(task, 3));
1437 	inq->usn[task_get_uint8(task, 3)] = 0;
1438 	return inq;
1439 }
1440 
1441 static struct scsi_inquiry_device_identification *
scsi_inquiry_unmarshall_device_identification(struct scsi_task * task)1442 scsi_inquiry_unmarshall_device_identification(struct scsi_task *task)
1443 {
1444 	struct scsi_inquiry_device_identification *inq = scsi_malloc(task,
1445 							     sizeof(*inq));
1446 	int remaining = task_get_uint16(task, 2);
1447 	unsigned char *dptr;
1448 
1449 	if (inq == NULL) {
1450 		return NULL;
1451 	}
1452 	inq->qualifier             = (task_get_uint8(task, 0) >> 5) & 0x07;
1453 	inq->device_type           = task_get_uint8(task, 0) & 0x1f;
1454 	inq->pagecode              = task_get_uint8(task, 1);
1455 
1456 	dptr = &task->datain.data[4];
1457 	while (remaining > 0) {
1458 		struct scsi_inquiry_device_designator *dev =
1459 			scsi_malloc(task, sizeof(*dev));
1460 		if (dev == NULL) {
1461 			goto err;
1462 		}
1463 
1464 		dev->next = inq->designators;
1465 		inq->designators = dev;
1466 
1467 		dev->protocol_identifier = (dptr[0]>>4) & 0x0f;
1468 		dev->code_set            = dptr[0] & 0x0f;
1469 		dev->piv                 = !!(dptr[1]&0x80);
1470 		dev->association         = (dptr[1]>>4)&0x03;
1471 		dev->designator_type     = dptr[1]&0x0f;
1472 
1473 		dev->designator_length   = dptr[3];
1474 		dev->designator = scsi_malloc(task, dev->designator_length + 1);
1475 		if (dev->designator == NULL) {
1476 			goto err;
1477 		}
1478 		dev->designator[dev->designator_length] = 0;
1479 		memcpy(dev->designator, &dptr[4],
1480 		       dev->designator_length);
1481 
1482 		remaining -= 4;
1483 		remaining -= dev->designator_length;
1484 
1485 		dptr += dev->designator_length + 4;
1486 	}
1487 	return inq;
1488 
1489  err:
1490 	while (inq->designators) {
1491 		struct scsi_inquiry_device_designator *dev = inq->designators;
1492 		inq->designators = dev->next;
1493 	}
1494 
1495 	return NULL;
1496 }
1497 
1498 static struct scsi_inquiry_block_limits *
scsi_inquiry_unmarshall_block_limits(struct scsi_task * task)1499 scsi_inquiry_unmarshall_block_limits(struct scsi_task *task)
1500 {
1501 	struct scsi_inquiry_block_limits *inq = scsi_malloc(task,
1502 							    sizeof(*inq));
1503 	if (inq == NULL) {
1504 		return NULL;
1505 	}
1506 	inq->qualifier             = (task_get_uint8(task, 0) >> 5) & 0x07;
1507 	inq->device_type           = task_get_uint8(task, 0) & 0x1f;
1508 	inq->pagecode              = task_get_uint8(task, 1);
1509 
1510 	inq->wsnz                  = task_get_uint8(task, 4) & 0x01;
1511 	inq->max_cmp               = task_get_uint8(task, 5);
1512 	inq->opt_gran              = task_get_uint16(task, 6);
1513 	inq->max_xfer_len          = task_get_uint32(task, 8);
1514 	inq->opt_xfer_len          = task_get_uint32(task, 12);
1515 	inq->max_prefetch          = task_get_uint32(task, 16);
1516 	inq->max_unmap             = task_get_uint32(task, 20);
1517 	inq->max_unmap_bdc         = task_get_uint32(task, 24);
1518 	inq->opt_unmap_gran        = task_get_uint32(task, 28);
1519 	inq->ugavalid              = !!(task_get_uint8(task, 32)&0x80);
1520 	inq->unmap_gran_align      = task_get_uint32(task, 32) & 0x7fffffff;
1521 	inq->max_ws_len            = task_get_uint32(task, 36);
1522 	inq->max_ws_len            = (inq->max_ws_len << 32)
1523 				   	| task_get_uint32(task, 40);
1524 
1525 	inq->max_atomic_xfer_len   = task_get_uint32(task, 44);
1526 	inq->atomic_align          = task_get_uint32(task, 48);
1527 	inq->atomic_gran           = task_get_uint32(task, 52);
1528 	inq->max_atomic_tl_with_atomic_boundary =
1529                 task_get_uint32(task, 56);
1530 	inq->max_atomic_boundary_size =
1531                 task_get_uint32(task, 60);
1532 
1533 	return inq;
1534 }
1535 
1536 static struct scsi_inquiry_block_device_characteristics *
scsi_inquiry_unmarshall_block_device_characteristics(struct scsi_task * task)1537 scsi_inquiry_unmarshall_block_device_characteristics(struct scsi_task *task)
1538 {
1539 	struct scsi_inquiry_block_device_characteristics *inq =
1540 		scsi_malloc(task, sizeof(*inq));
1541 	if (inq == NULL) {
1542 		return NULL;
1543 	}
1544 	inq->qualifier             = (task_get_uint8(task, 0) >> 5) & 0x07;
1545 	inq->device_type           = task_get_uint8(task, 0) & 0x1f;
1546 	inq->pagecode              = task_get_uint8(task, 1);
1547 
1548 	inq->medium_rotation_rate  = task_get_uint16(task, 4);
1549 	inq->product_type          = task_get_uint8(task, 6);
1550 	inq->wabereq               = (task_get_uint8(task, 7) >> 6) & 0x03;
1551 	inq->wacereq               = (task_get_uint8(task, 7) >> 4) & 0x03;
1552 	inq->nominal_form_factor   = task_get_uint8(task, 7) & 0x0f;
1553 	inq->fuab                  = !!(task_get_uint8(task, 8) & 0x02);
1554 	inq->vbuls                 = !!(task_get_uint8(task, 8) & 0x01);
1555 	return inq;
1556 }
1557 
1558 struct scsi_inquiry_logical_block_provisioning *
scsi_inquiry_unmarshall_logical_block_provisioning(struct scsi_task * task)1559 scsi_inquiry_unmarshall_logical_block_provisioning(struct scsi_task *task)
1560 {
1561 	struct scsi_inquiry_logical_block_provisioning *inq =
1562 		scsi_malloc(task, sizeof(*inq));
1563 	if (inq == NULL) {
1564 		return NULL;
1565 	}
1566 	inq->qualifier             = (task_get_uint8(task, 0) >> 5) & 0x07;
1567 	inq->device_type           = task_get_uint8(task, 0) & 0x1f;
1568 	inq->pagecode              = task_get_uint8(task, 1);
1569 
1570 	inq->threshold_exponent = task_get_uint8(task, 4);
1571 	inq->lbpu               = !!(task_get_uint8(task, 5) & 0x80);
1572 	inq->lbpws              = !!(task_get_uint8(task, 5) & 0x40);
1573 	inq->lbpws10            = !!(task_get_uint8(task, 5) & 0x20);
1574 	inq->lbprz              = !!(task_get_uint8(task, 5) & 0x04);
1575 	inq->anc_sup            = !!(task_get_uint8(task, 5) & 0x02);
1576 	inq->dp	                = !!(task_get_uint8(task, 5) & 0x01);
1577 	inq->provisioning_type  = task_get_uint8(task, 6) & 0x07;
1578 
1579 	return inq;
1580 }
1581 
1582 /*
1583  * unmarshall the data in blob for inquiry into a structure
1584  */
1585 static void *
scsi_inquiry_datain_unmarshall(struct scsi_task * task)1586 scsi_inquiry_datain_unmarshall(struct scsi_task *task)
1587 {
1588 	if (scsi_inquiry_evpd_set(task) == 0) {
1589 		return scsi_inquiry_unmarshall_standard(task);
1590 	}
1591 
1592 	switch (scsi_inquiry_page_code(task))
1593 	{
1594 	case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES:
1595 		return scsi_inquiry_unmarshall_supported_pages(task);
1596 	case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER:
1597 		return scsi_inquiry_unmarshall_unit_serial_number(task);
1598 	case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION:
1599 		return scsi_inquiry_unmarshall_device_identification(task);
1600 	case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS:
1601 		return scsi_inquiry_unmarshall_block_limits(task);
1602 	case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS:
1603 		return scsi_inquiry_unmarshall_block_device_characteristics(task);
1604 	case  SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
1605 		return scsi_inquiry_unmarshall_logical_block_provisioning(task);
1606 	default:
1607 		return NULL;
1608 	}
1609 }
1610 
1611 /*
1612  * READ6
1613  */
1614 struct scsi_task *
scsi_cdb_read6(uint32_t lba,uint32_t xferlen,int blocksize)1615 scsi_cdb_read6(uint32_t lba, uint32_t xferlen, int blocksize)
1616 {
1617 	struct scsi_task *task;
1618 	int num_blocks;
1619 
1620 	num_blocks = xferlen/blocksize;
1621 	if (num_blocks > 256) {
1622 		return NULL;
1623 	}
1624 
1625 	if (lba > 0x1fffff) {
1626 		return NULL;
1627 	}
1628 
1629 	task = malloc(sizeof(struct scsi_task));
1630 	if (task == NULL) {
1631 		return NULL;
1632 	}
1633 
1634 	memset(task, 0, sizeof(struct scsi_task));
1635 	task->cdb[0]   = SCSI_OPCODE_READ6;
1636 	task->cdb_size = 6;
1637 
1638 	task->cdb[1] = (lba>>16)&0x1f;
1639 	task->cdb[2] = (lba>> 8)&0xff;
1640 	task->cdb[3] = (lba    )&0xff;
1641 
1642 	if (num_blocks < 256) {
1643 		task->cdb[4] = num_blocks & 0xff;
1644 	}
1645 
1646 	if (xferlen != 0) {
1647 		task->xfer_dir = SCSI_XFER_READ;
1648 	} else {
1649 		task->xfer_dir = SCSI_XFER_NONE;
1650 	}
1651 	task->expxferlen = xferlen;
1652 
1653 	return task;
1654 }
1655 
1656 /*
1657  * READ10
1658  */
1659 struct scsi_task *
scsi_cdb_read10(uint32_t lba,uint32_t xferlen,int blocksize,int rdprotect,int dpo,int fua,int fua_nv,int group_number)1660 scsi_cdb_read10(uint32_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number)
1661 {
1662 	struct scsi_task *task;
1663 
1664 	task = malloc(sizeof(struct scsi_task));
1665 	if (task == NULL) {
1666 		return NULL;
1667 	}
1668 
1669 	memset(task, 0, sizeof(struct scsi_task));
1670 	task->cdb[0]   = SCSI_OPCODE_READ10;
1671 
1672 	task->cdb[1] |= ((rdprotect & 0x07) << 5);
1673 	if (dpo) {
1674 		task->cdb[1] |= 0x10;
1675 	}
1676 	if (fua) {
1677 		task->cdb[1] |= 0x08;
1678 	}
1679 	if (fua_nv) {
1680 		task->cdb[1] |= 0x02;
1681 	}
1682 
1683 	scsi_set_uint32(&task->cdb[2], lba);
1684 	scsi_set_uint16(&task->cdb[7], xferlen/blocksize);
1685 
1686 	task->cdb[6] |= (group_number & 0x1f);
1687 
1688 	task->cdb_size = 10;
1689 	if (xferlen != 0) {
1690 		task->xfer_dir = SCSI_XFER_READ;
1691 	} else {
1692 		task->xfer_dir = SCSI_XFER_NONE;
1693 	}
1694 	task->expxferlen = xferlen;
1695 
1696 	return task;
1697 }
1698 
1699 /*
1700  * READ12
1701  */
1702 struct scsi_task *
scsi_cdb_read12(uint32_t lba,uint32_t xferlen,int blocksize,int rdprotect,int dpo,int fua,int fua_nv,int group_number)1703 scsi_cdb_read12(uint32_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number)
1704 {
1705 	struct scsi_task *task;
1706 
1707 	task = malloc(sizeof(struct scsi_task));
1708 	if (task == NULL) {
1709 		return NULL;
1710 	}
1711 
1712 	memset(task, 0, sizeof(struct scsi_task));
1713 	task->cdb[0]   = SCSI_OPCODE_READ12;
1714 
1715 	task->cdb[1] |= ((rdprotect & 0x07) << 5);
1716 	if (dpo) {
1717 		task->cdb[1] |= 0x10;
1718 	}
1719 	if (fua) {
1720 		task->cdb[1] |= 0x08;
1721 	}
1722 	if (fua_nv) {
1723 		task->cdb[1] |= 0x02;
1724 	}
1725 
1726 	scsi_set_uint32(&task->cdb[2], lba);
1727 	scsi_set_uint32(&task->cdb[6], xferlen/blocksize);
1728 
1729 	task->cdb[10] |= (group_number & 0x1f);
1730 
1731 	task->cdb_size = 12;
1732 	if (xferlen != 0) {
1733 		task->xfer_dir = SCSI_XFER_READ;
1734 	} else {
1735 		task->xfer_dir = SCSI_XFER_NONE;
1736 	}
1737 	task->expxferlen = xferlen;
1738 
1739 	return task;
1740 }
1741 
1742 /*
1743  * READ16
1744  */
1745 struct scsi_task *
scsi_cdb_read16(uint64_t lba,uint32_t xferlen,int blocksize,int rdprotect,int dpo,int fua,int fua_nv,int group_number)1746 scsi_cdb_read16(uint64_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number)
1747 {
1748 	struct scsi_task *task;
1749 
1750 	task = malloc(sizeof(struct scsi_task));
1751 	if (task == NULL) {
1752 		return NULL;
1753 	}
1754 
1755 	memset(task, 0, sizeof(struct scsi_task));
1756 	task->cdb[0]   = SCSI_OPCODE_READ16;
1757 
1758 	task->cdb[1] |= ((rdprotect & 0x07) << 5);
1759 	if (dpo) {
1760 		task->cdb[1] |= 0x10;
1761 	}
1762 	if (fua) {
1763 		task->cdb[1] |= 0x08;
1764 	}
1765 	if (fua_nv) {
1766 		task->cdb[1] |= 0x02;
1767 	}
1768 
1769 	scsi_set_uint32(&task->cdb[2], lba >> 32);
1770 	scsi_set_uint32(&task->cdb[6], lba & 0xffffffff);
1771 	scsi_set_uint32(&task->cdb[10], xferlen/blocksize);
1772 
1773 	task->cdb[14] |= (group_number & 0x1f);
1774 
1775 	task->cdb_size = 16;
1776 	if (xferlen != 0) {
1777 		task->xfer_dir = SCSI_XFER_READ;
1778 	} else {
1779 		task->xfer_dir = SCSI_XFER_NONE;
1780 	}
1781 	task->expxferlen = xferlen;
1782 
1783 	return task;
1784 }
1785 
1786 /*
1787  * WRITE10
1788  */
1789 struct scsi_task *
scsi_cdb_write10(uint32_t lba,uint32_t xferlen,int blocksize,int wrprotect,int dpo,int fua,int fua_nv,int group_number)1790 scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number)
1791 {
1792 	struct scsi_task *task;
1793 
1794 	task = malloc(sizeof(struct scsi_task));
1795 	if (task == NULL) {
1796 		return NULL;
1797 	}
1798 
1799 	memset(task, 0, sizeof(struct scsi_task));
1800 	task->cdb[0]   = SCSI_OPCODE_WRITE10;
1801 
1802 	task->cdb[1] |= ((wrprotect & 0x07) << 5);
1803 	if (dpo) {
1804 		task->cdb[1] |= 0x10;
1805 	}
1806 	if (fua) {
1807 		task->cdb[1] |= 0x08;
1808 	}
1809 	if (fua_nv) {
1810 		task->cdb[1] |= 0x02;
1811 	}
1812 
1813 	scsi_set_uint32(&task->cdb[2], lba);
1814 	scsi_set_uint16(&task->cdb[7], xferlen/blocksize);
1815 
1816 	task->cdb[6] |= (group_number & 0x1f);
1817 
1818 	task->cdb_size = 10;
1819 	if (xferlen != 0) {
1820 		task->xfer_dir = SCSI_XFER_WRITE;
1821 	} else {
1822 		task->xfer_dir = SCSI_XFER_NONE;
1823 	}
1824 	task->expxferlen = xferlen;
1825 
1826 	return task;
1827 }
1828 
1829 /*
1830  * WRITE12
1831  */
1832 struct scsi_task *
scsi_cdb_write12(uint32_t lba,uint32_t xferlen,int blocksize,int wrprotect,int dpo,int fua,int fua_nv,int group_number)1833 scsi_cdb_write12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number)
1834 {
1835 	struct scsi_task *task;
1836 
1837 	task = malloc(sizeof(struct scsi_task));
1838 	if (task == NULL) {
1839 		return NULL;
1840 	}
1841 
1842 	memset(task, 0, sizeof(struct scsi_task));
1843 	task->cdb[0]   = SCSI_OPCODE_WRITE12;
1844 
1845 	task->cdb[1] |= ((wrprotect & 0x07) << 5);
1846 	if (dpo) {
1847 		task->cdb[1] |= 0x10;
1848 	}
1849 	if (fua) {
1850 		task->cdb[1] |= 0x08;
1851 	}
1852 	if (fua_nv) {
1853 		task->cdb[1] |= 0x02;
1854 	}
1855 
1856 	scsi_set_uint32(&task->cdb[2], lba);
1857 	scsi_set_uint32(&task->cdb[6], xferlen/blocksize);
1858 
1859 	task->cdb[10] |= (group_number & 0x1f);
1860 
1861 	task->cdb_size = 12;
1862 	if (xferlen != 0) {
1863 		task->xfer_dir = SCSI_XFER_WRITE;
1864 	} else {
1865 		task->xfer_dir = SCSI_XFER_NONE;
1866 	}
1867 	task->expxferlen = xferlen;
1868 
1869 	return task;
1870 }
1871 
1872 /*
1873  * WRITE16
1874  */
1875 struct scsi_task *
scsi_cdb_write16(uint64_t lba,uint32_t xferlen,int blocksize,int wrprotect,int dpo,int fua,int fua_nv,int group_number)1876 scsi_cdb_write16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number)
1877 {
1878 	struct scsi_task *task;
1879 
1880 	task = malloc(sizeof(struct scsi_task));
1881 	if (task == NULL) {
1882 		return NULL;
1883 	}
1884 
1885 	memset(task, 0, sizeof(struct scsi_task));
1886 	task->cdb[0]   = SCSI_OPCODE_WRITE16;
1887 
1888 	task->cdb[1] |= ((wrprotect & 0x07) << 5);
1889 	if (dpo) {
1890 		task->cdb[1] |= 0x10;
1891 	}
1892 	if (fua) {
1893 		task->cdb[1] |= 0x08;
1894 	}
1895 	if (fua_nv) {
1896 		task->cdb[1] |= 0x02;
1897 	}
1898 
1899 	scsi_set_uint32(&task->cdb[2], lba >> 32);
1900 	scsi_set_uint32(&task->cdb[6], lba & 0xffffffff);
1901 	scsi_set_uint32(&task->cdb[10], xferlen / blocksize);
1902 
1903 	task->cdb[14] |= (group_number & 0x1f);
1904 
1905 	task->cdb_size = 16;
1906 	if (xferlen != 0) {
1907 		task->xfer_dir = SCSI_XFER_WRITE;
1908 	} else {
1909 		task->xfer_dir = SCSI_XFER_NONE;
1910 	}
1911 	task->expxferlen = xferlen;
1912 
1913 	return task;
1914 }
1915 
1916 /*
1917  * WRITEATOMIC16
1918  */
1919 struct scsi_task *
scsi_cdb_writeatomic16(uint64_t lba,uint32_t xferlen,int blocksize,int wrprotect,int dpo,int fua,int group_number)1920 scsi_cdb_writeatomic16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int group_number)
1921 {
1922 	struct scsi_task *task;
1923 
1924 	task = malloc(sizeof(struct scsi_task));
1925 	if (task == NULL) {
1926 		return NULL;
1927 	}
1928 
1929 	memset(task, 0, sizeof(struct scsi_task));
1930 	task->cdb[0]   = SCSI_OPCODE_WRITE_ATOMIC16;
1931 
1932 	task->cdb[1] |= ((wrprotect & 0x07) << 5);
1933 	if (dpo) {
1934 		task->cdb[1] |= 0x10;
1935 	}
1936 	if (fua) {
1937 		task->cdb[1] |= 0x08;
1938 	}
1939 
1940 	scsi_set_uint32(&task->cdb[2], lba >> 32);
1941 	scsi_set_uint32(&task->cdb[6], lba & 0xffffffff);
1942 	scsi_set_uint16(&task->cdb[12], xferlen / blocksize);
1943 
1944 	task->cdb[14] |= (group_number & 0x1f);
1945 
1946 	task->cdb_size = 16;
1947 	if (xferlen != 0) {
1948 		task->xfer_dir = SCSI_XFER_WRITE;
1949 	} else {
1950 		task->xfer_dir = SCSI_XFER_NONE;
1951 	}
1952 	task->expxferlen = xferlen;
1953 
1954 	return task;
1955 }
1956 
1957 /*
1958  * ORWRITE
1959  */
1960 struct scsi_task *
scsi_cdb_orwrite(uint64_t lba,uint32_t xferlen,int blocksize,int wrprotect,int dpo,int fua,int fua_nv,int group_number)1961 scsi_cdb_orwrite(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number)
1962 {
1963 	struct scsi_task *task;
1964 
1965 	task = malloc(sizeof(struct scsi_task));
1966 	if (task == NULL) {
1967 		return NULL;
1968 	}
1969 
1970 	memset(task, 0, sizeof(struct scsi_task));
1971 	task->cdb[0]   = SCSI_OPCODE_ORWRITE;
1972 
1973 	task->cdb[1] |= ((wrprotect & 0x07) << 5);
1974 	if (dpo) {
1975 		task->cdb[1] |= 0x10;
1976 	}
1977 	if (fua) {
1978 		task->cdb[1] |= 0x08;
1979 	}
1980 	if (fua_nv) {
1981 		task->cdb[1] |= 0x02;
1982 	}
1983 
1984 	scsi_set_uint32(&task->cdb[2], lba >> 32);
1985 	scsi_set_uint32(&task->cdb[6], lba & 0xffffffff);
1986 	scsi_set_uint32(&task->cdb[10], xferlen/blocksize);
1987 
1988 	task->cdb[14] |= (group_number & 0x1f);
1989 
1990 	task->cdb_size = 16;
1991 	if (xferlen != 0) {
1992 		task->xfer_dir = SCSI_XFER_WRITE;
1993 	} else {
1994 		task->xfer_dir = SCSI_XFER_NONE;
1995 	}
1996 	task->expxferlen = xferlen;
1997 
1998 	return task;
1999 }
2000 
2001 /*
2002  * COMPAREANDWRITE
2003  */
2004 struct scsi_task *
scsi_cdb_compareandwrite(uint64_t lba,uint32_t xferlen,int blocksize,int wrprotect,int dpo,int fua,int fua_nv,int group_number)2005 scsi_cdb_compareandwrite(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number)
2006 {
2007 	struct scsi_task *task;
2008 
2009 	task = malloc(sizeof(struct scsi_task));
2010 	if (task == NULL) {
2011 		return NULL;
2012 	}
2013 
2014 	memset(task, 0, sizeof(struct scsi_task));
2015 	task->cdb[0]   = SCSI_OPCODE_COMPARE_AND_WRITE;
2016 
2017 	task->cdb[1] |= ((wrprotect & 0x07) << 5);
2018 	if (dpo) {
2019 		task->cdb[1] |= 0x10;
2020 	}
2021 	if (fua) {
2022 		task->cdb[1] |= 0x08;
2023 	}
2024 	if (fua_nv) {
2025 		task->cdb[1] |= 0x02;
2026 	}
2027 
2028 	scsi_set_uint32(&task->cdb[2], lba >> 32);
2029 	scsi_set_uint32(&task->cdb[6], lba & 0xffffffff);
2030 	task->cdb[13] = xferlen / blocksize / 2;
2031 
2032 	task->cdb[14] |= (group_number & 0x1f);
2033 	task->cdb_size = 16;
2034 	if (xferlen != 0) {
2035 		task->xfer_dir = SCSI_XFER_WRITE;
2036 	} else {
2037 		task->xfer_dir = SCSI_XFER_NONE;
2038 	}
2039 	task->expxferlen = xferlen;
2040 
2041 	return task;
2042 }
2043 
2044 /*
2045  * VERIFY10
2046  */
2047 struct scsi_task *
scsi_cdb_verify10(uint32_t lba,uint32_t xferlen,int vprotect,int dpo,int bytchk,int blocksize)2048 scsi_cdb_verify10(uint32_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize)
2049 {
2050 	struct scsi_task *task;
2051 
2052 	task = malloc(sizeof(struct scsi_task));
2053 	if (task == NULL) {
2054 		return NULL;
2055 	}
2056 
2057 	memset(task, 0, sizeof(struct scsi_task));
2058 	task->cdb[0]   = SCSI_OPCODE_VERIFY10;
2059 
2060 	if (vprotect) {
2061 		task->cdb[1] |= ((vprotect << 5) & 0xe0);
2062 	}
2063 	if (dpo) {
2064 		task->cdb[1] |= 0x10;
2065 	}
2066 	if (bytchk) {
2067 		task->cdb[1] |= 0x02;
2068 	}
2069 
2070 	scsi_set_uint32(&task->cdb[2], lba);
2071 	scsi_set_uint16(&task->cdb[7], xferlen/blocksize);
2072 
2073 	task->cdb_size = 10;
2074 	if (xferlen != 0 && bytchk) {
2075 		task->xfer_dir = SCSI_XFER_WRITE;
2076 		task->expxferlen = xferlen;
2077 	} else {
2078 		task->xfer_dir = SCSI_XFER_NONE;
2079 		task->expxferlen = 0;
2080 	}
2081 
2082 	return task;
2083 }
2084 
2085 /*
2086  * VERIFY12
2087  */
2088 struct scsi_task *
scsi_cdb_verify12(uint32_t lba,uint32_t xferlen,int vprotect,int dpo,int bytchk,int blocksize)2089 scsi_cdb_verify12(uint32_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize)
2090 {
2091 	struct scsi_task *task;
2092 
2093 	task = malloc(sizeof(struct scsi_task));
2094 	if (task == NULL) {
2095 		return NULL;
2096 	}
2097 
2098 	memset(task, 0, sizeof(struct scsi_task));
2099 	task->cdb[0]   = SCSI_OPCODE_VERIFY12;
2100 
2101 	if (vprotect) {
2102 		task->cdb[1] |= ((vprotect << 5) & 0xe0);
2103 	}
2104 	if (dpo) {
2105 		task->cdb[1] |= 0x10;
2106 	}
2107 	if (bytchk) {
2108 		task->cdb[1] |= 0x02;
2109 	}
2110 
2111 	scsi_set_uint32(&task->cdb[2], lba);
2112 	scsi_set_uint32(&task->cdb[6], xferlen/blocksize);
2113 
2114 	task->cdb_size = 12;
2115 	if (xferlen != 0 && bytchk) {
2116 		task->xfer_dir = SCSI_XFER_WRITE;
2117 		task->expxferlen = xferlen;
2118 	} else {
2119 		task->xfer_dir = SCSI_XFER_NONE;
2120 		task->expxferlen = 0;
2121 	}
2122 
2123 	return task;
2124 }
2125 
2126 /*
2127  * VERIFY16
2128  */
2129 struct scsi_task *
scsi_cdb_verify16(uint64_t lba,uint32_t xferlen,int vprotect,int dpo,int bytchk,int blocksize)2130 scsi_cdb_verify16(uint64_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize)
2131 {
2132 	struct scsi_task *task;
2133 
2134 	task = malloc(sizeof(struct scsi_task));
2135 	if (task == NULL) {
2136 		return NULL;
2137 	}
2138 
2139 	memset(task, 0, sizeof(struct scsi_task));
2140 	task->cdb[0]   = SCSI_OPCODE_VERIFY16;
2141 
2142 	if (vprotect) {
2143 		task->cdb[1] |= ((vprotect << 5) & 0xe0);
2144 	}
2145 	if (dpo) {
2146 		task->cdb[1] |= 0x10;
2147 	}
2148 	if (bytchk) {
2149 		task->cdb[1] |= 0x02;
2150 	}
2151 
2152 	scsi_set_uint32(&task->cdb[2], lba >> 32);
2153 	scsi_set_uint32(&task->cdb[6], lba & 0xffffffff);
2154 	scsi_set_uint32(&task->cdb[10], xferlen/blocksize);
2155 
2156 	task->cdb_size = 16;
2157 	if (xferlen != 0 && bytchk) {
2158 		task->xfer_dir = SCSI_XFER_WRITE;
2159 		task->expxferlen = xferlen;
2160 	} else {
2161 		task->xfer_dir = SCSI_XFER_NONE;
2162 		task->expxferlen = 0;
2163 	}
2164 
2165 	return task;
2166 }
2167 
2168 /*
2169  * UNMAP
2170  */
2171 struct scsi_task *
scsi_cdb_unmap(int anchor,int group,uint16_t xferlen)2172 scsi_cdb_unmap(int anchor, int group, uint16_t xferlen)
2173 {
2174 	struct scsi_task *task;
2175 
2176 	task = malloc(sizeof(struct scsi_task));
2177 	if (task == NULL) {
2178 		return NULL;
2179 	}
2180 
2181 	memset(task, 0, sizeof(struct scsi_task));
2182 	task->cdb[0]   = SCSI_OPCODE_UNMAP;
2183 
2184 	if (anchor) {
2185 		task->cdb[1] |= 0x01;
2186 	}
2187 	task->cdb[6] |= group & 0x1f;
2188 
2189 	scsi_set_uint16(&task->cdb[7], xferlen);
2190 
2191 	task->cdb_size = 10;
2192 	if (xferlen != 0) {
2193 		task->xfer_dir = SCSI_XFER_WRITE;
2194 	} else {
2195 		task->xfer_dir = SCSI_XFER_NONE;
2196 	}
2197 	task->expxferlen = xferlen;
2198 
2199 	return task;
2200 }
2201 
2202 /*
2203  * PERSISTENT_RESEERVE_IN
2204  */
2205 struct scsi_task *
scsi_cdb_persistent_reserve_in(enum scsi_persistent_in_sa sa,uint16_t xferlen)2206 scsi_cdb_persistent_reserve_in(enum scsi_persistent_in_sa sa, uint16_t xferlen)
2207 {
2208 	struct scsi_task *task;
2209 
2210 	task = malloc(sizeof(struct scsi_task));
2211 	if (task == NULL) {
2212 		return NULL;
2213 	}
2214 
2215 	memset(task, 0, sizeof(struct scsi_task));
2216 	task->cdb[0]   = SCSI_OPCODE_PERSISTENT_RESERVE_IN;
2217 
2218 	task->cdb[1] |= sa & 0x1f;
2219 
2220 	scsi_set_uint16(&task->cdb[7], xferlen);
2221 
2222 	task->cdb_size = 10;
2223 	if (xferlen != 0) {
2224 		task->xfer_dir = SCSI_XFER_READ;
2225 	} else {
2226 		task->xfer_dir = SCSI_XFER_NONE;
2227 	}
2228 	task->expxferlen = xferlen;
2229 
2230 	return task;
2231 }
2232 
2233 /*
2234  * PERSISTENT_RESERVE_OUT
2235  */
2236 struct scsi_task *
scsi_cdb_persistent_reserve_out(enum scsi_persistent_out_sa sa,enum scsi_persistent_out_scope scope,enum scsi_persistent_out_type type,void * param)2237 scsi_cdb_persistent_reserve_out(enum scsi_persistent_out_sa sa, enum scsi_persistent_out_scope scope, enum scsi_persistent_out_type type, void *param)
2238 {
2239 	struct scsi_task *task;
2240 	struct scsi_persistent_reserve_out_basic *basic;
2241 	struct scsi_iovec *iov;
2242 	unsigned char *buf;
2243 	int xferlen;
2244 
2245 	task = malloc(sizeof(struct scsi_task));
2246 	if (task == NULL)
2247 		goto err;
2248 
2249 	memset(task, 0, sizeof(struct scsi_task));
2250 
2251 	iov = scsi_malloc(task, sizeof(struct scsi_iovec));
2252 	if (iov == NULL)
2253 		goto err;
2254 
2255 	switch(sa) {
2256 	case SCSI_PERSISTENT_RESERVE_REGISTER:
2257 	case SCSI_PERSISTENT_RESERVE_RESERVE:
2258 	case SCSI_PERSISTENT_RESERVE_RELEASE:
2259 	case SCSI_PERSISTENT_RESERVE_CLEAR:
2260 	case SCSI_PERSISTENT_RESERVE_PREEMPT:
2261 	case SCSI_PERSISTENT_RESERVE_PREEMPT_AND_ABORT:
2262 	case SCSI_PERSISTENT_RESERVE_REGISTER_AND_IGNORE_EXISTING_KEY:
2263 		basic = param;
2264 
2265 		xferlen = 24;
2266 		buf = scsi_malloc(task, xferlen);
2267 		if (buf == NULL)
2268 			goto err;
2269 
2270 		memset(buf, 0, xferlen);
2271 		scsi_set_uint64(&buf[0], basic->reservation_key);
2272 		scsi_set_uint64(&buf[8], basic->service_action_reservation_key);
2273 		if (basic->spec_i_pt) {
2274 			buf[20] |= 0x08;
2275 		}
2276 		if (basic->all_tg_pt) {
2277 			buf[20] |= 0x04;
2278 		}
2279 		if (basic->aptpl) {
2280 			buf[20] |= 0x01;
2281 		}
2282 		break;
2283 	case SCSI_PERSISTENT_RESERVE_REGISTER_AND_MOVE:
2284 		/* XXX FIXME */
2285 		goto err;
2286 	default:
2287 		goto err;
2288 	}
2289 
2290 	task->cdb[0] = SCSI_OPCODE_PERSISTENT_RESERVE_OUT;
2291 	task->cdb[1] |= sa & 0x1f;
2292 	task->cdb[2] = ((scope << 4) & 0xf0) | (type & 0x0f);
2293 
2294 	scsi_set_uint32(&task->cdb[5], xferlen);
2295 
2296 	task->cdb_size = 10;
2297 	task->xfer_dir = SCSI_XFER_WRITE;
2298 	task->expxferlen = xferlen;
2299 
2300 	iov->iov_base = buf;
2301 	iov->iov_len  = xferlen;
2302 	scsi_task_set_iov_out(task, iov, 1);
2303 
2304 	return task;
2305 
2306 err:
2307 	scsi_free_scsi_task(task);
2308 	return NULL;
2309 }
2310 
2311 /*
2312  * WRITE_SAME10
2313  */
2314 struct scsi_task *
scsi_cdb_writesame10(int wrprotect,int anchor,int unmap,uint32_t lba,int group,uint16_t num_blocks,uint32_t datalen)2315 scsi_cdb_writesame10(int wrprotect, int anchor, int unmap, uint32_t lba, int group, uint16_t num_blocks, uint32_t datalen)
2316 {
2317 	struct scsi_task *task;
2318 
2319 	task = malloc(sizeof(struct scsi_task));
2320 	if (task == NULL) {
2321 		return NULL;
2322 	}
2323 
2324 	memset(task, 0, sizeof(struct scsi_task));
2325 	task->cdb[0]   = SCSI_OPCODE_WRITE_SAME10;
2326 
2327 	if (wrprotect) {
2328 		task->cdb[1] |= ((wrprotect & 0x7) << 5);
2329 	}
2330 	if (anchor) {
2331 		task->cdb[1] |= 0x10;
2332 	}
2333 	if (unmap) {
2334 		task->cdb[1] |= 0x08;
2335 	}
2336 	scsi_set_uint32(&task->cdb[2], lba);
2337 	if (group) {
2338 		task->cdb[6] |= (group & 0x1f);
2339 	}
2340 	scsi_set_uint16(&task->cdb[7], num_blocks);
2341 
2342 	task->cdb_size = 10;
2343 	task->xfer_dir = SCSI_XFER_WRITE;
2344 	task->expxferlen = datalen;
2345 
2346 	return task;
2347 }
2348 
2349 /*
2350  * WRITE_SAME16
2351  */
2352 struct scsi_task *
scsi_cdb_writesame16(int wrprotect,int anchor,int unmap,uint64_t lba,int group,uint32_t num_blocks,uint32_t datalen)2353 scsi_cdb_writesame16(int wrprotect, int anchor, int unmap, uint64_t lba, int group, uint32_t num_blocks, uint32_t datalen)
2354 {
2355 	struct scsi_task *task;
2356 
2357 	task = malloc(sizeof(struct scsi_task));
2358 	if (task == NULL) {
2359 		return NULL;
2360 	}
2361 
2362 	memset(task, 0, sizeof(struct scsi_task));
2363 	task->cdb[0]   = SCSI_OPCODE_WRITE_SAME16;
2364 
2365 	if (wrprotect) {
2366 		task->cdb[1] |= ((wrprotect & 0x7) << 5);
2367 	}
2368 	if (anchor) {
2369 		task->cdb[1] |= 0x10;
2370 	}
2371 	if (unmap) {
2372 		task->cdb[1] |= 0x08;
2373 	}
2374 	if (datalen == 0) {
2375 		task->cdb[1] |= 0x01;
2376 	}
2377 	scsi_set_uint32(&task->cdb[2], lba >> 32);
2378 	scsi_set_uint32(&task->cdb[6], lba & 0xffffffff);
2379 	scsi_set_uint32(&task->cdb[10], num_blocks);
2380 	if (group) {
2381 		task->cdb[14] |= (group & 0x1f);
2382 	}
2383 
2384 	task->cdb_size = 16;
2385 	task->xfer_dir = SCSI_XFER_WRITE;
2386 	task->expxferlen = datalen;
2387 
2388 	return task;
2389 }
2390 
2391 /*
2392  * MODESENSE6
2393  */
2394 struct scsi_task *
scsi_cdb_modesense6(int dbd,enum scsi_modesense_page_control pc,enum scsi_modesense_page_code page_code,int sub_page_code,unsigned char alloc_len)2395 scsi_cdb_modesense6(int dbd, enum scsi_modesense_page_control pc,
2396 		    enum scsi_modesense_page_code page_code,
2397 		    int sub_page_code, unsigned char alloc_len)
2398 {
2399 	struct scsi_task *task;
2400 
2401 	task = malloc(sizeof(struct scsi_task));
2402 	if (task == NULL) {
2403 		return NULL;
2404 	}
2405 
2406 	memset(task, 0, sizeof(struct scsi_task));
2407 	task->cdb[0]   = SCSI_OPCODE_MODESENSE6;
2408 
2409 	if (dbd) {
2410 		task->cdb[1] |= 0x08;
2411 	}
2412 	task->cdb[2] = pc<<6 | page_code;
2413 	task->cdb[3] = sub_page_code;
2414 	task->cdb[4] = alloc_len;
2415 
2416 	task->cdb_size = 6;
2417 	if (alloc_len != 0) {
2418 		task->xfer_dir = SCSI_XFER_READ;
2419 	} else {
2420 		task->xfer_dir = SCSI_XFER_NONE;
2421 	}
2422 	task->expxferlen = alloc_len;
2423 
2424 	return task;
2425 }
2426 
2427 /*
2428  * MODESENSE10
2429  */
2430 struct scsi_task *
scsi_cdb_modesense10(int llbaa,int dbd,enum scsi_modesense_page_control pc,enum scsi_modesense_page_code page_code,int sub_page_code,unsigned char alloc_len)2431 scsi_cdb_modesense10(int llbaa, int dbd, enum scsi_modesense_page_control pc,
2432 		    enum scsi_modesense_page_code page_code,
2433 		    int sub_page_code, unsigned char alloc_len)
2434 {
2435 	struct scsi_task *task;
2436 
2437 	task = malloc(sizeof(struct scsi_task));
2438 	if (task == NULL) {
2439 		return NULL;
2440 	}
2441 
2442 	memset(task, 0, sizeof(struct scsi_task));
2443 	task->cdb[0]   = SCSI_OPCODE_MODESENSE10;
2444 
2445 	if (llbaa) {
2446 		task->cdb[1] |= 0x10;
2447 	}
2448 	if (dbd) {
2449 		task->cdb[1] |= 0x08;
2450 	}
2451 	task->cdb[2] = pc<<6 | page_code;
2452 	task->cdb[3] = sub_page_code;
2453 
2454 	scsi_set_uint16(&task->cdb[7], alloc_len);
2455 
2456 	task->cdb_size = 10;
2457 	if (alloc_len != 0) {
2458 		task->xfer_dir = SCSI_XFER_READ;
2459 	} else {
2460 		task->xfer_dir = SCSI_XFER_NONE;
2461 	}
2462 	task->expxferlen = alloc_len;
2463 
2464 	return task;
2465 }
2466 
2467 /*
2468  * MODESELECT6
2469  */
2470 struct scsi_task *
scsi_cdb_modeselect6(int pf,int sp,int param_len)2471 scsi_cdb_modeselect6(int pf, int sp, int param_len)
2472 {
2473 	struct scsi_task *task;
2474 
2475 	task = malloc(sizeof(struct scsi_task));
2476 	if (task == NULL) {
2477 		return NULL;
2478 	}
2479 
2480 	memset(task, 0, sizeof(struct scsi_task));
2481 	task->cdb[0]   = SCSI_OPCODE_MODESELECT6;
2482 
2483 	if (pf) {
2484 		task->cdb[1] |= 0x10;
2485 	}
2486 	if (sp) {
2487 		task->cdb[1] |= 0x01;
2488 	}
2489 	task->cdb[4] = param_len;
2490 
2491 	task->cdb_size = 6;
2492 	if (param_len != 0) {
2493 		task->xfer_dir = SCSI_XFER_WRITE;
2494 	} else {
2495 		task->xfer_dir = SCSI_XFER_NONE;
2496 	}
2497 	task->expxferlen = param_len;
2498 
2499 	return task;
2500 }
2501 
2502 /*
2503  * MODESELECT10
2504  */
2505 struct scsi_task *
scsi_cdb_modeselect10(int pf,int sp,int param_len)2506 scsi_cdb_modeselect10(int pf, int sp, int param_len)
2507 {
2508 	struct scsi_task *task;
2509 
2510 	task = malloc(sizeof(struct scsi_task));
2511 	if (task == NULL) {
2512 		return NULL;
2513 	}
2514 
2515 	memset(task, 0, sizeof(struct scsi_task));
2516 	task->cdb[0]   = SCSI_OPCODE_MODESELECT10;
2517 
2518 	if (pf) {
2519 		task->cdb[1] |= 0x10;
2520 	}
2521 	if (sp) {
2522 		task->cdb[1] |= 0x01;
2523 	}
2524 
2525 	scsi_set_uint16(&task->cdb[7], param_len);
2526 
2527 	task->cdb_size = 10;
2528 	if (param_len != 0) {
2529 		task->xfer_dir = SCSI_XFER_WRITE;
2530 	} else {
2531 		task->xfer_dir = SCSI_XFER_NONE;
2532 	}
2533 	task->expxferlen = param_len;
2534 
2535 	return task;
2536 }
2537 
2538 struct scsi_mode_page *
scsi_modesense_get_page(struct scsi_mode_sense * ms,enum scsi_modesense_page_code page_code,int subpage_code)2539 scsi_modesense_get_page(struct scsi_mode_sense *ms,
2540 			enum scsi_modesense_page_code page_code,
2541 			int subpage_code)
2542 {
2543 	struct scsi_mode_page *mp;
2544 
2545 	for (mp = ms->pages; mp; mp = mp->next) {
2546 		if (mp->page_code == page_code
2547 		&&  mp->subpage_code == subpage_code) {
2548 			return mp;
2549 		}
2550 	}
2551 	return NULL;
2552 }
2553 
2554 
2555 /*
2556  * parse the data in blob and calculate the size of a full
2557  * modesense6 datain structure
2558  */
2559 static int
scsi_modesense_datain_getfullsize(struct scsi_task * task,int is_modesense6)2560 scsi_modesense_datain_getfullsize(struct scsi_task *task, int is_modesense6)
2561 {
2562 	int len;
2563 
2564 	if (is_modesense6) {
2565 		len = task_get_uint8(task, 0) + 1;
2566 	} else {
2567 		len = task_get_uint16(task, 0) + 2;
2568 	}
2569 
2570 	return len;
2571 }
2572 
2573 static void
scsi_parse_mode_caching(struct scsi_task * task,int pos,struct scsi_mode_page * mp)2574 scsi_parse_mode_caching(struct scsi_task *task, int pos, struct scsi_mode_page *mp)
2575 {
2576 	mp->caching.ic   = !!(task_get_uint8(task, pos) & 0x80);
2577 	mp->caching.abpf = !!(task_get_uint8(task, pos) & 0x40);
2578 	mp->caching.cap  = !!(task_get_uint8(task, pos) & 0x20);
2579 	mp->caching.disc = !!(task_get_uint8(task, pos) & 0x10);
2580 	mp->caching.size = !!(task_get_uint8(task, pos) & 0x08);
2581 	mp->caching.wce  = !!(task_get_uint8(task, pos) & 0x04);
2582 	mp->caching.mf   = !!(task_get_uint8(task, pos) & 0x02);
2583 	mp->caching.rcd  = !!(task_get_uint8(task, pos) & 0x01);
2584 
2585 	mp->caching.demand_read_retention_priority =
2586 		(task_get_uint8(task, pos + 1) >> 4) & 0x0f;
2587 	mp->caching.write_retention_priority       =
2588 		task_get_uint8(task, pos + 1) & 0x0f;
2589 
2590 	mp->caching.disable_prefetch_transfer_length =
2591 		task_get_uint16(task, pos + 2);
2592 	mp->caching.minimum_prefetch = task_get_uint16(task, pos + 4);
2593 	mp->caching.maximum_prefetch = task_get_uint16(task, pos + 6);
2594 	mp->caching.maximum_prefetch_ceiling = task_get_uint16(task, pos + 8);
2595 
2596 	mp->caching.fsw    = !!(task_get_uint8(task, pos + 10) & 0x80);
2597 	mp->caching.lbcss  = !!(task_get_uint8(task, pos + 10) & 0x40);
2598 	mp->caching.dra    = !!(task_get_uint8(task, pos + 10) & 0x20);
2599 	mp->caching.nv_dis = !!(task_get_uint8(task, pos + 10) & 0x01);
2600 
2601 	mp->caching.number_of_cache_segments = task_get_uint8(task, pos + 11);
2602 	mp->caching.cache_segment_size = task_get_uint16(task, pos + 12);
2603 }
2604 
2605 static void
scsi_parse_mode_control(struct scsi_task * task,int pos,struct scsi_mode_page * mp)2606 scsi_parse_mode_control(struct scsi_task *task, int pos, struct scsi_mode_page *mp)
2607 {
2608 	mp->control.tst      = (task_get_uint8(task, pos) >> 5) & 0x07;
2609 	mp->control.tmf_only = !!(task_get_uint8(task, pos) & 0x10);
2610 	mp->control.dpicz    = !!(task_get_uint8(task, pos) & 0x08);
2611 	mp->control.d_sense  = !!(task_get_uint8(task, pos) & 0x04);
2612 	mp->control.gltsd    = !!(task_get_uint8(task, pos) & 0x02);
2613 	mp->control.rlec     = !!(task_get_uint8(task, pos) & 0x01);
2614 
2615 	mp->control.queue_algorithm_modifier  =
2616 		(task_get_uint8(task, pos + 1) >> 4) & 0x0f;
2617 	mp->control.nuar = task_get_uint8(task, pos + 1) & 0x08;
2618 	mp->control.qerr = (task_get_uint8(task, pos + 1) >> 1) & 0x03;
2619 
2620 	mp->control.vs  = !!(task_get_uint8(task, pos + 2) & 0x80);
2621 	mp->control.rac = !!(task_get_uint8(task, pos + 2) & 0x40);
2622 	mp->control.ua_intlck_ctrl =
2623 		(task_get_uint8(task, pos + 2) >> 4) & 0x0f;
2624 	mp->control.swp = !!(task_get_uint8(task, pos + 2) & 0x08);
2625 
2626 	mp->control.ato   = !!(task_get_uint8(task, pos + 3) & 0x80);
2627 	mp->control.tas   = !!(task_get_uint8(task, pos + 3) & 0x40);
2628 	mp->control.atmpe = !!(task_get_uint8(task, pos + 3) & 0x20);
2629 	mp->control.rwwp  = !!(task_get_uint8(task, pos + 3) & 0x10);
2630 	mp->control.autoload_mode = !!(task_get_uint8(task, pos + 3) & 0x07);
2631 
2632 	mp->control.busy_timeout_period =
2633 		task_get_uint16(task, pos + 6);
2634 	mp->control.extended_selftest_completion_time =
2635 		task_get_uint16(task, pos + 8);
2636 }
2637 
2638 static void
scsi_parse_mode_power_condition(struct scsi_task * task,int pos,struct scsi_mode_page * mp)2639 scsi_parse_mode_power_condition(struct scsi_task *task, int pos, struct scsi_mode_page *mp)
2640 {
2641 	mp->power_condition.pm_bg_precedence =
2642 		(task_get_uint8(task, pos) >> 6) & 0x03;
2643 	mp->power_condition.standby_y =
2644 		!!(task_get_uint8(task, pos) & 0x01);
2645 
2646 	mp->power_condition.idle_c =
2647 		!!(task_get_uint8(task, pos + 1) & 0x08);
2648 	mp->power_condition.idle_b =
2649 		!!(task_get_uint8(task, pos + 1) & 0x04);
2650 	mp->power_condition.idle_a =
2651 		!!(task_get_uint8(task, pos + 1) & 0x02);
2652 	mp->power_condition.standby_z =
2653 		!!(task_get_uint8(task, pos + 1) & 0x01);
2654 
2655 	mp->power_condition.idle_a_condition_timer =
2656 		task_get_uint32(task, pos + 2);
2657 	mp->power_condition.standby_z_condition_timer =
2658 		task_get_uint32(task, pos + 6);
2659 	mp->power_condition.idle_b_condition_timer =
2660 		task_get_uint32(task, pos + 10);
2661 	mp->power_condition.idle_c_condition_timer =
2662 		task_get_uint32(task, pos + 14);
2663 	mp->power_condition.standby_y_condition_timer =
2664 		task_get_uint32(task, pos + 18);
2665 
2666 	mp->power_condition.ccf_idle =
2667 		(task_get_uint8(task, pos + 37) >> 6) & 0x03;
2668 	mp->power_condition.ccf_standby =
2669 		(task_get_uint8(task, pos + 37) >> 4) & 0x03;
2670 	mp->power_condition.ccf_stopped =
2671 		(task_get_uint8(task, pos + 37) >> 2) & 0x03;
2672 }
2673 
2674 static void
scsi_parse_mode_disconnect_reconnect(struct scsi_task * task,int pos,struct scsi_mode_page * mp)2675 scsi_parse_mode_disconnect_reconnect(struct scsi_task *task, int pos, struct scsi_mode_page *mp)
2676 {
2677 	mp->disconnect_reconnect.buffer_full_ratio =
2678 		task_get_uint8(task, pos);
2679 	mp->disconnect_reconnect.buffer_empty_ratio =
2680 		task_get_uint8(task, pos + 1);
2681 	mp->disconnect_reconnect.bus_inactivity_limit =
2682 		task_get_uint16(task, pos + 2);
2683 	mp->disconnect_reconnect.disconnect_time_limit =
2684 		task_get_uint16(task, pos + 4);
2685 	mp->disconnect_reconnect.connect_time_limit =
2686 		task_get_uint16(task, pos + 6);
2687 	mp->disconnect_reconnect.maximum_burst_size =
2688 		task_get_uint16(task, pos + 8);
2689 	mp->disconnect_reconnect.emdp =
2690 		!!(task_get_uint8(task, pos + 10) & 0x80);
2691 	mp->disconnect_reconnect.fair_arbitration =
2692 		(task_get_uint8(task, pos + 10) >> 4) & 0x0f;
2693 	mp->disconnect_reconnect.dimm =
2694 		!!(task_get_uint8(task, pos + 10) & 0x08);
2695 	mp->disconnect_reconnect.dtdc =
2696 		task_get_uint8(task, pos + 10) & 0x07;
2697 	mp->disconnect_reconnect.first_burst_size =
2698 		task_get_uint16(task, pos + 12);
2699 }
2700 
2701 static void
scsi_parse_mode_informational_exceptions_control(struct scsi_task * task,int pos,struct scsi_mode_page * mp)2702 scsi_parse_mode_informational_exceptions_control(struct scsi_task *task, int pos, struct scsi_mode_page *mp)
2703 {
2704 	mp->iec.perf           = !!(task_get_uint8(task, pos) & 0x80);
2705 	mp->iec.ebf            = !!(task_get_uint8(task, pos) & 0x20);
2706 	mp->iec.ewasc          = !!(task_get_uint8(task, pos) & 0x10);
2707 	mp->iec.dexcpt         = !!(task_get_uint8(task, pos) & 0x08);
2708 	mp->iec.test           = !!(task_get_uint8(task, pos) & 0x04);
2709 	mp->iec.ebackerr       = !!(task_get_uint8(task, pos) & 0x02);
2710 	mp->iec.logerr         = !!(task_get_uint8(task, pos) & 0x01);
2711 	mp->iec.mrie           = task_get_uint8(task, pos + 1) & 0x0f;
2712 	mp->iec.interval_timer = task_get_uint32(task, pos + 2);
2713 	mp->iec.report_count   = task_get_uint32(task, pos + 6);
2714 }
2715 
2716 
2717 /*
2718  * parse and unmarshall the mode sense data in buffer
2719  */
2720 static struct scsi_mode_sense *
scsi_modesense_datain_unmarshall(struct scsi_task * task,int is_modesense6)2721 scsi_modesense_datain_unmarshall(struct scsi_task *task, int is_modesense6)
2722 {
2723 	struct scsi_mode_sense *ms;
2724 	int hdr_len;
2725 	int pos;
2726 
2727 	if (is_modesense6) {
2728 		hdr_len = 4;
2729 	} else {
2730 		hdr_len = 8;
2731 	}
2732 
2733 	if (task->datain.size < hdr_len) {
2734 		return NULL;
2735 	}
2736 
2737 	ms = scsi_malloc(task, sizeof(struct scsi_mode_sense));
2738 	if (ms == NULL) {
2739 		return NULL;
2740 	}
2741 
2742 	if (is_modesense6) {
2743 		ms->mode_data_length          = task_get_uint8(task, 0);
2744 		ms->medium_type               = task_get_uint8(task, 1);
2745 		ms->device_specific_parameter = task_get_uint8(task, 2);
2746 		ms->block_descriptor_length   = task_get_uint8(task, 3);
2747 		ms->pages                     = NULL;
2748 	} else {
2749 		ms->mode_data_length          = task_get_uint16(task, 0);
2750 		ms->medium_type               = task_get_uint8(task, 2);
2751 		ms->device_specific_parameter = task_get_uint8(task, 3);
2752 		ms->longlba = task_get_uint8(task, 4) & 0x01;
2753 		ms->block_descriptor_length   = task_get_uint16(task, 6);
2754 		ms->pages                     = NULL;
2755 	}
2756 
2757 	if (ms->mode_data_length + 1 > task->datain.size) {
2758 		return NULL;
2759 	}
2760 
2761 	pos = hdr_len + ms->block_descriptor_length;
2762 	while (pos < task->datain.size) {
2763 		struct scsi_mode_page *mp;
2764 
2765 		mp = scsi_malloc(task, sizeof(struct scsi_mode_page));
2766 		if (mp == NULL) {
2767 			return ms;
2768 		}
2769 		mp->ps           = task_get_uint8(task, pos) & 0x80;
2770 		mp->spf          = task_get_uint8(task, pos) & 0x40;
2771 		mp->page_code    = task_get_uint8(task, pos) & 0x3f;
2772 		pos++;
2773 
2774 		if (mp->spf) {
2775 			mp->subpage_code = task_get_uint8(task, pos);
2776 			mp->len = task_get_uint16(task, pos + 1);
2777 			pos += 3;
2778 		} else {
2779 			mp->subpage_code = 0;
2780 			mp->len          = task_get_uint8(task, pos);
2781 			pos++;
2782 		}
2783 
2784 		switch (mp->page_code) {
2785 		case SCSI_MODEPAGE_CACHING:
2786 			scsi_parse_mode_caching(task, pos, mp);
2787 			break;
2788 		case SCSI_MODEPAGE_CONTROL:
2789 			scsi_parse_mode_control(task, pos, mp);
2790 			break;
2791 		case SCSI_MODEPAGE_DISCONNECT_RECONNECT:
2792 			scsi_parse_mode_disconnect_reconnect(task, pos, mp);
2793 			break;
2794 		case SCSI_MODEPAGE_INFORMATIONAL_EXCEPTIONS_CONTROL:
2795 			scsi_parse_mode_informational_exceptions_control(task, pos, mp);
2796 			break;
2797 		case SCSI_MODEPAGE_POWER_CONDITION:
2798 			scsi_parse_mode_power_condition(task, pos, mp);
2799 			break;
2800 		default:
2801 			/* TODO: process other pages, or add raw data to struct
2802 			 * scsi_mode_page.  */
2803 			break;
2804 		}
2805 
2806 		mp->next  = ms->pages;
2807 		ms->pages = mp;
2808 
2809 		pos += mp->len;
2810 	}
2811 
2812 	return ms;
2813 }
2814 
2815 static struct scsi_data *
scsi_modesense_marshall_caching(struct scsi_task * task,struct scsi_mode_page * mp,int hdr_size)2816 scsi_modesense_marshall_caching(struct scsi_task *task,
2817 				struct scsi_mode_page *mp,
2818 				int hdr_size)
2819 {
2820 	struct scsi_data *data;
2821 
2822 	data = scsi_malloc(task, sizeof(struct scsi_data));
2823 
2824 	data->size = 20 + hdr_size;
2825 	data->data = scsi_malloc(task, data->size);
2826 
2827 	if (mp->caching.ic)   data->data[hdr_size + 2] |= 0x80;
2828 	if (mp->caching.abpf) data->data[hdr_size + 2] |= 0x40;
2829 	if (mp->caching.cap)  data->data[hdr_size + 2] |= 0x20;
2830 	if (mp->caching.disc) data->data[hdr_size + 2] |= 0x10;
2831 	if (mp->caching.size) data->data[hdr_size + 2] |= 0x08;
2832 	if (mp->caching.wce)  data->data[hdr_size + 2] |= 0x04;
2833 	if (mp->caching.mf)   data->data[hdr_size + 2] |= 0x02;
2834 	if (mp->caching.rcd)  data->data[hdr_size + 2] |= 0x01;
2835 
2836 	data->data[hdr_size + 3] |= (mp->caching.demand_read_retention_priority << 4) & 0xf0;
2837 	data->data[hdr_size + 3] |= mp->caching.write_retention_priority & 0x0f;
2838 
2839 	scsi_set_uint16(&data->data[hdr_size + 4], mp->caching.disable_prefetch_transfer_length);
2840 	scsi_set_uint16(&data->data[hdr_size + 6], mp->caching.minimum_prefetch);
2841 	scsi_set_uint16(&data->data[hdr_size + 8], mp->caching.maximum_prefetch);
2842 	scsi_set_uint16(&data->data[hdr_size + 10], mp->caching.maximum_prefetch_ceiling);
2843 
2844 	if (mp->caching.fsw)    data->data[hdr_size + 12] |= 0x80;
2845 	if (mp->caching.lbcss)  data->data[hdr_size + 12] |= 0x40;
2846 	if (mp->caching.dra)    data->data[hdr_size + 12] |= 0x20;
2847 	if (mp->caching.nv_dis) data->data[hdr_size + 12] |= 0x01;
2848 
2849 	data->data[hdr_size + 13] = mp->caching.number_of_cache_segments;
2850 
2851 	scsi_set_uint16(&data->data[hdr_size + 14], mp->caching.cache_segment_size);
2852 
2853 	return data;
2854 }
2855 
2856 static struct scsi_data *
scsi_modesense_marshall_control(struct scsi_task * task,struct scsi_mode_page * mp,int hdr_size)2857 scsi_modesense_marshall_control(struct scsi_task *task,
2858 				struct scsi_mode_page *mp,
2859 				int hdr_size)
2860 {
2861 	struct scsi_data *data;
2862 
2863 	data = scsi_malloc(task, sizeof(struct scsi_data));
2864 
2865 	data->size = 12 + hdr_size;
2866 	data->data = scsi_malloc(task, data->size);
2867 
2868 	data->data[hdr_size + 2] |= (mp->control.tst << 5) & 0xe0;
2869 	if (mp->control.tmf_only) data->data[hdr_size + 2] |= 0x10;
2870 	if (mp->control.dpicz)    data->data[hdr_size + 2] |= 0x08;
2871 	if (mp->control.d_sense)  data->data[hdr_size + 2] |= 0x04;
2872 	if (mp->control.gltsd)    data->data[hdr_size + 2] |= 0x02;
2873 	if (mp->control.rlec)     data->data[hdr_size + 2] |= 0x01;
2874 
2875 	data->data[hdr_size + 3] |= (mp->control.queue_algorithm_modifier << 4) & 0xf0;
2876 	if (mp->control.nuar)     data->data[hdr_size + 3] |= 0x08;
2877 	data->data[hdr_size + 3] |= (mp->control.qerr << 1) & 0x06;
2878 
2879 	if (mp->control.vs)       data->data[hdr_size + 4] |= 0x80;
2880 	if (mp->control.rac)      data->data[hdr_size + 4] |= 0x40;
2881 	data->data[hdr_size + 4] |= (mp->control.ua_intlck_ctrl << 4) & 0x30;
2882 	if (mp->control.swp)      data->data[hdr_size + 4] |= 0x08;
2883 
2884 	if (mp->control.ato)      data->data[hdr_size + 5] |= 0x80;
2885 	if (mp->control.tas)      data->data[hdr_size + 5] |= 0x40;
2886 	if (mp->control.atmpe)    data->data[hdr_size + 5] |= 0x20;
2887 	if (mp->control.rwwp)     data->data[hdr_size + 5] |= 0x10;
2888 	data->data[hdr_size + 5] |= mp->control.autoload_mode & 0x07;
2889 
2890 	scsi_set_uint16(&data->data[hdr_size + 8], mp->control.busy_timeout_period);
2891 	scsi_set_uint16(&data->data[hdr_size + 10], mp->control.extended_selftest_completion_time);
2892 
2893 	return data;
2894 }
2895 
2896 static struct scsi_data *
scsi_modesense_marshall_power_condition(struct scsi_task * task,struct scsi_mode_page * mp,int hdr_size)2897 scsi_modesense_marshall_power_condition(struct scsi_task *task,
2898 					struct scsi_mode_page *mp,
2899 					int hdr_size)
2900 {
2901 	struct scsi_data *data;
2902 
2903 	data = scsi_malloc(task, sizeof(struct scsi_data));
2904 
2905 	data->size = 40 + hdr_size;
2906 	data->data = scsi_malloc(task, data->size);
2907 
2908 	data->data[hdr_size + 2] |=
2909 		(mp->power_condition.pm_bg_precedence << 6) & 0xc0;
2910 	if (mp->power_condition.standby_y) data->data[hdr_size + 2] |= 0x01;
2911 
2912 	if (mp->power_condition.idle_c) data->data[hdr_size + 3] |= 0x08;
2913 	if (mp->power_condition.idle_b) data->data[hdr_size + 3] |= 0x04;
2914 	if (mp->power_condition.idle_a) data->data[hdr_size + 3] |= 0x02;
2915 	if (mp->power_condition.standby_z) data->data[hdr_size + 3] |= 0x01;
2916 
2917 	scsi_set_uint32(&data->data[hdr_size + 4],
2918 		mp->power_condition.idle_a_condition_timer);
2919 	scsi_set_uint32(&data->data[hdr_size + 8],
2920 		mp->power_condition.standby_z_condition_timer);
2921 	scsi_set_uint32(&data->data[hdr_size + 12],
2922 		mp->power_condition.idle_b_condition_timer);
2923 	scsi_set_uint32(&data->data[hdr_size + 16],
2924 		mp->power_condition.idle_c_condition_timer);
2925 	scsi_set_uint32(&data->data[hdr_size + 20],
2926 		mp->power_condition.standby_y_condition_timer);
2927 
2928 	data->data[hdr_size + 39] |=
2929 		(mp->power_condition.ccf_idle << 6) & 0xc0;
2930 	data->data[hdr_size + 39] |=
2931 		(mp->power_condition.ccf_standby << 4) & 0x30;
2932 	data->data[hdr_size + 39] |=
2933 		(mp->power_condition.ccf_stopped << 2) & 0x0c;
2934 
2935 	return data;
2936 }
2937 
2938 static struct scsi_data *
scsi_modesense_marshall_disconnect_reconnect(struct scsi_task * task,struct scsi_mode_page * mp,int hdr_size)2939 scsi_modesense_marshall_disconnect_reconnect(struct scsi_task *task,
2940 					struct scsi_mode_page *mp,
2941 					int hdr_size)
2942 {
2943 	struct scsi_data *data;
2944 
2945 	data = scsi_malloc(task, sizeof(struct scsi_data));
2946 
2947 	data->size = 16 + hdr_size;
2948 	data->data = scsi_malloc(task, data->size);
2949 
2950 	data->data[hdr_size + 2] = mp->disconnect_reconnect.buffer_full_ratio;
2951 	data->data[hdr_size + 3] = mp->disconnect_reconnect.buffer_empty_ratio;
2952 	scsi_set_uint16(&data->data[hdr_size + 4], mp->disconnect_reconnect.bus_inactivity_limit);
2953 	scsi_set_uint16(&data->data[hdr_size + 6], mp->disconnect_reconnect.disconnect_time_limit);
2954 	scsi_set_uint16(&data->data[hdr_size + 8], mp->disconnect_reconnect.connect_time_limit);
2955 	scsi_set_uint16(&data->data[hdr_size + 10], mp->disconnect_reconnect.maximum_burst_size);
2956 
2957 	if (mp->disconnect_reconnect.emdp) data->data[hdr_size + 12] |= 0x80;
2958 	data->data[hdr_size + 12] |= (mp->disconnect_reconnect.fair_arbitration << 4) & 0x70;
2959 	if (mp->disconnect_reconnect.dimm) data->data[hdr_size + 12] |= 0x08;
2960 	data->data[hdr_size + 12] |= mp->disconnect_reconnect.dtdc & 0x07;
2961 
2962 	scsi_set_uint16(&data->data[hdr_size + 14], mp->disconnect_reconnect.first_burst_size);
2963 
2964 	return data;
2965 }
2966 
2967 static struct scsi_data *
scsi_modesense_marshall_informational_exceptions_control(struct scsi_task * task,struct scsi_mode_page * mp,int hdr_size)2968 scsi_modesense_marshall_informational_exceptions_control(struct scsi_task *task,
2969 					struct scsi_mode_page *mp,
2970 					int hdr_size)
2971 {
2972 	struct scsi_data *data;
2973 
2974 	data = scsi_malloc(task, sizeof(struct scsi_data));
2975 
2976 	data->size = 12 + hdr_size;
2977 	data->data = scsi_malloc(task, data->size);
2978 
2979 	if (mp->iec.perf)     data->data[hdr_size + 2] |= 0x80;
2980 	if (mp->iec.ebf)      data->data[hdr_size + 2] |= 0x20;
2981 	if (mp->iec.ewasc)    data->data[hdr_size + 2] |= 0x10;
2982 	if (mp->iec.dexcpt)   data->data[hdr_size + 2] |= 0x08;
2983 	if (mp->iec.test)     data->data[hdr_size + 2] |= 0x04;
2984 	if (mp->iec.ebackerr) data->data[hdr_size + 2] |= 0x02;
2985 	if (mp->iec.logerr)   data->data[hdr_size + 2] |= 0x01;
2986 
2987 	data->data[hdr_size + 3] |= mp->iec.mrie & 0x0f;
2988 
2989 	scsi_set_uint32(&data->data[hdr_size + 4], mp->iec.interval_timer);
2990 	scsi_set_uint32(&data->data[hdr_size + 8], mp->iec.report_count);
2991 
2992 	return data;
2993 }
2994 
2995 /*
2996  * marshall the mode sense data out buffer
2997  */
2998 struct scsi_data *
scsi_modesense_dataout_marshall(struct scsi_task * task,struct scsi_mode_page * mp,int is_modeselect6)2999 scsi_modesense_dataout_marshall(struct scsi_task *task,
3000 				struct scsi_mode_page *mp,
3001 				int is_modeselect6)
3002 {
3003 	struct scsi_data *data;
3004 	int hdr_size = is_modeselect6 ? 4 : 8;
3005 
3006 	switch (mp->page_code) {
3007 	case SCSI_MODEPAGE_CACHING:
3008 		data = scsi_modesense_marshall_caching(task, mp, hdr_size);
3009 		break;
3010 	case SCSI_MODEPAGE_CONTROL:
3011 		data = scsi_modesense_marshall_control(task, mp, hdr_size);
3012 		break;
3013 	case SCSI_MODEPAGE_DISCONNECT_RECONNECT:
3014 		data = scsi_modesense_marshall_disconnect_reconnect(task, mp, hdr_size);
3015 		break;
3016 	case SCSI_MODEPAGE_INFORMATIONAL_EXCEPTIONS_CONTROL:
3017 		data = scsi_modesense_marshall_informational_exceptions_control(task, mp, hdr_size);
3018 		break;
3019 	case SCSI_MODEPAGE_POWER_CONDITION:
3020 		data = scsi_modesense_marshall_power_condition(task, mp, hdr_size);
3021 		break;
3022 	default:
3023 		/* TODO error reporting ? */
3024 		return NULL;
3025 	}
3026 
3027 	if (data == NULL) {
3028 		return NULL;
3029 	}
3030 
3031 	data->data[hdr_size + 0] = mp->page_code & 0x3f;
3032 	if (mp->ps) {
3033 		data->data[hdr_size + 0] |= 0x80;
3034 	}
3035 	if (mp->spf) {
3036 		data->data[hdr_size + 0] |= 0x40;
3037 		data->data[hdr_size + 1] = mp->subpage_code;
3038 		scsi_set_uint16(&data->data[hdr_size + 2], data->size -hdr_size - 4);
3039 	} else {
3040 		data->data[hdr_size + 1] = (data->size - hdr_size - 2) & 0xff;
3041 	}
3042 
3043 	return data;
3044 }
3045 
3046 
3047 /*
3048  * STARTSTOPUNIT
3049  */
3050 struct scsi_task *
scsi_cdb_startstopunit(int immed,int pcm,int pc,int no_flush,int loej,int start)3051 scsi_cdb_startstopunit(int immed, int pcm, int pc, int no_flush, int loej, int start)
3052 {
3053 	struct scsi_task *task;
3054 
3055 	task = malloc(sizeof(struct scsi_task));
3056 	if (task == NULL) {
3057 		return NULL;
3058 	}
3059 
3060 	memset(task, 0, sizeof(struct scsi_task));
3061 	task->cdb[0]   = SCSI_OPCODE_STARTSTOPUNIT;
3062 
3063 	if (immed) {
3064 		task->cdb[1] |= 0x01;
3065 	}
3066 	task->cdb[3] |= pcm & 0x0f;
3067 	task->cdb[4] |= (pc << 4) & 0xf0;
3068 	if (no_flush) {
3069 		task->cdb[4] |= 0x04;
3070 	}
3071 	if (loej) {
3072 		task->cdb[4] |= 0x02;
3073 	}
3074 	if (start) {
3075 		task->cdb[4] |= 0x01;
3076 	}
3077 
3078 
3079 	task->cdb_size   = 6;
3080 	task->xfer_dir   = SCSI_XFER_NONE;
3081 	task->expxferlen = 0;
3082 
3083 	return task;
3084 }
3085 
3086 /*
3087  * PREVENTALLOWMEDIUMREMOVAL
3088  */
3089 struct scsi_task *
scsi_cdb_preventallow(int prevent)3090 scsi_cdb_preventallow(int prevent)
3091 {
3092 	struct scsi_task *task;
3093 
3094 	task = malloc(sizeof(struct scsi_task));
3095 	if (task == NULL) {
3096 		return NULL;
3097 	}
3098 
3099 	memset(task, 0, sizeof(struct scsi_task));
3100 	task->cdb[0]   = SCSI_OPCODE_PREVENTALLOW;
3101 
3102 	task->cdb[4] = prevent & 0x03;
3103 
3104 	task->cdb_size   = 6;
3105 	task->xfer_dir   = SCSI_XFER_NONE;
3106 	task->expxferlen = 0;
3107 
3108 	return task;
3109 }
3110 
3111 /*
3112  * SYNCHRONIZECACHE10
3113  */
3114 struct scsi_task *
scsi_cdb_synchronizecache10(int lba,int num_blocks,int syncnv,int immed)3115 scsi_cdb_synchronizecache10(int lba, int num_blocks, int syncnv, int immed)
3116 {
3117 	struct scsi_task *task;
3118 
3119 	task = malloc(sizeof(struct scsi_task));
3120 	if (task == NULL) {
3121 		return NULL;
3122 	}
3123 
3124 	memset(task, 0, sizeof(struct scsi_task));
3125 	task->cdb[0]   = SCSI_OPCODE_SYNCHRONIZECACHE10;
3126 
3127 	if (syncnv) {
3128 		task->cdb[1] |= 0x04;
3129 	}
3130 	if (immed) {
3131 		task->cdb[1] |= 0x02;
3132 	}
3133 	scsi_set_uint32(&task->cdb[2], lba);
3134 	scsi_set_uint16(&task->cdb[7], num_blocks);
3135 
3136 	task->cdb_size   = 10;
3137 	task->xfer_dir   = SCSI_XFER_NONE;
3138 	task->expxferlen = 0;
3139 
3140 	return task;
3141 }
3142 
3143 /*
3144  * SYNCHRONIZECACHE16
3145  */
3146 struct scsi_task *
scsi_cdb_synchronizecache16(uint64_t lba,uint32_t num_blocks,int syncnv,int immed)3147 scsi_cdb_synchronizecache16(uint64_t lba, uint32_t num_blocks, int syncnv, int immed)
3148 {
3149 	struct scsi_task *task;
3150 
3151 	task = malloc(sizeof(struct scsi_task));
3152 	if (task == NULL) {
3153 		return NULL;
3154 	}
3155 
3156 	memset(task, 0, sizeof(struct scsi_task));
3157 	task->cdb[0]   = SCSI_OPCODE_SYNCHRONIZECACHE16;
3158 
3159 	if (syncnv) {
3160 		task->cdb[1] |= 0x04;
3161 	}
3162 	if (immed) {
3163 		task->cdb[1] |= 0x02;
3164 	}
3165 	scsi_set_uint32(&task->cdb[2], lba >> 32);
3166 	scsi_set_uint32(&task->cdb[6], lba & 0xffffffff);
3167 	scsi_set_uint32(&task->cdb[10], num_blocks);
3168 
3169 	task->cdb_size   = 16;
3170 	task->xfer_dir   = SCSI_XFER_NONE;
3171 	task->expxferlen = 0;
3172 
3173 	return task;
3174 }
3175 
3176 /*
3177  * PREFETCH10
3178  */
3179 struct scsi_task *
scsi_cdb_prefetch10(uint32_t lba,int num_blocks,int immed,int group)3180 scsi_cdb_prefetch10(uint32_t lba, int num_blocks, int immed, int group)
3181 {
3182 	struct scsi_task *task;
3183 
3184 	task = malloc(sizeof(struct scsi_task));
3185 	if (task == NULL) {
3186 		return NULL;
3187 	}
3188 
3189 	memset(task, 0, sizeof(struct scsi_task));
3190 	task->cdb[0]   = SCSI_OPCODE_PREFETCH10;
3191 
3192 	if (immed) {
3193 		task->cdb[1] |= 0x02;
3194 	}
3195 	scsi_set_uint32(&task->cdb[2], lba);
3196 	task->cdb[6] |= group & 0x1f;
3197 	scsi_set_uint16(&task->cdb[7], num_blocks);
3198 
3199 	task->cdb_size   = 10;
3200 	task->xfer_dir   = SCSI_XFER_NONE;
3201 	task->expxferlen = 0;
3202 
3203 	return task;
3204 }
3205 
3206 /*
3207  * PREFETCH16
3208  */
3209 struct scsi_task *
scsi_cdb_prefetch16(uint64_t lba,int num_blocks,int immed,int group)3210 scsi_cdb_prefetch16(uint64_t lba, int num_blocks, int immed, int group)
3211 {
3212 	struct scsi_task *task;
3213 
3214 	task = malloc(sizeof(struct scsi_task));
3215 	if (task == NULL) {
3216 		return NULL;
3217 	}
3218 
3219 	memset(task, 0, sizeof(struct scsi_task));
3220 	task->cdb[0]   = SCSI_OPCODE_PREFETCH16;
3221 
3222 	if (immed) {
3223 		task->cdb[1] |= 0x02;
3224 	}
3225 	scsi_set_uint32(&task->cdb[2], lba >> 32);
3226 	scsi_set_uint32(&task->cdb[6], lba & 0xffffffff);
3227 	scsi_set_uint32(&task->cdb[10], num_blocks);
3228 
3229 	task->cdb[14] |= group & 0x1f;
3230 
3231 	task->cdb_size   = 16;
3232 	task->xfer_dir   = SCSI_XFER_NONE;
3233 	task->expxferlen = 0;
3234 
3235 	return task;
3236 }
3237 
3238 /*
3239  * SERVICEACTIONIN16
3240  */
3241 struct scsi_task *
scsi_cdb_serviceactionin16(enum scsi_service_action_in sa,uint32_t xferlen)3242 scsi_cdb_serviceactionin16(enum scsi_service_action_in sa, uint32_t xferlen)
3243 {
3244 	struct scsi_task *task;
3245 
3246 	task = malloc(sizeof(struct scsi_task));
3247 	if (task == NULL) {
3248 		return NULL;
3249 	}
3250 
3251 	memset(task, 0, sizeof(struct scsi_task));
3252 	task->cdb[0]   = SCSI_OPCODE_SERVICE_ACTION_IN;
3253 
3254 	task->cdb[1] = sa;
3255 
3256 	scsi_set_uint32(&task->cdb[10], xferlen);
3257 
3258 	task->cdb_size   = 16;
3259 	if (xferlen != 0) {
3260 		task->xfer_dir = SCSI_XFER_READ;
3261 	} else {
3262 		task->xfer_dir = SCSI_XFER_NONE;
3263 	}
3264 	task->expxferlen = xferlen;
3265 
3266 	return task;
3267 }
3268 
3269 /*
3270  * READCAPACITY16
3271  */
3272 struct scsi_task *
scsi_cdb_readcapacity16(void)3273 scsi_cdb_readcapacity16(void)
3274 {
3275 	return scsi_cdb_serviceactionin16(SCSI_READCAPACITY16, 32);
3276 }
3277 
3278 /*
3279  * GET_LBA_STATUS
3280  */
3281 struct scsi_task *
scsi_cdb_get_lba_status(uint64_t starting_lba,uint32_t alloc_len)3282 scsi_cdb_get_lba_status(uint64_t starting_lba, uint32_t alloc_len)
3283 {
3284 	struct scsi_task *task;
3285 
3286 	task = malloc(sizeof(struct scsi_task));
3287 	if (task == NULL) {
3288 		return NULL;
3289 	}
3290 
3291 	memset(task, 0, sizeof(struct scsi_task));
3292 	task->cdb[0]   = SCSI_OPCODE_SERVICE_ACTION_IN;
3293 
3294 	task->cdb[1] = SCSI_GET_LBA_STATUS;
3295 
3296 	scsi_set_uint32(&task->cdb[2], starting_lba >> 32);
3297 	scsi_set_uint32(&task->cdb[6], starting_lba & 0xffffffff);
3298 	scsi_set_uint32(&task->cdb[10], alloc_len);
3299 
3300 	task->cdb_size   = 16;
3301 	if (alloc_len != 0) {
3302 		task->xfer_dir = SCSI_XFER_READ;
3303 	} else {
3304 		task->xfer_dir = SCSI_XFER_NONE;
3305 	}
3306 	task->expxferlen = alloc_len;
3307 
3308 	return task;
3309 }
3310 
3311 /*
3312  * WRITEVERIFY10
3313  */
3314 struct scsi_task *
scsi_cdb_writeverify10(uint32_t lba,uint32_t xferlen,int blocksize,int wrprotect,int dpo,int bytchk,int group_number)3315 scsi_cdb_writeverify10(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number)
3316 {
3317 	struct scsi_task *task;
3318 
3319 	task = malloc(sizeof(struct scsi_task));
3320 	if (task == NULL) {
3321 		return NULL;
3322 	}
3323 
3324 	memset(task, 0, sizeof(struct scsi_task));
3325 	task->cdb[0]   = SCSI_OPCODE_WRITE_VERIFY10;
3326 
3327 	task->cdb[1] |= ((wrprotect & 0x07) << 5);
3328 	if (dpo) {
3329 		task->cdb[1] |= 0x10;
3330 	}
3331 	if (bytchk) {
3332 		task->cdb[1] |= 0x02;
3333 	}
3334 
3335 	scsi_set_uint32(&task->cdb[2], lba);
3336 	scsi_set_uint16(&task->cdb[7], xferlen/blocksize);
3337 
3338 	task->cdb[6] |= (group_number & 0x1f);
3339 
3340 	task->cdb_size = 10;
3341 	if (xferlen != 0) {
3342 		task->xfer_dir = SCSI_XFER_WRITE;
3343 	} else {
3344 		task->xfer_dir = SCSI_XFER_NONE;
3345 	}
3346 	task->expxferlen = xferlen;
3347 
3348 	return task;
3349 }
3350 
3351 /*
3352  * WRITEVERIFY12
3353  */
3354 struct scsi_task *
scsi_cdb_writeverify12(uint32_t lba,uint32_t xferlen,int blocksize,int wrprotect,int dpo,int bytchk,int group_number)3355 scsi_cdb_writeverify12(uint32_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number)
3356 {
3357 	struct scsi_task *task;
3358 
3359 	task = malloc(sizeof(struct scsi_task));
3360 	if (task == NULL) {
3361 		return NULL;
3362 	}
3363 
3364 	memset(task, 0, sizeof(struct scsi_task));
3365 	task->cdb[0]   = SCSI_OPCODE_WRITE_VERIFY12;
3366 
3367 	task->cdb[1] |= ((wrprotect & 0x07) << 5);
3368 	if (dpo) {
3369 		task->cdb[1] |= 0x10;
3370 	}
3371 	if (bytchk) {
3372 		task->cdb[1] |= 0x02;
3373 	}
3374 
3375 	scsi_set_uint32(&task->cdb[2], lba);
3376 	scsi_set_uint32(&task->cdb[6], xferlen/blocksize);
3377 
3378 	task->cdb[10] |= (group_number & 0x1f);
3379 
3380 	task->cdb_size = 12;
3381 	if (xferlen != 0) {
3382 		task->xfer_dir = SCSI_XFER_WRITE;
3383 	} else {
3384 		task->xfer_dir = SCSI_XFER_NONE;
3385 	}
3386 	task->expxferlen = xferlen;
3387 
3388 	return task;
3389 }
3390 
3391 /*
3392  * WRITEVERIFY16
3393  */
3394 struct scsi_task *
scsi_cdb_writeverify16(uint64_t lba,uint32_t xferlen,int blocksize,int wrprotect,int dpo,int bytchk,int group_number)3395 scsi_cdb_writeverify16(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int bytchk, int group_number)
3396 {
3397 	struct scsi_task *task;
3398 
3399 	task = malloc(sizeof(struct scsi_task));
3400 	if (task == NULL) {
3401 		return NULL;
3402 	}
3403 
3404 	memset(task, 0, sizeof(struct scsi_task));
3405 	task->cdb[0]   = SCSI_OPCODE_WRITE_VERIFY16;
3406 
3407 	task->cdb[1] |= ((wrprotect & 0x07) << 5);
3408 	if (dpo) {
3409 		task->cdb[1] |= 0x10;
3410 	}
3411 	if (bytchk) {
3412 		task->cdb[1] |= 0x02;
3413 	}
3414 
3415 	scsi_set_uint32(&task->cdb[2], lba >> 32);
3416 	scsi_set_uint32(&task->cdb[6], lba & 0xffffffff);
3417 	scsi_set_uint32(&task->cdb[10], xferlen/blocksize);
3418 
3419 	task->cdb[14] |= (group_number & 0x1f);
3420 
3421 	task->cdb_size = 16;
3422 	if (xferlen != 0) {
3423 		task->xfer_dir = SCSI_XFER_WRITE;
3424 	} else {
3425 		task->xfer_dir = SCSI_XFER_NONE;
3426 	}
3427 	task->expxferlen = xferlen;
3428 
3429 	return task;
3430 }
3431 
3432 /*
3433  * EXTENDED COPY
3434  */
3435 struct scsi_task *
scsi_cdb_extended_copy(int param_len)3436 scsi_cdb_extended_copy(int param_len)
3437 {
3438 	struct scsi_task *task;
3439 
3440 	task = malloc(sizeof(struct scsi_task));
3441 	if (task == NULL)
3442 		return NULL;
3443 
3444 	memset(task, 0, sizeof(struct scsi_task));
3445 	task->cdb[0]	= SCSI_OPCODE_EXTENDED_COPY;
3446 	task->cdb[10]	= (param_len >> 24) & 0xFF;
3447 	task->cdb[11]	= (param_len >> 16) & 0xFF;
3448 	task->cdb[12] 	= (param_len >> 8) & 0xFF;
3449 	task->cdb[13]	= param_len & 0xFF;
3450 	/* Inititalize other fields in CDB */
3451 	task->cdb_size = 16;
3452         if (param_len) {
3453                 task->xfer_dir = SCSI_XFER_WRITE;
3454         }
3455 	task->expxferlen = param_len;
3456 
3457 	return task;
3458 }
3459 
3460 /*
3461  * RECEIVE COPY RESULTS
3462  */
3463 struct scsi_task *
scsi_cdb_receive_copy_results(enum scsi_copy_results_sa sa,int list_id,int xferlen)3464 scsi_cdb_receive_copy_results(enum scsi_copy_results_sa sa, int list_id, int xferlen)
3465 {
3466 	struct scsi_task *task;
3467 
3468 	task = malloc(sizeof(struct scsi_task));
3469 	if (task == NULL) {
3470 		return NULL;
3471 	}
3472 
3473 	memset(task, 0, sizeof(struct scsi_task));
3474 	task->cdb[0]   = SCSI_OPCODE_RECEIVE_COPY_RESULTS;
3475 	task->cdb[1] |= sa & 0x1f;
3476 	task->cdb[2] = list_id & 0xFF;
3477 
3478 	scsi_set_uint32(&task->cdb[10], xferlen);
3479 
3480 	task->cdb_size = 16;
3481 	if (xferlen != 0) {
3482 		task->xfer_dir = SCSI_XFER_READ;
3483 	} else {
3484 		task->xfer_dir = SCSI_XFER_NONE;
3485 	}
3486 	task->expxferlen = xferlen;
3487 
3488 	return task;
3489 }
3490 
3491 int
scsi_datain_getfullsize(struct scsi_task * task)3492 scsi_datain_getfullsize(struct scsi_task *task)
3493 {
3494 	switch (task->cdb[0]) {
3495 	case SCSI_OPCODE_TESTUNITREADY:
3496 		return 0;
3497 	case SCSI_OPCODE_INQUIRY:
3498 		return scsi_inquiry_datain_getfullsize(task);
3499 	case SCSI_OPCODE_MODESENSE6:
3500 		return scsi_modesense_datain_getfullsize(task, 1);
3501 	case SCSI_OPCODE_READCAPACITY10:
3502 		return scsi_readcapacity10_datain_getfullsize(task);
3503 	case SCSI_OPCODE_SYNCHRONIZECACHE10:
3504 		return 0;
3505 	case SCSI_OPCODE_READTOC:
3506 		return scsi_readtoc_datain_getfullsize(task);
3507 	case SCSI_OPCODE_REPORTLUNS:
3508 		return scsi_reportluns_datain_getfullsize(task);
3509 	case SCSI_OPCODE_PERSISTENT_RESERVE_IN:
3510 		return scsi_persistentreservein_datain_getfullsize(task);
3511 	case SCSI_OPCODE_MAINTENANCE_IN:
3512 		return scsi_maintenancein_datain_getfullsize(task);
3513 	}
3514 	return -1;
3515 }
3516 
3517 void *
scsi_datain_unmarshall(struct scsi_task * task)3518 scsi_datain_unmarshall(struct scsi_task *task)
3519 {
3520 	if (!task || !task->datain.size)
3521 		return NULL;
3522 
3523 	switch (task->cdb[0]) {
3524 	case SCSI_OPCODE_INQUIRY:
3525 		return scsi_inquiry_datain_unmarshall(task);
3526 	case SCSI_OPCODE_MODESENSE6:
3527 		return scsi_modesense_datain_unmarshall(task, 1);
3528 	case SCSI_OPCODE_MODESENSE10:
3529 		return scsi_modesense_datain_unmarshall(task, 0);
3530 	case SCSI_OPCODE_READCAPACITY10:
3531 		return scsi_readcapacity10_datain_unmarshall(task);
3532 	case SCSI_OPCODE_READTOC:
3533 		return scsi_readtoc_datain_unmarshall(task);
3534 	case SCSI_OPCODE_REPORTLUNS:
3535 		return scsi_reportluns_datain_unmarshall(task);
3536 	case SCSI_OPCODE_SERVICE_ACTION_IN:
3537 		return scsi_serviceactionin_datain_unmarshall(task);
3538 	case SCSI_OPCODE_PERSISTENT_RESERVE_IN:
3539 		return scsi_persistentreservein_datain_unmarshall(task);
3540 	case SCSI_OPCODE_MAINTENANCE_IN:
3541 		return scsi_maintenancein_datain_unmarshall(task);
3542 	case SCSI_OPCODE_RECEIVE_COPY_RESULTS:
3543 		return scsi_receivecopyresults_datain_unmarshall(task);
3544 	}
3545 	return NULL;
3546 }
3547 
3548 
3549 static struct scsi_read6_cdb *
scsi_read6_cdb_unmarshall(struct scsi_task * task)3550 scsi_read6_cdb_unmarshall(struct scsi_task *task)
3551 {
3552 	struct scsi_read6_cdb *read6;
3553 
3554 	read6 = scsi_malloc(task, sizeof(struct scsi_read6_cdb));
3555 	if (read6 == NULL) {
3556 		return NULL;
3557 	}
3558 
3559 	read6->opcode          = SCSI_OPCODE_READ6;
3560 	read6->lba             = scsi_get_uint32(&task->cdb[0]) & 0x001fffff;
3561 	read6->transfer_length = task->cdb[4];
3562 	read6->control         = task->cdb[5];
3563 
3564         return read6;
3565 }
3566 
3567 static struct scsi_read10_cdb *
scsi_read10_cdb_unmarshall(struct scsi_task * task)3568 scsi_read10_cdb_unmarshall(struct scsi_task *task)
3569 {
3570 	struct scsi_read10_cdb *read10;
3571 
3572 	read10 = scsi_malloc(task, sizeof(struct scsi_read10_cdb));
3573 	if (read10 == NULL) {
3574 		return NULL;
3575 	}
3576 
3577 	read10->opcode          = SCSI_OPCODE_READ10;
3578 	read10->rdprotect       = (task->cdb[1] >> 5) & 0x7;
3579 	read10->dpo             = !!(task->cdb[1] & 0x10);
3580 	read10->fua             = !!(task->cdb[1] & 0x08);
3581 	read10->fua_nv          = !!(task->cdb[1] & 0x02);
3582 	read10->lba             = scsi_get_uint32(&task->cdb[2]);
3583 	read10->group           = task->cdb[6] & 0x1f;
3584 	read10->transfer_length = scsi_get_uint16(&task->cdb[7]);
3585 	read10->control         = task->cdb[9];
3586 
3587         return read10;
3588 }
3589 
3590 static struct scsi_read12_cdb *
scsi_read12_cdb_unmarshall(struct scsi_task * task)3591 scsi_read12_cdb_unmarshall(struct scsi_task *task)
3592 {
3593 	struct scsi_read12_cdb *read12;
3594 
3595 	read12 = scsi_malloc(task, sizeof(struct scsi_read12_cdb));
3596 	if (read12 == NULL) {
3597 		return NULL;
3598 	}
3599 
3600 	read12->opcode          = SCSI_OPCODE_READ12;
3601 	read12->rdprotect       = (task->cdb[1] >> 5) & 0x7;
3602 	read12->dpo             = !!(task->cdb[1] & 0x10);
3603 	read12->fua             = !!(task->cdb[1] & 0x08);
3604 	read12->rarc            = !!(task->cdb[1] & 0x04);
3605 	read12->fua_nv          = !!(task->cdb[1] & 0x02);
3606 	read12->lba             = scsi_get_uint32(&task->cdb[2]);
3607 	read12->transfer_length = scsi_get_uint32(&task->cdb[6]);
3608 	read12->group           = task->cdb[10] & 0x1f;
3609 	read12->control         = task->cdb[11];
3610 
3611         return read12;
3612 }
3613 
3614 static struct scsi_read16_cdb *
scsi_read16_cdb_unmarshall(struct scsi_task * task)3615 scsi_read16_cdb_unmarshall(struct scsi_task *task)
3616 {
3617 	struct scsi_read16_cdb *read16;
3618 
3619 	read16 = scsi_malloc(task, sizeof(struct scsi_read16_cdb));
3620 	if (read16 == NULL) {
3621 		return NULL;
3622 	}
3623 
3624 	read16->opcode          = SCSI_OPCODE_READ16;
3625 	read16->rdprotect       = (task->cdb[1] >> 5) & 0x7;
3626 	read16->dpo             = !!(task->cdb[1] & 0x10);
3627 	read16->fua             = !!(task->cdb[1] & 0x08);
3628 	read16->rarc            = !!(task->cdb[1] & 0x04);
3629 	read16->fua_nv          = !!(task->cdb[1] & 0x02);
3630 	read16->lba             = scsi_get_uint64(&task->cdb[2]);
3631 	read16->transfer_length = scsi_get_uint32(&task->cdb[10]);
3632 	read16->group           = task->cdb[14] & 0x1f;
3633 	read16->control         = task->cdb[15];
3634 
3635         return read16;
3636 }
3637 
3638 static struct scsi_verify10_cdb *
scsi_verify10_cdb_unmarshall(struct scsi_task * task)3639 scsi_verify10_cdb_unmarshall(struct scsi_task *task)
3640 {
3641 	struct scsi_verify10_cdb *verify10;
3642 
3643 	verify10 = scsi_malloc(task, sizeof(struct scsi_verify10_cdb));
3644 	if (verify10 == NULL) {
3645 		return NULL;
3646 	}
3647 
3648 	verify10->opcode              = SCSI_OPCODE_VERIFY10;
3649 	verify10->vrprotect           = (task->cdb[1] >> 5) & 0x7;
3650 	verify10->dpo                 = !!(task->cdb[1] & 0x10);
3651 	verify10->bytchk              = !!(task->cdb[1] & 0x02);
3652 	verify10->lba                 = scsi_get_uint32(&task->cdb[2]);
3653 	verify10->group               = task->cdb[6] & 0x1f;
3654 	verify10->verification_length = scsi_get_uint16(&task->cdb[7]);
3655 	verify10->control             = task->cdb[9];
3656 
3657         return verify10;
3658 }
3659 
3660 static struct scsi_verify12_cdb *
scsi_verify12_cdb_unmarshall(struct scsi_task * task)3661 scsi_verify12_cdb_unmarshall(struct scsi_task *task)
3662 {
3663 	struct scsi_verify12_cdb *verify12;
3664 
3665 	verify12 = scsi_malloc(task, sizeof(struct scsi_verify12_cdb));
3666 	if (verify12 == NULL) {
3667 		return NULL;
3668 	}
3669 
3670 	verify12->opcode              = SCSI_OPCODE_VERIFY12;
3671 	verify12->vrprotect           = (task->cdb[1] >> 5) & 0x7;
3672 	verify12->dpo                 = !!(task->cdb[1] & 0x10);
3673 	verify12->bytchk              = !!(task->cdb[1] & 0x02);
3674 	verify12->lba                 = scsi_get_uint32(&task->cdb[2]);
3675 	verify12->verification_length = scsi_get_uint32(&task->cdb[6]);
3676 	verify12->group               = task->cdb[10] & 0x1f;
3677 	verify12->control             = task->cdb[11];
3678 
3679         return verify12;
3680 }
3681 
3682 static struct scsi_verify16_cdb *
scsi_verify16_cdb_unmarshall(struct scsi_task * task)3683 scsi_verify16_cdb_unmarshall(struct scsi_task *task)
3684 {
3685 	struct scsi_verify16_cdb *verify16;
3686 
3687 	verify16 = scsi_malloc(task, sizeof(struct scsi_verify16_cdb));
3688 	if (verify16 == NULL) {
3689 		return NULL;
3690 	}
3691 
3692 	verify16->opcode              = SCSI_OPCODE_VERIFY16;
3693 	verify16->vrprotect           = (task->cdb[1] >> 5) & 0x7;
3694 	verify16->dpo                 = !!(task->cdb[1] & 0x10);
3695 	verify16->bytchk              = !!(task->cdb[1] & 0x02);
3696 	verify16->lba                 = scsi_get_uint64(&task->cdb[2]);
3697 	verify16->verification_length = scsi_get_uint32(&task->cdb[10]);
3698 	verify16->group               = task->cdb[14] & 0x1f;
3699 	verify16->control             = task->cdb[15];
3700 
3701         return verify16;
3702 }
3703 
3704 static struct scsi_write10_cdb *
scsi_write10_cdb_unmarshall(struct scsi_task * task)3705 scsi_write10_cdb_unmarshall(struct scsi_task *task)
3706 {
3707 	struct scsi_write10_cdb *write10;
3708 
3709 	write10 = scsi_malloc(task, sizeof(struct scsi_write10_cdb));
3710 	if (write10 == NULL) {
3711 		return NULL;
3712 	}
3713 
3714 	write10->opcode          = SCSI_OPCODE_WRITE10;
3715 	write10->wrprotect       = (task->cdb[1] >> 5) & 0x7;
3716 	write10->dpo             = !!(task->cdb[1] & 0x10);
3717 	write10->fua             = !!(task->cdb[1] & 0x08);
3718 	write10->fua_nv          = !!(task->cdb[1] & 0x02);
3719 	write10->lba             = scsi_get_uint32(&task->cdb[2]);
3720 	write10->group           = task->cdb[6] & 0x1f;
3721 	write10->transfer_length = scsi_get_uint16(&task->cdb[7]);
3722 	write10->control         = task->cdb[9];
3723 
3724         return write10;
3725 }
3726 
3727 static struct scsi_write12_cdb *
scsi_write12_cdb_unmarshall(struct scsi_task * task)3728 scsi_write12_cdb_unmarshall(struct scsi_task *task)
3729 {
3730 	struct scsi_write12_cdb *write12;
3731 
3732 	write12 = scsi_malloc(task, sizeof(struct scsi_write12_cdb));
3733 	if (write12 == NULL) {
3734 		return NULL;
3735 	}
3736 
3737 	write12->opcode          = SCSI_OPCODE_WRITE12;
3738 	write12->wrprotect       = (task->cdb[1] >> 5) & 0x7;
3739 	write12->dpo             = !!(task->cdb[1] & 0x10);
3740 	write12->fua             = !!(task->cdb[1] & 0x08);
3741 	write12->fua_nv          = !!(task->cdb[1] & 0x02);
3742 	write12->lba             = scsi_get_uint32(&task->cdb[2]);
3743 	write12->transfer_length = scsi_get_uint32(&task->cdb[6]);
3744 	write12->group           = task->cdb[10] & 0x1f;
3745 	write12->control         = task->cdb[11];
3746 
3747         return write12;
3748 }
3749 
3750 static struct scsi_write16_cdb *
scsi_write16_cdb_unmarshall(struct scsi_task * task)3751 scsi_write16_cdb_unmarshall(struct scsi_task *task)
3752 {
3753 	struct scsi_write16_cdb *write16;
3754 
3755 	write16 = scsi_malloc(task, sizeof(struct scsi_write16_cdb));
3756 	if (write16 == NULL) {
3757 		return NULL;
3758 	}
3759 
3760 	write16->opcode          = SCSI_OPCODE_WRITE16;
3761 	write16->wrprotect       = (task->cdb[1] >> 5) & 0x7;
3762 	write16->dpo             = !!(task->cdb[1] & 0x10);
3763 	write16->fua             = !!(task->cdb[1] & 0x08);
3764 	write16->fua_nv          = !!(task->cdb[1] & 0x02);
3765 	write16->lba             = scsi_get_uint64(&task->cdb[2]);
3766 	write16->transfer_length = scsi_get_uint32(&task->cdb[10]);
3767 	write16->group           = task->cdb[14] & 0x1f;
3768 	write16->control         = task->cdb[15];
3769 
3770         return write16;
3771 }
3772 
3773 static struct scsi_writeatomic16_cdb *
scsi_writeatomic16_cdb_unmarshall(struct scsi_task * task)3774 scsi_writeatomic16_cdb_unmarshall(struct scsi_task *task)
3775 {
3776 	struct scsi_writeatomic16_cdb *writeatomic16;
3777 
3778 	writeatomic16 = scsi_malloc(task, sizeof(struct scsi_writeatomic16_cdb));
3779 	if (writeatomic16 == NULL) {
3780 		return NULL;
3781 	}
3782 
3783 	writeatomic16->opcode          = SCSI_OPCODE_WRITE_ATOMIC16;
3784 	writeatomic16->wrprotect       = (task->cdb[1] >> 5) & 0x7;
3785 	writeatomic16->dpo             = !!(task->cdb[1] & 0x10);
3786 	writeatomic16->fua             = !!(task->cdb[1] & 0x08);
3787 	writeatomic16->lba             = scsi_get_uint64(&task->cdb[2]);
3788 	writeatomic16->transfer_length = scsi_get_uint16(&task->cdb[12]);
3789 	writeatomic16->group           = task->cdb[14] & 0x1f;
3790 	writeatomic16->control         = task->cdb[15];
3791 
3792         return writeatomic16;
3793 }
3794 
3795 void *
scsi_cdb_unmarshall(struct scsi_task * task,enum scsi_opcode opcode)3796 scsi_cdb_unmarshall(struct scsi_task *task, enum scsi_opcode opcode)
3797 {
3798 	if (task->cdb[0] != opcode) {
3799 		return NULL;
3800 	}
3801 
3802 	switch (task->cdb[0]) {
3803 	case SCSI_OPCODE_READ6:
3804 		return scsi_read6_cdb_unmarshall(task);
3805 	case SCSI_OPCODE_READ10:
3806 		return scsi_read10_cdb_unmarshall(task);
3807 	case SCSI_OPCODE_READ12:
3808 		return scsi_read12_cdb_unmarshall(task);
3809 	case SCSI_OPCODE_READ16:
3810 		return scsi_read16_cdb_unmarshall(task);
3811 	case SCSI_OPCODE_VERIFY10:
3812 		return scsi_verify10_cdb_unmarshall(task);
3813 	case SCSI_OPCODE_VERIFY12:
3814 		return scsi_verify12_cdb_unmarshall(task);
3815 	case SCSI_OPCODE_VERIFY16:
3816 		return scsi_verify16_cdb_unmarshall(task);
3817 	case SCSI_OPCODE_WRITE10:
3818 		return scsi_write10_cdb_unmarshall(task);
3819 	case SCSI_OPCODE_WRITE12:
3820 		return scsi_write12_cdb_unmarshall(task);
3821 	case SCSI_OPCODE_WRITE16:
3822 		return scsi_write16_cdb_unmarshall(task);
3823 	case SCSI_OPCODE_WRITE_ATOMIC16:
3824 		return scsi_writeatomic16_cdb_unmarshall(task);
3825 	}
3826 	return NULL;
3827 }
3828 
3829 const char *
scsi_devtype_to_str(enum scsi_inquiry_peripheral_device_type type)3830 scsi_devtype_to_str(enum scsi_inquiry_peripheral_device_type type)
3831 {
3832 	switch (type) {
3833 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS:
3834 		return "DIRECT_ACCESS";
3835 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SEQUENTIAL_ACCESS:
3836 		return "SEQUENTIAL_ACCESS";
3837 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_PRINTER:
3838 		return "PRINTER";
3839 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_PROCESSOR:
3840 		return "PROCESSOR";
3841 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_WRITE_ONCE:
3842 		return "WRITE_ONCE";
3843 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_MMC:
3844 		return "MMC";
3845 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SCANNER:
3846 		return "SCANNER";
3847 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OPTICAL_MEMORY:
3848 		return "OPTICAL_MEMORY";
3849 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_MEDIA_CHANGER:
3850 		return "MEDIA_CHANGER";
3851 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_COMMUNICATIONS:
3852 		return "COMMUNICATIONS";
3853 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_STORAGE_ARRAY_CONTROLLER:
3854 		return "STORAGE_ARRAY_CONTROLLER";
3855 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_ENCLOSURE_SERVICES:
3856 		return "ENCLOSURE_SERVICES";
3857 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SIMPLIFIED_DIRECT_ACCESS:
3858 		return "SIMPLIFIED_DIRECT_ACCESS";
3859 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OPTICAL_CARD_READER:
3860 		return "OPTICAL_CARD_READER";
3861 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_BRIDGE_CONTROLLER:
3862 		return "BRIDGE_CONTROLLER";
3863 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_OSD:
3864 		return "OSD";
3865 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_AUTOMATION:
3866 		return "AUTOMATION";
3867 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SEQURITY_MANAGER:
3868 		return "SEQURITY_MANAGER";
3869 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_WELL_KNOWN_LUN:
3870 		return "WELL_KNOWN_LUN";
3871 	case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_UNKNOWN:
3872 		return "UNKNOWN";
3873 	}
3874 	return "unknown";
3875 }
3876 
3877 const char *
scsi_devqualifier_to_str(enum scsi_inquiry_peripheral_qualifier qualifier)3878 scsi_devqualifier_to_str(enum scsi_inquiry_peripheral_qualifier qualifier)
3879 {
3880 	switch (qualifier) {
3881 	case SCSI_INQUIRY_PERIPHERAL_QUALIFIER_CONNECTED:
3882 		return "CONNECTED";
3883 	case SCSI_INQUIRY_PERIPHERAL_QUALIFIER_DISCONNECTED:
3884 		return "DISCONNECTED";
3885 	case SCSI_INQUIRY_PERIPHERAL_QUALIFIER_NOT_SUPPORTED:
3886 		return "NOT_SUPPORTED";
3887 	}
3888 	return "unknown";
3889 }
3890 
3891 const char *
scsi_version_to_str(enum scsi_version version)3892 scsi_version_to_str(enum scsi_version version)
3893 {
3894 	switch (version) {
3895 	case SCSI_VERSION_SPC:
3896 		return "ANSI INCITS 301-1997 (SPC)";
3897 	case SCSI_VERSION_SPC2:
3898 		return "ANSI INCITS 351-2001 (SPC-2)";
3899 	case SCSI_VERSION_SPC3:
3900 		return "ANSI INCITS 408-2005 (SPC-3)";
3901 	}
3902 	return "unknown";
3903 }
3904 
3905 const char *
scsi_version_descriptor_to_str(enum scsi_version_descriptor version_descriptor)3906 scsi_version_descriptor_to_str(enum scsi_version_descriptor version_descriptor)
3907 {
3908 	switch (version_descriptor) {
3909 	case SCSI_VERSION_DESCRIPTOR_ISCSI:
3910 		return "iSCSI";
3911 	case SCSI_VERSION_DESCRIPTOR_SBC:
3912 		return "SBC";
3913 	case SCSI_VERSION_DESCRIPTOR_SBC_ANSI_INCITS_306_1998:
3914 		return "SBC ANSI INCITS 306-1998";
3915 	case SCSI_VERSION_DESCRIPTOR_SBC_T10_0996_D_R08C:
3916 		return "SBC T10/0996-D revision 08c";
3917 	case SCSI_VERSION_DESCRIPTOR_SBC_2:
3918 		return "SBC-2";
3919 	case SCSI_VERSION_DESCRIPTOR_SBC_2_ISO_IEC_14776_322:
3920 		return "SBC-2 ISO/IEC 14776-322";
3921 	case SCSI_VERSION_DESCRIPTOR_SBC_2_ANSI_INCITS_405_2005:
3922 		return "SBC-2 ANSI INCITS 405-2005";
3923 	case SCSI_VERSION_DESCRIPTOR_SBC_2_T10_1417_D_R16:
3924 		return "SBC-2 T10/1417-D revision 16";
3925 	case SCSI_VERSION_DESCRIPTOR_SBC_2_T10_1417_D_R5A:
3926 		return "SBC-2 T10/1417-D revision 5A";
3927 	case SCSI_VERSION_DESCRIPTOR_SBC_2_T10_1417_D_R15:
3928 		return "SBC-2 T10/1417-D revision 15";
3929 	case SCSI_VERSION_DESCRIPTOR_SBC_3:
3930 		return "SBC-3";
3931 	case SCSI_VERSION_DESCRIPTOR_SPC:
3932 		return "SPC";
3933 	case SCSI_VERSION_DESCRIPTOR_SPC_ANSI_INCITS_301_1997:
3934 		return "SPC ANSI INCITS 301-1997";
3935 	case SCSI_VERSION_DESCRIPTOR_SPC_T10_0995_D_R11A:
3936 		return "SPC T10/0995-D revision 11a";
3937 	case SCSI_VERSION_DESCRIPTOR_SPC_2:
3938 		return "SPC-2";
3939 	case SCSI_VERSION_DESCRIPTOR_SPC_2_ISO_IEC_14776_452:
3940 		return "SPC-2 ISO.IEC 14776-452";
3941 	case SCSI_VERSION_DESCRIPTOR_SPC_2_ANSI_INCITS_351_2001:
3942 		return "SPC-2 ANSI INCITS 351-2001";
3943 	case SCSI_VERSION_DESCRIPTOR_SPC_2_T10_1236_D_R20:
3944 		return "SPC-2 T10/1236-D revision 20";
3945 	case SCSI_VERSION_DESCRIPTOR_SPC_2_T10_1236_D_R12:
3946 		return "SPC-2 T10/1236-D revision 12";
3947 	case SCSI_VERSION_DESCRIPTOR_SPC_2_T10_1236_D_R18:
3948 		return "SPC-2 T10/1236-D revision 18";
3949 	case SCSI_VERSION_DESCRIPTOR_SPC_2_T10_1236_D_R19:
3950 		return "SPC-2 T10/1236-D revision 19";
3951 	case SCSI_VERSION_DESCRIPTOR_SPC_3:
3952 		return "SPC-3";
3953 	case SCSI_VERSION_DESCRIPTOR_SPC_3_ISO_IEC_14776_453:
3954 		return "SPC-3 ISO/IEC 14776-453";
3955 	case SCSI_VERSION_DESCRIPTOR_SPC_3_ANSI_INCITS_408_2005:
3956 		return "SPC-3 ANSI INCITS 408-2005";
3957 	case SCSI_VERSION_DESCRIPTOR_SPC_3_T10_1416_D_R7:
3958 		return "SPC-3 T10/1416-D revision 7";
3959 	case SCSI_VERSION_DESCRIPTOR_SPC_3_T10_1416_D_R21:
3960 		return "SPC-3 T10/1416-D revision 21";
3961 	case SCSI_VERSION_DESCRIPTOR_SPC_3_T10_1416_D_R22:
3962 		return "SPC-3 T10/1416-D revision 22";
3963 	case SCSI_VERSION_DESCRIPTOR_SPC_3_T10_1416_D_R23:
3964 		return "SPC-3 T10/1416-D revision 23";
3965 	case SCSI_VERSION_DESCRIPTOR_SPC_4:
3966 		return "SPC-4";
3967 	case SCSI_VERSION_DESCRIPTOR_SPC_4_T10_1731_D_R16:
3968 		return "SPC-4 T10/1731-D revision 16";
3969 	case SCSI_VERSION_DESCRIPTOR_SPC_4_T10_1731_D_R18:
3970 		return "SPC-4 T10/1731-D revision 18";
3971 	case SCSI_VERSION_DESCRIPTOR_SPC_4_T10_1731_D_R23:
3972 		return "SPC-4 T10/1731-D revision 23";
3973 	case SCSI_VERSION_DESCRIPTOR_SSC:
3974 		return "SSC";
3975 	case SCSI_VERSION_DESCRIPTOR_UAS_T10_2095D_R04:
3976 		return "UAS T10/2095-D revision 04";
3977 	}
3978 	return "unknown";
3979 }
3980 
3981 const char *
scsi_inquiry_pagecode_to_str(int pagecode)3982 scsi_inquiry_pagecode_to_str(int pagecode)
3983 {
3984 	switch (pagecode) {
3985 	case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES:
3986 	     return "SUPPORTED_VPD_PAGES";
3987 	case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER:
3988 		return "UNIT_SERIAL_NUMBER";
3989 	case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION:
3990 		return "DEVICE_IDENTIFICATION";
3991 	case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS:
3992 		return "BLOCK_LIMITS";
3993 	case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS:
3994 		return "BLOCK_DEVICE_CHARACTERISTICS";
3995 	case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
3996 		return "LOGICAL_BLOCK_PROVISIONING";
3997 	}
3998 	return "unknown";
3999 }
4000 
4001 
4002 const char *
scsi_protocol_identifier_to_str(int identifier)4003 scsi_protocol_identifier_to_str(int identifier)
4004 {
4005 	switch (identifier) {
4006 	case SCSI_PROTOCOL_IDENTIFIER_FIBRE_CHANNEL:
4007 	     return "FIBRE_CHANNEL";
4008 	case SCSI_PROTOCOL_IDENTIFIER_PARALLEL_SCSI:
4009 	     return "PARALLEL_SCSI";
4010 	case SCSI_PROTOCOL_IDENTIFIER_SSA:
4011 		return "SSA";
4012 	case SCSI_PROTOCOL_IDENTIFIER_IEEE_1394:
4013 		return "IEEE_1394";
4014 	case SCSI_PROTOCOL_IDENTIFIER_RDMA:
4015 		return "RDMA";
4016 	case SCSI_PROTOCOL_IDENTIFIER_ISCSI:
4017 		return "ISCSI";
4018 	case SCSI_PROTOCOL_IDENTIFIER_SAS:
4019 		return "SAS";
4020 	case SCSI_PROTOCOL_IDENTIFIER_ADT:
4021 		return "ADT";
4022 	case SCSI_PROTOCOL_IDENTIFIER_ATA:
4023 		return "ATA";
4024 	}
4025 	return "unknown";
4026 }
4027 
4028 const char *
scsi_codeset_to_str(int codeset)4029 scsi_codeset_to_str(int codeset)
4030 {
4031 	switch (codeset) {
4032 	case SCSI_CODESET_BINARY:
4033 		return "BINARY";
4034 	case SCSI_CODESET_ASCII:
4035 		return "ASCII";
4036 	case SCSI_CODESET_UTF8:
4037 		return "UTF8";
4038 	}
4039 	return "unknown";
4040 }
4041 
4042 const char *
scsi_association_to_str(int association)4043 scsi_association_to_str(int association)
4044 {
4045 	switch (association) {
4046 	case SCSI_ASSOCIATION_LOGICAL_UNIT:
4047 		return "LOGICAL_UNIT";
4048 	case SCSI_ASSOCIATION_TARGET_PORT:
4049 		return "TARGET_PORT";
4050 	case SCSI_ASSOCIATION_TARGET_DEVICE:
4051 		return "TARGET_DEVICE";
4052 	}
4053 	return "unknown";
4054 }
4055 
4056 const char *
scsi_designator_type_to_str(int type)4057 scsi_designator_type_to_str(int type)
4058 {
4059 	switch (type) {
4060 	case SCSI_DESIGNATOR_TYPE_VENDOR_SPECIFIC:
4061 		return "VENDOR_SPECIFIC";
4062 	case SCSI_DESIGNATOR_TYPE_T10_VENDORT_ID:
4063 		return "T10_VENDORT_ID";
4064 	case SCSI_DESIGNATOR_TYPE_EUI_64:
4065 		return "EUI_64";
4066 	case SCSI_DESIGNATOR_TYPE_NAA:
4067 		return "NAA";
4068 	case SCSI_DESIGNATOR_TYPE_RELATIVE_TARGET_PORT:
4069 		return "RELATIVE_TARGET_PORT";
4070 	case SCSI_DESIGNATOR_TYPE_TARGET_PORT_GROUP:
4071 		return "TARGET_PORT_GROUP";
4072 	case SCSI_DESIGNATOR_TYPE_LOGICAL_UNIT_GROUP:
4073 		return "LOGICAL_UNIT_GROUP";
4074 	case SCSI_DESIGNATOR_TYPE_MD5_LOGICAL_UNIT_IDENTIFIER:
4075 		return "MD5_LOGICAL_UNIT_IDENTIFIER";
4076 	case SCSI_DESIGNATOR_TYPE_SCSI_NAME_STRING:
4077 		return "SCSI_NAME_STRING";
4078 	}
4079 	return "unknown";
4080 }
4081 
4082 void
scsi_set_task_private_ptr(struct scsi_task * task,void * ptr)4083 scsi_set_task_private_ptr(struct scsi_task *task, void *ptr)
4084 {
4085 	task->ptr = ptr;
4086 }
4087 
4088 void *
scsi_get_task_private_ptr(struct scsi_task * task)4089 scsi_get_task_private_ptr(struct scsi_task *task)
4090 {
4091 	return task->ptr;
4092 }
4093 
4094 void
scsi_task_set_iov_out(struct scsi_task * task,struct scsi_iovec * iov,int niov)4095 scsi_task_set_iov_out(struct scsi_task *task, struct scsi_iovec *iov, int niov)
4096 {
4097 	task->iovector_out.iov = iov;
4098 	task->iovector_out.niov = niov;
4099 }
4100 
4101 void
scsi_task_set_iov_in(struct scsi_task * task,struct scsi_iovec * iov,int niov)4102 scsi_task_set_iov_in(struct scsi_task *task, struct scsi_iovec *iov, int niov)
4103 {
4104 	task->iovector_in.iov = iov;
4105 	task->iovector_in.niov = niov;
4106 }
4107 
4108 void
scsi_task_reset_iov(struct scsi_iovector * iovector)4109 scsi_task_reset_iov(struct scsi_iovector *iovector)
4110 {
4111 	iovector->offset = 0;
4112 	iovector->consumed = 0;
4113 }
4114 
4115 #define IOVECTOR_INITAL_ALLOC (16)
4116 
4117 static int
scsi_iovector_add(struct scsi_task * task,struct scsi_iovector * iovector,int len,unsigned char * buf)4118 scsi_iovector_add(struct scsi_task *task, struct scsi_iovector *iovector, int len, unsigned char *buf)
4119 {
4120 	if (len < 0) {
4121 		return -1;
4122 	}
4123 
4124 	if (iovector->iov == NULL) {
4125 		iovector->iov = scsi_malloc(task, IOVECTOR_INITAL_ALLOC*sizeof(struct iovec));
4126 		if (iovector->iov == NULL) {
4127 			return -1;
4128 		}
4129 		iovector->nalloc = IOVECTOR_INITAL_ALLOC;
4130 	}
4131 
4132 	/* iovec allocation is too small */
4133 	if (iovector->nalloc < iovector->niov + 1) {
4134 		struct scsi_iovec *old_iov = iovector->iov;
4135 		iovector->iov = scsi_malloc(task, 2 * iovector->nalloc * sizeof(struct iovec));
4136 		if (iovector->iov == NULL) {
4137 			return -1;
4138 		}
4139 		memcpy(iovector->iov, old_iov, iovector->niov * sizeof(struct iovec));
4140 		iovector->nalloc <<= 1;
4141 	}
4142 
4143 	iovector->iov[iovector->niov].iov_len = len;
4144 	iovector->iov[iovector->niov].iov_base = buf;
4145 	iovector->niov++;
4146 
4147 	return 0;
4148 }
4149 
4150 int
scsi_task_add_data_in_buffer(struct scsi_task * task,int len,unsigned char * buf)4151 scsi_task_add_data_in_buffer(struct scsi_task *task, int len, unsigned char *buf)
4152 {
4153 	return scsi_iovector_add(task, &task->iovector_in, len, buf);
4154 }
4155 
4156 int
scsi_task_add_data_out_buffer(struct scsi_task * task,int len,unsigned char * buf)4157 scsi_task_add_data_out_buffer(struct scsi_task *task, int len, unsigned char *buf)
4158 {
4159 	return scsi_iovector_add(task, &task->iovector_out, len, buf);
4160 }
4161 
4162 int
scsi_task_get_status(struct scsi_task * task,struct scsi_sense * sense)4163 scsi_task_get_status(struct scsi_task *task, struct scsi_sense *sense)
4164 {
4165 	if (sense) {
4166 		memcpy(sense, &task->sense, sizeof(struct scsi_sense));
4167 	}
4168 	return task->status;
4169 }
4170