1 /*
2 * Copyright (c) 2021 Douglas Gilbert.
3 * All rights reserved.
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the BSD_LICENSE file.
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 */
9
10 #include <fcntl.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <stdbool.h>
18 #include <string.h>
19 #include <errno.h>
20
21 #include "sg_pt.h"
22 #include "sg_lib.h"
23 #include "sg_pr2serr.h"
24
25 /* Version 1.02 20210618 */
26
27 /* List of function names with external linkage that need to be defined
28 *
29 * check_pt_file_handle
30 * clear_scsi_pt_obj
31 * construct_scsi_pt_obj
32 * construct_scsi_pt_obj_with_fd
33 * destruct_scsi_pt_obj
34 * do_scsi_pt
35 * do_nvm_pt
36 * get_pt_actual_lengths
37 * get_pt_duration_ns
38 * get_pt_file_handle
39 * get_pt_nvme_nsid
40 * get_pt_req_lengths
41 * get_pt_result
42 * get_scsi_pt_cdb_buf
43 * get_scsi_pt_cdb_len
44 * get_scsi_pt_duration_ms
45 * get_scsi_pt_os_err
46 * get_scsi_pt_os_err_str
47 * get_scsi_pt_resid
48 * get_scsi_pt_result_category
49 * get_scsi_pt_sense_buf
50 * get_scsi_pt_sense_len
51 * get_scsi_pt_status_response
52 * get_scsi_pt_transport_err
53 * get_scsi_pt_transport_err_str
54 * partial_clear_scsi_pt_obj
55 * pt_device_is_nvme
56 * scsi_pt_close_device
57 * scsi_pt_open_device
58 * scsi_pt_open_flags
59 * set_pt_file_handle
60 * set_pt_metadata_xfer
61 * set_scsi_pt_cdb
62 * set_scsi_pt_data_in
63 * set_scsi_pt_data_out
64 * set_scsi_pt_flags
65 * set_scsi_pt_packet_id
66 * set_scsi_pt_sense
67 * set_scsi_pt_tag
68 * set_scsi_pt_task_attr
69 * set_scsi_pt_task_management
70 * set_scsi_pt_transport_err
71 */
72
73 /* Simply defines all the functions needed by the pt interface (see sg_pt.h).
74 * They do nothing. This allows decoding of hex files (e.g. with the --in=
75 * or --inhex= option) with utilities like sg_vpd and sg_logs. */
76
77 struct sg_pt_dummy {
78 int dummy;
79 };
80
81 struct sg_pt_base {
82 struct sg_pt_dummy impl;
83 };
84
85
86 /* Returns >= 0 if successful. If error in Unix returns negated errno. */
87 int
scsi_pt_open_device(const char * device_name,bool read_only,int verbose)88 scsi_pt_open_device(const char * device_name, bool read_only, int verbose)
89 {
90 int oflags = 0 /* O_NONBLOCK*/ ;
91
92 oflags |= (read_only ? O_RDONLY : O_RDWR);
93 return scsi_pt_open_flags(device_name, oflags, verbose);
94 }
95
96 /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed
97 * together. The 'flags' argument is ignored in OSF-1.
98 * Returns >= 0 if successful, otherwise returns negated errno. */
99 int
scsi_pt_open_flags(const char * device_name,int flags,int verbose)100 scsi_pt_open_flags(const char * device_name, int flags, int verbose)
101 {
102 if (device_name) {}
103 if (flags) {}
104 if (verbose) {}
105 errno = EINVAL;
106 return -1;
107 }
108
109 /* Returns 0 if successful. If error in Unix returns negated errno. */
110 int
scsi_pt_close_device(int device_fd)111 scsi_pt_close_device(int device_fd)
112 {
113 if (device_fd) {}
114 return 0;
115 }
116
117 struct sg_pt_base *
construct_scsi_pt_obj_with_fd(int device_fd,int verbose)118 construct_scsi_pt_obj_with_fd(int device_fd, int verbose)
119 {
120 struct sg_pt_dummy * ptp;
121
122 if (device_fd) {}
123 ptp = (struct sg_pt_dummy *)malloc(sizeof(struct sg_pt_dummy));
124 if (ptp) {
125 memset(ptp, 0, sizeof(struct sg_pt_dummy));
126 } else if (verbose)
127 pr2ws("%s: malloc() out of memory\n", __func__);
128 return (struct sg_pt_base *)ptp;
129 }
130
131 struct sg_pt_base *
construct_scsi_pt_obj(void)132 construct_scsi_pt_obj(void)
133 {
134 return construct_scsi_pt_obj_with_fd(-1, 0);
135 }
136
137 void
destruct_scsi_pt_obj(struct sg_pt_base * vp)138 destruct_scsi_pt_obj(struct sg_pt_base * vp)
139 {
140 struct sg_pt_dummy * ptp = &vp->impl;
141
142 if (ptp)
143 free(ptp);
144 }
145
146 void
clear_scsi_pt_obj(struct sg_pt_base * vp)147 clear_scsi_pt_obj(struct sg_pt_base * vp)
148 {
149 struct sg_pt_dummy * ptp = &vp->impl;
150
151 if (ptp) {
152 ptp->dummy = 0;
153 }
154 }
155
156 void
partial_clear_scsi_pt_obj(struct sg_pt_base * vp)157 partial_clear_scsi_pt_obj(struct sg_pt_base * vp)
158 {
159 struct sg_pt_dummy * ptp = &vp->impl;
160
161 if (NULL == ptp)
162 return;
163 ptp->dummy = 0;
164 }
165
166 void
set_scsi_pt_cdb(struct sg_pt_base * vp,const uint8_t * cdb,int cdb_len)167 set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb,
168 int cdb_len)
169 {
170 if (vp) {}
171 if (cdb) {}
172 if (cdb_len) {}
173 }
174
175 int
get_scsi_pt_cdb_len(const struct sg_pt_base * vp)176 get_scsi_pt_cdb_len(const struct sg_pt_base * vp)
177 {
178 if (vp) {}
179 return 6;
180 }
181
182 uint8_t *
get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)183 get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)
184 {
185 if (vp) {}
186 return NULL;
187 }
188
189 void
set_scsi_pt_sense(struct sg_pt_base * vp,uint8_t * sense,int max_sense_len)190 set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense,
191 int max_sense_len)
192 {
193 if (vp) {}
194 if (sense) {}
195 if (max_sense_len) {}
196 }
197
198 /* from device */
199 void
set_scsi_pt_data_in(struct sg_pt_base * vp,uint8_t * dxferp,int dxfer_len)200 set_scsi_pt_data_in(struct sg_pt_base * vp, uint8_t * dxferp,
201 int dxfer_len)
202 {
203 if (vp) {}
204 if (dxferp) {}
205 if (dxfer_len) {}
206 }
207
208 /* to device */
209 void
set_scsi_pt_data_out(struct sg_pt_base * vp,const uint8_t * dxferp,int dxfer_len)210 set_scsi_pt_data_out(struct sg_pt_base * vp, const uint8_t * dxferp,
211 int dxfer_len)
212 {
213 if (vp) {}
214 if (dxferp) {}
215 if (dxfer_len) {}
216 }
217
218 void
set_scsi_pt_packet_id(struct sg_pt_base * vp,int pack_id)219 set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id)
220 {
221 if (vp) {}
222 if (pack_id) {}
223 }
224
225 void
set_scsi_pt_tag(struct sg_pt_base * vp,uint64_t tag)226 set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag)
227 {
228 if (vp) {}
229 if (tag) {}
230 }
231
232 void
set_scsi_pt_task_management(struct sg_pt_base * vp,int tmf_code)233 set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code)
234 {
235 if (vp) {}
236 if (tmf_code) {}
237 }
238
239 void
set_scsi_pt_task_attr(struct sg_pt_base * vp,int attrib,int priority)240 set_scsi_pt_task_attr(struct sg_pt_base * vp, int attrib, int priority)
241 {
242 if (vp) {}
243 if (attrib) {}
244 if (priority) {}
245 }
246
247 void
set_scsi_pt_flags(struct sg_pt_base * vp,int flags)248 set_scsi_pt_flags(struct sg_pt_base * vp, int flags)
249 {
250 if (vp) {}
251 if (flags) {}
252 }
253
254 int
do_scsi_pt(struct sg_pt_base * vp,int device_fd,int time_secs,int verbose)255 do_scsi_pt(struct sg_pt_base * vp, int device_fd, int time_secs, int verbose)
256 {
257 if (vp) {}
258 if (device_fd) {}
259 if (time_secs) {}
260 if (verbose) {}
261 return 0;
262 }
263
264 int
get_scsi_pt_result_category(const struct sg_pt_base * vp)265 get_scsi_pt_result_category(const struct sg_pt_base * vp)
266 {
267 if (vp) {}
268 return 0;
269 }
270
271 int
get_scsi_pt_resid(const struct sg_pt_base * vp)272 get_scsi_pt_resid(const struct sg_pt_base * vp)
273 {
274 if (vp) {}
275 return 0;
276 }
277
278 void
get_pt_req_lengths(const struct sg_pt_base * vp,int * req_dinp,int * req_doutp)279 get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp,
280 int * req_doutp)
281 {
282 if (vp) {}
283 if (req_dinp) {}
284 if (req_doutp) {}
285 }
286
287 void
get_pt_actual_lengths(const struct sg_pt_base * vp,int * act_dinp,int * act_doutp)288 get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp,
289 int * act_doutp)
290 {
291 if (vp) {}
292 if (act_dinp) {}
293 if (act_doutp) {}
294 }
295
296
297 int
get_scsi_pt_status_response(const struct sg_pt_base * vp)298 get_scsi_pt_status_response(const struct sg_pt_base * vp)
299 {
300 if (vp) {}
301 return 0;
302 }
303
304 int
get_scsi_pt_sense_len(const struct sg_pt_base * vp)305 get_scsi_pt_sense_len(const struct sg_pt_base * vp)
306 {
307 if (vp) {}
308 return 0;
309 }
310
311 uint8_t *
get_scsi_pt_sense_buf(const struct sg_pt_base * vp)312 get_scsi_pt_sense_buf(const struct sg_pt_base * vp)
313 {
314 if (vp) {}
315 return NULL;
316 }
317
318 int
get_scsi_pt_duration_ms(const struct sg_pt_base * vp)319 get_scsi_pt_duration_ms(const struct sg_pt_base * vp)
320 {
321 if (vp) {}
322 return 0;
323 }
324
325 /* If not available return 0 otherwise return number of nanoseconds that the
326 * lower layers (and hardware) took to execute the command just completed. */
327 uint64_t
get_pt_duration_ns(const struct sg_pt_base * vp)328 get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused)))
329 {
330 return 0;
331 }
332
333 int
get_scsi_pt_transport_err(const struct sg_pt_base * vp)334 get_scsi_pt_transport_err(const struct sg_pt_base * vp)
335 {
336 if (vp) {}
337 return 0;
338 }
339
340 int
get_scsi_pt_os_err(const struct sg_pt_base * vp)341 get_scsi_pt_os_err(const struct sg_pt_base * vp)
342 {
343 if (vp) {}
344 return 0;
345 }
346
347 bool
pt_device_is_nvme(const struct sg_pt_base * vp)348 pt_device_is_nvme(const struct sg_pt_base * vp)
349 {
350 if (vp) {}
351 return false;
352 }
353
354 char *
get_scsi_pt_transport_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)355 get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len,
356 char * b)
357 {
358 if (vp) {}
359 if (max_b_len) {}
360 if (b) {}
361 return NULL;
362 }
363
364 char *
get_scsi_pt_os_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)365 get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
366 {
367 if (vp) {}
368 if (max_b_len) {}
369 if (b) {}
370 return NULL;
371 }
372
373 int
do_nvm_pt(struct sg_pt_base * vp,int submq,int timeout_secs,int verbose)374 do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int verbose)
375 {
376 if (vp) { }
377 if (submq) { }
378 if (timeout_secs) { }
379 if (verbose) { }
380 return SCSI_PT_DO_NOT_SUPPORTED;
381 }
382
383 int
check_pt_file_handle(int device_fd,const char * device_name,int vb)384 check_pt_file_handle(int device_fd, const char * device_name, int vb)
385 {
386 if (device_fd) {}
387 if (device_name) {}
388 if (vb) {}
389 return 0;
390 }
391
392 /* Valid file handles (which is the return value) are >= 0 . Returns -1
393 * if there is no valid file handle. */
394 int
get_pt_file_handle(const struct sg_pt_base * vp)395 get_pt_file_handle(const struct sg_pt_base * vp)
396 {
397 if (vp) { }
398 return -1;
399 }
400
401 /* If a NVMe block device (which includes the NSID) handle is associated
402 * with 'vp', then its NSID is returned (values range from 0x1 to
403 * 0xffffffe). Otherwise 0 is returned. */
404 uint32_t
get_pt_nvme_nsid(const struct sg_pt_base * vp)405 get_pt_nvme_nsid(const struct sg_pt_base * vp)
406 {
407 if (vp) { }
408 return 0;
409 }
410
411 uint32_t
get_pt_result(const struct sg_pt_base * vp)412 get_pt_result(const struct sg_pt_base * vp)
413 {
414 if (vp) { }
415 return 0;
416 }
417
418 int
set_pt_file_handle(struct sg_pt_base * vp,int dev_han,int vb)419 set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb)
420 {
421 if (vp) { }
422 if (dev_han) { }
423 if (vb) { }
424 return 0;
425 }
426
427 void
set_pt_metadata_xfer(struct sg_pt_base * vp,uint8_t * mdxferp,uint32_t mdxfer_len,bool out_true)428 set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp,
429 uint32_t mdxfer_len, bool out_true)
430 {
431 if (vp) { }
432 if (mdxferp) { }
433 if (mdxfer_len) { }
434 if (out_true) { }
435 }
436
437 void
set_scsi_pt_transport_err(struct sg_pt_base * vp,int err)438 set_scsi_pt_transport_err(struct sg_pt_base * vp, int err)
439 {
440 if (vp) { }
441 if (err) { }
442 }
443