| #include <unistd.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "sg_lib.h" |
| #include "sg_pt.h" |
| |
| /* This is a simple program executing a SCSI INQUIRY command and a |
| TEST UNIT READY command using the SCSI generic pass through |
| interface. This allows this example program to be ported to |
| OSes other than linux. |
| |
| * Copyright (C) 2006-20018 D. Gilbert |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2, or (at your option) |
| * any later version. |
| |
| Invocation: sg_simple5 [-x] <scsi_device> |
| |
| Version 1.03 (20180220) |
| |
| */ |
| |
| #define INQ_REPLY_LEN 96 |
| #define INQ_CMD_LEN 6 |
| #define TUR_CMD_LEN 6 |
| |
| #define CMD_TIMEOUT_SECS 60 |
| |
| |
| int main(int argc, char * argv[]) |
| { |
| int sg_fd, k, ok, dsize, res, duration, resid, cat, got, slen; |
| uint8_t inq_cdb [INQ_CMD_LEN] = |
| {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; |
| uint8_t tur_cdb [TUR_CMD_LEN] = |
| {0x00, 0, 0, 0, 0, 0}; |
| uint8_t inqBuff[INQ_REPLY_LEN]; |
| char * file_name = 0; |
| char b[512]; |
| uint8_t sense_b[32]; |
| int verbose = 0; |
| struct sg_pt_base * ptvp; |
| |
| for (k = 1; k < argc; ++k) { |
| if (0 == strcmp("-v", argv[k])) |
| verbose = 1; |
| else if (0 == strcmp("-vv", argv[k])) |
| verbose = 2; |
| else if (0 == strcmp("-vvv", argv[k])) |
| verbose = 3; |
| else if (*argv[k] == '-') { |
| printf("Unrecognized switch: %s\n", argv[k]); |
| file_name = 0; |
| break; |
| } |
| else if (0 == file_name) |
| file_name = argv[k]; |
| else { |
| printf("too many arguments\n"); |
| file_name = 0; |
| break; |
| } |
| } |
| if (0 == file_name) { |
| printf("Usage: 'sg_simple5 [-v|-vv|-vvv] <device>'\n"); |
| return 1; |
| } |
| |
| sg_fd = scsi_pt_open_device(file_name, 1 /* ro */, 0); |
| /* N.B. An access mode of O_RDWR is required for some SCSI commands */ |
| if (sg_fd < 0) { |
| fprintf(stderr, "error opening file: %s: %s\n", |
| file_name, safe_strerror(-sg_fd)); |
| return 1; |
| } |
| |
| dsize = sizeof(inqBuff); |
| ok = 0; |
| |
| ptvp = construct_scsi_pt_obj(); /* one object per command */ |
| if (NULL == ptvp) { |
| fprintf(stderr, "sg_simple5: out of memory\n"); |
| return -1; |
| } |
| set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_cdb)); |
| set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); |
| set_scsi_pt_data_in(ptvp, inqBuff, dsize); |
| res = do_scsi_pt(ptvp, sg_fd, CMD_TIMEOUT_SECS, verbose); |
| if (res < 0) { |
| fprintf(stderr, " pass through os error: %s\n", |
| safe_strerror(-res)); |
| goto finish_inq; |
| } else if (SCSI_PT_DO_BAD_PARAMS == res) { |
| fprintf(stderr, " bad pass through setup\n"); |
| goto finish_inq; |
| } else if (SCSI_PT_DO_TIMEOUT == res) { |
| fprintf(stderr, " pass through timeout\n"); |
| goto finish_inq; |
| } |
| if ((verbose > 1) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0)) |
| fprintf(stderr, " duration=%d ms\n", duration); |
| resid = get_scsi_pt_resid(ptvp); |
| switch ((cat = get_scsi_pt_result_category(ptvp))) { |
| case SCSI_PT_RESULT_GOOD: |
| got = dsize - resid; |
| if (verbose && (resid > 0)) |
| fprintf(stderr, " requested %d bytes but " |
| "got %d bytes)\n", dsize, got); |
| break; |
| case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */ |
| if (verbose) { |
| sg_get_scsi_status_str(get_scsi_pt_status_response(ptvp), |
| sizeof(b), b); |
| fprintf(stderr, " scsi status: %s\n", b); |
| } |
| goto finish_inq; |
| case SCSI_PT_RESULT_SENSE: |
| slen = get_scsi_pt_sense_len(ptvp); |
| if (verbose) { |
| sg_get_sense_str("", sense_b, slen, (verbose > 1), |
| sizeof(b), b); |
| fprintf(stderr, "%s", b); |
| } |
| if (verbose && (resid > 0)) { |
| got = dsize - resid; |
| if ((verbose) || (got > 0)) |
| fprintf(stderr, " requested %d bytes but " |
| "got %d bytes\n", dsize, got); |
| } |
| goto finish_inq; |
| case SCSI_PT_RESULT_TRANSPORT_ERR: |
| if (verbose) { |
| get_scsi_pt_transport_err_str(ptvp, sizeof(b), b); |
| fprintf(stderr, " transport: %s", b); |
| } |
| goto finish_inq; |
| case SCSI_PT_RESULT_OS_ERR: |
| if (verbose) { |
| get_scsi_pt_os_err_str(ptvp, sizeof(b), b); |
| fprintf(stderr, " os: %s", b); |
| } |
| goto finish_inq; |
| default: |
| fprintf(stderr, " unknown pass through result " |
| "category (%d)\n", cat); |
| goto finish_inq; |
| } |
| |
| ok = 1; |
| finish_inq: |
| destruct_scsi_pt_obj(ptvp); |
| |
| if (ok) { /* output result if it is available */ |
| char * p = (char *)inqBuff; |
| |
| printf("Some of the INQUIRY command's results:\n"); |
| printf(" %.8s %.16s %.4s\n", p + 8, p + 16, p + 32); |
| } |
| ok = 0; |
| |
| |
| /* Now prepare TEST UNIT READY command */ |
| ptvp = construct_scsi_pt_obj(); /* one object per command */ |
| if (NULL == ptvp) { |
| fprintf(stderr, "sg_simple5: out of memory\n"); |
| return -1; |
| } |
| set_scsi_pt_cdb(ptvp, tur_cdb, sizeof(tur_cdb)); |
| set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); |
| /* no data in or out */ |
| res = do_scsi_pt(ptvp, sg_fd, CMD_TIMEOUT_SECS, verbose); |
| if (res < 0) { |
| fprintf(stderr, " pass through os error: %s\n", |
| safe_strerror(-res)); |
| goto finish_inq; |
| } else if (SCSI_PT_DO_BAD_PARAMS == res) { |
| fprintf(stderr, " bad pass through setup\n"); |
| goto finish_inq; |
| } else if (SCSI_PT_DO_TIMEOUT == res) { |
| fprintf(stderr, " pass through timeout\n"); |
| goto finish_inq; |
| } |
| if ((verbose > 1) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0)) |
| fprintf(stderr, " duration=%d ms\n", duration); |
| resid = get_scsi_pt_resid(ptvp); |
| switch ((cat = get_scsi_pt_result_category(ptvp))) { |
| case SCSI_PT_RESULT_GOOD: |
| break; |
| case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */ |
| if (verbose) { |
| sg_get_scsi_status_str(get_scsi_pt_status_response(ptvp), |
| sizeof(b), b); |
| fprintf(stderr, " scsi status: %s\n", b); |
| } |
| goto finish_tur; |
| case SCSI_PT_RESULT_SENSE: |
| slen = get_scsi_pt_sense_len(ptvp); |
| if (verbose) { |
| sg_get_sense_str("", sense_b, slen, (verbose > 1), |
| sizeof(b), b); |
| fprintf(stderr, "%s", b); |
| } |
| goto finish_tur; |
| case SCSI_PT_RESULT_TRANSPORT_ERR: |
| if (verbose) { |
| get_scsi_pt_transport_err_str(ptvp, sizeof(b), b); |
| fprintf(stderr, " transport: %s", b); |
| } |
| goto finish_tur; |
| case SCSI_PT_RESULT_OS_ERR: |
| if (verbose) { |
| get_scsi_pt_os_err_str(ptvp, sizeof(b), b); |
| fprintf(stderr, " os: %s", b); |
| } |
| goto finish_tur; |
| default: |
| fprintf(stderr, " unknown pass through result " |
| "category (%d)\n", cat); |
| goto finish_tur; |
| } |
| |
| ok = 1; |
| finish_tur: |
| destruct_scsi_pt_obj(ptvp); |
| |
| if (ok) |
| printf("Test Unit Ready successful so unit is ready!\n"); |
| else |
| printf("Test Unit Ready failed so unit may _not_ be ready!\n"); |
| |
| scsi_pt_close_device(sg_fd); |
| return 0; |
| } |