xref: /aosp_15_r20/external/sg3_utils/include/sg_pt.h (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
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