1*44704f69SBart Van Assche #ifndef SG_PT_H 2*44704f69SBart Van Assche #define SG_PT_H 3*44704f69SBart Van Assche 4*44704f69SBart Van Assche /* 5*44704f69SBart Van Assche * Copyright (c) 2005-2021 Douglas Gilbert. 6*44704f69SBart Van Assche * All rights reserved. 7*44704f69SBart Van Assche * Use of this source code is governed by a BSD-style 8*44704f69SBart Van Assche * license that can be found in the BSD_LICENSE file. 9*44704f69SBart Van Assche * 10*44704f69SBart Van Assche * SPDX-License-Identifier: BSD-2-Clause 11*44704f69SBart Van Assche */ 12*44704f69SBart Van Assche 13*44704f69SBart Van Assche #include <stdint.h> 14*44704f69SBart Van Assche #include <stdbool.h> 15*44704f69SBart Van Assche 16*44704f69SBart Van Assche #ifdef __cplusplus 17*44704f69SBart Van Assche extern "C" { 18*44704f69SBart Van Assche #endif 19*44704f69SBart Van Assche 20*44704f69SBart Van Assche /* This declaration hides the fact that each implementation has its own 21*44704f69SBart Van Assche * structure "derived" (using a C++ term) from this one. It compiles 22*44704f69SBart Van Assche * because 'struct sg_pt_base' is only referenced (by pointer: 'objp') 23*44704f69SBart Van Assche * in this interface. An instance of this structure represents the 24*44704f69SBart Van Assche * context of one synchronous SCSI (or NVME) command and the context 25*44704f69SBart Van Assche * can be re-used. If an instance of sg_pt_base is shared across several 26*44704f69SBart Van Assche * threads then it is up to the application to take care of multi-threaded 27*44704f69SBart Van Assche * issues with that instance. */ 28*44704f69SBart Van Assche struct sg_pt_base; 29*44704f69SBart Van Assche 30*44704f69SBart Van Assche 31*44704f69SBart Van Assche /* The format of the version string is like this: "3.04 20180213". 32*44704f69SBart Van Assche * The leading digit will be incremented if this interface changes 33*44704f69SBart Van Assche * in a way that may impact backward compatibility. */ 34*44704f69SBart Van Assche const char * scsi_pt_version(); 35*44704f69SBart Van Assche const char * sg_pt_version(); /* both functions give same result */ 36*44704f69SBart Van Assche 37*44704f69SBart Van Assche 38*44704f69SBart Van Assche /* Returns file descriptor or file handle and is >= 0 if successful. 39*44704f69SBart Van Assche * If error in Unix returns negated errno. */ 40*44704f69SBart Van Assche int scsi_pt_open_device(const char * device_name, bool read_only, 41*44704f69SBart Van Assche int verbose); 42*44704f69SBart Van Assche 43*44704f69SBart Van Assche /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed 44*44704f69SBart Van Assche * together. Returns valid file descriptor or handle ( >= 0 ) if successful, 45*44704f69SBart Van Assche * otherwise returns -1 or a negated errno. 46*44704f69SBart Van Assche * In Win32 O_EXCL translated to equivalent. */ 47*44704f69SBart Van Assche int scsi_pt_open_flags(const char * device_name, int flags, int verbose); 48*44704f69SBart Van Assche 49*44704f69SBart Van Assche /* Returns 0 if successful. 'device_fd' should be a value that was previously 50*44704f69SBart Van Assche * returned by scsi_pt_open_device() or scsi_pt_open_flags() that has not 51*44704f69SBart Van Assche * already been closed. If error in Unix returns negated errno. */ 52*44704f69SBart Van Assche int scsi_pt_close_device(int device_fd); 53*44704f69SBart Van Assche 54*44704f69SBart Van Assche /* Assumes dev_fd is an "open" file handle associated with device_name. If 55*44704f69SBart Van Assche * the implementation (possibly for one OS) cannot determine from dev_fd if 56*44704f69SBart Van Assche * a SCSI or NVMe pass-through is referenced, then it might guess based on 57*44704f69SBart Van Assche * device_name. Returns 1 if SCSI generic pass-though device, returns 2 if 58*44704f69SBart Van Assche * secondary SCSI pass-through device (in Linux a bsg device); returns 3 is 59*44704f69SBart Van Assche * char NVMe device (i.e. no NSID); returns 4 if block NVMe device (includes 60*44704f69SBart Van Assche * NSID), 5 is also a NVMe device (FreeBSD CAM NVMe (e.g. /dev/nda0)) or 0 61*44704f69SBart Van Assche * if something else (e.g. ATA block device) or dev_fd < 0. 62*44704f69SBart Van Assche * The return value differs somewhat by OS. 63*44704f69SBart Van Assche * If error, returns negated errno (operating system) value. */ 64*44704f69SBart Van Assche int check_pt_file_handle(int dev_fd, const char * device_name, int verbose); 65*44704f69SBart Van Assche 66*44704f69SBart Van Assche 67*44704f69SBart Van Assche /* Creates an object that can be used to issue one or more SCSI commands 68*44704f69SBart Van Assche * (or task management functions). Returns NULL if problem. 69*44704f69SBart Van Assche * Once this object has been created it should be destroyed with 70*44704f69SBart Van Assche * destruct_scsi_pt_obj() when it is no longer needed. */ 71*44704f69SBart Van Assche struct sg_pt_base * construct_scsi_pt_obj(void); 72*44704f69SBart Van Assche 73*44704f69SBart Van Assche /* An alternate and preferred way to create an object that can be used to 74*44704f69SBart Van Assche * issue one or more SCSI (or NVMe) commands (or task management functions). 75*44704f69SBart Van Assche * This variant associates a device file descriptor (handle) with the object 76*44704f69SBart Van Assche * and a verbose argument that causes messages to be written to stderr if 77*44704f69SBart Van Assche * errors occur. The reason for this is to optionally allow the detection of 78*44704f69SBart Van Assche * NVMe devices that will cause pt_device_is_nvme() to return true. Set 79*44704f69SBart Van Assche * dev_fd to -1 if no open device file descriptor is available. Caller 80*44704f69SBart Van Assche * should additionally call get_scsi_pt_os_err() after this call to check 81*44704f69SBart Van Assche * for errors. The dev_fd argument may be -1 to indicate no device file 82*44704f69SBart Van Assche * descriptor. */ 83*44704f69SBart Van Assche struct sg_pt_base * 84*44704f69SBart Van Assche construct_scsi_pt_obj_with_fd(int dev_fd, int verbose); 85*44704f69SBart Van Assche 86*44704f69SBart Van Assche /* Forget any previous dev_fd and install the one given. May attempt to 87*44704f69SBart Van Assche * find file type (e.g. if pass-though) from OS so there could be an error. 88*44704f69SBart Van Assche * Returns 0 for success or the same value as get_scsi_pt_os_err() 89*44704f69SBart Van Assche * will return. dev_fd should be >= 0 for a valid file handle or -1 . */ 90*44704f69SBart Van Assche int set_pt_file_handle(struct sg_pt_base * objp, int dev_fd, int verbose); 91*44704f69SBart Van Assche 92*44704f69SBart Van Assche /* Valid file handles (which is the return value) are >= 0 . Returns -1 93*44704f69SBart Van Assche * if there is no valid file handle. */ 94*44704f69SBart Van Assche int get_pt_file_handle(const struct sg_pt_base * objp); 95*44704f69SBart Van Assche 96*44704f69SBart Van Assche /* Clear state information held in *objp . This allows this object to be 97*44704f69SBart Van Assche * used to issue more than one SCSI command. The dev_fd is remembered. 98*44704f69SBart Van Assche * Use set_pt_file_handle() to change dev_fd. */ 99*44704f69SBart Van Assche void clear_scsi_pt_obj(struct sg_pt_base * objp); 100*44704f69SBart Van Assche 101*44704f69SBart Van Assche /* Partially clear state information held in *objp . Any error settings and 102*44704f69SBart Van Assche * the data-in and data-out settings are cleared. So dev_fd, cdb and sense 103*44704f69SBart Van Assche * settings are kept. */ 104*44704f69SBart Van Assche void partial_clear_scsi_pt_obj(struct sg_pt_base * objp); 105*44704f69SBart Van Assche 106*44704f69SBart Van Assche /* Set the CDB (command descriptor block). May also be a NVMe Admin command 107*44704f69SBart Van Assche * which will be 64 bytes long. 108*44704f69SBart Van Assche * 109*44704f69SBart Van Assche * Note that the sg_cmds_is_nvme() function found in sg_cmds_basic.h can be 110*44704f69SBart Van Assche * called after this function to "guess" which command set the given command 111*44704f69SBart Van Assche * belongs to. It is valid to supply a cdb value of NULL. */ 112*44704f69SBart Van Assche void set_scsi_pt_cdb(struct sg_pt_base * objp, const uint8_t * cdb, 113*44704f69SBart Van Assche int cdb_len); 114*44704f69SBart Van Assche 115*44704f69SBart Van Assche /* Set the sense buffer and the maximum length of that buffer. For NVMe 116*44704f69SBart Van Assche * commands this "sense" buffer will receive the 4 DWORDs of from the 117*44704f69SBart Van Assche * completion queue. It is valid to supply a sense value of NULL. */ 118*44704f69SBart Van Assche void set_scsi_pt_sense(struct sg_pt_base * objp, uint8_t * sense, 119*44704f69SBart Van Assche int max_sense_len); 120*44704f69SBart Van Assche 121*44704f69SBart Van Assche /* Set a pointer and length to be used for data transferred from device */ 122*44704f69SBart Van Assche void set_scsi_pt_data_in(struct sg_pt_base * objp, /* from device */ 123*44704f69SBart Van Assche uint8_t * dxferp, int dxfer_ilen); 124*44704f69SBart Van Assche 125*44704f69SBart Van Assche /* Set a pointer and length to be used for data transferred to device */ 126*44704f69SBart Van Assche void set_scsi_pt_data_out(struct sg_pt_base * objp, /* to device */ 127*44704f69SBart Van Assche const uint8_t * dxferp, int dxfer_olen); 128*44704f69SBart Van Assche 129*44704f69SBart Van Assche /* Set a pointer and length to be used for metadata transferred to 130*44704f69SBart Van Assche * (out_true=true) or from (out_true=false) device (NVMe only) */ 131*44704f69SBart Van Assche void set_pt_metadata_xfer(struct sg_pt_base * objp, uint8_t * mdxferp, 132*44704f69SBart Van Assche uint32_t mdxfer_len, bool out_true); 133*44704f69SBart Van Assche 134*44704f69SBart Van Assche /* The following "set_"s implementations may be dummies */ 135*44704f69SBart Van Assche void set_scsi_pt_packet_id(struct sg_pt_base * objp, int pack_id); 136*44704f69SBart Van Assche void set_scsi_pt_tag(struct sg_pt_base * objp, uint64_t tag); 137*44704f69SBart Van Assche void set_scsi_pt_task_management(struct sg_pt_base * objp, int tmf_code); 138*44704f69SBart Van Assche void set_scsi_pt_task_attr(struct sg_pt_base * objp, int attribute, 139*44704f69SBart Van Assche int priority); 140*44704f69SBart Van Assche 141*44704f69SBart Van Assche /* Following is a guard which is defined when set_scsi_pt_flags() is 142*44704f69SBart Van Assche * present. Older versions of this library may not have this function. */ 143*44704f69SBart Van Assche #define SCSI_PT_FLAGS_FUNCTION 1 144*44704f69SBart Van Assche /* If neither QUEUE_AT_HEAD nor QUEUE_AT_TAIL are given, or both 145*44704f69SBart Van Assche * are given, use the pass-through default. */ 146*44704f69SBart Van Assche #define SCSI_PT_FLAGS_QUEUE_AT_TAIL 0x10 147*44704f69SBart Van Assche #define SCSI_PT_FLAGS_QUEUE_AT_HEAD 0x20 148*44704f69SBart Van Assche /* Set (potentially OS dependent) flags for pass-through mechanism. 149*44704f69SBart Van Assche * Apart from contradictions, flags can be OR-ed together. */ 150*44704f69SBart Van Assche void set_scsi_pt_flags(struct sg_pt_base * objp, int flags); 151*44704f69SBart Van Assche 152*44704f69SBart Van Assche #define SCSI_PT_DO_START_OK 0 153*44704f69SBart Van Assche #define SCSI_PT_DO_BAD_PARAMS 1 154*44704f69SBart Van Assche #define SCSI_PT_DO_TIMEOUT 2 155*44704f69SBart Van Assche #define SCSI_PT_DO_NOT_SUPPORTED 4 156*44704f69SBart Van Assche #define SCSI_PT_DO_NVME_STATUS 48 /* == SG_LIB_NVME_STATUS */ 157*44704f69SBart Van Assche /* If OS error prior to or during command submission then returns negated 158*44704f69SBart Van Assche * error value (e.g. Unix '-errno'). This includes interrupted system calls 159*44704f69SBart Van Assche * (e.g. by a signal) in which case -EINTR would be returned. Note that 160*44704f69SBart Van Assche * system call errors also can be fetched with get_scsi_pt_os_err(). 161*44704f69SBart Van Assche * Return 0 if okay (i.e. at the very least: command sent). Positive 162*44704f69SBart Van Assche * return values are errors (see SCSI_PT_DO_* defines). If a file descriptor 163*44704f69SBart Van Assche * has already been provided by construct_scsi_pt_obj_with_fd() then the 164*44704f69SBart Van Assche * given 'fd' can be -1 or the same value as given to the constructor. */ 165*44704f69SBart Van Assche int do_scsi_pt(struct sg_pt_base * objp, int fd, int timeout_secs, 166*44704f69SBart Van Assche int verbose); 167*44704f69SBart Van Assche 168*44704f69SBart Van Assche /* NVMe Admin commands can be sent directly to do_scsi_pt(). Unfortunately 169*44704f69SBart Van Assche * NVMe has at least one other command set: "NVM" to access user data and 170*44704f69SBart Van Assche * the opcodes in the NVM command set overlap with the Admin command set. 171*44704f69SBart Van Assche * So NVMe Admin commands should be sent do_scsi_pt() while NVMe "NVM" 172*44704f69SBart Van Assche * commands should be sent to this function. No SCSI commands should be 173*44704f69SBart Van Assche * sent to this function. Currently submq is not implemented and all 174*44704f69SBart Van Assche * submitted NVM commands are sent on queue 0, the same queue use for 175*44704f69SBart Van Assche * Admin commands. The return values follow the same pattern as do_scsi_pt(), 176*44704f69SBart Van Assche * with 0 returned being good. The NVMe device file descriptor must either 177*44704f69SBart Van Assche * be given to the obj constructor, or a prior set_pt_file_handle() call. */ 178*44704f69SBart Van Assche int do_nvm_pt(struct sg_pt_base * objp, int submq, int timeout_secs, 179*44704f69SBart Van Assche int verbose); 180*44704f69SBart Van Assche 181*44704f69SBart Van Assche #define SCSI_PT_RESULT_GOOD 0 182*44704f69SBart Van Assche #define SCSI_PT_RESULT_STATUS 1 /* other than GOOD and CHECK CONDITION */ 183*44704f69SBart Van Assche #define SCSI_PT_RESULT_SENSE 2 184*44704f69SBart Van Assche #define SCSI_PT_RESULT_TRANSPORT_ERR 3 185*44704f69SBart Van Assche #define SCSI_PT_RESULT_OS_ERR 4 186*44704f69SBart Van Assche /* This function, called soon after do_scsi_pt(), returns one of the above 187*44704f69SBart Van Assche * result categories. The highest numbered applicable category is returned. 188*44704f69SBart Van Assche * 189*44704f69SBart Van Assche * Note that the sg_cmds_process_resp() function found in sg_cmds_basic.h 190*44704f69SBart Van Assche * is useful for processing SCSI command responses. 191*44704f69SBart Van Assche * And the sg_cmds_is_nvme() function found in sg_cmds_basic.h can be called 192*44704f69SBart Van Assche * after set_scsi_pt_cdb() to "guess" which command set the given command 193*44704f69SBart Van Assche * belongs to. */ 194*44704f69SBart Van Assche int get_scsi_pt_result_category(const struct sg_pt_base * objp); 195*44704f69SBart Van Assche 196*44704f69SBart Van Assche /* If not available return 0 which implies there is no residual value. If 197*44704f69SBart Van Assche * supported it is the number of bytes requested to transfer less the 198*44704f69SBart Van Assche * number actually transferred. This it typically important for data-in 199*44704f69SBart Van Assche * transfers. For data-out (only) transfers, the 'dout_req_len - 200*44704f69SBart Van Assche * dout_act_len' is returned. For bidi transfer the data-in residual is 201*44704f69SBart Van Assche * returned. */ 202*44704f69SBart Van Assche int get_scsi_pt_resid(const struct sg_pt_base * objp); 203*44704f69SBart Van Assche 204*44704f69SBart Van Assche /* Returns SCSI status value (from device that received the command). If an 205*44704f69SBart Van Assche * NVMe command was issued directly (i.e. through do_scsi_pt() then return 206*44704f69SBart Van Assche * NVMe status (i.e. ((SCT << 8) | SC)). If problem returns -1. */ 207*44704f69SBart Van Assche int get_scsi_pt_status_response(const struct sg_pt_base * objp); 208*44704f69SBart Van Assche 209*44704f69SBart Van Assche /* Returns SCSI status value or, if NVMe command given to do_scsi_pt(), 210*44704f69SBart Van Assche * then returns NVMe result (i.e. DWord(0) from completion queue). If 211*44704f69SBart Van Assche * 'objp' is NULL then returns 0xffffffff. */ 212*44704f69SBart Van Assche uint32_t get_pt_result(const struct sg_pt_base * objp); 213*44704f69SBart Van Assche 214*44704f69SBart Van Assche /* These two get functions should just echo what has been given to 215*44704f69SBart Van Assche * set_scsi_pt_cdb(). If it has not been called or clear_scsi_pt_obj() 216*44704f69SBart Van Assche * has been called then they return 0 and NULL respectively. */ 217*44704f69SBart Van Assche int get_scsi_pt_cdb_len(const struct sg_pt_base * objp); 218*44704f69SBart Van Assche uint8_t * get_scsi_pt_cdb_buf(const struct sg_pt_base * objp); 219*44704f69SBart Van Assche 220*44704f69SBart Van Assche /* Actual sense length returned. If sense data is present but 221*44704f69SBart Van Assche actual sense length is not known, return 'max_sense_len' */ 222*44704f69SBart Van Assche int get_scsi_pt_sense_len(const struct sg_pt_base * objp); 223*44704f69SBart Van Assche uint8_t * get_scsi_pt_sense_buf(const struct sg_pt_base * objp); 224*44704f69SBart Van Assche 225*44704f69SBart Van Assche /* If not available return 0 (for success). */ 226*44704f69SBart Van Assche int get_scsi_pt_os_err(const struct sg_pt_base * objp); 227*44704f69SBart Van Assche char * get_scsi_pt_os_err_str(const struct sg_pt_base * objp, int max_b_len, 228*44704f69SBart Van Assche char * b); 229*44704f69SBart Van Assche 230*44704f69SBart Van Assche /* If not available return 0 (for success) */ 231*44704f69SBart Van Assche int get_scsi_pt_transport_err(const struct sg_pt_base * objp); 232*44704f69SBart Van Assche void set_scsi_pt_transport_err(struct sg_pt_base * objp, int err); 233*44704f69SBart Van Assche char * get_scsi_pt_transport_err_str(const struct sg_pt_base * objp, 234*44704f69SBart Van Assche int max_b_len, char * b); 235*44704f69SBart Van Assche 236*44704f69SBart Van Assche /* If not available return -1 otherwise return number of milliseconds 237*44704f69SBart Van Assche * that the lower layers (and hardware) took to execute the previous 238*44704f69SBart Van Assche * command. */ 239*44704f69SBart Van Assche int get_scsi_pt_duration_ms(const struct sg_pt_base * objp); 240*44704f69SBart Van Assche 241*44704f69SBart Van Assche /* If not available return 0 otherwise return number of nanoseconds that the 242*44704f69SBart Van Assche * lower layers (and hardware) took to execute the command just completed. */ 243*44704f69SBart Van Assche uint64_t get_pt_duration_ns(const struct sg_pt_base * objp); 244*44704f69SBart Van Assche 245*44704f69SBart Van Assche /* The two functions yield requested and actual data transfer lengths in 246*44704f69SBart Van Assche * bytes. The second argument is a pointer to the data-in length; the third 247*44704f69SBart Van Assche * argument is a pointer to the data-out length. The pointers may be NULL. 248*44704f69SBart Van Assche * The _actual_ values are related to resid (residual count from DMA) */ 249*44704f69SBart Van Assche void get_pt_req_lengths(const struct sg_pt_base * objp, int * req_dinp, 250*44704f69SBart Van Assche int * req_doutp); 251*44704f69SBart Van Assche void get_pt_actual_lengths(const struct sg_pt_base * objp, int * act_dinp, 252*44704f69SBart Van Assche int * act_doutp); 253*44704f69SBart Van Assche 254*44704f69SBart Van Assche /* Return true if device associated with 'objp' uses NVMe command set. To 255*44704f69SBart Van Assche * be useful (in modifying the type of command sent (SCSI or NVMe) then 256*44704f69SBart Van Assche * construct_scsi_pt_obj_with_fd() should be used followed by an invocation 257*44704f69SBart Van Assche * of this function. */ 258*44704f69SBart Van Assche bool pt_device_is_nvme(const struct sg_pt_base * objp); 259*44704f69SBart Van Assche 260*44704f69SBart Van Assche /* If a NVMe block device (which includes the NSID) handle is associated 261*44704f69SBart Van Assche * with 'objp', then its NSID is returned (values range from 0x1 to 262*44704f69SBart Van Assche * 0xffffffe). Otherwise 0 is returned. */ 263*44704f69SBart Van Assche uint32_t get_pt_nvme_nsid(const struct sg_pt_base * objp); 264*44704f69SBart Van Assche 265*44704f69SBart Van Assche 266*44704f69SBart Van Assche /* Should be invoked once per objp after other processing is complete in 267*44704f69SBart Van Assche * order to clean up resources. For ever successful construct_scsi_pt_obj() 268*44704f69SBart Van Assche * call there should be one destruct_scsi_pt_obj(). If the 269*44704f69SBart Van Assche * construct_scsi_pt_obj_with_fd() function was used to create this object 270*44704f69SBart Van Assche * then the dev_fd provided to that constructor is not altered by this 271*44704f69SBart Van Assche * destructor. So the user should still close dev_fd (perhaps with 272*44704f69SBart Van Assche * scsi_pt_close_device() ). */ 273*44704f69SBart Van Assche void destruct_scsi_pt_obj(struct sg_pt_base * objp); 274*44704f69SBart Van Assche 275*44704f69SBart Van Assche #ifdef SG_LIB_WIN32 276*44704f69SBart Van Assche #define SG_LIB_WIN32_DIRECT 1 277*44704f69SBart Van Assche 278*44704f69SBart Van Assche /* Request SPT direct interface when state_direct is 1, state_direct set 279*44704f69SBart Van Assche * to 0 for the SPT indirect interface. Default setting selected by build 280*44704f69SBart Van Assche * (i.e. library compile time) and is usually indirect. */ 281*44704f69SBart Van Assche void scsi_pt_win32_direct(int state_direct); 282*44704f69SBart Van Assche 283*44704f69SBart Van Assche /* Returns current SPT interface state, 1 for direct, 0 for indirect */ 284*44704f69SBart Van Assche int scsi_pt_win32_spt_state(void); 285*44704f69SBart Van Assche 286*44704f69SBart Van Assche #endif 287*44704f69SBart Van Assche 288*44704f69SBart Van Assche #ifdef __cplusplus 289*44704f69SBart Van Assche } 290*44704f69SBart Van Assche #endif 291*44704f69SBart Van Assche 292*44704f69SBart Van Assche #endif /* SG_PT_H */ 293