443 lines
8.3 KiB
C
443 lines
8.3 KiB
C
/*
|
|
* Copyright (c) 2021 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
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "sg_pt.h"
|
|
#include "sg_lib.h"
|
|
#include "sg_pr2serr.h"
|
|
|
|
/* Version 1.02 20210618 */
|
|
|
|
/* List of function names with external linkage that need to be defined
|
|
*
|
|
* check_pt_file_handle
|
|
* clear_scsi_pt_obj
|
|
* construct_scsi_pt_obj
|
|
* construct_scsi_pt_obj_with_fd
|
|
* destruct_scsi_pt_obj
|
|
* do_scsi_pt
|
|
* do_nvm_pt
|
|
* get_pt_actual_lengths
|
|
* get_pt_duration_ns
|
|
* get_pt_file_handle
|
|
* get_pt_nvme_nsid
|
|
* get_pt_req_lengths
|
|
* get_pt_result
|
|
* get_scsi_pt_cdb_buf
|
|
* get_scsi_pt_cdb_len
|
|
* get_scsi_pt_duration_ms
|
|
* get_scsi_pt_os_err
|
|
* get_scsi_pt_os_err_str
|
|
* get_scsi_pt_resid
|
|
* get_scsi_pt_result_category
|
|
* get_scsi_pt_sense_buf
|
|
* get_scsi_pt_sense_len
|
|
* get_scsi_pt_status_response
|
|
* get_scsi_pt_transport_err
|
|
* get_scsi_pt_transport_err_str
|
|
* partial_clear_scsi_pt_obj
|
|
* pt_device_is_nvme
|
|
* scsi_pt_close_device
|
|
* scsi_pt_open_device
|
|
* scsi_pt_open_flags
|
|
* set_pt_file_handle
|
|
* set_pt_metadata_xfer
|
|
* set_scsi_pt_cdb
|
|
* set_scsi_pt_data_in
|
|
* set_scsi_pt_data_out
|
|
* set_scsi_pt_flags
|
|
* set_scsi_pt_packet_id
|
|
* set_scsi_pt_sense
|
|
* set_scsi_pt_tag
|
|
* set_scsi_pt_task_attr
|
|
* set_scsi_pt_task_management
|
|
* set_scsi_pt_transport_err
|
|
*/
|
|
|
|
/* Simply defines all the functions needed by the pt interface (see sg_pt.h).
|
|
* They do nothing. This allows decoding of hex files (e.g. with the --in=
|
|
* or --inhex= option) with utilities like sg_vpd and sg_logs. */
|
|
|
|
struct sg_pt_dummy {
|
|
int dummy;
|
|
};
|
|
|
|
struct sg_pt_base {
|
|
struct sg_pt_dummy impl;
|
|
};
|
|
|
|
|
|
/* Returns >= 0 if successful. If error in Unix returns negated errno. */
|
|
int
|
|
scsi_pt_open_device(const char * device_name, bool read_only, int verbose)
|
|
{
|
|
int oflags = 0 /* O_NONBLOCK*/ ;
|
|
|
|
oflags |= (read_only ? O_RDONLY : O_RDWR);
|
|
return scsi_pt_open_flags(device_name, oflags, verbose);
|
|
}
|
|
|
|
/* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed
|
|
* together. The 'flags' argument is ignored in OSF-1.
|
|
* Returns >= 0 if successful, otherwise returns negated errno. */
|
|
int
|
|
scsi_pt_open_flags(const char * device_name, int flags, int verbose)
|
|
{
|
|
if (device_name) {}
|
|
if (flags) {}
|
|
if (verbose) {}
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
/* Returns 0 if successful. If error in Unix returns negated errno. */
|
|
int
|
|
scsi_pt_close_device(int device_fd)
|
|
{
|
|
if (device_fd) {}
|
|
return 0;
|
|
}
|
|
|
|
struct sg_pt_base *
|
|
construct_scsi_pt_obj_with_fd(int device_fd, int verbose)
|
|
{
|
|
struct sg_pt_dummy * ptp;
|
|
|
|
if (device_fd) {}
|
|
ptp = (struct sg_pt_dummy *)malloc(sizeof(struct sg_pt_dummy));
|
|
if (ptp) {
|
|
memset(ptp, 0, sizeof(struct sg_pt_dummy));
|
|
} else if (verbose)
|
|
pr2ws("%s: malloc() out of memory\n", __func__);
|
|
return (struct sg_pt_base *)ptp;
|
|
}
|
|
|
|
struct sg_pt_base *
|
|
construct_scsi_pt_obj(void)
|
|
{
|
|
return construct_scsi_pt_obj_with_fd(-1, 0);
|
|
}
|
|
|
|
void
|
|
destruct_scsi_pt_obj(struct sg_pt_base * vp)
|
|
{
|
|
struct sg_pt_dummy * ptp = &vp->impl;
|
|
|
|
if (ptp)
|
|
free(ptp);
|
|
}
|
|
|
|
void
|
|
clear_scsi_pt_obj(struct sg_pt_base * vp)
|
|
{
|
|
struct sg_pt_dummy * ptp = &vp->impl;
|
|
|
|
if (ptp) {
|
|
ptp->dummy = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
partial_clear_scsi_pt_obj(struct sg_pt_base * vp)
|
|
{
|
|
struct sg_pt_dummy * ptp = &vp->impl;
|
|
|
|
if (NULL == ptp)
|
|
return;
|
|
ptp->dummy = 0;
|
|
}
|
|
|
|
void
|
|
set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb,
|
|
int cdb_len)
|
|
{
|
|
if (vp) {}
|
|
if (cdb) {}
|
|
if (cdb_len) {}
|
|
}
|
|
|
|
int
|
|
get_scsi_pt_cdb_len(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return 6;
|
|
}
|
|
|
|
uint8_t *
|
|
get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense,
|
|
int max_sense_len)
|
|
{
|
|
if (vp) {}
|
|
if (sense) {}
|
|
if (max_sense_len) {}
|
|
}
|
|
|
|
/* from device */
|
|
void
|
|
set_scsi_pt_data_in(struct sg_pt_base * vp, uint8_t * dxferp,
|
|
int dxfer_len)
|
|
{
|
|
if (vp) {}
|
|
if (dxferp) {}
|
|
if (dxfer_len) {}
|
|
}
|
|
|
|
/* to device */
|
|
void
|
|
set_scsi_pt_data_out(struct sg_pt_base * vp, const uint8_t * dxferp,
|
|
int dxfer_len)
|
|
{
|
|
if (vp) {}
|
|
if (dxferp) {}
|
|
if (dxfer_len) {}
|
|
}
|
|
|
|
void
|
|
set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id)
|
|
{
|
|
if (vp) {}
|
|
if (pack_id) {}
|
|
}
|
|
|
|
void
|
|
set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag)
|
|
{
|
|
if (vp) {}
|
|
if (tag) {}
|
|
}
|
|
|
|
void
|
|
set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code)
|
|
{
|
|
if (vp) {}
|
|
if (tmf_code) {}
|
|
}
|
|
|
|
void
|
|
set_scsi_pt_task_attr(struct sg_pt_base * vp, int attrib, int priority)
|
|
{
|
|
if (vp) {}
|
|
if (attrib) {}
|
|
if (priority) {}
|
|
}
|
|
|
|
void
|
|
set_scsi_pt_flags(struct sg_pt_base * vp, int flags)
|
|
{
|
|
if (vp) {}
|
|
if (flags) {}
|
|
}
|
|
|
|
int
|
|
do_scsi_pt(struct sg_pt_base * vp, int device_fd, int time_secs, int verbose)
|
|
{
|
|
if (vp) {}
|
|
if (device_fd) {}
|
|
if (time_secs) {}
|
|
if (verbose) {}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
get_scsi_pt_result_category(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
get_scsi_pt_resid(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp,
|
|
int * req_doutp)
|
|
{
|
|
if (vp) {}
|
|
if (req_dinp) {}
|
|
if (req_doutp) {}
|
|
}
|
|
|
|
void
|
|
get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp,
|
|
int * act_doutp)
|
|
{
|
|
if (vp) {}
|
|
if (act_dinp) {}
|
|
if (act_doutp) {}
|
|
}
|
|
|
|
|
|
int
|
|
get_scsi_pt_status_response(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
get_scsi_pt_sense_len(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return 0;
|
|
}
|
|
|
|
uint8_t *
|
|
get_scsi_pt_sense_buf(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
get_scsi_pt_duration_ms(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return 0;
|
|
}
|
|
|
|
/* If not available return 0 otherwise return number of nanoseconds that the
|
|
* lower layers (and hardware) took to execute the command just completed. */
|
|
uint64_t
|
|
get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused)))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
get_scsi_pt_transport_err(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
get_scsi_pt_os_err(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
pt_device_is_nvme(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) {}
|
|
return false;
|
|
}
|
|
|
|
char *
|
|
get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len,
|
|
char * b)
|
|
{
|
|
if (vp) {}
|
|
if (max_b_len) {}
|
|
if (b) {}
|
|
return NULL;
|
|
}
|
|
|
|
char *
|
|
get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
|
|
{
|
|
if (vp) {}
|
|
if (max_b_len) {}
|
|
if (b) {}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int verbose)
|
|
{
|
|
if (vp) { }
|
|
if (submq) { }
|
|
if (timeout_secs) { }
|
|
if (verbose) { }
|
|
return SCSI_PT_DO_NOT_SUPPORTED;
|
|
}
|
|
|
|
int
|
|
check_pt_file_handle(int device_fd, const char * device_name, int vb)
|
|
{
|
|
if (device_fd) {}
|
|
if (device_name) {}
|
|
if (vb) {}
|
|
return 0;
|
|
}
|
|
|
|
/* Valid file handles (which is the return value) are >= 0 . Returns -1
|
|
* if there is no valid file handle. */
|
|
int
|
|
get_pt_file_handle(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) { }
|
|
return -1;
|
|
}
|
|
|
|
/* If a NVMe block device (which includes the NSID) handle is associated
|
|
* with 'vp', then its NSID is returned (values range from 0x1 to
|
|
* 0xffffffe). Otherwise 0 is returned. */
|
|
uint32_t
|
|
get_pt_nvme_nsid(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) { }
|
|
return 0;
|
|
}
|
|
|
|
uint32_t
|
|
get_pt_result(const struct sg_pt_base * vp)
|
|
{
|
|
if (vp) { }
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb)
|
|
{
|
|
if (vp) { }
|
|
if (dev_han) { }
|
|
if (vb) { }
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp,
|
|
uint32_t mdxfer_len, bool out_true)
|
|
{
|
|
if (vp) { }
|
|
if (mdxferp) { }
|
|
if (mdxfer_len) { }
|
|
if (out_true) { }
|
|
}
|
|
|
|
void
|
|
set_scsi_pt_transport_err(struct sg_pt_base * vp, int err)
|
|
{
|
|
if (vp) { }
|
|
if (err) { }
|
|
}
|