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