aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2009-03-08 22:51:37 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2009-03-08 22:51:37 +0000
commit95a3b3405ec97a9bae89c22a291e0a35f5ce9ce7 (patch)
treee9dc57b87e3e92db0fd71743c221e6a5a37289e7
parente87790cce3aeaa2db441b0fc0f52d55f0cd69597 (diff)
downloadsg3_utils-95a3b3405ec97a9bae89c22a291e0a35f5ce9ce7.tar.gz
sgv4 bsg work
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@229 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--lib/sg_pt_common.c2
-rw-r--r--lib/sg_pt_linux.c155
2 files changed, 144 insertions, 13 deletions
diff --git a/lib/sg_pt_common.c b/lib/sg_pt_common.c
index 14e06b3a..842047d1 100644
--- a/lib/sg_pt_common.c
+++ b/lib/sg_pt_common.c
@@ -32,7 +32,7 @@
#include "sg_pt.h"
-static const char * scsi_pt_version_str = "2.03 20090204";
+static const char * scsi_pt_version_str = "2.04 20090308";
const char *
scsi_pt_version()
diff --git a/lib/sg_pt_linux.c b/lib/sg_pt_linux.c
index 5bfbdc15..0c88d679 100644
--- a/lib/sg_pt_linux.c
+++ b/lib/sg_pt_linux.c
@@ -27,7 +27,7 @@
*
*/
-/* sg_pt_linux version 1.11 20090307 */
+/* sg_pt_linux version 1.11 20090308 */
#include <stdio.h>
#include <stdlib.h>
@@ -509,10 +509,13 @@ find_bsg_major(int verbose)
} else
break;
}
- if ((NULL == cp) && (verbose > 3)) {
+ if (verbose > 3) {
if (NULL == sg_warnings_strm)
sg_warnings_strm = stderr;
- fprintf(sg_warnings_strm, "found no bsg char device in %s\n",
+ if (cp)
+ fprintf(sg_warnings_strm, "found bsg_major=%d\n", bsg_major);
+ else
+ fprintf(sg_warnings_strm, "found no bsg char device in %s\n",
proc_devices);
}
fclose(fp);
@@ -541,7 +544,6 @@ scsi_pt_open_flags(const char * device_name, int flags, int verbose)
bsg_major_checked = 1;
find_bsg_major(verbose);
}
-
if (verbose > 1) {
if (NULL == sg_warnings_strm)
sg_warnings_strm = stderr;
@@ -589,6 +591,17 @@ destruct_scsi_pt_obj(struct sg_pt_base * vp)
}
void
+clear_scsi_pt_obj(struct sg_pt_base * vp)
+{
+ struct sg_pt_linux_scsi * ptp = &vp->impl;
+
+ if (ptp) {
+ memset(ptp, 0, sizeof(struct sg_pt_linux_scsi));
+ ptp->io_hdr.guard = 'Q';
+ }
+}
+
+void
set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb,
int cdb_len)
{
@@ -722,14 +735,6 @@ get_scsi_pt_transport_err(const struct sg_pt_base * vp)
return ptp->io_hdr.transport_status;
}
-int
-get_scsi_pt_os_err(const struct sg_pt_base * vp)
-{
- const struct sg_pt_linux_scsi * ptp = &vp->impl;
-
- return ptp->os_err;
-}
-
/* Combine driver and transport (called "host" in linux kernel) statuses */
char *
get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len,
@@ -796,6 +801,14 @@ get_scsi_pt_result_category(const struct sg_pt_base * vp)
return SCSI_PT_RESULT_GOOD;
}
+int
+get_scsi_pt_os_err(const struct sg_pt_base * vp)
+{
+ const struct sg_pt_linux_scsi * ptp = &vp->impl;
+
+ return ptp->os_err;
+}
+
char *
get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
{
@@ -809,5 +822,123 @@ get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
return b;
}
+/* Executes SCSI command using sg v3 interface */
+static int
+do_scsi_pt_v3(struct sg_pt_linux_scsi * ptp, int fd, int time_secs,
+ int verbose)
+{
+ struct sg_io_hdr v3_hdr;
+
+ memset(&v3_hdr, 0, sizeof(v3_hdr));
+ /* convert v4 to v3 header */
+ v3_hdr.interface_id = 'S';
+ v3_hdr.dxfer_direction = SG_DXFER_NONE;
+ v3_hdr.cmdp = (void *)(long)ptp->io_hdr.request;
+ v3_hdr.cmd_len = (unsigned char)ptp->io_hdr.request_len;
+ if (ptp->io_hdr.din_xfer_len > 0) {
+ if (ptp->io_hdr.dout_xfer_len > 0) {
+ if (verbose)
+ fprintf(sg_warnings_strm, "sgv3 doesn't support bidi\n");
+ return SCSI_PT_DO_BAD_PARAMS;
+ }
+ v3_hdr.dxferp = (void *)(long)ptp->io_hdr.din_xferp;
+ v3_hdr.dxfer_len = (unsigned int)ptp->io_hdr.din_xfer_len;
+ v3_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ } else if (ptp->io_hdr.dout_xfer_len > 0) {
+ v3_hdr.dxferp = (void *)(long)ptp->io_hdr.dout_xferp;
+ v3_hdr.dxfer_len = (unsigned int)ptp->io_hdr.dout_xfer_len;
+ v3_hdr.dxfer_direction = SG_DXFER_TO_DEV;
+ }
+ if (ptp->io_hdr.response && (ptp->io_hdr.response_len > 0)) {
+ v3_hdr.sbp = (void *)(long)ptp->io_hdr.response;
+ v3_hdr.mx_sb_len = (unsigned char)ptp->io_hdr.request_len;
+ }
+ v3_hdr.pack_id = (int)ptp->io_hdr.spare_in;
+
+ if (NULL == v3_hdr.cmdp) {
+ if (verbose)
+ fprintf(sg_warnings_strm, "No SCSI command (cdb) given\n");
+ return SCSI_PT_DO_BAD_PARAMS;
+ }
+ /* io_hdr.timeout is in milliseconds */
+ v3_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT);
+ if (v3_hdr.sbp && (v3_hdr.sb_len_wr > 0))
+ memset(v3_hdr.sbp, 0, v3_hdr.sb_len_wr);
+ if (ioctl(fd, SG_IO, &v3_hdr) < 0) {
+ ptp->os_err = errno;
+ if (verbose)
+ fprintf(sg_warnings_strm, "ioctl(SG_IO v3) failed with os_err "
+ "(errno) = %d\n", ptp->os_err);
+ return -ptp->os_err;
+ }
+ ptp->io_hdr.device_status = (__u32)v3_hdr.status;
+ ptp->io_hdr.driver_status = (__u32)v3_hdr.driver_status;
+ ptp->io_hdr.transport_status = (__u32)v3_hdr.host_status;
+ ptp->io_hdr.duration = (__u32)v3_hdr.duration;
+ ptp->io_hdr.din_resid = (__s32)v3_hdr.resid;
+ return 0;
+}
+
+/* Executes SCSI command (or at least forwards it to lower layers).
+ * Clears os_err field prior to active call (whose result may set it
+ * again). */
+int
+do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose)
+{
+ struct sg_pt_linux_scsi * ptp = &vp->impl;
+ void * p;
+
+ if (! bsg_major_checked) {
+ bsg_major_checked = 1;
+ find_bsg_major(verbose);
+ }
+ if (NULL == sg_warnings_strm)
+ sg_warnings_strm = stderr;
+ ptp->os_err = 0;
+ if (ptp->in_err) {
+ if (verbose)
+ fprintf(sg_warnings_strm, "Replicated or unused set_scsi_pt... "
+ "functions\n");
+ return SCSI_PT_DO_BAD_PARAMS;
+ }
+ if (bsg_major <= 0)
+ return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
+ else {
+ struct stat a_stat;
+
+ if (fstat(fd, &a_stat) < 0) {
+ ptp->os_err = errno;
+ if (verbose)
+ fprintf(sg_warnings_strm, "fstat() failed with os_err "
+ "(errno) = %d\n", ptp->os_err);
+ return -ptp->os_err;
+ }
+ if (! S_ISCHR(a_stat.st_mode) ||
+ (bsg_major != (int)major(a_stat.st_rdev)))
+ return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
+ }
+
+ if (! ptp->io_hdr.request) {
+ if (verbose)
+ fprintf(sg_warnings_strm, "No SCSI command (cdb) given (v4)\n");
+ return SCSI_PT_DO_BAD_PARAMS;
+ }
+ /* io_hdr.timeout is in milliseconds */
+ ptp->io_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) :
+ DEF_TIMEOUT);
+ if (ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 0)) {
+ p = (void *)(long)ptp->io_hdr.response;
+ memset(p, 0, ptp->io_hdr.max_response_len);
+ }
+ if (ioctl(fd, SG_IO, &ptp->io_hdr) < 0) {
+ ptp->os_err = errno;
+ if (verbose)
+ fprintf(sg_warnings_strm, "ioctl(SG_IO v4) failed with os_err "
+ "(errno) = %d\n", ptp->os_err);
+ return -ptp->os_err;
+ }
+ return 0;
+}
+
#endif
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<