summaryrefslogtreecommitdiffstats
path: root/scsicmds.h
blob: 2a1eaab00bca0261825fb50970641efe4c63375d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
/*
 * scsicmds.h
 *
 * Home page of code is: https://www.smartmontools.org
 *
 * Copyright (C) 2002-8 Bruce Allen
 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
 * Copyright (C) 2003-2023 Douglas Gilbert <dgilbert@interlog.com>
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 *
 * N.B. What was formerly known as "SMART" are now called "informational
 * exceptions" in recent t10.org drafts (i.e. recent SCSI).
 *
 */


#ifndef SCSICMDS_H_
#define SCSICMDS_H_

#define SCSICMDS_H_CVSID "$Id: scsicmds.h 5462 2023-03-13 10:45:06Z chrfranke $\n"

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

/* #define SCSI_DEBUG 1 */ /* Comment out to disable command debugging */

/* Following conditional defines just in case OS already has them defined.
 * If they are defined we hope they are defined correctly (for SCSI). */
#ifndef TEST_UNIT_READY
#define TEST_UNIT_READY 0x0
#endif
#ifndef LOG_SELECT
#define LOG_SELECT 0x4c
#endif
#ifndef LOG_SENSE
#define LOG_SENSE 0x4d
#endif
#ifndef MODE_SENSE_6
#define MODE_SENSE_6 0x1a
#endif
#ifndef MODE_SENSE_10
#define MODE_SENSE_10 0x5a
#endif
#ifndef MODE_SELECT_6
#define MODE_SELECT_6 0x15
#endif
#ifndef MODE_SELECT_10
#define MODE_SELECT_10 0x55
#endif
#ifndef INQUIRY
#define INQUIRY 0x12
#endif
#ifndef REQUEST_SENSE
#define REQUEST_SENSE  0x03
#endif
#ifndef RECEIVE_DIAGNOSTIC
#define RECEIVE_DIAGNOSTIC  0x1c
#endif
#ifndef SEND_DIAGNOSTIC
#define SEND_DIAGNOSTIC  0x1d
#endif
#ifndef READ_DEFECT_10
#define READ_DEFECT_10  0x37
#endif
#ifndef READ_DEFECT_12
#define READ_DEFECT_12  0xb7
#endif
#ifndef START_STOP_UNIT         /* SSU */
#define START_STOP_UNIT  0x1b
#endif
#ifndef REPORT_LUNS
#define REPORT_LUNS  0xa0
#endif
#ifndef READ_CAPACITY_10
#define READ_CAPACITY_10  0x25
#endif
#ifndef SERVICE_ACTION_IN_16
#define SERVICE_ACTION_IN_16  0x9e
#endif
#ifndef SAI_READ_CAPACITY_16    /* service action in for READ_CAPACITY_16 */
#define SAI_READ_CAPACITY_16  0x10
#endif
#ifndef SAI_GET_PHY_ELEM_STATUS    /* Get physical element status */
#define SAI_GET_PHY_ELEM_STATUS  0x17
#endif
#ifndef SAI_REPORT_SUPPORTED_OPCODES
#define SAI_REPORT_SUPPORTED_OPCODES  0xc
#endif
#ifndef MAINTENANCE_IN_12
#define MAINTENANCE_IN_12  0xa3
#endif
#ifndef MI_REP_SUP_OPCODES
#define MI_REP_SUP_OPCODES  0xc    /* maintenance in (12) */
#endif

#ifndef SAT_ATA_PASSTHROUGH_12
#define SAT_ATA_PASSTHROUGH_12 0xa1
#endif
#ifndef SAT_ATA_PASSTHROUGH_16
#define SAT_ATA_PASSTHROUGH_16 0x85
#endif


#define DXFER_NONE        0
#define DXFER_FROM_DEVICE 1
#define DXFER_TO_DEVICE   2


/* scsi_rsoc_elem and scsi_device is defined in dev_interface.h */

struct scsi_cmnd_io
{
    uint8_t * cmnd;     /* [in]: ptr to SCSI command block (cdb) */
    size_t  cmnd_len;   /* [in]: number of bytes in SCSI command */
    int dxfer_dir;      /* [in]: DXFER_NONE, DXFER_FROM_DEVICE, or
                                 DXFER_TO_DEVICE */
    uint8_t * dxferp;   /* [in]: ptr to outgoing or incoming data buffer */
    size_t dxfer_len;   /* [in]: bytes to be transferred to/from dxferp */
    uint8_t * sensep;   /* [in]: ptr to sense buffer, filled when
                                 CHECK CONDITION status occurs */
    size_t max_sense_len; /* [in]: max number of bytes to write to sensep */
    unsigned timeout;   /* [in]: seconds, 0-> default timeout (60 seconds?) */
    size_t resp_sense_len;  /* [out]: sense buffer length written */
    uint8_t scsi_status;  /* [out]: 0->ok, 2->CHECK CONDITION, etc ... */
    int resid;          /* [out]: Number of bytes requested to be transferred
                                  less actual number transferred (0 if not
                                   supported) */
};

struct scsi_sense_disect {
    uint8_t resp_code;
    uint8_t sense_key;
    uint8_t asc;
    uint8_t ascq;
    int progress; /* -1 -> N/A, 0-65535 -> available */
};

/* Useful data from Informational Exception Control mode page (0x1c) */
#define SCSI_IECMP_RAW_LEN 64
struct scsi_iec_mode_page {
    uint8_t requestedCurrent;
    uint8_t gotCurrent;
    uint8_t requestedChangeable;
    uint8_t gotChangeable;
    uint8_t modese_len;   /* 0 (don't know), 6 or 10 */
    uint8_t raw_curr[SCSI_IECMP_RAW_LEN];
    uint8_t raw_chg[SCSI_IECMP_RAW_LEN];
};

/* Carrier for Error counter log pages (e.g. read, write, verify ...) */
struct scsiErrorCounter {
    uint8_t gotPC[7];
    uint8_t gotExtraPC;
    uint64_t counter[8];
};

/* Carrier for Non-medium error log page */
struct scsiNonMediumError {
    uint8_t gotPC0;
    uint8_t gotExtraPC;
    uint64_t counterPC0;
    uint8_t gotTFE_H;
    uint64_t counterTFE_H; /* Track following errors [Hitachi] */
    uint8_t gotPE_H;
    uint64_t counterPE_H;  /* Positioning errors [Hitachi] */
};

struct scsi_readcap_resp {
    uint64_t num_lblocks;       /* Number of Logical Blocks on device */
    uint32_t lb_size;   /* should be available in all non-error cases */
    /* following fields from READ CAPACITY(16) or set to 0 */
    uint8_t prot_type;  /* 0, 1, 2 or 3 protection type, deduced from
                         * READ CAPACITY(16) P_TYPE and PROT_EN fields */
    uint8_t p_i_exp;    /* Protection information Intervals Exponent */
    uint8_t lb_p_pb_exp;/* Logical Blocks per Physical Block Exponent */
    bool lbpme;         /* Logical Block Provisioning Management Enabled */
    bool lbprz;         /* Logical Block Provisioning Read Zeros */
    uint16_t l_a_lba;   /* Lowest Aligned Logical Block Address */
};

struct scsi_supp_log_pages {
    uint8_t page_code;
    uint8_t subpage_code;
};

/* SCSI Peripheral types (of interest) */
#define SCSI_PT_DIRECT_ACCESS           0x0
#define SCSI_PT_SEQUENTIAL_ACCESS       0x1
#define SCSI_PT_WO                      0x4      /* write once device */
#define SCSI_PT_CDROM                   0x5
#define SCSI_PT_OPTICAL                 0x7
#define SCSI_PT_MEDIUM_CHANGER          0x8
#define SCSI_PT_ENCLOSURE               0xd
#define SCSI_PT_RBC                     0xe
#define SCSI_PT_HOST_MANAGED            0x14    /* Zoned disk */

/* Transport protocol identifiers or just Protocol identifiers */
#define SCSI_TPROTO_FCP 0
#define SCSI_TPROTO_SPI 1
#define SCSI_TPROTO_SSA 2
#define SCSI_TPROTO_1394 3
#define SCSI_TPROTO_SRP 4            /* SCSI over RDMA */
#define SCSI_TPROTO_ISCSI 5
#define SCSI_TPROTO_SAS 6
#define SCSI_TPROTO_ADT 7
#define SCSI_TPROTO_ATA 8
#define SCSI_TPROTO_UAS 9            /* USB attached SCSI */
#define SCSI_TPROTO_SOP 0xa          /* SCSI over PCIe */
#define SCSI_TPROTO_PCIE 0xb         /* includes NVMe */
#define SCSI_TPROTO_NONE 0xf


/* SCSI Log Pages retrieved by LOG SENSE. 0x0 to 0x3f, 0x30 to 0x3e vendor */
#define SUPPORTED_LPAGES                    0x00
#define BUFFER_OVERRUN_LPAGE                0x01
#define WRITE_ERROR_COUNTER_LPAGE           0x02
#define READ_ERROR_COUNTER_LPAGE            0x03
#define READ_REVERSE_ERROR_COUNTER_LPAGE    0x04
#define VERIFY_ERROR_COUNTER_LPAGE          0x05
#define NON_MEDIUM_ERROR_LPAGE              0x06
#define LAST_N_ERROR_EVENTS_LPAGE           0x07
#define FORMAT_STATUS_LPAGE                 0x08
#define LAST_N_DEFERRED_LPAGE               0x0b   /* or async events */
#define LB_PROV_LPAGE                       0x0c   /* SBC-3 */
#define TEMPERATURE_LPAGE                   0x0d
#define STARTSTOP_CYCLE_COUNTER_LPAGE       0x0e
#define APPLICATION_CLIENT_LPAGE            0x0f
#define SELFTEST_RESULTS_LPAGE              0x10
#define SS_MEDIA_LPAGE                      0x11   /* SBC-3 */
#define DEVICE_STATS_LPAGE                  0x14   /* SSC-5 */
#define BACKGROUND_RESULTS_LPAGE            0x15   /* SBC-3 */
#define ATA_PT_RESULTS_LPAGE                0x16   /* SAT */
#define NONVOL_CACHE_LPAGE                  0x17   /* SBC-3 */
#define PROTOCOL_SPECIFIC_LPAGE             0x18
#define GEN_STATS_PERF_LPAGE                0x19
#define POWER_COND_TRANS_LPAGE              0x1a
#define IE_LPAGE                            0x2f

/* SCSI Log subpages (8 bits), added spc4r05 2006, standardized SPC-4 2015 */
#define NO_SUBPAGE_L_SPAGE              0x0     /* 0x0-0x3f,0x0 */
#define LAST_N_INQ_DAT_L_SPAGE          0x1     /* 0xb,0x1 */
#define LAST_N_MODE_PG_L_SPAGE          0x2     /* 0xb,0x2 */
#define ENVIRO_REP_L_SPAGE              0x1     /* 0xd,0x1 */
#define ENVIRO_LIMITS_L_SPAGE           0x2     /* 0xd,0x2 */
#define UTILIZATION_L_SPAGE             0x1     /* 0xe,0x1 */
#define ZB_DEV_STATS_L_SPAGE            0x1     /* 0x14,0x1 */
#define PEND_DEFECTS_L_SPAGE            0x1     /* 0x15,0x1 */
#define BACKGROUND_OP_L_SPAGE           0x2     /* 0x15,0x2 */
#define LPS_MISALIGN_L_SPAGE            0x3     /* 0x15,0x3 */
#define SUPP_SPAGE_L_SPAGE              0xff    /* 0x0,0xff pages+subpages */

/* Seagate vendor specific log pages. */
#define SEAGATE_CACHE_LPAGE                 0x37
#define SEAGATE_FARM_LPAGE                  0x3d
#define SEAGATE_FACTORY_LPAGE               0x3e

/* Seagate vendor specific log sub-pages. */
#define SEAGATE_FARM_CURRENT_L_SPAGE        0x3     /* 0x3d,0x3 */

/* Log page response lengths */
#define LOG_RESP_SELF_TEST_LEN 0x194

/* See the SSC-2 document at www.t10.org . Earlier note: From IBM
Documentation, see http://www.storage.ibm.com/techsup/hddtech/prodspecs.htm */
#define TAPE_ALERTS_LPAGE                        0x2e

/* ANSI SCSI-3 Mode Pages */
#define VENDOR_UNIQUE_PAGE                       0x00
#define READ_WRITE_ERROR_RECOVERY_PAGE           0x01
#define DISCONNECT_RECONNECT_PAGE                0x02
#define FORMAT_DEVICE_PAGE                       0x03
#define RIGID_DISK_DRIVE_GEOMETRY_PAGE           0x04
#define FLEXIBLE_DISK_PAGE                       0x05
#define VERIFY_ERROR_RECOVERY_PAGE               0x07
#define CACHING_PAGE                             0x08
#define PERIPHERAL_DEVICE_PAGE                   0x09
#define XOR_CONTROL_MODE_PAGE                    0x10
#define CONTROL_MODE_PAGE                        0x0a
#define MEDIUM_TYPES_SUPPORTED_PAGE              0x0b
#define NOTCH_PAGE                               0x0c
#define CD_DEVICE_PAGE                           0x0d
#define CD_AUDIO_CONTROL_PAGE                    0x0e
#define DATA_COMPRESSION_PAGE                    0x0f
#define ENCLOSURE_SERVICES_MANAGEMENT_PAGE       0x14
#define PROTOCOL_SPECIFIC_LUN_PAGE               0x18
#define PROTOCOL_SPECIFIC_PORT_PAGE              0x19
#define POWER_CONDITION_PAGE                     0x1a
#define INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE    0x1c
#define FAULT_FAILURE_REPORTING_PAGE             0x1c

/* Background control mode subpage is [0x1c,0x1] */
#define BACKGROUND_CONTROL_M_SUBPAGE             0x1   /* SBC-2 */

#define ALL_MODE_PAGES                           0x3f

/* Mode page control field */
#define MPAGE_CONTROL_CURRENT               0
#define MPAGE_CONTROL_CHANGEABLE            1
#define MPAGE_CONTROL_DEFAULT               2
#define MPAGE_CONTROL_SAVED                 3

/* SCSI Vital Product Data (VPD) pages */
#define SCSI_VPD_SUPPORTED_VPD_PAGES    0x0
#define SCSI_VPD_UNIT_SERIAL_NUMBER     0x80
#define SCSI_VPD_DEVICE_IDENTIFICATION  0x83
#define SCSI_VPD_EXTENDED_INQUIRY_DATA  0x86
#define SCSI_VPD_ATA_INFORMATION        0x89
#define SCSI_VPD_POWER_CONDITION        0x8a
#define SCSI_VPD_POWER_CONSUMPTION      0x8d
#define SCSI_VPD_BLOCK_LIMITS           0xb0
#define SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS   0xb1
#define SCSI_VPD_LOGICAL_BLOCK_PROVISIONING     0xb2
#define SCSI_VPD_ZONED_BLOCK_DEV_CHAR   0xb6

/* defines for useful SCSI Status codes */
#define SCSI_STATUS_CHECK_CONDITION     0x2

/* defines for useful Sense Key codes */
#define SCSI_SK_NO_SENSE                0x0
#define SCSI_SK_RECOVERED_ERR           0x1
#define SCSI_SK_NOT_READY               0x2
#define SCSI_SK_MEDIUM_ERROR            0x3
#define SCSI_SK_HARDWARE_ERROR          0x4
#define SCSI_SK_ILLEGAL_REQUEST         0x5
#define SCSI_SK_UNIT_ATTENTION          0x6
#define SCSI_SK_DATA_PROTECT            0x7
#define SCSI_SK_ABORTED_COMMAND         0xb
#define SCSI_SK_MISCOMPARE              0xe
#define SCSI_SK_COMPLETED               0xf

/* defines for useful Additional Sense Codes (ASCs) */
#define SCSI_ASC_NOT_READY              0x4     /* more info in ASCQ code */
#define SCSI_ASC_NO_MEDIUM              0x3a    /* more info in ASCQ code */
#define SCSI_ASC_UNKNOWN_OPCODE         0x20
#define SCSI_ASC_INVALID_FIELD          0x24
#define SCSI_ASC_UNKNOWN_PARAM          0x26
#define SCSI_ASC_WARNING                0xb
#define SCSI_ASC_IMPENDING_FAILURE      0x5d

#define SCSI_ASCQ_ATA_PASS_THROUGH      0x1d

/* Simplified error code (negative values as per errno) */
#define SIMPLE_NO_ERROR                 0
#define SIMPLE_ERR_NOT_READY            1
#define SIMPLE_ERR_BAD_OPCODE           2
#define SIMPLE_ERR_BAD_FIELD            3       /* in cbd */
#define SIMPLE_ERR_BAD_PARAM            4       /* in data */
#define SIMPLE_ERR_BAD_RESP             5       /* response fails sanity */
#define SIMPLE_ERR_NO_MEDIUM            6       /* no medium present */
#define SIMPLE_ERR_BECOMING_READY       7       /* device will be ready soon */
#define SIMPLE_ERR_TRY_AGAIN            8       /* some warning, try again */
#define SIMPLE_ERR_MEDIUM_HARDWARE      9       /* medium or hardware error */
#define SIMPLE_ERR_UNKNOWN              10      /* unknown sense value */
#define SIMPLE_ERR_ABORTED_COMMAND      11      /* probably transport error */
#define SIMPLE_ERR_PROTECTION           12      /* data protect sense key */
#define SIMPLE_ERR_MISCOMPARE           13      /* from VERIFY commands */


/* defines for functioncode parameter in SENDDIAGNOSTIC function */
#define SCSI_DIAG_NO_SELF_TEST          0x00
#define SCSI_DIAG_DEF_SELF_TEST         0xff
#define SCSI_DIAG_BG_SHORT_SELF_TEST    0x01
#define SCSI_DIAG_BG_EXTENDED_SELF_TEST 0x02
#define SCSI_DIAG_FG_SHORT_SELF_TEST    0x05
#define SCSI_DIAG_FG_EXTENDED_SELF_TEST 0x06
#define SCSI_DIAG_ABORT_SELF_TEST       0x04

/* Defines for power_cond in scsiSetPowerCondition() (SSU command) */
#define SCSI_POW_COND_ACTIVE            0x1
#define SCSI_POW_COND_IDLE              0x2
#define SCSI_POW_COND_STANDBY           0x3


/* SCSI command timeout values (units are seconds) */
#define SCSI_TIMEOUT_DEFAULT    60  // should be longer than the spin up time
                                    // of a disk in JBOD.

#define SCSI_TIMEOUT_SELF_TEST  (5 * 60 * 60)   /* allow max 5 hours for */
                                            /* extended foreground self test */

#define LOGPAGEHDRSIZE  4

class scsi_device;

// Set of supported SCSI VPD pages. Constructor fetches Supported VPD pages
// VPD page and remembers the response for later queries.
class supported_vpd_pages
{
public:
    explicit supported_vpd_pages(scsi_device * device);

    bool is_supported(int vpd_page_num) const;

private:
    int num_valid;      /* 0 or less for invalid */
    unsigned char pages[256];
};

extern supported_vpd_pages * supported_vpd_pages_p;

/* This is a heuristic that takes into account the command bytes and length
 * to decide whether the presented unstructured sequence of bytes could be
 * a SCSI command. If so it returns true otherwise false. Vendor specific
 * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed
 * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The
 * only SCSI commands considered above 16 bytes of length are the Variable
 * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e).
 * Both have an inbuilt length field which can be cross checked with clen.
 * No NVMe commands (64 bytes long plus some extra added by some OSes) have
 * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS
 * structures that are sent across the wire. The FIS register structure is
 * used to move a command from a SATA host to device, but the ATA 'command'
 * is not the first byte. So it is harder to say what will happen if a
 * FIS structure is presented as a SCSI command, hopefully there is a low
 * probability this function will yield true in that case. */
bool is_scsi_cdb(const uint8_t * cdbp, int clen);

// Print SCSI debug messages?
extern unsigned char scsi_debugmode;

void scsi_do_sense_disect(const struct scsi_cmnd_io * in,
                          struct scsi_sense_disect * out);

int scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo);

const char * scsiErrString(int scsiErr);

/* Yield string associated with sense_key value. Returns 'buff'. */
char * scsi_get_sense_key_str(int sense_key, int buff_len, char * buff);

int scsi_vpd_dev_id_iter(const unsigned char * initial_desig_desc,
                         int page_len, int * off, int m_assoc,
                         int m_desig_type, int m_code_set);

int scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s,
                          int slen, int * transport);


/* STANDARD SCSI Commands  */
int scsiTestUnitReady(scsi_device * device);

int scsiStdInquiry(scsi_device * device, uint8_t *pBuf, int bufLen);

int scsiInquiryVpd(scsi_device * device, int vpd_page, uint8_t *pBuf,
                   int bufLen);

int scsiLogSense(scsi_device * device, int pagenum, int subpagenum,
                 uint8_t *pBuf, int bufLen, int known_resp_len);

int scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum,
                  int subpagenum, uint8_t *pBuf, int bufLen);

int scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc,
                  uint8_t *pBuf, int bufLen);

int scsiModeSelect(scsi_device * device, int sp, uint8_t *pBuf, int bufLen);

int scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc,
                    uint8_t *pBuf, int bufLen);

int scsiModeSelect10(scsi_device * device, int sp, uint8_t *pBuf, int bufLen);

int scsiModePageOffset(const uint8_t * resp, int len, int modese_len);

int scsiRequestSense(scsi_device * device,
                     struct scsi_sense_disect * sense_info);

int scsiSetPowerCondition(scsi_device * device, int power_cond,
                          int pcond_modifier = 0);

int scsiSendDiagnostic(scsi_device * device, int functioncode, uint8_t *pBuf,
                       int bufLen);

bool scsi_pass_through_yield_sense(scsi_device * device, scsi_cmnd_io * iop,
                                   struct scsi_sense_disect & sinfo);

int scsiReadDefect10(scsi_device * device, int req_plist, int req_glist,
                     int dl_format, uint8_t *pBuf, int bufLen);

int scsiReadDefect12(scsi_device * device, int req_plist, int req_glist,
                     int dl_format, int addrDescIndex, uint8_t *pBuf,
                     int bufLen);

int scsiReadCapacity10(scsi_device * device, unsigned int * last_lbp,
                       unsigned int * lb_sizep);

int scsiReadCapacity16(scsi_device * device, uint8_t *pBuf, int bufLen);

int scsiRSOCcmd(scsi_device * device, bool rctd, uint8_t rep_opt,
		uint8_t opcode, uint16_t serv_act, uint8_t *pBuf, int bufLen,
	        int & rspLen);

/* SMART specific commands */
int scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
                uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp,
                uint8_t *triptemp);

int scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp,
                      int modese_len);
int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp);
int scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp);
int scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
                            const struct scsi_iec_mode_page *iecp);
void scsiDecodeErrCounterPage(unsigned char * resp,
                              struct scsiErrorCounter *ecp,
                              int allocLen);
void scsiDecodeNonMediumErrPage(unsigned char * resp,
                                struct scsiNonMediumError *nmep,
                                int allocLen);
int scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
                                  int modese_len);
int scsiCountFailedSelfTests(scsi_device * device, int noisy);
int scsiSelfTestInProgress(scsi_device * device, int * inProgress);
int scsiFetchControlGLTSD(scsi_device * device, int modese_len, int current);
int scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len);
int scsiFetchTransportProtocol(scsi_device * device, int modese_len);
int scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp,
               int * haw_zbcp);
int scsiGetSetCache(scsi_device * device,  int modese_len, short int * wce,
                    short int * rcd);
uint64_t scsiGetSize(scsi_device * device, bool avoid_rcap16,
                     struct scsi_readcap_resp * srrp);

/* T10 Standard IE Additional Sense Code strings taken from t10.org */
char * scsiGetIEString(uint8_t asc, uint8_t ascq, char * b, int blen);
int scsiGetTemp(scsi_device * device, uint8_t *currenttemp, uint8_t *triptemp);


int scsiSmartDefaultSelfTest(scsi_device * device);
int scsiSmartShortSelfTest(scsi_device * device);
int scsiSmartExtendSelfTest(scsi_device * device);
int scsiSmartShortCapSelfTest(scsi_device * device);
int scsiSmartExtendCapSelfTest(scsi_device * device);
int scsiSmartSelfTestAbort(scsi_device * device);

const char * scsiTapeAlertsTapeDevice(unsigned short code);
const char * scsiTapeAlertsChangerDevice(unsigned short code);

const char * scsi_get_opcode_name(const uint8_t * cdbp);
void scsi_format_id_string(char * out, const uint8_t * in, int n);

/* Read binary starting at 'up' for 'len' bytes and output as ASCII
 * hexadecimal into pout(). 16 bytes per line are output with an
 * additional space between 8th and 9th byte on each line (for readability).
 * 'no_ascii' selects one of 3 output format types:
 *     > 0     each line has address then up to 16 ASCII-hex bytes
 *     = 0     in addition, the bytes are rendered in ASCII to the right
 *             of each line, non-printable characters shown as '.'
 *     < 0     only the ASCII-hex bytes are listed (i.e. without address) */
void dStrHex(const uint8_t * up, int len, int no_ascii);

/* Read binary starting at 'up' for 'len' bytes and output as ASCII
 * hexadecimal into FILE pointer (fp). If fp is nullptr, then send to
 * pout(). Note that 'stdout' and 'stderr' can be given for 'fp'.
 * See dStrHex() above for more information. */
void dStrHexFp(const uint8_t * up, int len, int no_ascii, FILE * fp);

/* Attempt to find the first SCSI sense data descriptor that matches the
 * given 'desc_type'. If found return pointer to start of sense data
 * descriptor; otherwise (including fixed format sense data) returns
 * nullptr. */
const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep,
                                              int sense_len, int desc_type);


/* SCSI command transmission interface function declaration. Its
 * definition is target OS specific (see os_<OS>.c file).
 * Returns 0 if SCSI command successfully launched and response
 * received. Even when 0 is returned the caller should check
 * scsi_cmnd_io::scsi_status for SCSI defined errors and warnings
 * (e.g. CHECK CONDITION). If the SCSI command could not be issued
 * (e.g. device not present or not a SCSI device) or some other problem
 * arises (e.g. timeout) then returns a negative errno value. */
// Moved to C++ interface
//int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report);



#endif