xref: /aosp_15_r20/external/sg3_utils/lib/sg_pt_haiku.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1 /*
2  * Copyright (c) 2017 Leorize.
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 
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdarg.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include <device/CAM.h>
16 #include <scsi.h>
17 
18 #include "sg_lib.h"
19 #include "sg_pt.h"
20 
21 #if defined(__GNUC__) || defined(__clang__)
22 static int pr2ws(const char * fmt, ...)
23         __attribute__ ((format (printf, 1, 2)));
24 #else
25 static int pr2ws(const char * fmt, ...);
26 #endif
27 
28 static int
pr2ws(const char * fmt,...)29 pr2ws(const char * fmt, ...)
30 {
31     va_list args;
32     int n;
33 
34     va_start(args, fmt);
35     n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
36     va_end(args);
37     return n;
38 }
39 
40 struct sg_pt_haiku_scsi {
41     raw_device_command raw_command;
42     size_t data_len;
43     int in_err;
44     int os_err;
45     int dev_fd;
46 };
47 
48 struct sg_pt_base {
49     struct sg_pt_haiku_scsi impl;
50 };
51 
52 /* Returns >= 0 if successful. If error in Unix returns negated errno. */
53 int
scsi_pt_open_device(const char * device_name,bool read_only,int verbose)54 scsi_pt_open_device(const char * device_name, bool read_only, int verbose)
55 {
56     int oflags = O_NONBLOCK;
57 
58     oflags |= (read_only ? O_RDONLY : O_RDWR);
59     return scsi_pt_open_flags(device_name, oflags, verbose);
60 }
61 
62 /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed */
63 /* together. The 'flags' argument is advisory and may be ignored. */
64 /* Returns >= 0 if successful, otherwise returns negated errno. */
65 int
scsi_pt_open_flags(const char * device_name,int flags,int verbose)66 scsi_pt_open_flags(const char * device_name, int flags, int verbose)
67 {
68     int fd;
69 
70     if (verbose > 1) {
71         pr2ws("open %s with flags=0x%x\n", device_name, flags);
72     }
73     fd = open(device_name, flags);
74     if (fd < 0)
75         fd = -errno;
76     return fd;
77 }
78 
79 /* Returns 0 if successful. If error in Unix returns negated errno. */
80 int
scsi_pt_close_device(int device_fd)81 scsi_pt_close_device(int device_fd)
82 {
83     int res;
84 
85     res = close(device_fd);
86     if (res < 0)
87         res = -errno;
88     return res;
89 }
90 
91 struct sg_pt_base *
construct_scsi_pt_obj_with_fd(int device_fd,int verbose)92 construct_scsi_pt_obj_with_fd(int device_fd, int verbose)
93 {
94     struct sg_pt_haiku_scsi * ptp;
95 
96     /* The following 2 lines are temporary. It is to avoid a NULL pointer
97      * crash when an old utility is used with a newer library built after
98      * the sg_warnings_strm cleanup */
99     if (NULL == sg_warnings_strm)
100         sg_warnings_strm = stderr;
101 
102     ptp = (struct sg_pt_haiku_scsi *)
103            calloc(1, sizeof(struct sg_pt_haiku_scsi));
104     if (ptp) {
105         ptp->raw_command.flags = B_RAW_DEVICE_REPORT_RESIDUAL;
106         ptp->dev_fd = device_fd;
107     } else if (verbose)
108         pr2ws("%s: malloc() out of memory\n", __func__);
109     return (struct sg_pt_base *)ptp;
110 }
111 
112 struct sg_pt_base *
construct_scsi_pt_obj()113 construct_scsi_pt_obj()
114 {
115     return construct_scsi_pt_obj_with_fd(-1, 0);
116 }
117 
118 void
destruct_scsi_pt_obj(struct sg_pt_base * vp)119 destruct_scsi_pt_obj(struct sg_pt_base * vp)
120 {
121     struct sg_pt_haiku_scsi * ptp = &vp->impl;
122 
123     if (ptp)
124         free(ptp);
125 }
126 
127 void
clear_scsi_pt_obj(struct sg_pt_base * vp)128 clear_scsi_pt_obj(struct sg_pt_base * vp)
129 {
130     struct sg_pt_haiku_scsi * ptp = &vp->impl;
131 
132     if (ptp) {
133 
134         int fd = ptp->dev_fd;
135         memset(ptp, 0, sizeof(struct sg_pt_haiku_scsi));
136         ptp->dev_fd = fd;
137         ptp->raw_command.flags = B_RAW_DEVICE_REPORT_RESIDUAL;
138     }
139 }
140 
141 void
set_scsi_pt_cdb(struct sg_pt_base * vp,const unsigned char * cdb,int cdb_len)142 set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb,
143                 int cdb_len)
144 {
145     struct sg_pt_haiku_scsi * ptp = &vp->impl;
146 
147     for (int i = 0; i < 16; ++i)
148         if (ptp->raw_command.command[i])
149             ++ptp->in_err;
150     memcpy(ptp->raw_command.command, cdb, cdb_len);
151     ptp->raw_command.command_length = (uint8_t)cdb_len;
152 }
153 
154 void
set_scsi_pt_sense(struct sg_pt_base * vp,unsigned char * sense,int max_sense_len)155 set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense,
156                   int max_sense_len)
157 {
158     struct sg_pt_haiku_scsi * ptp = &vp->impl;
159 
160     if (ptp->raw_command.sense_data)
161         ++ptp->in_err;
162     memset(sense, 0, max_sense_len);
163     ptp->raw_command.sense_data = sense;
164     ptp->raw_command.sense_data_length = max_sense_len;
165 }
166 
167 /* Setup for data transfer from device */
168 void
set_scsi_pt_data_in(struct sg_pt_base * vp,unsigned char * dxferp,int dxfer_len)169 set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp,
170                     int dxfer_len)
171 {
172     struct sg_pt_haiku_scsi * ptp = &vp->impl;
173 
174     if (ptp->raw_command.data)
175         ++ptp->in_err;
176     if (dxfer_len > 0) {
177         ptp->raw_command.data = dxferp;
178         ptp->raw_command.data_length = dxfer_len;
179         ptp->data_len = dxfer_len;
180         ptp->raw_command.flags |= B_RAW_DEVICE_DATA_IN;
181     }
182 }
183 
184 /* Setup for data transfer toward device */
185 void
set_scsi_pt_data_out(struct sg_pt_base * vp,const unsigned char * dxferp,int dxfer_len)186 set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp,
187                      int dxfer_len)
188 {
189     struct sg_pt_haiku_scsi * ptp = &vp->impl;
190 
191     if (ptp->raw_command.data)
192         ++ptp->in_err;
193     if (dxfer_len > 0) {
194         ptp->raw_command.data = (unsigned char *)dxferp;
195         ptp->raw_command.data_length = dxfer_len;
196         ptp->data_len = dxfer_len;
197         ptp->raw_command.flags &= ~B_RAW_DEVICE_DATA_IN;
198     }
199 }
200 
201 void
set_scsi_pt_packet_id(struct sg_pt_base * vp,int pack_id)202 set_scsi_pt_packet_id(struct sg_pt_base * vp __attribute__ ((unused)),
203                       int pack_id __attribute__ ((unused)))
204 {
205 }
206 
207 void
set_scsi_pt_tag(struct sg_pt_base * vp,uint64_t tag)208 set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag __attribute__ ((unused)))
209 {
210     struct sg_pt_haiku_scsi * ptp = &vp->impl;
211 
212     ++ptp->in_err;
213 }
214 
215 void
set_scsi_pt_task_management(struct sg_pt_base * vp,int tmf_code)216 set_scsi_pt_task_management(struct sg_pt_base * vp,
217                             int tmf_code __attribute__ ((unused)))
218 {
219     struct sg_pt_haiku_scsi * ptp = &vp->impl;
220 
221     ++ptp->in_err;
222 }
223 
224 void
set_scsi_pt_task_attr(struct sg_pt_base * vp,int attrib,int priority)225 set_scsi_pt_task_attr(struct sg_pt_base * vp,
226                       int attrib __attribute__ ((unused)),
227                       int priority __attribute__ ((unused)))
228 {
229     struct sg_pt_haiku_scsi * ptp = &vp->impl;
230 
231     ++ptp->in_err;
232 }
233 
234 void
set_scsi_pt_flags(struct sg_pt_base * vp,int flags)235 set_scsi_pt_flags(struct sg_pt_base * vp __attribute__ ((unused)),
236                   int flags __attribute__ ((unused)))
237 {
238 }
239 
240 /* Executes SCSI command (or at least forwards it to lower layers).
241  * Clears os_err field prior to active call (whose result may set it
242  * again). */
243 int
do_scsi_pt(struct sg_pt_base * vp,int fd,int timeout_secs,int verbose)244 do_scsi_pt(struct sg_pt_base * vp, int fd, int timeout_secs, int verbose)
245 {
246     struct sg_pt_haiku_scsi * ptp = &vp->impl;
247 
248     ptp->os_err = 0;
249     if (ptp->in_err) {
250         if (verbose)
251             pr2ws("Replicated or unused set_scsi_pt...\n");
252         return SCSI_PT_DO_BAD_PARAMS;
253     }
254     if (fd >= 0) {
255         if ((ptp->dev_fd >= 0) && (fd != ptp->dev_fd)) {
256             if (verbose)
257                 pr2ws("%s: file descriptor given to create() and here "
258                       "differ\n", __func__);
259             return SCSI_PT_DO_BAD_PARAMS;
260         }
261         ptp->dev_fd = fd;
262     } else if (ptp->dev_fd < 0) {
263         if (verbose)
264             pr2ws("%s: invalid file descriptors\n", __func__);
265         return SCSI_PT_DO_BAD_PARAMS;
266     } else
267         fd = ptp->dev_fd;
268 
269     if (NULL == ptp->raw_command.command) {
270         if (verbose)
271             pr2ws("No SCSI command (cdb) given\n");
272         return SCSI_PT_DO_BAD_PARAMS;
273     }
274     /* raw_command.timeout is in microseconds */
275     ptp->raw_command.timeout = ((timeout_secs > 0) ? (timeout_secs * 1000000) :
276                                                    CAM_TIME_DEFAULT);
277 
278     if (ioctl(fd, B_RAW_DEVICE_COMMAND, &ptp->raw_command) < 0) {
279         ptp->os_err = errno;
280         if (verbose > 1)
281             pr2ws("ioctl(B_RAW_DEVICE_COMMAND) failed: %s (errno=%d)\n",
282                   safe_strerror(ptp->os_err), ptp->os_err);
283         return -ptp->os_err;
284     }
285 
286     return SCSI_PT_DO_START_OK;
287 }
288 
289 int
get_scsi_pt_result_category(const struct sg_pt_base * vp)290 get_scsi_pt_result_category(const struct sg_pt_base * vp)
291 {
292     int cam_status_masked;
293     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
294 
295     if (ptp->os_err)
296         return SCSI_PT_RESULT_OS_ERR;
297     cam_status_masked = ptp->raw_command.cam_status & CAM_STATUS_MASK;
298     if (cam_status_masked != CAM_REQ_CMP &&
299         cam_status_masked != CAM_REQ_CMP_ERR)
300         return SCSI_PT_RESULT_TRANSPORT_ERR;
301     else if ((SAM_STAT_CHECK_CONDITION == ptp->raw_command.scsi_status) ||
302              (SAM_STAT_COMMAND_TERMINATED == ptp->raw_command.scsi_status))
303         return SCSI_PT_RESULT_SENSE;
304     else if (ptp->raw_command.scsi_status)
305         return SCSI_PT_RESULT_STATUS;
306     else
307         return SCSI_PT_RESULT_GOOD;
308 }
309 
310 int
get_scsi_pt_resid(const struct sg_pt_base * vp)311 get_scsi_pt_resid(const struct sg_pt_base * vp)
312 {
313     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
314 
315     /* For various reasons Haiku return data_len - data_resid */
316     return ptp->data_len - ptp->raw_command.data_length;
317 }
318 
319 int
get_scsi_pt_status_response(const struct sg_pt_base * vp)320 get_scsi_pt_status_response(const struct sg_pt_base * vp)
321 {
322     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
323 
324     return ptp->raw_command.scsi_status;
325 }
326 
327 uint8_t *
get_scsi_pt_sense_buf(const struct sg_pt_base * vp)328 get_scsi_pt_sense_buf(const struct sg_pt_base * vp)
329 {
330     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
331 
332     return (uint8_t *)ptp->raw_command.sense_data;
333 }
334 
335 int
get_scsi_pt_sense_len(const struct sg_pt_base * vp)336 get_scsi_pt_sense_len(const struct sg_pt_base * vp)
337 {
338     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
339 
340     return ptp->raw_command.sense_data_length;
341 }
342 
343 int
get_scsi_pt_os_err(const struct sg_pt_base * vp)344 get_scsi_pt_os_err(const struct sg_pt_base * vp)
345 {
346     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
347 
348     return ptp->os_err;
349 }
350 
351 char *
get_scsi_pt_os_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)352 get_scsi_pt_os_err_str(const struct sg_pt_base * vp __attribute__ ((unused)),
353                        int max_b_len, char * b)
354 {
355     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
356 
357     const char *cp;
358 
359     cp = safe_strerror(ptp->os_err);
360     strncpy(b, cp, max_b_len);
361     if ((int)strlen(cp) >= max_b_len)
362         b[max_b_len - 1] = '\0';
363     return b;
364 }
365 
366 int
get_scsi_pt_transport_err(const struct sg_pt_base * vp)367 get_scsi_pt_transport_err(const struct sg_pt_base * vp)
368 {
369     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
370 
371     if ((ptp->raw_command.cam_status & CAM_STATUS_MASK) != CAM_REQ_CMP ||
372         (ptp->raw_command.cam_status & CAM_STATUS_MASK) != CAM_REQ_CMP_ERR)
373         return ptp->raw_command.cam_status & CAM_STATUS_MASK;
374 
375     return 0;
376 }
377 
378 char *
get_scsi_pt_transport_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)379 get_scsi_pt_transport_err_str(
380                 const struct sg_pt_base * vp __attribute__ ((unused)),
381                               int max_b_len, char * b)
382 {
383     strncpy(b, "no transport error available", max_b_len);
384     b[max_b_len - 1] = '\0';
385     return b;
386 }
387 
388 int
get_scsi_pt_duration_ms(const struct sg_pt_base * vp)389 get_scsi_pt_duration_ms(const struct sg_pt_base * vp __attribute__ ((unused)))
390 {
391     return -1;
392 }
393 
394 void
partial_clear_scsi_pt_obj(struct sg_pt_base * vp)395 partial_clear_scsi_pt_obj(struct sg_pt_base * vp)
396 {
397     struct sg_pt_haiku_scsi * ptp = &vp->impl;
398 
399     if (NULL == ptp)
400         return;
401     ptp->in_err = 0;
402     ptp->os_err = 0;
403     ptp->data_len = 0;
404     ptp->raw_command.cam_status = 0;
405     ptp->raw_command.data_length = 0;
406 }
407 
pt_device_is_nvme(const struct sg_pt_base * vp)408 bool pt_device_is_nvme(const struct sg_pt_base * vp __attribute__ ((unused)))
409 {
410     return 0;
411 }
412 
413 int
check_pt_file_handle(int device_fd,const char * device_name,int vb)414 check_pt_file_handle(int device_fd, const char * device_name, int vb)
415 {
416     if (device_fd) {}
417     if (device_name) {}
418     if (vb) {}
419     return 1;   /* guess it is a SCSI generic pass-though device */
420 }
421 
422 int
do_nvm_pt(struct sg_pt_base * vp,int submq,int timeout_secs,int verbose)423 do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int verbose)
424 {
425     if (vp) { }
426     if (submq) { }
427     if (timeout_secs) { }
428     if (verbose) { }
429     return SCSI_PT_DO_NOT_SUPPORTED;
430 }
431 
432 void
get_pt_actual_lengths(const struct sg_pt_base * vp,int * act_dinp,int * act_doutp)433 get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp,
434                       int * act_doutp)
435 {
436     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
437 
438     if (ptp->data_len == 0) {
439         if (act_dinp)
440             *act_dinp = 0;
441         if (act_doutp)
442             *act_doutp = 0;
443     } else if (act_dinp && (ptp->raw_command.flags & B_RAW_DEVICE_DATA_IN)) {
444         /* "For various reasons Haiku return data_len - data_resid" */
445         *act_dinp = ptp->raw_command.data_length;
446         if (act_doutp)
447             *act_doutp = 0;
448     } else if (act_doutp &&
449                !(ptp->raw_command.flags & B_RAW_DEVICE_DATA_IN)) {
450         *act_doutp = ptp->raw_command.data_length;
451         if (act_dinp)
452             *act_dinp = 0;
453     } else {
454         if (act_dinp)
455             *act_dinp = 0;
456         if (act_doutp)
457             *act_doutp = 0;
458     }
459 }
460 
461 /* If not available return 0 otherwise return number of nanoseconds that the
462  * lower layers (and hardware) took to execute the command just completed. */
463 uint64_t
get_pt_duration_ns(const struct sg_pt_base * vp)464 get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused)))
465 {
466     return 0;
467 }
468 
469 /* Valid file handles (which is the return value) are >= 0 . Returns -1
470  * if there is no valid file handle. */
471 int
get_pt_file_handle(const struct sg_pt_base * vp)472 get_pt_file_handle(const struct sg_pt_base * vp)
473 {
474     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
475 
476     return ptp->dev_fd;
477 }
478 
479 
480 /* If a NVMe block device (which includes the NSID) handle is associated
481  * with 'vp', then its NSID is returned (values range from 0x1 to
482  * 0xffffffe). Otherwise 0 is returned. */
483 uint32_t
get_pt_nvme_nsid(const struct sg_pt_base * vp)484 get_pt_nvme_nsid(const struct sg_pt_base * vp)
485 {
486     if (vp) { }
487     return 0;
488 }
489 
490 void
get_pt_req_lengths(const struct sg_pt_base * vp,int * req_dinp,int * req_doutp)491 get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp,
492                    int * req_doutp)
493 {
494     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
495 
496     if (ptp->data_len == 0) {
497         if (req_dinp)
498             *req_dinp = 0;
499         if (req_doutp)
500             *req_doutp = 0;
501     } else if (req_dinp && (ptp->raw_command.flags & B_RAW_DEVICE_DATA_IN)) {
502         /* "For various reasons Haiku return data_len - data_resid" */
503         *req_dinp = ptp->data_len;
504         if (req_doutp)
505             *req_doutp = 0;
506     } else if (req_doutp &&
507                !(ptp->raw_command.flags & B_RAW_DEVICE_DATA_IN)) {
508         *req_doutp = ptp->data_len;
509         if (req_dinp)
510             *req_dinp = 0;
511     } else {
512         if (req_dinp)
513             *req_dinp = 0;
514         if (req_doutp)
515             *req_doutp = 0;
516     }
517 }
518 
519 uint32_t
get_pt_result(const struct sg_pt_base * vp)520 get_pt_result(const struct sg_pt_base * vp)
521 {
522     return (uint32_t)get_scsi_pt_status_response(vp);
523 }
524 
525 uint8_t *
get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)526 get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)
527 {
528     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
529 
530     return (uint8_t *)ptp->raw_command.command;
531 }
532 
533 int
get_scsi_pt_cdb_len(const struct sg_pt_base * vp)534 get_scsi_pt_cdb_len(const struct sg_pt_base * vp)
535 {
536     const struct sg_pt_haiku_scsi * ptp = &vp->impl;
537 
538     return (int)ptp->raw_command.command_length;
539 }
540 
541 /* Forget any previous dev_han and install the one given. May attempt to
542  * find file type (e.g. if pass-though) from OS so there could be an error.
543  * Returns 0 for success or the same value as get_scsi_pt_os_err()
544  * will return. dev_han should be >= 0 for a valid file handle or -1 . */
545 int
set_pt_file_handle(struct sg_pt_base * vp,int dev_han,int vb)546 set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb)
547 {
548     struct sg_pt_haiku_scsi * ptp = &vp->impl;
549 
550     if (vb) {}
551     ptp->dev_fd = (dev_han < 0) ? -1 : dev_han;
552     ptp->in_err = 0;
553     ptp->os_err = 0;
554     return 0;
555 }
556 
557 void
set_scsi_pt_transport_err(struct sg_pt_base * vp,int err)558 set_scsi_pt_transport_err(struct sg_pt_base * vp, int err)
559 {
560     if (vp) { }
561     if (err) { }
562 }
563 
564 void
set_pt_metadata_xfer(struct sg_pt_base * vp,uint8_t * mdxferp,uint32_t mdxfer_len,bool out_true)565 set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp,
566                      uint32_t mdxfer_len, bool out_true)
567 {
568     if (vp) { }
569     if (mdxferp) { }
570     if (mdxfer_len) { }
571     if (out_true) { }
572 }
573