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
|
#ifndef SG_CMDS_BASIC_H
#define SG_CMDS_BASIC_H
/*
* Copyright (c) 2004-2023 Douglas Gilbert.
* All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the BSD_LICENSE file.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
/*
* Error, warning and verbose output is sent to the file pointed to by
* sg_warnings_strm which is declared in sg_lib.h and can be set with
* the sg_set_warnings_strm() function. If not given sg_warnings_strm
* defaults to stderr.
* If 'noisy' is false and 'verbose' is zero then following functions should
* not output anything to sg_warnings_strm. If 'noisy' is true and 'verbose'
* is zero then Unit Attention, Recovered, Medium and Hardware errors (sense
* keys) send output to sg_warnings_strm. Increasing values of 'verbose'
* send increasing amounts of (debug) output to sg_warnings_strm.
*/
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Functions with the "_pt" suffix take a pointer to an object (derived from)
* sg_pt_base rather than an open file descriptor as their first argument.
* That object is assumed to be constructed and have a device file descriptor
* associated with it. clear_scsi_pt_obj() is called at the start of each
* "_pt" function. Caller is responsible for lifetime of ptp.
* If the sense buffer is accessed outside the "_pt" function then the caller
* must invoke set_scsi_pt_sense() _prior_ to the "_pt" function. Otherwise
* a sense buffer local to "_pt" function is used.
* Usually the cdb pointer will be NULL going into the "_pt" functions but
* could be given by the caller in which case it will used rather than a
* locally generated one. */
struct sg_pt_base;
/* Invokes a SCSI INQUIRY command and yields the response
* Returns 0 when successful, SG_LIB_CAT_INVALID_OP -> not supported,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
* SG_LIB_CAT_ABORTED_COMMAND, a negated errno or -1 -> other errors */
int sg_ll_inquiry(int sg_fd, bool cmddt, bool evpd, int pg_op, void * resp,
int mx_resp_len, bool noisy, int verbose);
/* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when
* successful, various SG_LIB_CAT_* positive values, negated error or -1
* for other errors. The CMDDT field is obsolete in the INQUIRY cdb (since
* spc3r16 in 2003) so * an argument to set it has been removed (use the
* REPORT SUPPORTED OPERATION CODES command instead). Adds the ability to
* set the command abort timeout and the ability to report the residual
* count. If timeout_secs is zero or less the default command abort timeout
* (60 seconds) is used. If residp is non-NULL then the residual value is
* written where residp points. A residual value of 0 implies mx_resp_len
* bytes have be written where resp points. If the residual value equals
* mx_resp_len then no bytes have been written. */
int sg_ll_inquiry_v2(int sg_fd, bool evpd, int pg_op, void * resp,
int mx_resp_len, int timeout_secs, int * residp,
bool noisy, int verbose);
/* Similar to sg_ll_inquiry_v2(). See note above about "_pt" suffix. */
int sg_ll_inquiry_pt(struct sg_pt_base * ptp, bool evpd, int pg_op,
void * resp, int mx_resp_len, int timeout_secs,
int * residp, bool noisy, int verbose);
/* Invokes a SCSI LOG SELECT command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> Log Select not supported,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
* SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_NOT_READY -> device not ready,
* -1 -> other failure */
int sg_ll_log_select(int sg_fd, bool pcr, bool sp, int pc, int pg_code,
int subpg_code, uint8_t * paramp, int param_len,
bool noisy, int verbose);
/* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> Log Sense not supported,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
* SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
* -1 -> other failure */
int sg_ll_log_sense(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
int subpg_code, int paramp, uint8_t * resp,
int mx_resp_len, bool noisy, int verbose);
/* Same as sg_ll_log_sense() apart from timeout_secs and residp. See
* sg_ll_inquiry_v2() for their description */
int sg_ll_log_sense_v2(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
int subpg_code, int paramp, uint8_t * resp,
int mx_resp_len, int timeout_secs, int * residp,
bool noisy, int verbose);
/* Invokes a SCSI MODE SELECT (6) command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ ->
* bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready,
* SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND,
* -1 -> other failure */
int sg_ll_mode_select6(int sg_fd, bool pf, bool sp, void * paramp,
int param_len, bool noisy, int verbose);
/* v2 adds RTD (revert to defaults) bit, added in spc5r11 */
int sg_ll_mode_select6_v2(int sg_fd, bool pf, bool rtd, bool sp,
void * paramp, int param_len, bool noisy,
int verbose);
/* Invokes a SCSI MODE SELECT (10) command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ ->
* bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready,
* SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND,
* -1 -> other failure */
int sg_ll_mode_select10(int sg_fd, bool pf, bool sp, void * paramp,
int param_len, bool noisy, int verbose);
/* v2 adds RTD (revert to defaults) bit, added in spc5r11 */
int sg_ll_mode_select10_v2(int sg_fd, bool pf, bool rtd, bool sp,
void * paramp, int param_len, bool noisy,
int verbose);
/* Invokes a SCSI MODE SENSE (6) command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ ->
* bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready,
* SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND,
* -1 -> other failure */
int sg_ll_mode_sense6(int sg_fd, bool dbd, int pc, int pg_code,
int sub_pg_code, void * resp, int mx_resp_len,
bool noisy, int verbose);
/* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ ->
* bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready,
* SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND,
* -1 -> other failure */
int sg_ll_mode_sense10(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
int sub_pg_code, void * resp, int mx_resp_len,
bool noisy, int verbose);
/* Same as sg_ll_mode_sense10() apart from timeout_secs and residp. See
* sg_ll_inquiry_v2() for their description */
int sg_ll_mode_sense10_v2(int sg_fd, bool llbaa, bool dbd, int pc,
int pg_code, int sub_pg_code, void * resp,
int mx_resp_len, int timeout_secs, int * residp,
bool noisy, int verbose);
/* Invokes a SCSI PREVENT ALLOW MEDIUM REMOVAL command (SPC-3)
* prevent==0 allows removal, prevent==1 prevents removal ...
* Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> command not supported
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
* SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
* -1 -> other failure */
int sg_ll_prevent_allow(int sg_fd, int prevent, bool noisy, int verbose);
/* Invokes a SCSI READ CAPACITY (10) command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_UNIT_ATTENTION
* -> perhaps media changed, SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
* SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
* -1 -> other failure */
int sg_ll_readcap_10(int sg_fd, bool pmi, unsigned int lba, void * resp,
int mx_resp_len, bool noisy, int verbose);
/* Invokes a SCSI READ CAPACITY (16) command. Returns 0 -> success,
* SG_LIB_CAT_UNIT_ATTENTION -> media changed??, SG_LIB_CAT_INVALID_OP
* -> cdb not supported, SG_LIB_CAT_IlLEGAL_REQ -> bad field in cdb
* SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
* -1 -> other failure */
int sg_ll_readcap_16(int sg_fd, bool pmi, uint64_t llba, void * resp,
int mx_resp_len, bool noisy, int verbose);
/* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> Report Luns not supported,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
* SG_LIB_NOT_READY (shouldn't happen), -1 -> other failure */
int sg_ll_report_luns(int sg_fd, int select_report, void * resp,
int mx_resp_len, bool noisy, int verbose);
/* Similar to sg_ll_report_luns(). See note above about "_pt" suffix. */
int sg_ll_report_luns_pt(struct sg_pt_base * ptp, int select_report,
void * resp, int mx_resp_len, bool noisy,
int verbose);
/* Invokes a SCSI REQUEST SENSE command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> Request Sense not supported??,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
* -1 -> other failure */
int sg_ll_request_sense(int sg_fd, bool desc, void * resp, int mx_resp_len,
bool noisy, int verbose);
/* Similar to sg_ll_request_sense(). See note above about "_pt" suffix. */
int sg_ll_request_sense_pt(struct sg_pt_base * ptp, bool desc, void * resp,
int mx_resp_len, bool noisy, int verbose);
/* Invokes a SCSI START STOP UNIT command (SBC + MMC).
* Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> Start stop unit not supported,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
* SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
* -1 -> other failure
* SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and
* format_layer_number(mmc) fields. They also overlap on the noflush(sbc)
* and fl(mmc) one bit field. This is the cause of the awkardly named
* pc_mod__fl_num and noflush__fl arguments to this function. */
int sg_ll_start_stop_unit(int sg_fd, bool immed, int pc_mod__fl_num,
int power_cond, bool noflush__fl, bool loej,
bool start, bool noisy, int verbose);
/* Similar to sg_ll_start_stop_unit(). See note above about "_pt" suffix. */
int sg_ll_start_stop_unit_pt(struct sg_pt_base * ptp, bool immed,
int pc_mod__fl_num, int power_cond,
bool noflush__fl, bool loej, bool start,
bool noisy, int verbose);
/* Invokes a SCSI SYNCHRONIZE CACHE (10) command. Return of 0 -> success,
* SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND,
* SG_LIB_CAT_INVALID_OP -> cdb not supported,
* SG_LIB_CAT_IlLEGAL_REQ -> bad field in cdb
* SG_LIB_CAT_NOT_READY -> device not ready, -1 -> other failure */
int sg_ll_sync_cache_10(int sg_fd, bool sync_nv, bool immed, int group,
unsigned int lba, unsigned int count, bool noisy,
int verbose);
/* Invokes a SCSI TEST UNIT READY command.
* 'pack_id' is just for diagnostics, safe to set to 0.
* Return of 0 -> success, SG_LIB_CAT_UNIT_ATTENTION,
* SG_LIB_CAT_NOT_READY -> device not ready,
* SG_LIB_CAT_ABORTED_COMMAND, -1 -> other failure */
int sg_ll_test_unit_ready(int sg_fd, int pack_id, bool noisy, int verbose);
/* Similar to sg_ll_test_unit_ready(). See note above about "_pt" suffix. */
int sg_ll_test_unit_ready_pt(struct sg_pt_base * ptp, int pack_id,
bool noisy, int verbose);
/* Invokes a SCSI TEST UNIT READY command.
* 'pack_id' is just for diagnostics, safe to set to 0.
* Looks for progress indicator if 'progress' non-NULL;
* if found writes value [0..65535] else write -1.
* Return of 0 -> success, SG_LIB_CAT_UNIT_ATTENTION,
* SG_LIB_CAT_ABORTED_COMMAND, SG_LIB_CAT_NOT_READY ->
* device not ready, -1 -> other failure */
int sg_ll_test_unit_ready_progress(int sg_fd, int pack_id, int * progress,
bool noisy, int verbose);
/* Similar to sg_ll_test_unit_ready_progress(). See note above about "_pt"
* suffix. */
int sg_ll_test_unit_ready_progress_pt(struct sg_pt_base * ptp, int pack_id,
int * progress, bool noisy, int verbose);
struct sg_simple_inquiry_resp {
uint8_t peripheral_qualifier;
uint8_t peripheral_type;
uint8_t byte_1; /* was 'rmb' prior to version 1.39 */
/* now rmb == !!(0x80 & byte_1) */
uint8_t version; /* as per recent drafts: whole of byte 2 */
uint8_t byte_3;
uint8_t byte_5;
uint8_t byte_6;
uint8_t byte_7;
char vendor[9]; /* T10 field is 8 bytes, NUL char appended */
char product[17];
char revision[5];
};
/* Yields most of first 36 bytes of a standard INQUIRY (evpd==0) response.
* Returns 0 when successful, SG_LIB_CAT_INVALID_OP -> not supported,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
* a negated errno or -1 -> other errors */
int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
bool noisy, int verbose);
/* Similar to sg_simple_inquiry(). See note above about "_pt" suffix. */
int sg_simple_inquiry_pt(struct sg_pt_base * ptvp,
struct sg_simple_inquiry_resp * inq_data, bool noisy,
int verbose);
/* MODE SENSE commands yield a response that has header then zero or more
* block descriptors followed by mode pages. In most cases users are
* interested in the first mode page. This function returns the (byte)
* offset of the start of the first mode page. Set mode_sense_6 to true for
* MODE SENSE (6) and false for MODE SENSE (10). Returns >= 0 is successful
* or -1 if failure. If there is a failure a message is written to err_buff
* if it is non-NULL and err_buff_len > 0. */
int sg_mode_page_offset(const uint8_t * resp, int resp_len,
bool mode_sense_6, char * err_buff, int err_buff_len);
/* MODE SENSE commands yield a response that has header then zero or more
* block descriptors followed by mode pages. This functions returns the
* length (in bytes) of those three components. Note that the return value
* can exceed resp_len in which case the MODE SENSE command should be
* re-issued with a larger response buffer. If bd_lenp is non-NULL and if
* successful the block descriptor length (in bytes) is written to *bd_lenp.
* Set mode_sense_6 to true for MODE SENSE (6) and false for MODE SENSE (10)
* responses. Returns -1 if there is an error (e.g. response too short). */
int sg_msense_calc_length(const uint8_t * resp, int resp_len,
bool mode_sense_6, int * bd_lenp);
/* Fetches current, changeable, default and/or saveable mode pages (note:
* _only_ mode pages) as indicated by pcontrol_arr for given pg_code and
* sub_pg_code. If mode6 is true then use MODE SENSE (6) else use MODE SENSE
* (10). If flexible true and mode data length seems wrong then try and fix
* (compensating hack for bad device or driver). pcontrol_arr should have 4
* elements for output of current, changeable, default and saved values
* respectively. Each element should be NULL or a pointer to memory that is
* at least mx_mpage_len bytes long. The length of the fetched mode page
* (or pages) is written to the reported_lenp pointer, if it is non-NULL.
* That should be the length written to each pointer within pcontrol_arr .
* If success_mask pointer is not NULL then first zeros it. Then set bits
* 0, 1, 2 and/or 3 if the current, changeable, default and saved values
* respectively have been fetched. Returns 0 if overall success, otherwise
* a SG_LIB_CAT type error is returned or -1 for an uncategorized error.
* If error on current page then stops and returns that error; otherwise
* continues if an error is detected, returning the first error encountered.
* So if the saved page control is not supported, for example, then 7 is
* written to *smask and SG_LIB_CAT_ILLEGAL_REQ is returned. */
int sg_get_mode_page_controls(int sg_fd, bool mode6, int pg_code,
int sub_pg_code, bool dbd, bool flexible,
int mx_mpage_len, int * success_mask,
void * pcontrol_arr[], int * reported_lenp,
int verbose);
/* Returns file descriptor >= 0 if successful. If error in Unix returns
negated errno. Implementation calls scsi_pt_open_device(). */
int sg_cmds_open_device(const char * device_name, bool read_only, int verbose);
/* Returns file descriptor >= 0 if successful. If error in Unix returns
negated errno. Implementation calls scsi_pt_open_flags(). */
int sg_cmds_open_flags(const char * device_name, int flags, int verbose);
/* Returns 0 if successful. If error in Unix returns negated errno.
Implementation calls scsi_pt_close_device(). */
int sg_cmds_close_device(int device_fd);
const char * sg_cmds_version();
#define SG_NO_DATA_IN 0
/* This is a helper function used by sg_cmds_* implementations after the
* call to the pass-through. pt_res is returned from do_scsi_pt(). If valid
* sense data is found it is decoded and output to sg_warnings_strm (def:
* stderr); depending on the 'noisy' and 'verbose' settings. Returns -2 for
* sense data (may not be fatal), -1 for failed, 0, or a positive number. If
* 'mx_di_len > 0' then asks pass-through for resid and returns
* (mx_di_len - resid); otherwise returns 0. So for data-in it should return
* the actual number of bytes received. For data-out (to device) or no data
* call with 'mx_di_len' set to 0 or less. If -2 returned then sense category
* output via 'o_sense_cat' pointer (if not NULL). Note that several sense
* categories also have data in bytes received; -2 is still returned. */
int sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin,
int pt_res, bool noisy, int verbose,
int * o_sense_cat);
/* NVMe devices use a different command set. This function will return true
* if the device associated with 'pvtp' is a NVME device, else it will
* return false (e.g. for SCSI devices). */
bool sg_cmds_is_nvme(const struct sg_pt_base * ptvp);
#ifdef __cplusplus
}
#endif
#endif
|