version 1.1.1.1, 2012/02/21 16:32:16
|
version 1.1.1.2, 2013/07/22 01:17:35
|
Line 7
|
Line 7
|
* Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> |
* Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> |
* |
* |
* Additional SCSI work: |
* Additional SCSI work: |
* Copyright (C) 2003-10 Douglas Gilbert <dgilbert@interlog.com> | * Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com> |
* |
* |
* This program is free software; you can redistribute it and/or modify |
* 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 |
* it under the terms of the GNU General Public License as published by |
Line 15
|
Line 15
|
* any later version. |
* any later version. |
* |
* |
* You should have received a copy of the GNU General Public License |
* You should have received a copy of the GNU General Public License |
* (for example COPYING); if not, write to the Free | * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. |
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
* |
* |
* This code was originally developed as a Senior Thesis by Michael Cornwell |
* This code was originally developed as a Senior Thesis by Michael Cornwell |
* at the Concurrent Systems Laboratory (now part of the Storage Systems |
* at the Concurrent Systems Laboratory (now part of the Storage Systems |
Line 55 const char *scsicmds_c_cvsid="$Id$"
|
Line 54 const char *scsicmds_c_cvsid="$Id$"
|
// Print SCSI debug messages? |
// Print SCSI debug messages? |
unsigned char scsi_debugmode = 0; |
unsigned char scsi_debugmode = 0; |
|
|
|
supported_vpd_pages * supported_vpd_pages_p = NULL; |
|
|
|
|
|
supported_vpd_pages::supported_vpd_pages(scsi_device * device) : num_valid(0) |
|
{ |
|
unsigned char b[0x1fc]; /* size chosen for old INQUIRY command */ |
|
int n; |
|
|
|
memset(b, 0, sizeof(b)); |
|
if (device && (0 == scsiInquiryVpd(device, SCSI_VPD_SUPPORTED_VPD_PAGES, |
|
b, sizeof(b)))) { |
|
num_valid = (b[2] << 8) + b[3]; |
|
n = sizeof(pages); |
|
if (num_valid > n) |
|
num_valid = n; |
|
memcpy(pages, b + 4, num_valid); |
|
} |
|
} |
|
|
|
bool |
|
supported_vpd_pages::is_supported(int vpd_page_num) const |
|
{ |
|
/* Supported VPD pages numbers start at offset 4 and should be in |
|
* ascending order but don't assume that. */ |
|
for (int k = 0; k < num_valid; ++k) { |
|
if (vpd_page_num == pages[k]) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
/* output binary in hex and optionally ascii */ |
/* output binary in hex and optionally ascii */ |
void dStrHex(const char* str, int len, int no_ascii) | void |
| dStrHex(const char* str, int len, int no_ascii) |
{ |
{ |
const char* p = str; |
const char* p = str; |
unsigned char c; |
unsigned char c; |
Line 67 void dStrHex(const char* str, int len, int no_ascii)
|
Line 98 void dStrHex(const char* str, int len, int no_ascii)
|
int cpos = cpstart; |
int cpos = cpstart; |
int bpos = bpstart; |
int bpos = bpstart; |
int i, k; |
int i, k; |
| |
if (len <= 0) return; |
if (len <= 0) return; |
memset(buff,' ',80); |
memset(buff,' ',80); |
buff[80]='\0'; |
buff[80]='\0'; |
k = sprintf(buff + 1, "%.2x", a); | k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a); |
buff[k + 1] = ' '; |
buff[k + 1] = ' '; |
if (bpos >= ((bpstart + (9 * 3)))) |
if (bpos >= ((bpstart + (9 * 3)))) |
bpos++; |
bpos++; |
Line 82 void dStrHex(const char* str, int len, int no_ascii)
|
Line 113 void dStrHex(const char* str, int len, int no_ascii)
|
bpos += 3; |
bpos += 3; |
if (bpos == (bpstart + (9 * 3))) |
if (bpos == (bpstart + (9 * 3))) |
bpos++; |
bpos++; |
sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c); | snprintf(buff+bpos, sizeof(buff)-bpos, "%.2x", (int)(unsigned char)c); |
buff[bpos + 2] = ' '; |
buff[bpos + 2] = ' '; |
if (no_ascii) |
if (no_ascii) |
buff[cpos++] = ' '; |
buff[cpos++] = ' '; |
Line 98 void dStrHex(const char* str, int len, int no_ascii)
|
Line 129 void dStrHex(const char* str, int len, int no_ascii)
|
cpos = cpstart; |
cpos = cpstart; |
a += 16; |
a += 16; |
memset(buff,' ',80); |
memset(buff,' ',80); |
k = sprintf(buff + 1, "%.2x", a); | k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a); |
buff[k + 1] = ' '; |
buff[k + 1] = ' '; |
} |
} |
} |
} |
Line 133 static struct scsi_opcode_name opcode_name_arr[] = {
|
Line 164 static struct scsi_opcode_name opcode_name_arr[] = {
|
{READ_CAPACITY_16, "read capacity(16)"}, /* 0x9e,0x10 */ |
{READ_CAPACITY_16, "read capacity(16)"}, /* 0x9e,0x10 */ |
{REPORT_LUNS, "report luns"}, /* 0xa0 */ |
{REPORT_LUNS, "report luns"}, /* 0xa0 */ |
{SAT_ATA_PASSTHROUGH_12, "ata pass-through(12)"}, /* 0xa1 */ |
{SAT_ATA_PASSTHROUGH_12, "ata pass-through(12)"}, /* 0xa1 */ |
|
{READ_DEFECT_12, "read defect list(12)"}, /* 0xb7 */ |
}; |
}; |
|
|
static const char * vendor_specific = "<vendor specific>"; |
static const char * vendor_specific = "<vendor specific>"; |
|
|
/* Need to expand to take service action into account. For commands |
/* Need to expand to take service action into account. For commands |
* of interest the service action is in the 2nd command byte */ |
* of interest the service action is in the 2nd command byte */ |
const char * scsi_get_opcode_name(UINT8 opcode) | const char * |
| scsi_get_opcode_name(UINT8 opcode) |
{ |
{ |
int k; |
int k; |
int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]); |
int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]); |
Line 157 const char * scsi_get_opcode_name(UINT8 opcode)
|
Line 190 const char * scsi_get_opcode_name(UINT8 opcode)
|
return NULL; |
return NULL; |
} |
} |
|
|
| void |
void scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf, | scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf, |
struct scsi_sense_disect * out) | struct scsi_sense_disect * out) |
{ |
{ |
int resp_code; |
int resp_code; |
|
|
memset(out, 0, sizeof(struct scsi_sense_disect)); |
memset(out, 0, sizeof(struct scsi_sense_disect)); |
if (SCSI_STATUS_CHECK_CONDITION == io_buf->scsi_status) { |
if (SCSI_STATUS_CHECK_CONDITION == io_buf->scsi_status) { |
resp_code = (io_buf->sensep[0] & 0x7f); |
resp_code = (io_buf->sensep[0] & 0x7f); |
out->error_code = resp_code; | out->resp_code = resp_code; |
if (resp_code >= 0x72) { |
if (resp_code >= 0x72) { |
out->sense_key = (io_buf->sensep[1] & 0xf); |
out->sense_key = (io_buf->sensep[1] & 0xf); |
out->asc = io_buf->sensep[2]; |
out->asc = io_buf->sensep[2]; |
Line 181 void scsi_do_sense_disect(const struct scsi_cmnd_io *
|
Line 214 void scsi_do_sense_disect(const struct scsi_cmnd_io *
|
} |
} |
} |
} |
|
|
int scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo) | int |
| scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo) |
{ |
{ |
switch (sinfo->sense_key) { |
switch (sinfo->sense_key) { |
case SCSI_SK_NO_SENSE: |
case SCSI_SK_NO_SENSE: |
case SCSI_SK_RECOVERED_ERR: |
case SCSI_SK_RECOVERED_ERR: |
return SIMPLE_NO_ERROR; |
return SIMPLE_NO_ERROR; |
case SCSI_SK_NOT_READY: |
case SCSI_SK_NOT_READY: |
if (SCSI_ASC_NO_MEDIUM == sinfo->asc) | if (SCSI_ASC_NO_MEDIUM == sinfo->asc) |
return SIMPLE_ERR_NO_MEDIUM; |
return SIMPLE_ERR_NO_MEDIUM; |
else if (SCSI_ASC_NOT_READY == sinfo->asc) { |
else if (SCSI_ASC_NOT_READY == sinfo->asc) { |
if (0x1 == sinfo->ascq) |
if (0x1 == sinfo->ascq) |
Line 203 int scsiSimpleSenseFilter(const struct scsi_sense_dise
|
Line 237 int scsiSimpleSenseFilter(const struct scsi_sense_dise
|
case SCSI_SK_ILLEGAL_REQUEST: |
case SCSI_SK_ILLEGAL_REQUEST: |
if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc) |
if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc) |
return SIMPLE_ERR_BAD_OPCODE; |
return SIMPLE_ERR_BAD_OPCODE; |
else if (SCSI_ASC_UNKNOWN_FIELD == sinfo->asc) | else if (SCSI_ASC_INVALID_FIELD == sinfo->asc) |
return SIMPLE_ERR_BAD_FIELD; |
return SIMPLE_ERR_BAD_FIELD; |
else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc) |
else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc) |
return SIMPLE_ERR_BAD_PARAM; |
return SIMPLE_ERR_BAD_PARAM; |
Line 218 int scsiSimpleSenseFilter(const struct scsi_sense_dise
|
Line 252 int scsiSimpleSenseFilter(const struct scsi_sense_dise
|
} |
} |
} |
} |
|
|
const char * scsiErrString(int scsiErr) | const char * |
| scsiErrString(int scsiErr) |
{ |
{ |
if (scsiErr < 0) |
if (scsiErr < 0) |
return strerror(-scsiErr); |
return strerror(-scsiErr); |
switch (scsiErr) { |
switch (scsiErr) { |
case SIMPLE_NO_ERROR: | case SIMPLE_NO_ERROR: |
return "no error"; |
return "no error"; |
case SIMPLE_ERR_NOT_READY: | case SIMPLE_ERR_NOT_READY: |
return "device not ready"; |
return "device not ready"; |
case SIMPLE_ERR_BAD_OPCODE: | case SIMPLE_ERR_BAD_OPCODE: |
return "unsupported scsi opcode"; |
return "unsupported scsi opcode"; |
case SIMPLE_ERR_BAD_FIELD: | case SIMPLE_ERR_BAD_FIELD: |
return "unsupported field in scsi command"; |
return "unsupported field in scsi command"; |
case SIMPLE_ERR_BAD_PARAM: | case SIMPLE_ERR_BAD_PARAM: |
return "badly formed scsi parameters"; |
return "badly formed scsi parameters"; |
case SIMPLE_ERR_BAD_RESP: | case SIMPLE_ERR_BAD_RESP: |
return "scsi response fails sanity test"; |
return "scsi response fails sanity test"; |
case SIMPLE_ERR_NO_MEDIUM: | case SIMPLE_ERR_NO_MEDIUM: |
return "no medium present"; |
return "no medium present"; |
case SIMPLE_ERR_BECOMING_READY: | case SIMPLE_ERR_BECOMING_READY: |
return "device will be ready soon"; |
return "device will be ready soon"; |
case SIMPLE_ERR_TRY_AGAIN: | case SIMPLE_ERR_TRY_AGAIN: |
return "unit attention reported, try again"; |
return "unit attention reported, try again"; |
case SIMPLE_ERR_MEDIUM_HARDWARE: | case SIMPLE_ERR_MEDIUM_HARDWARE: |
return "medium or hardware error (serious)"; |
return "medium or hardware error (serious)"; |
case SIMPLE_ERR_UNKNOWN: | case SIMPLE_ERR_UNKNOWN: |
return "unknown error (unexpected sense key)"; |
return "unknown error (unexpected sense key)"; |
case SIMPLE_ERR_ABORTED_COMMAND: | case SIMPLE_ERR_ABORTED_COMMAND: |
return "aborted command"; |
return "aborted command"; |
default: |
default: |
return "unknown error"; |
return "unknown error"; |
Line 261 const char * scsiErrString(int scsiErr)
|
Line 296 const char * scsiErrString(int scsiErr)
|
* descriptor; returns -1 if normal end condition and -2 for an abnormal |
* descriptor; returns -1 if normal end condition and -2 for an abnormal |
* termination. Matches association, designator_type and/or code_set when |
* termination. Matches association, designator_type and/or code_set when |
* any of those values are greater than or equal to zero. */ |
* any of those values are greater than or equal to zero. */ |
int scsi_vpd_dev_id_iter(const unsigned char * initial_desig_desc, | int |
int page_len, int * off, int m_assoc, | scsi_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len, |
int m_desig_type, int m_code_set) | int * off, int m_assoc, int m_desig_type, int m_code_set) |
{ |
{ |
const unsigned char * ucp; |
const unsigned char * ucp; |
int k, c_set, assoc, desig_type; |
int k, c_set, assoc, desig_type; |
Line 290 int scsi_vpd_dev_id_iter(const unsigned char * initial
|
Line 325 int scsi_vpd_dev_id_iter(const unsigned char * initial
|
/* Decode VPD page 0x83 logical unit designator into a string. If both |
/* Decode VPD page 0x83 logical unit designator into a string. If both |
* numeric address and SCSI name string present, prefer the former. |
* numeric address and SCSI name string present, prefer the former. |
* Returns 0 on success, -1 on error with error string in s. */ |
* Returns 0 on success, -1 on error with error string in s. */ |
int scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, | int |
int slen, int * transport) | scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen, |
| int * transport) |
{ |
{ |
int m, c_set, assoc, desig_type, i_len, naa, off, u, have_scsi_ns; |
int m, c_set, assoc, desig_type, i_len, naa, off, u, have_scsi_ns; |
const unsigned char * ucp; |
const unsigned char * ucp; |
const unsigned char * ip; |
const unsigned char * ip; |
char * orig_s = s; | int si = 0; |
|
|
if (transport) |
if (transport) |
*transport = -1; | *transport = -1; |
if (slen < 32) { |
if (slen < 32) { |
if (slen > 0) | if (slen > 0) |
s[0] = '\0'; | s[0] = '\0'; |
return -1; | return -1; |
} |
} |
have_scsi_ns = 0; |
have_scsi_ns = 0; |
s[0] = '\0'; |
s[0] = '\0'; |
Line 312 int scsi_decode_lu_dev_id(const unsigned char * b, int
|
Line 348 int scsi_decode_lu_dev_id(const unsigned char * b, int
|
ucp = b + off; |
ucp = b + off; |
i_len = ucp[3]; |
i_len = ucp[3]; |
if ((off + i_len + 4) > blen) { |
if ((off + i_len + 4) > blen) { |
s += sprintf(s, "error: designator length"); | snprintf(s+si, slen-si, "error: designator length"); |
return -1; | return -1; |
} |
} |
assoc = ((ucp[1] >> 4) & 0x3); |
assoc = ((ucp[1] >> 4) & 0x3); |
if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0)) | if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0)) |
*transport = (ucp[0] >> 4) & 0xf; | *transport = (ucp[0] >> 4) & 0xf; |
if (0 != assoc) | if (0 != assoc) |
continue; | continue; |
ip = ucp + 4; |
ip = ucp + 4; |
c_set = (ucp[0] & 0xf); |
c_set = (ucp[0] & 0xf); |
desig_type = (ucp[1] & 0xf); |
desig_type = (ucp[1] & 0xf); |
Line 330 int scsi_decode_lu_dev_id(const unsigned char * b, int
|
Line 366 int scsi_decode_lu_dev_id(const unsigned char * b, int
|
break; |
break; |
case 2: /* EUI-64 based */ |
case 2: /* EUI-64 based */ |
if ((8 != i_len) && (12 != i_len) && (16 != i_len)) { |
if ((8 != i_len) && (12 != i_len) && (16 != i_len)) { |
s += sprintf(s, "error: EUI-64 length"); | snprintf(s+si, slen-si, "error: EUI-64 length"); |
return -1; | return -1; |
} | } |
if (have_scsi_ns) | if (have_scsi_ns) |
s = orig_s; | si = 0; |
s += sprintf(s, "0x"); | si += snprintf(s+si, slen-si, "0x"); |
for (m = 0; m < i_len; ++m) |
for (m = 0; m < i_len; ++m) |
s += sprintf(s, "%02x", (unsigned int)ip[m]); | si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); |
break; |
break; |
case 3: /* NAA */ |
case 3: /* NAA */ |
if (1 != c_set) { |
if (1 != c_set) { |
s += sprintf(s, "error: NAA bad code_set"); | snprintf(s+si, slen-si, "error: NAA bad code_set"); |
return -1; | return -1; |
} | } |
naa = (ip[0] >> 4) & 0xff; |
naa = (ip[0] >> 4) & 0xff; |
if ((naa < 2) || (naa > 6) || (4 == naa)) { |
if ((naa < 2) || (naa > 6) || (4 == naa)) { |
s += sprintf(s, "error: unexpected NAA"); | snprintf(s+si, slen-si, "error: unexpected NAA"); |
return -1; | return -1; |
} |
} |
if (have_scsi_ns) | if (have_scsi_ns) |
s = orig_s; | si = 0; |
if (2 == naa) { /* NAA IEEE Extended */ |
if (2 == naa) { /* NAA IEEE Extended */ |
if (8 != i_len) { |
if (8 != i_len) { |
s += sprintf(s, "error: NAA 2 length"); | snprintf(s+si, slen-si, "error: NAA 2 length"); |
return -1; | return -1; |
} |
} |
s += sprintf(s, "0x"); | si += snprintf(s+si, slen-si, "0x"); |
for (m = 0; m < 8; ++m) |
for (m = 0; m < 8; ++m) |
s += sprintf(s, "%02x", (unsigned int)ip[m]); | si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); |
} else if ((3 == naa ) || (5 == naa)) { |
} else if ((3 == naa ) || (5 == naa)) { |
/* NAA=3 Locally assigned; NAA=5 IEEE Registered */ |
/* NAA=3 Locally assigned; NAA=5 IEEE Registered */ |
if (8 != i_len) { |
if (8 != i_len) { |
s += sprintf(s, "error: NAA 3 or 5 length"); | snprintf(s+si, slen-si, "error: NAA 3 or 5 length"); |
return -1; | return -1; |
} |
} |
s += sprintf(s, "0x"); | si += snprintf(s+si, slen-si, "0x"); |
for (m = 0; m < 8; ++m) |
for (m = 0; m < 8; ++m) |
s += sprintf(s, "%02x", (unsigned int)ip[m]); | si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); |
} else if (6 == naa) { /* NAA IEEE Registered extended */ |
} else if (6 == naa) { /* NAA IEEE Registered extended */ |
if (16 != i_len) { |
if (16 != i_len) { |
s += sprintf(s, "error: NAA 6 length"); | snprintf(s+si, slen-si, "error: NAA 6 length"); |
return -1; | return -1; |
} |
} |
s += sprintf(s, "0x"); | si += snprintf(s+si, slen-si, "0x"); |
for (m = 0; m < 16; ++m) |
for (m = 0; m < 16; ++m) |
s += sprintf(s, "%02x", (unsigned int)ip[m]); | si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); |
} |
} |
break; |
break; |
case 4: /* Relative target port */ |
case 4: /* Relative target port */ |
Line 385 int scsi_decode_lu_dev_id(const unsigned char * b, int
|
Line 421 int scsi_decode_lu_dev_id(const unsigned char * b, int
|
break; |
break; |
case 8: /* SCSI name string */ |
case 8: /* SCSI name string */ |
if (3 != c_set) { |
if (3 != c_set) { |
s += sprintf(s, "error: SCSI name string"); | snprintf(s+si, slen-si, "error: SCSI name string"); |
return -1; | return -1; |
} |
} |
/* does %s print out UTF-8 ok?? */ |
/* does %s print out UTF-8 ok?? */ |
if (orig_s == s) { | if (si == 0) { |
s += sprintf(s, "%s", (const char *)ip); | si += snprintf(s+si, slen-si, "%s", (const char *)ip); |
++have_scsi_ns; | ++have_scsi_ns; |
} | } |
break; |
break; |
default: /* reserved */ |
default: /* reserved */ |
break; |
break; |
} |
} |
} |
} |
if (-2 == u) { |
if (-2 == u) { |
s += sprintf(s, "error: bad structure"); | snprintf(s+si, slen-si, "error: bad structure"); |
return -1; | return -1; |
} |
} |
return 0; |
return 0; |
} |
} |
Line 412 int scsi_decode_lu_dev_id(const unsigned char * b, int
|
Line 448 int scsi_decode_lu_dev_id(const unsigned char * b, int
|
If known_resp_len > 0 then a single fetch is done for this response |
If known_resp_len > 0 then a single fetch is done for this response |
length. If known_resp_len == 0 then twin fetches are performed, the |
length. If known_resp_len == 0 then twin fetches are performed, the |
first to deduce the response length, then send the same command again |
first to deduce the response length, then send the same command again |
requesting the deduced response length. This protects certain fragile | requesting the deduced response length. This protects certain fragile |
HBAs. The twin fetch technique should not be used with the TapeAlert |
HBAs. The twin fetch technique should not be used with the TapeAlert |
log page since it clears its state flags after each fetch. */ |
log page since it clears its state flags after each fetch. */ |
int scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf, | int |
int bufLen, int known_resp_len) | scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf, |
| int bufLen, int known_resp_len) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
Line 468 int scsiLogSense(scsi_device * device, int pagenum, in
|
Line 505 int scsiLogSense(scsi_device * device, int pagenum, in
|
pageLen = 252; /* some IBM tape drives don't like double fetch */ |
pageLen = 252; /* some IBM tape drives don't like double fetch */ |
/* some SCSI HBA don't like "odd" length transfers */ |
/* some SCSI HBA don't like "odd" length transfers */ |
if (pageLen % 2) |
if (pageLen % 2) |
pageLen += 1; | pageLen += 1; |
if (pageLen > bufLen) |
if (pageLen > bufLen) |
pageLen = bufLen; |
pageLen = bufLen; |
} |
} |
Line 507 int scsiLogSense(scsi_device * device, int pagenum, in
|
Line 544 int scsiLogSense(scsi_device * device, int pagenum, in
|
* Returns 0 if ok, 1 if NOT READY, 2 if command not supported, * 3 if |
* Returns 0 if ok, 1 if NOT READY, 2 if command not supported, * 3 if |
* field in command not supported, * 4 if bad parameter to command or |
* field in command not supported, * 4 if bad parameter to command or |
* returns negated errno. SPC-4 sections 6.5 and 7.2 (rev 20) */ |
* returns negated errno. SPC-4 sections 6.5 and 7.2 (rev 20) */ |
int scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum, | int |
int subpagenum, UINT8 *pBuf, int bufLen) | scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum, |
| int subpagenum, UINT8 *pBuf, int bufLen) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
Line 540 int scsiLogSelect(scsi_device * device, int pcr, int s
|
Line 578 int scsiLogSelect(scsi_device * device, int pcr, int s
|
|
|
/* Send MODE SENSE (6 byte) command. Returns 0 if ok, 1 if NOT READY, |
/* Send MODE SENSE (6 byte) command. Returns 0 if ok, 1 if NOT READY, |
* 2 if command not supported (then MODE SENSE(10) should be supported), |
* 2 if command not supported (then MODE SENSE(10) should be supported), |
* 3 if field in command not supported or returns negated errno. | * 3 if field in command not supported or returns negated errno. |
* SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */ |
* SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */ |
int scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc, | int |
UINT8 *pBuf, int bufLen) | scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc, |
| UINT8 *pBuf, int bufLen) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
Line 594 int scsiModeSense(scsi_device * device, int pagenum, i
|
Line 633 int scsiModeSense(scsi_device * device, int pagenum, i
|
* from a corresponding 6 byte MODE SENSE command. Such a response should |
* from a corresponding 6 byte MODE SENSE command. Such a response should |
* have a 4 byte header followed by 0 or more 8 byte block descriptors |
* have a 4 byte header followed by 0 or more 8 byte block descriptors |
* (normally 1) and then 1 mode page. Returns 0 if ok, 1 if NOT READY, |
* (normally 1) and then 1 mode page. Returns 0 if ok, 1 if NOT READY, |
* 2 if command not supported (then MODE SELECT(10) may be supported), | * 2 if command not supported (then MODE SELECT(10) may be supported), |
* 3 if field in command not supported, 4 if bad parameter to command |
* 3 if field in command not supported, 4 if bad parameter to command |
* or returns negated errno. SPC-3 sections 6.7 and 7.4 (rev 22a) */ |
* or returns negated errno. SPC-3 sections 6.7 and 7.4 (rev 22a) */ |
int scsiModeSelect(scsi_device * device, int sp, UINT8 *pBuf, int bufLen) | int |
| scsiModeSelect(scsi_device * device, int sp, UINT8 *pBuf, int bufLen) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
Line 634 int scsiModeSelect(scsi_device * device, int sp, UINT8
|
Line 674 int scsiModeSelect(scsi_device * device, int sp, UINT8
|
return scsiSimpleSenseFilter(&sinfo); |
return scsiSimpleSenseFilter(&sinfo); |
} |
} |
|
|
/* MODE SENSE (10 byte). Returns 0 if ok, 1 if NOT READY, 2 if command | /* MODE SENSE (10 byte). Returns 0 if ok, 1 if NOT READY, 2 if command |
* not supported (then MODE SENSE(6) might be supported), 3 if field in |
* not supported (then MODE SENSE(6) might be supported), 3 if field in |
* command not supported or returns negated errno. | * command not supported or returns negated errno. |
* SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */ |
* SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */ |
int scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc, | int |
UINT8 *pBuf, int bufLen) | scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc, |
| UINT8 *pBuf, int bufLen) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
Line 688 int scsiModeSense10(scsi_device * device, int pagenum,
|
Line 729 int scsiModeSense10(scsi_device * device, int pagenum,
|
/* Sends a 10 byte MODE SELECT command. Assumes given pBuf is the response |
/* Sends a 10 byte MODE SELECT command. Assumes given pBuf is the response |
* from a corresponding 10 byte MODE SENSE command. Such a response should |
* from a corresponding 10 byte MODE SENSE command. Such a response should |
* have a 8 byte header followed by 0 or more 8 byte block descriptors |
* have a 8 byte header followed by 0 or more 8 byte block descriptors |
* (normally 1) and then 1 mode page. Returns 0 if ok, 1 NOT REAFY, 2 if | * (normally 1) and then 1 mode page. Returns 0 if ok, 1 NOT REAFY, 2 if |
* command not supported (then MODE SELECT(6) may be supported), 3 if field |
* command not supported (then MODE SELECT(6) may be supported), 3 if field |
* in command not supported, 4 if bad parameter to command or returns |
* in command not supported, 4 if bad parameter to command or returns |
* negated errno. SPC-3 sections 6.8 and 7.4 (rev 22a) */ |
* negated errno. SPC-3 sections 6.8 and 7.4 (rev 22a) */ |
int scsiModeSelect10(scsi_device * device, int sp, UINT8 *pBuf, int bufLen) | int |
| scsiModeSelect10(scsi_device * device, int sp, UINT8 *pBuf, int bufLen) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
Line 707 int scsiModeSelect10(scsi_device * device, int sp, UIN
|
Line 749 int scsiModeSelect10(scsi_device * device, int sp, UIN
|
hdr_plus_1_pg = pg_offset + pg_len; |
hdr_plus_1_pg = pg_offset + pg_len; |
if (hdr_plus_1_pg > bufLen) |
if (hdr_plus_1_pg > bufLen) |
return -EINVAL; |
return -EINVAL; |
pBuf[0] = 0; | pBuf[0] = 0; |
pBuf[1] = 0; /* Length of returned mode sense data reserved for SELECT */ |
pBuf[1] = 0; /* Length of returned mode sense data reserved for SELECT */ |
pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */ |
pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */ |
memset(&io_hdr, 0, sizeof(io_hdr)); |
memset(&io_hdr, 0, sizeof(io_hdr)); |
Line 733 int scsiModeSelect10(scsi_device * device, int sp, UIN
|
Line 775 int scsiModeSelect10(scsi_device * device, int sp, UIN
|
/* Standard INQUIRY returns 0 for ok, anything else is a major problem. |
/* Standard INQUIRY returns 0 for ok, anything else is a major problem. |
* bufLen should be 36 for unsafe devices (like USB mass storage stuff) |
* bufLen should be 36 for unsafe devices (like USB mass storage stuff) |
* otherwise they can lock up! SPC-3 sections 6.4 and 7.6 (rev 22a) */ |
* otherwise they can lock up! SPC-3 sections 6.4 and 7.6 (rev 22a) */ |
int scsiStdInquiry(scsi_device * device, UINT8 *pBuf, int bufLen) | int |
| scsiStdInquiry(scsi_device * device, UINT8 *pBuf, int bufLen) |
{ |
{ |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
UINT8 cdb[6]; |
UINT8 cdb[6]; |
UINT8 sense[32]; |
UINT8 sense[32]; |
|
|
if ((bufLen < 0) || (bufLen > 255)) | if ((bufLen < 0) || (bufLen > 1023)) |
return -EINVAL; |
return -EINVAL; |
memset(&io_hdr, 0, sizeof(io_hdr)); |
memset(&io_hdr, 0, sizeof(io_hdr)); |
memset(cdb, 0, sizeof(cdb)); |
memset(cdb, 0, sizeof(cdb)); |
Line 748 int scsiStdInquiry(scsi_device * device, UINT8 *pBuf,
|
Line 791 int scsiStdInquiry(scsi_device * device, UINT8 *pBuf,
|
io_hdr.dxfer_len = bufLen; |
io_hdr.dxfer_len = bufLen; |
io_hdr.dxferp = pBuf; |
io_hdr.dxferp = pBuf; |
cdb[0] = INQUIRY; |
cdb[0] = INQUIRY; |
cdb[4] = bufLen; | cdb[3] = (bufLen >> 8) & 0xff; |
| cdb[4] = (bufLen & 0xff); |
io_hdr.cmnd = cdb; |
io_hdr.cmnd = cdb; |
io_hdr.cmnd_len = sizeof(cdb); |
io_hdr.cmnd_len = sizeof(cdb); |
io_hdr.sensep = sense; |
io_hdr.sensep = sense; |
Line 762 int scsiStdInquiry(scsi_device * device, UINT8 *pBuf,
|
Line 806 int scsiStdInquiry(scsi_device * device, UINT8 *pBuf,
|
} |
} |
|
|
/* INQUIRY to fetch Vital Page Data. Returns 0 if ok, 1 if NOT READY |
/* INQUIRY to fetch Vital Page Data. Returns 0 if ok, 1 if NOT READY |
* (unlikely), 2 if command not supported, 3 if field in command not | * (unlikely), 2 if command not supported, 3 if field in command not |
* supported, 5 if response indicates that EVPD bit ignored or returns |
* supported, 5 if response indicates that EVPD bit ignored or returns |
* negated errno. SPC-3 section 6.4 and 7.6 (rev 22a) */ |
* negated errno. SPC-3 section 6.4 and 7.6 (rev 22a) */ |
int scsiInquiryVpd(scsi_device * device, int vpd_page, UINT8 *pBuf, int bufLen) | int |
| scsiInquiryVpd(scsi_device * device, int vpd_page, UINT8 *pBuf, int bufLen) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
Line 773 int scsiInquiryVpd(scsi_device * device, int vpd_page,
|
Line 818 int scsiInquiryVpd(scsi_device * device, int vpd_page,
|
UINT8 sense[32]; |
UINT8 sense[32]; |
int res; |
int res; |
|
|
if ((bufLen < 0) || (bufLen > 255)) | /* Assume SCSI_VPD_SUPPORTED_VPD_PAGES is first VPD page fetched */ |
| if ((SCSI_VPD_SUPPORTED_VPD_PAGES != vpd_page) && |
| supported_vpd_pages_p && |
| (! supported_vpd_pages_p->is_supported(vpd_page))) |
| return 3; |
| |
| if ((bufLen < 0) || (bufLen > 1023)) |
return -EINVAL; |
return -EINVAL; |
|
try_again: |
memset(&io_hdr, 0, sizeof(io_hdr)); |
memset(&io_hdr, 0, sizeof(io_hdr)); |
memset(cdb, 0, sizeof(cdb)); |
memset(cdb, 0, sizeof(cdb)); |
if (bufLen > 1) |
if (bufLen > 1) |
Line 785 int scsiInquiryVpd(scsi_device * device, int vpd_page,
|
Line 837 int scsiInquiryVpd(scsi_device * device, int vpd_page,
|
cdb[0] = INQUIRY; |
cdb[0] = INQUIRY; |
cdb[1] = 0x1; /* set EVPD bit (enable Vital Product Data) */ |
cdb[1] = 0x1; /* set EVPD bit (enable Vital Product Data) */ |
cdb[2] = vpd_page; |
cdb[2] = vpd_page; |
cdb[4] = bufLen; | cdb[3] = (bufLen >> 8) & 0xff; |
| cdb[4] = (bufLen & 0xff); |
io_hdr.cmnd = cdb; |
io_hdr.cmnd = cdb; |
io_hdr.cmnd_len = sizeof(cdb); |
io_hdr.cmnd_len = sizeof(cdb); |
io_hdr.sensep = sense; |
io_hdr.sensep = sense; |
Line 795 int scsiInquiryVpd(scsi_device * device, int vpd_page,
|
Line 848 int scsiInquiryVpd(scsi_device * device, int vpd_page,
|
if (!device->scsi_pass_through(&io_hdr)) |
if (!device->scsi_pass_through(&io_hdr)) |
return -device->get_errno(); |
return -device->get_errno(); |
scsi_do_sense_disect(&io_hdr, &sinfo); |
scsi_do_sense_disect(&io_hdr, &sinfo); |
|
if ((SCSI_STATUS_CHECK_CONDITION == io_hdr.scsi_status) && |
|
(SCSI_SK_ILLEGAL_REQUEST == sinfo.sense_key) && |
|
(SCSI_ASC_INVALID_FIELD == sinfo.asc) && |
|
(cdb[3] > 0)) { |
|
bufLen &= 0xff; /* make sure cdb[3] is 0 next time around */ |
|
goto try_again; |
|
} |
|
|
if ((res = scsiSimpleSenseFilter(&sinfo))) |
if ((res = scsiSimpleSenseFilter(&sinfo))) |
return res; |
return res; |
/* Guard against devices that ignore EVPD bit and do standard INQUIRY */ |
/* Guard against devices that ignore EVPD bit and do standard INQUIRY */ |
Line 810 int scsiInquiryVpd(scsi_device * device, int vpd_page,
|
Line 871 int scsiInquiryVpd(scsi_device * device, int vpd_page,
|
|
|
/* REQUEST SENSE command. Returns 0 if ok, anything else major problem. |
/* REQUEST SENSE command. Returns 0 if ok, anything else major problem. |
* SPC-3 section 6.27 (rev 22a) */ |
* SPC-3 section 6.27 (rev 22a) */ |
int scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info) | int |
| scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
UINT8 cdb[6]; |
UINT8 cdb[6]; |
UINT8 sense[32]; |
UINT8 sense[32]; |
UINT8 buff[18]; |
UINT8 buff[18]; |
int len; |
int len; |
UINT8 ecode; | UINT8 resp_code; |
|
|
memset(&io_hdr, 0, sizeof(io_hdr)); |
memset(&io_hdr, 0, sizeof(io_hdr)); |
memset(cdb, 0, sizeof(cdb)); |
memset(cdb, 0, sizeof(cdb)); |
Line 835 int scsiRequestSense(scsi_device * device, struct scsi
|
Line 897 int scsiRequestSense(scsi_device * device, struct scsi
|
if (!device->scsi_pass_through(&io_hdr)) |
if (!device->scsi_pass_through(&io_hdr)) |
return -device->get_errno(); |
return -device->get_errno(); |
if (sense_info) { |
if (sense_info) { |
ecode = buff[0] & 0x7f; | resp_code = buff[0] & 0x7f; |
sense_info->error_code = ecode; | sense_info->resp_code = resp_code; |
sense_info->sense_key = buff[2] & 0xf; |
sense_info->sense_key = buff[2] & 0xf; |
sense_info->asc = 0; |
sense_info->asc = 0; |
sense_info->ascq = 0; |
sense_info->ascq = 0; |
if ((0x70 == ecode) || (0x71 == ecode)) { | if ((0x70 == resp_code) || (0x71 == resp_code)) { |
len = buff[7] + 8; |
len = buff[7] + 8; |
if (len > 13) { |
if (len > 13) { |
sense_info->asc = buff[12]; |
sense_info->asc = buff[12]; |
sense_info->ascq = buff[13]; |
sense_info->ascq = buff[13]; |
} |
} |
} |
} |
|
// fill progrss indicator, if available |
|
sense_info->progress = -1; |
|
switch (resp_code) { |
|
const unsigned char * ucp; |
|
int sk, sk_pr; |
|
case 0x70: |
|
case 0x71: |
|
sk = (buff[2] & 0xf); |
|
if ((sizeof(buff) < 18) || |
|
((SCSI_SK_NO_SENSE != sk) && (SCSI_SK_NOT_READY != sk))) { |
|
break; |
|
} |
|
if (buff[15] & 0x80) { /* SKSV bit set */ |
|
sense_info->progress = (buff[16] << 8) + buff[17]; |
|
break; |
|
} else { |
|
break; |
|
} |
|
case 0x72: |
|
case 0x73: |
|
/* sense key specific progress (0x2) or progress descriptor (0xa) */ |
|
sk = (buff[1] & 0xf); |
|
sk_pr = (SCSI_SK_NO_SENSE == sk) || (SCSI_SK_NOT_READY == sk); |
|
if (sk_pr && ((ucp = sg_scsi_sense_desc_find(buff, sizeof(buff), 2))) && |
|
(0x6 == ucp[1]) && (0x80 & ucp[4])) { |
|
sense_info->progress = (ucp[5] << 8) + ucp[6]; |
|
break; |
|
} else if (((ucp = sg_scsi_sense_desc_find(buff, sizeof(buff), 0xa))) && |
|
((0x6 == ucp[1]))) { |
|
sense_info->progress = (ucp[6] << 8) + ucp[7]; |
|
break; |
|
} else |
|
break; |
|
default: |
|
return 0; |
|
} |
} |
} |
return 0; |
return 0; |
} |
} |
Line 854 int scsiRequestSense(scsi_device * device, struct scsi
|
Line 952 int scsiRequestSense(scsi_device * device, struct scsi
|
/* SEND DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if command |
/* SEND DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if command |
* not supported, 3 if field in command not supported or returns negated |
* not supported, 3 if field in command not supported or returns negated |
* errno. SPC-3 section 6.28 (rev 22a) */ |
* errno. SPC-3 section 6.28 (rev 22a) */ |
int scsiSendDiagnostic(scsi_device * device, int functioncode, UINT8 *pBuf, int bufLen) | int |
| scsiSendDiagnostic(scsi_device * device, int functioncode, UINT8 *pBuf, |
| int bufLen) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
Line 881 int scsiSendDiagnostic(scsi_device * device, int funct
|
Line 981 int scsiSendDiagnostic(scsi_device * device, int funct
|
io_hdr.max_sense_len = sizeof(sense); |
io_hdr.max_sense_len = sizeof(sense); |
/* worst case is an extended foreground self test on a big disk */ |
/* worst case is an extended foreground self test on a big disk */ |
io_hdr.timeout = SCSI_TIMEOUT_SELF_TEST; |
io_hdr.timeout = SCSI_TIMEOUT_SELF_TEST; |
| |
if (!device->scsi_pass_through(&io_hdr)) |
if (!device->scsi_pass_through(&io_hdr)) |
return -device->get_errno(); |
return -device->get_errno(); |
scsi_do_sense_disect(&io_hdr, &sinfo); |
scsi_do_sense_disect(&io_hdr, &sinfo); |
Line 891 int scsiSendDiagnostic(scsi_device * device, int funct
|
Line 991 int scsiSendDiagnostic(scsi_device * device, int funct
|
/* RECEIVE DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if |
/* RECEIVE DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if |
* command not supported, 3 if field in command not supported or returns |
* command not supported, 3 if field in command not supported or returns |
* negated errno. SPC-3 section 6.18 (rev 22a) */ |
* negated errno. SPC-3 section 6.18 (rev 22a) */ |
int scsiReceiveDiagnostic(scsi_device * device, int pcv, int pagenum, UINT8 *pBuf, | int |
| scsiReceiveDiagnostic(scsi_device * device, int pcv, int pagenum, UINT8 *pBuf, |
int bufLen) |
int bufLen) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
Line 922 int scsiReceiveDiagnostic(scsi_device * device, int pc
|
Line 1023 int scsiReceiveDiagnostic(scsi_device * device, int pc
|
} |
} |
|
|
/* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */ |
/* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */ |
static int _testunitready(scsi_device * device, struct scsi_sense_disect * sinfo) | static int |
| _testunitready(scsi_device * device, struct scsi_sense_disect * sinfo) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
UINT8 cdb[6]; |
UINT8 cdb[6]; |
Line 948 static int _testunitready(scsi_device * device, struct
|
Line 1050 static int _testunitready(scsi_device * device, struct
|
|
|
/* Returns 0 for device responds and media ready, 1 for device responds and |
/* Returns 0 for device responds and media ready, 1 for device responds and |
media not ready, or returns a negated errno value */ |
media not ready, or returns a negated errno value */ |
int scsiTestUnitReady(scsi_device * device) | int |
| scsiTestUnitReady(scsi_device * device) |
{ |
{ |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
int status; |
int status; |
Line 959 int scsiTestUnitReady(scsi_device * device)
|
Line 1062 int scsiTestUnitReady(scsi_device * device)
|
status = scsiSimpleSenseFilter(&sinfo); |
status = scsiSimpleSenseFilter(&sinfo); |
if (SIMPLE_ERR_TRY_AGAIN == status) { |
if (SIMPLE_ERR_TRY_AGAIN == status) { |
/* power on reset, media changed, ok ... try again */ |
/* power on reset, media changed, ok ... try again */ |
status = _testunitready(device, &sinfo); | status = _testunitready(device, &sinfo); |
if (0 != status) |
if (0 != status) |
return status; |
return status; |
status = scsiSimpleSenseFilter(&sinfo); |
status = scsiSimpleSenseFilter(&sinfo); |
Line 970 int scsiTestUnitReady(scsi_device * device)
|
Line 1073 int scsiTestUnitReady(scsi_device * device)
|
/* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if |
/* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if |
* command not supported, 3 if field in command not supported or returns |
* command not supported, 3 if field in command not supported or returns |
* negated errno. SBC-2 section 5.12 (rev 16) */ |
* negated errno. SBC-2 section 5.12 (rev 16) */ |
int scsiReadDefect10(scsi_device * device, int req_plist, int req_glist, int dl_format, | int |
UINT8 *pBuf, int bufLen) | scsiReadDefect10(scsi_device * device, int req_plist, int req_glist, |
| int dl_format, UINT8 *pBuf, int bufLen) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
Line 1000 int scsiReadDefect10(scsi_device * device, int req_pli
|
Line 1104 int scsiReadDefect10(scsi_device * device, int req_pli
|
return scsiSimpleSenseFilter(&sinfo); |
return scsiSimpleSenseFilter(&sinfo); |
} |
} |
|
|
|
/* READ DEFECT (12) command. Returns 0 if ok, 1 if NOT READY, 2 if |
|
* command not supported, 3 if field in command not supported or returns |
|
* negated errno. SBC-3 section 5.18 (rev 35; vale Mark Evans) */ |
|
int |
|
scsiReadDefect12(scsi_device * device, int req_plist, int req_glist, |
|
int dl_format, int addrDescIndex, UINT8 *pBuf, int bufLen) |
|
{ |
|
struct scsi_cmnd_io io_hdr; |
|
struct scsi_sense_disect sinfo; |
|
UINT8 cdb[12]; |
|
UINT8 sense[32]; |
|
|
|
memset(&io_hdr, 0, sizeof(io_hdr)); |
|
memset(cdb, 0, sizeof(cdb)); |
|
io_hdr.dxfer_dir = DXFER_FROM_DEVICE; |
|
io_hdr.dxfer_len = bufLen; |
|
io_hdr.dxferp = pBuf; |
|
cdb[0] = READ_DEFECT_12; |
|
cdb[1] = (unsigned char)(((req_plist << 4) & 0x10) | |
|
((req_glist << 3) & 0x8) | (dl_format & 0x7)); |
|
cdb[2] = (addrDescIndex >> 24) & 0xff; |
|
cdb[3] = (addrDescIndex >> 16) & 0xff; |
|
cdb[4] = (addrDescIndex >> 8) & 0xff; |
|
cdb[5] = addrDescIndex & 0xff; |
|
cdb[6] = (bufLen >> 24) & 0xff; |
|
cdb[7] = (bufLen >> 16) & 0xff; |
|
cdb[8] = (bufLen >> 8) & 0xff; |
|
cdb[9] = bufLen & 0xff; |
|
io_hdr.cmnd = cdb; |
|
io_hdr.cmnd_len = sizeof(cdb); |
|
io_hdr.sensep = sense; |
|
io_hdr.max_sense_len = sizeof(sense); |
|
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; |
|
|
|
if (!device->scsi_pass_through(&io_hdr)) |
|
return -device->get_errno(); |
|
scsi_do_sense_disect(&io_hdr, &sinfo); |
|
return scsiSimpleSenseFilter(&sinfo); |
|
} |
|
|
/* READ CAPACITY (10) command. Returns 0 if ok, 1 if NOT READY, 2 if |
/* READ CAPACITY (10) command. Returns 0 if ok, 1 if NOT READY, 2 if |
* command not supported, 3 if field in command not supported or returns |
* command not supported, 3 if field in command not supported or returns |
* negated errno. SBC-3 section 5.15 (rev 26) */ |
* negated errno. SBC-3 section 5.15 (rev 26) */ |
int scsiReadCapacity10(scsi_device * device, unsigned int * last_lbap, | int |
unsigned int * lb_sizep) | scsiReadCapacity10(scsi_device * device, unsigned int * last_lbap, |
| unsigned int * lb_sizep) |
{ |
{ |
int res; |
int res; |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
Line 1044 int scsiReadCapacity10(scsi_device * device, unsigned
|
Line 1189 int scsiReadCapacity10(scsi_device * device, unsigned
|
/* READ CAPACITY (16) command. The bufLen argument should be 32. Returns 0 |
/* READ CAPACITY (16) command. The bufLen argument should be 32. Returns 0 |
* if ok, 1 if NOT READY, 2 if command not supported, 3 if field in command |
* if ok, 1 if NOT READY, 2 if command not supported, 3 if field in command |
* not supported or returns negated errno. SBC-3 section 5.16 (rev 26) */ |
* not supported or returns negated errno. SBC-3 section 5.16 (rev 26) */ |
int scsiReadCapacity16(scsi_device * device, UINT8 *pBuf, int bufLen) | int |
| scsiReadCapacity16(scsi_device * device, UINT8 *pBuf, int bufLen) |
{ |
{ |
struct scsi_cmnd_io io_hdr; |
struct scsi_cmnd_io io_hdr; |
struct scsi_sense_disect sinfo; |
struct scsi_sense_disect sinfo; |
Line 1077 int scsiReadCapacity16(scsi_device * device, UINT8 *pB
|
Line 1223 int scsiReadCapacity16(scsi_device * device, UINT8 *pB
|
/* Return number of bytes of storage in 'device' or 0 if error. If |
/* Return number of bytes of storage in 'device' or 0 if error. If |
* successful and lb_sizep is not NULL then the logical block size |
* successful and lb_sizep is not NULL then the logical block size |
* in bytes is written to the location pointed to by lb_sizep. */ |
* in bytes is written to the location pointed to by lb_sizep. */ |
uint64_t scsiGetSize(scsi_device * device, unsigned int * lb_sizep) | uint64_t |
| scsiGetSize(scsi_device * device, unsigned int * lb_sizep, |
| int * lb_per_pb_expp) |
{ |
{ |
unsigned int last_lba, lb_size; |
unsigned int last_lba, lb_size; |
int k, res; |
int k, res; |
Line 1086 uint64_t scsiGetSize(scsi_device * device, unsigned in
|
Line 1234 uint64_t scsiGetSize(scsi_device * device, unsigned in
|
|
|
res = scsiReadCapacity10(device, &last_lba, &lb_size); |
res = scsiReadCapacity10(device, &last_lba, &lb_size); |
if (res) { |
if (res) { |
if (scsi_debugmode) | if (scsi_debugmode) |
pout("scsiGetSize: READ CAPACITY(10) failed, res=%d\n", res); | pout("scsiGetSize: READ CAPACITY(10) failed, res=%d\n", res); |
return ret_val; | return 0; |
} |
} |
if (0xffffffff == last_lba) { |
if (0xffffffff == last_lba) { |
res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp)); | res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp)); |
if (res) { |
if (res) { |
if (scsi_debugmode) | if (scsi_debugmode) |
pout("scsiGetSize: READ CAPACITY(16) failed, res=%d\n", res); | pout("scsiGetSize: READ CAPACITY(16) failed, res=%d\n", res); |
return ret_val; | return 0; |
} | } |
for (k = 0; k < 8; ++k) { | for (k = 0; k < 8; ++k) { |
if (k > 0) | if (k > 0) |
ret_val <<= 8; |
ret_val <<= 8; |
ret_val |= rc16resp[k + 0]; |
ret_val |= rc16resp[k + 0]; |
} |
} |
} else | if (lb_per_pb_expp) |
ret_val = last_lba; | *lb_per_pb_expp = (rc16resp[13] & 0xf); |
| } else { |
| ret_val = last_lba; |
| if (lb_per_pb_expp) |
| *lb_per_pb_expp = 0; |
| } |
if (lb_sizep) |
if (lb_sizep) |
*lb_sizep = lb_size; | *lb_sizep = lb_size; |
++ret_val; /* last_lba is origin 0 so need to bump to get number of */ | ++ret_val; /* last_lba is origin 0 so need to bump to get number of */ |
return ret_val * lb_size; |
return ret_val * lb_size; |
} |
} |
|
|
|
/* Gets drive Protection and Logical/Physical block information. Writes |
|
* back bytes 12 to 31 from a READ CAPACITY 16 command to the rc16_12_31p |
|
* pointer. So rc16_12_31p should point to an array of 20 bytes. Returns 0 |
|
* if ok, 1 if NOT READY, 2 if command not supported, 3 if field in command |
|
* not supported or returns negated errno. */ |
|
int |
|
scsiGetProtPBInfo(scsi_device * device, unsigned char * rc16_12_31p) |
|
{ |
|
int res; |
|
UINT8 rc16resp[32]; |
|
|
|
res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp)); |
|
if (res) { |
|
if (scsi_debugmode) |
|
pout("scsiGetSize: READ CAPACITY(16) failed, res=%d\n", res); |
|
return res; |
|
} |
|
if (rc16_12_31p) |
|
memcpy(rc16_12_31p, rc16resp + 12, 20); |
|
return 0; |
|
} |
|
|
/* Offset into mode sense (6 or 10 byte) response that actual mode page |
/* Offset into mode sense (6 or 10 byte) response that actual mode page |
* starts at (relative to resp[0]). Returns -1 if problem */ |
* starts at (relative to resp[0]). Returns -1 if problem */ |
int scsiModePageOffset(const UINT8 * resp, int len, int modese_len) | int |
| scsiModePageOffset(const UINT8 * resp, int len, int modese_len) |
{ |
{ |
int resp_len, bd_len; |
int resp_len, bd_len; |
int offset = -1; |
int offset = -1; |
Line 1155 int scsiModePageOffset(const UINT8 * resp, int len, in
|
Line 1330 int scsiModePageOffset(const UINT8 * resp, int len, in
|
* tries a 10 byte MODE SENSE command. Returns 0 if successful, a positive |
* tries a 10 byte MODE SENSE command. Returns 0 if successful, a positive |
* number if a known error (see SIMPLE_ERR_ ...) or a negative errno |
* number if a known error (see SIMPLE_ERR_ ...) or a negative errno |
* value. */ |
* value. */ |
int scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp, int modese_len) | int |
| scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp, |
| int modese_len) |
{ |
{ |
int err = 0; |
int err = 0; |
|
|
Line 1183 int scsiFetchIECmpage(scsi_device * device, struct scs
|
Line 1360 int scsiFetchIECmpage(scsi_device * device, struct scs
|
iecp->modese_len = 0; |
iecp->modese_len = 0; |
return err; |
return err; |
} |
} |
} | } |
iecp->gotCurrent = 1; |
iecp->gotCurrent = 1; |
iecp->requestedChangeable = 1; |
iecp->requestedChangeable = 1; |
if (10 == iecp->modese_len) |
if (10 == iecp->modese_len) |
Line 1191 int scsiFetchIECmpage(scsi_device * device, struct scs
|
Line 1368 int scsiFetchIECmpage(scsi_device * device, struct scs
|
0, MPAGE_CONTROL_CHANGEABLE, |
0, MPAGE_CONTROL_CHANGEABLE, |
iecp->raw_chg, sizeof(iecp->raw_chg)); |
iecp->raw_chg, sizeof(iecp->raw_chg)); |
else if (6 == iecp->modese_len) |
else if (6 == iecp->modese_len) |
err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, | err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, |
0, MPAGE_CONTROL_CHANGEABLE, | 0, MPAGE_CONTROL_CHANGEABLE, |
iecp->raw_chg, sizeof(iecp->raw_chg)); |
iecp->raw_chg, sizeof(iecp->raw_chg)); |
if (err) |
if (err) |
return err; |
return err; |
Line 1200 int scsiFetchIECmpage(scsi_device * device, struct scs
|
Line 1377 int scsiFetchIECmpage(scsi_device * device, struct scs
|
return 0; |
return 0; |
} |
} |
|
|
int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp) | int |
| scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp) |
{ |
{ |
int offset; |
int offset; |
|
|
Line 1215 int scsi_IsExceptionControlEnabled(const struct scsi_i
|
Line 1393 int scsi_IsExceptionControlEnabled(const struct scsi_i
|
return 0; |
return 0; |
} |
} |
|
|
int scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp) | int |
| scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp) |
{ |
{ |
int offset; |
int offset; |
|
|
Line 1231 int scsi_IsWarningEnabled(const struct scsi_iec_mode_p
|
Line 1410 int scsi_IsWarningEnabled(const struct scsi_iec_mode_p
|
} |
} |
|
|
/* set EWASC and clear PERF, EBF, DEXCPT TEST and LOGERR */ |
/* set EWASC and clear PERF, EBF, DEXCPT TEST and LOGERR */ |
#define SCSI_IEC_MP_BYTE2_ENABLED 0x10 | #define SCSI_IEC_MP_BYTE2_ENABLED 0x10 |
#define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4 |
#define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4 |
/* exception/warning via an unrequested REQUEST SENSE command */ |
/* exception/warning via an unrequested REQUEST SENSE command */ |
#define SCSI_IEC_MP_MRIE 6 | #define SCSI_IEC_MP_MRIE 6 |
#define SCSI_IEC_MP_INTERVAL_T 0 |
#define SCSI_IEC_MP_INTERVAL_T 0 |
#define SCSI_IEC_MP_REPORT_COUNT 1 |
#define SCSI_IEC_MP_REPORT_COUNT 1 |
|
|
Line 1245 int scsi_IsWarningEnabled(const struct scsi_iec_mode_p
|
Line 1424 int scsi_IsWarningEnabled(const struct scsi_iec_mode_p
|
* is to be re-examined. |
* is to be re-examined. |
* When -r ioctl is invoked 3 or more time on 'smartctl -s on ...' |
* When -r ioctl is invoked 3 or more time on 'smartctl -s on ...' |
* then set the TEST bit (causes asc,ascq pair of 0x5d,0xff). */ |
* then set the TEST bit (causes asc,ascq pair of 0x5d,0xff). */ |
int scsiSetExceptionControlAndWarning(scsi_device * device, int enabled, | int |
const struct scsi_iec_mode_page *iecp) | scsiSetExceptionControlAndWarning(scsi_device * device, int enabled, |
| const struct scsi_iec_mode_page *iecp) |
{ |
{ |
int k, offset, resp_len; |
int k, offset, resp_len; |
int err = 0; |
int err = 0; |
Line 1304 int scsiSetExceptionControlAndWarning(scsi_device * de
|
Line 1484 int scsiSetExceptionControlAndWarning(scsi_device * de
|
pout("scsiSetExceptionControlAndWarning: already disabled\n"); |
pout("scsiSetExceptionControlAndWarning: already disabled\n"); |
return 0; /* nothing to do, leave other setting alone */ |
return 0; /* nothing to do, leave other setting alone */ |
} |
} |
if (wEnabled) | if (wEnabled) |
rout[offset + 2] &= EWASC_DISABLE; |
rout[offset + 2] &= EWASC_DISABLE; |
if (eCEnabled) { |
if (eCEnabled) { |
if (iecp->gotChangeable && | if (iecp->gotChangeable && |
(iecp->raw_chg[offset + 2] & DEXCPT_ENABLE)) |
(iecp->raw_chg[offset + 2] & DEXCPT_ENABLE)) |
rout[offset + 2] |= DEXCPT_ENABLE; |
rout[offset + 2] |= DEXCPT_ENABLE; |
rout[offset + 2] &= TEST_DISABLE;/* clear TEST bit for spec */ |
rout[offset + 2] &= TEST_DISABLE;/* clear TEST bit for spec */ |
Line 1320 int scsiSetExceptionControlAndWarning(scsi_device * de
|
Line 1500 int scsiSetExceptionControlAndWarning(scsi_device * de
|
return err; |
return err; |
} |
} |
|
|
int scsiGetTemp(scsi_device * device, UINT8 *currenttemp, UINT8 *triptemp) | int |
| scsiGetTemp(scsi_device * device, UINT8 *currenttemp, UINT8 *triptemp) |
{ |
{ |
UINT8 tBuf[252]; |
UINT8 tBuf[252]; |
int err; |
int err; |
Line 1342 int scsiGetTemp(scsi_device * device, UINT8 *currentte
|
Line 1523 int scsiGetTemp(scsi_device * device, UINT8 *currentte
|
* Fetching asc/ascq code potentially flagging an exception or warning. |
* Fetching asc/ascq code potentially flagging an exception or warning. |
* Returns 0 if ok, else error number. A current temperature of 255 |
* Returns 0 if ok, else error number. A current temperature of 255 |
* (Celsius) implies that the temperature not available. */ |
* (Celsius) implies that the temperature not available. */ |
int scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage, | int |
UINT8 *asc, UINT8 *ascq, UINT8 *currenttemp, | scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage, |
UINT8 *triptemp) | UINT8 *asc, UINT8 *ascq, UINT8 *currenttemp, UINT8 *triptemp) |
{ |
{ |
UINT8 tBuf[252]; |
UINT8 tBuf[252]; |
struct scsi_sense_disect sense_info; |
struct scsi_sense_disect sense_info; |
Line 1352 int scsiCheckIE(scsi_device * device, int hasIELogPage
|
Line 1533 int scsiCheckIE(scsi_device * device, int hasIELogPage
|
int temperatureSet = 0; |
int temperatureSet = 0; |
unsigned short pagesize; |
unsigned short pagesize; |
UINT8 currTemp, trTemp; |
UINT8 currTemp, trTemp; |
| |
*asc = 0; |
*asc = 0; |
*ascq = 0; |
*ascq = 0; |
*currenttemp = 0; |
*currenttemp = 0; |
Line 1366 int scsiCheckIE(scsi_device * device, int hasIELogPage
|
Line 1547 int scsiCheckIE(scsi_device * device, int hasIELogPage
|
return err; |
return err; |
} |
} |
// pull out page size from response, don't forget to add 4 |
// pull out page size from response, don't forget to add 4 |
pagesize = (unsigned short) ((tBuf[2] << 8) | tBuf[3]) + 4; | pagesize = (unsigned short) ((tBuf[2] << 8) | tBuf[3]) + 4; |
if ((pagesize < 4) || tBuf[4] || tBuf[5]) { |
if ((pagesize < 4) || tBuf[4] || tBuf[5]) { |
pout("Log Sense failed, IE page, bad parameter code or length\n"); |
pout("Log Sense failed, IE page, bad parameter code or length\n"); |
return SIMPLE_ERR_BAD_PARAM; |
return SIMPLE_ERR_BAD_PARAM; |
} |
} |
if (tBuf[7] > 1) { |
if (tBuf[7] > 1) { |
sense_info.asc = tBuf[8]; | sense_info.asc = tBuf[8]; |
sense_info.ascq = tBuf[9]; |
sense_info.ascq = tBuf[9]; |
if (! hasTempLogPage) { |
if (! hasTempLogPage) { |
if (tBuf[7] > 2) | if (tBuf[7] > 2) |
*currenttemp = tBuf[10]; |
*currenttemp = tBuf[10]; |
if (tBuf[7] > 3) /* IBM extension in SMART (IE) lpage */ |
if (tBuf[7] > 3) /* IBM extension in SMART (IE) lpage */ |
*triptemp = tBuf[11]; |
*triptemp = tBuf[11]; |
} |
} |
} | } |
} |
} |
if (0 == sense_info.asc) { | if (0 == sense_info.asc) { |
/* ties in with MRIE field of 6 in IEC mode page (0x1c) */ |
/* ties in with MRIE field of 6 in IEC mode page (0x1c) */ |
if ((err = scsiRequestSense(device, &sense_info))) { |
if ((err = scsiRequestSense(device, &sense_info))) { |
pout("Request Sense failed, [%s]\n", scsiErrString(err)); |
pout("Request Sense failed, [%s]\n", scsiErrString(err)); |
Line 1401 int scsiCheckIE(scsi_device * device, int hasIELogPage
|
Line 1582 int scsiCheckIE(scsi_device * device, int hasIELogPage
|
} |
} |
|
|
// The first character (W, C, I) tells the severity |
// The first character (W, C, I) tells the severity |
static const char * TapeAlertsMessageTable[]= { | static const char * TapeAlertsMessageTable[]= { |
" ", |
" ", |
/* 0x01 */ |
/* 0x01 */ |
"W: The tape drive is having problems reading data. No data has been lost,\n" |
"W: The tape drive is having problems reading data. No data has been lost,\n" |
Line 1625 static const char * TapeAlertsMessageTable[]= {
|
Line 1806 static const char * TapeAlertsMessageTable[]= {
|
" fault. If problem persists, call the supplier help line.", |
" fault. If problem persists, call the supplier help line.", |
}; |
}; |
|
|
const char * scsiTapeAlertsTapeDevice(unsigned short code) | const char * |
| scsiTapeAlertsTapeDevice(unsigned short code) |
{ |
{ |
const int num = sizeof(TapeAlertsMessageTable) / |
const int num = sizeof(TapeAlertsMessageTable) / |
sizeof(TapeAlertsMessageTable[0]); |
sizeof(TapeAlertsMessageTable[0]); |
|
|
return (code < num) ? TapeAlertsMessageTable[code] : "Unknown Alert"; | return (code < num) ? TapeAlertsMessageTable[code] : "Unknown Alert"; |
} |
} |
|
|
// The first character (W, C, I) tells the severity |
// The first character (W, C, I) tells the severity |
static const char * ChangerTapeAlertsMessageTable[]= { | static const char * ChangerTapeAlertsMessageTable[]= { |
" ", |
" ", |
/* 0x01 */ |
/* 0x01 */ |
"C: The library mechanism is having difficulty communicating with the\n" |
"C: The library mechanism is having difficulty communicating with the\n" |
Line 1760 static const char * ChangerTapeAlertsMessageTable[]= {
|
Line 1942 static const char * ChangerTapeAlertsMessageTable[]= {
|
"I: The library was unable to read the bar code on a cartridge.", |
"I: The library was unable to read the bar code on a cartridge.", |
}; |
}; |
|
|
const char * scsiTapeAlertsChangerDevice(unsigned short code) | const char * |
| scsiTapeAlertsChangerDevice(unsigned short code) |
{ |
{ |
const int num = sizeof(ChangerTapeAlertsMessageTable) / |
const int num = sizeof(ChangerTapeAlertsMessageTable) / |
sizeof(ChangerTapeAlertsMessageTable[0]); |
sizeof(ChangerTapeAlertsMessageTable[0]); |
|
|
return (code < num) ? ChangerTapeAlertsMessageTable[code] : "Unknown Alert"; | return (code < num) ? ChangerTapeAlertsMessageTable[code] : "Unknown Alert"; |
} |
} |
|
|
|
|
Line 1894 static const char * strs_for_asc_b[] = {
|
Line 2077 static const char * strs_for_asc_b[] = {
|
|
|
static char spare_buff[128]; |
static char spare_buff[128]; |
|
|
const char * scsiGetIEString(UINT8 asc, UINT8 ascq) | const char * |
| scsiGetIEString(UINT8 asc, UINT8 ascq) |
{ |
{ |
const char * rp; |
const char * rp; |
|
|
if (SCSI_ASC_IMPENDING_FAILURE == asc) { |
if (SCSI_ASC_IMPENDING_FAILURE == asc) { |
if (ascq == 0xff) |
if (ascq == 0xff) |
return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)"; |
return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)"; |
else if (ascq < | else if (ascq < |
(sizeof(strs_for_asc_5d) / sizeof(strs_for_asc_5d[0]))) { |
(sizeof(strs_for_asc_5d) / sizeof(strs_for_asc_5d[0]))) { |
rp = strs_for_asc_5d[ascq]; |
rp = strs_for_asc_5d[ascq]; |
if (strlen(rp) > 0) |
if (strlen(rp) > 0) |
Line 1925 const char * scsiGetIEString(UINT8 asc, UINT8 ascq)
|
Line 2109 const char * scsiGetIEString(UINT8 asc, UINT8 ascq)
|
|
|
/* This is not documented in t10.org, page 0x80 is vendor specific */ |
/* This is not documented in t10.org, page 0x80 is vendor specific */ |
/* Some IBM disks do an offline read-scan when they get this command. */ |
/* Some IBM disks do an offline read-scan when they get this command. */ |
int scsiSmartIBMOfflineTest(scsi_device * device) | int |
{ | scsiSmartIBMOfflineTest(scsi_device * device) |
| { |
UINT8 tBuf[256]; |
UINT8 tBuf[256]; |
int res; |
int res; |
| |
memset(tBuf, 0, sizeof(tBuf)); |
memset(tBuf, 0, sizeof(tBuf)); |
/* Build SMART Off-line Immediate Diag Header */ |
/* Build SMART Off-line Immediate Diag Header */ |
tBuf[0] = 0x80; /* Page Code */ |
tBuf[0] = 0x80; /* Page Code */ |
Line 1946 int scsiSmartIBMOfflineTest(scsi_device * device)
|
Line 2131 int scsiSmartIBMOfflineTest(scsi_device * device)
|
return res; |
return res; |
} |
} |
|
|
int scsiSmartDefaultSelfTest(scsi_device * device) | int |
{ | scsiSmartDefaultSelfTest(scsi_device * device) |
| { |
int res; |
int res; |
|
|
res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, NULL, 0); |
res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, NULL, 0); |
Line 1956 int scsiSmartDefaultSelfTest(scsi_device * device)
|
Line 2142 int scsiSmartDefaultSelfTest(scsi_device * device)
|
return res; |
return res; |
} |
} |
|
|
int scsiSmartShortSelfTest(scsi_device * device) | int |
{ | scsiSmartShortSelfTest(scsi_device * device) |
| { |
int res; |
int res; |
|
|
res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, NULL, 0); |
res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, NULL, 0); |
Line 1966 int scsiSmartShortSelfTest(scsi_device * device)
|
Line 2153 int scsiSmartShortSelfTest(scsi_device * device)
|
return res; |
return res; |
} |
} |
|
|
int scsiSmartExtendSelfTest(scsi_device * device) | int |
{ | scsiSmartExtendSelfTest(scsi_device * device) |
| { |
int res; |
int res; |
|
|
res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, NULL, 0); |
res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, NULL, 0); |
Line 1977 int scsiSmartExtendSelfTest(scsi_device * device)
|
Line 2165 int scsiSmartExtendSelfTest(scsi_device * device)
|
return res; |
return res; |
} |
} |
|
|
int scsiSmartShortCapSelfTest(scsi_device * device) | int |
{ | scsiSmartShortCapSelfTest(scsi_device * device) |
| { |
int res; |
int res; |
|
|
res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, NULL, 0); |
res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, NULL, 0); |
Line 1987 int scsiSmartShortCapSelfTest(scsi_device * device)
|
Line 2176 int scsiSmartShortCapSelfTest(scsi_device * device)
|
return res; |
return res; |
} |
} |
|
|
int scsiSmartExtendCapSelfTest(scsi_device * device) | int |
| scsiSmartExtendCapSelfTest(scsi_device * device) |
{ |
{ |
int res; |
int res; |
|
|
Line 1998 int scsiSmartExtendCapSelfTest(scsi_device * device)
|
Line 2188 int scsiSmartExtendCapSelfTest(scsi_device * device)
|
return res; |
return res; |
} |
} |
|
|
int scsiSmartSelfTestAbort(scsi_device * device) | int |
| scsiSmartSelfTestAbort(scsi_device * device) |
{ |
{ |
int res; |
int res; |
|
|
Line 2010 int scsiSmartSelfTestAbort(scsi_device * device)
|
Line 2201 int scsiSmartSelfTestAbort(scsi_device * device)
|
|
|
/* Returns 0 and the expected duration of an extended self test (in seconds) |
/* Returns 0 and the expected duration of an extended self test (in seconds) |
if successful; any other return value indicates a failure. */ |
if successful; any other return value indicates a failure. */ |
int scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec, int modese_len) | int |
| scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec, |
| int modese_len) |
{ |
{ |
int err, offset, res; |
int err, offset, res; |
UINT8 buff[64]; |
UINT8 buff[64]; |
Line 2029 int scsiFetchExtendedSelfTestTime(scsi_device * device
|
Line 2222 int scsiFetchExtendedSelfTestTime(scsi_device * device
|
} |
} |
if (10 == modese_len) { |
if (10 == modese_len) { |
err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, |
err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, |
MPAGE_CONTROL_CURRENT, | MPAGE_CONTROL_CURRENT, |
buff, sizeof(buff)); |
buff, sizeof(buff)); |
if (err) |
if (err) |
return err; |
return err; |
} | } |
offset = scsiModePageOffset(buff, sizeof(buff), modese_len); |
offset = scsiModePageOffset(buff, sizeof(buff), modese_len); |
if (offset < 0) |
if (offset < 0) |
return -EINVAL; |
return -EINVAL; |
Line 2046 int scsiFetchExtendedSelfTestTime(scsi_device * device
|
Line 2239 int scsiFetchExtendedSelfTestTime(scsi_device * device
|
return -EINVAL; |
return -EINVAL; |
} |
} |
|
|
void scsiDecodeErrCounterPage(unsigned char * resp, | void |
struct scsiErrorCounter *ecp) | scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp) |
{ |
{ |
int k, j, num, pl, pc; |
int k, j, num, pl, pc; |
unsigned char * ucp; |
unsigned char * ucp; |
Line 2061 void scsiDecodeErrCounterPage(unsigned char * resp,
|
Line 2254 void scsiDecodeErrCounterPage(unsigned char * resp,
|
pc = (ucp[0] << 8) | ucp[1]; |
pc = (ucp[0] << 8) | ucp[1]; |
pl = ucp[3] + 4; |
pl = ucp[3] + 4; |
switch (pc) { |
switch (pc) { |
case 0: | case 0: |
case 1: | case 1: |
case 2: | case 2: |
case 3: | case 3: |
case 4: | case 4: |
case 5: | case 5: |
case 6: | case 6: |
ecp->gotPC[pc] = 1; |
ecp->gotPC[pc] = 1; |
ullp = &ecp->counter[pc]; |
ullp = &ecp->counter[pc]; |
break; |
break; |
default: | default: |
ecp->gotExtraPC = 1; |
ecp->gotExtraPC = 1; |
ullp = &ecp->counter[7]; |
ullp = &ecp->counter[7]; |
break; |
break; |
Line 2093 void scsiDecodeErrCounterPage(unsigned char * resp,
|
Line 2286 void scsiDecodeErrCounterPage(unsigned char * resp,
|
} |
} |
} |
} |
|
|
void scsiDecodeNonMediumErrPage(unsigned char *resp, | void |
struct scsiNonMediumError *nmep) | scsiDecodeNonMediumErrPage(unsigned char *resp, |
| struct scsiNonMediumError *nmep) |
{ |
{ |
int k, j, num, pl, pc, szof; |
int k, j, num, pl, pc, szof; |
unsigned char * ucp; |
unsigned char * ucp; |
Line 2108 void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
Line 2302 void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
pc = (ucp[0] << 8) | ucp[1]; |
pc = (ucp[0] << 8) | ucp[1]; |
pl = ucp[3] + 4; |
pl = ucp[3] + 4; |
switch (pc) { |
switch (pc) { |
case 0: | case 0: |
nmep->gotPC0 = 1; |
nmep->gotPC0 = 1; |
k = pl - 4; |
k = pl - 4; |
xp = ucp + 4; |
xp = ucp + 4; |
Line 2123 void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
Line 2317 void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
nmep->counterPC0 |= xp[j]; |
nmep->counterPC0 |= xp[j]; |
} |
} |
break; |
break; |
case 0x8009: | case 0x8009: |
nmep->gotTFE_H = 1; |
nmep->gotTFE_H = 1; |
k = pl - 4; |
k = pl - 4; |
xp = ucp + 4; |
xp = ucp + 4; |
Line 2138 void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
Line 2332 void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
nmep->counterTFE_H |= xp[j]; |
nmep->counterTFE_H |= xp[j]; |
} |
} |
break; |
break; |
case 0x8015: | case 0x8015: |
nmep->gotPE_H = 1; |
nmep->gotPE_H = 1; |
k = pl - 4; |
k = pl - 4; |
xp = ucp + 4; |
xp = ucp + 4; |
Line 2153 void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
Line 2347 void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
nmep->counterPE_H |= xp[j]; |
nmep->counterPE_H |= xp[j]; |
} |
} |
break; |
break; |
default: | default: |
nmep->gotExtraPC = 1; |
nmep->gotExtraPC = 1; |
break; |
break; |
} |
} |
Line 2167 void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
Line 2361 void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
this function has a problem (typically -1), otherwise the bottom 8 |
this function has a problem (typically -1), otherwise the bottom 8 |
bits are the number of failed self tests and the 16 bits above that |
bits are the number of failed self tests and the 16 bits above that |
are the poweron hour of the most recent failure. Note: aborted self |
are the poweron hour of the most recent failure. Note: aborted self |
tests (typically by the user) and self tests in progress are not | tests (typically by the user) and self tests in progress are not |
considered failures. See Working Draft SCSI Primary Commands - 3 | considered failures. See Working Draft SCSI Primary Commands - 3 |
(SPC-3) section 7.2.10 T10/1416-D (rev 22a) */ |
(SPC-3) section 7.2.10 T10/1416-D (rev 22a) */ |
int scsiCountFailedSelfTests(scsi_device * fd, int noisy) | int |
| scsiCountFailedSelfTests(scsi_device * fd, int noisy) |
{ |
{ |
int num, k, n, err, res, fails, fail_hour; |
int num, k, n, err, res, fails, fail_hour; |
UINT8 * ucp; |
UINT8 * ucp; |
Line 2210 int scsiCountFailedSelfTests(scsi_device * fd, int noi
|
Line 2405 int scsiCountFailedSelfTests(scsi_device * fd, int noi
|
res = ucp[4] & 0xf; |
res = ucp[4] & 0xf; |
if ((res > 2) && (res < 8)) { |
if ((res > 2) && (res < 8)) { |
fails++; |
fails++; |
if (1 == fails) | if (1 == fails) |
fail_hour = (ucp[6] << 8) + ucp[7]; |
fail_hour = (ucp[6] << 8) + ucp[7]; |
} |
} |
} |
} |
Line 2219 int scsiCountFailedSelfTests(scsi_device * fd, int noi
|
Line 2414 int scsiCountFailedSelfTests(scsi_device * fd, int noi
|
|
|
/* Returns 0 if able to read self test log page; then outputs 1 into |
/* Returns 0 if able to read self test log page; then outputs 1 into |
*inProgress if self test still in progress, else outputs 0. */ |
*inProgress if self test still in progress, else outputs 0. */ |
int scsiSelfTestInProgress(scsi_device * fd, int * inProgress) | int |
| scsiSelfTestInProgress(scsi_device * fd, int * inProgress) |
{ |
{ |
int num; |
int num; |
UINT8 * ucp; |
UINT8 * ucp; |
Line 2246 int scsiSelfTestInProgress(scsi_device * fd, int * inP
|
Line 2442 int scsiSelfTestInProgress(scsi_device * fd, int * inP
|
malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD |
malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD |
bit is set. Examines default mode page when current==0 else examines |
bit is set. Examines default mode page when current==0 else examines |
current mode page. */ |
current mode page. */ |
int scsiFetchControlGLTSD(scsi_device * device, int modese_len, int current) | int |
| scsiFetchControlGLTSD(scsi_device * device, int modese_len, int current) |
{ |
{ |
int err, offset; |
int err, offset; |
UINT8 buff[64]; |
UINT8 buff[64]; |
Line 2268 int scsiFetchControlGLTSD(scsi_device * device, int mo
|
Line 2465 int scsiFetchControlGLTSD(scsi_device * device, int mo
|
buff, sizeof(buff)); |
buff, sizeof(buff)); |
if (err) |
if (err) |
return -EINVAL; |
return -EINVAL; |
} | } |
offset = scsiModePageOffset(buff, sizeof(buff), modese_len); |
offset = scsiModePageOffset(buff, sizeof(buff), modese_len); |
if ((offset >= 0) && (buff[offset + 1] >= 0xa)) |
if ((offset >= 0) && (buff[offset + 1] >= 0xa)) |
return (buff[offset + 2] & 2) ? 1 : 0; |
return (buff[offset + 2] & 2) ? 1 : 0; |
return -EINVAL; |
return -EINVAL; |
} |
} |
|
|
|
/* Returns a negative value on error, 0 if unknown and 1 if SSD, |
|
* otherwise the positive returned value is the speed in rpm. First checks |
|
* the Block Device Characteristics VPD page and if that fails it tries the |
|
* RIGID_DISK_DRIVE_GEOMETRY_PAGE mode page. */ |
|
|
|
int |
|
scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp) |
|
{ |
|
int err, offset, speed; |
|
UINT8 buff[64]; |
|
int pc = MPAGE_CONTROL_DEFAULT; |
|
|
|
memset(buff, 0, sizeof(buff)); |
|
if ((0 == scsiInquiryVpd(device, SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS, |
|
buff, sizeof(buff))) && |
|
(((buff[2] << 8) + buff[3]) > 2)) { |
|
speed = (buff[4] << 8) + buff[5]; |
|
if (form_factorp) |
|
*form_factorp = buff[7] & 0xf; |
|
return speed; |
|
} |
|
if (form_factorp) |
|
*form_factorp = 0; |
|
if (modese_len <= 6) { |
|
if ((err = scsiModeSense(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc, |
|
buff, sizeof(buff)))) { |
|
if (SIMPLE_ERR_BAD_OPCODE == err) |
|
modese_len = 10; |
|
else |
|
return -EINVAL; |
|
} else if (0 == modese_len) |
|
modese_len = 6; |
|
} |
|
if (10 == modese_len) { |
|
err = scsiModeSense10(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc, |
|
buff, sizeof(buff)); |
|
if (err) |
|
return -EINVAL; |
|
} |
|
offset = scsiModePageOffset(buff, sizeof(buff), modese_len); |
|
return (buff[offset + 20] << 8) | buff[offset + 21]; |
|
} |
|
|
|
/* Returns a non-zero value in case of error, wcep/rcdp == -1 - get value, |
|
0 - clear bit, 1 - set bit */ |
|
|
|
int |
|
scsiGetSetCache(scsi_device * device, int modese_len, short int * wcep, |
|
short int * rcdp) |
|
{ |
|
int err, offset, resp_len, sp; |
|
UINT8 buff[64], ch_buff[64]; |
|
short set_wce = *wcep; |
|
short set_rcd = *rcdp; |
|
|
|
memset(buff, 0, sizeof(buff)); |
|
if (modese_len <= 6) { |
|
if ((err = scsiModeSense(device, CACHING_PAGE, 0, MPAGE_CONTROL_CURRENT, |
|
buff, sizeof(buff)))) { |
|
if (SIMPLE_ERR_BAD_OPCODE == err) |
|
modese_len = 10; |
|
else { |
|
device->set_err(EINVAL, "SCSI MODE SENSE failed"); |
|
return -EINVAL; |
|
} |
|
} else if (0 == modese_len) |
|
modese_len = 6; |
|
} |
|
|
|
if (10 == modese_len) { |
|
err = scsiModeSense10(device, CACHING_PAGE, 0, MPAGE_CONTROL_CURRENT, |
|
buff, sizeof(buff)); |
|
if (err) { |
|
device->set_err(EINVAL, "SCSI MODE SENSE failed"); |
|
return -EINVAL; |
|
} |
|
} |
|
offset = scsiModePageOffset(buff, sizeof(buff), modese_len); |
|
if ((offset < 0) || (buff[offset + 1] < 0xa)) { |
|
device->set_err(EINVAL, "Bad response"); |
|
return SIMPLE_ERR_BAD_RESP; |
|
} |
|
|
|
*wcep = ((buff[offset + 2] & 0x04) != 0); |
|
*rcdp = ((buff[offset + 2] & 0x01) != 0); |
|
|
|
if((*wcep == set_wce || set_wce == -1) |
|
&& ((*rcdp == set_rcd) || set_rcd == -1)) |
|
return 0; // no changes needed or nothing to set |
|
|
|
if (modese_len == 6) |
|
err = scsiModeSense(device, CACHING_PAGE, 0, |
|
MPAGE_CONTROL_CHANGEABLE, |
|
ch_buff, sizeof(ch_buff)); |
|
else |
|
err = scsiModeSense10(device, CACHING_PAGE, 0, |
|
MPAGE_CONTROL_CHANGEABLE, |
|
ch_buff, sizeof(ch_buff)); |
|
if (err) { |
|
device->set_err(EINVAL, "WCE/RCD bits not changable"); |
|
return err; |
|
} |
|
|
|
// set WCE bit |
|
if(set_wce >= 0 && *wcep != set_wce) { |
|
if (0 == (ch_buff[offset + 2] & 0x04)) { |
|
device->set_err(EINVAL, "WCE bit not changable"); |
|
return 1; |
|
} |
|
if(set_wce) |
|
buff[offset + 2] |= 0x04; // set bit |
|
else |
|
buff[offset + 2] &= 0xfb; // clear bit |
|
} |
|
// set RCD bit |
|
if(set_rcd >= 0 && *rcdp != set_rcd) { |
|
if (0 == (ch_buff[offset + 2] & 0x01)) { |
|
device->set_err(EINVAL, "RCD bit not changable"); |
|
return 1; |
|
} |
|
if(set_rcd) |
|
buff[offset + 2] |= 0x01; // set bit |
|
else |
|
buff[offset + 2] &= 0xfe; // clear bit |
|
} |
|
|
|
if (10 == modese_len) { |
|
resp_len = (buff[0] << 8) + buff[1] + 2; |
|
buff[3] &= 0xef; /* for disks mask out DPOFUA bit */ |
|
} else { |
|
resp_len = buff[0] + 1; |
|
buff[2] &= 0xef; /* for disks mask out DPOFUA bit */ |
|
} |
|
sp = 0; /* Do not change saved values */ |
|
if (10 == modese_len) |
|
err = scsiModeSelect10(device, sp, buff, resp_len); |
|
else if (6 == modese_len) |
|
err = scsiModeSelect(device, sp, buff, resp_len); |
|
if(err) |
|
device->set_err(EINVAL, "MODE SELECT command failed"); |
|
return err; |
|
} |
|
|
|
|
/* Attempts to set or clear GLTSD bit in Control mode page. If enabled is |
/* Attempts to set or clear GLTSD bit in Control mode page. If enabled is |
0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if |
0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if |
successful, negative if low level error, > 0 if higher level error (e.g. |
successful, negative if low level error, > 0 if higher level error (e.g. |
SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */ |
SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */ |
int scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len) | int |
| scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len) |
{ |
{ |
int err, offset, resp_len, sp; |
int err, offset, resp_len, sp; |
UINT8 buff[64]; |
UINT8 buff[64]; |
Line 2303 int scsiSetControlGLTSD(scsi_device * device, int enab
|
Line 2645 int scsiSetControlGLTSD(scsi_device * device, int enab
|
buff, sizeof(buff)); |
buff, sizeof(buff)); |
if (err) |
if (err) |
return err; |
return err; |
} | } |
offset = scsiModePageOffset(buff, sizeof(buff), modese_len); |
offset = scsiModePageOffset(buff, sizeof(buff), modese_len); |
if ((offset < 0) || (buff[offset + 1] < 0xa)) |
if ((offset < 0) || (buff[offset + 1] < 0xa)) |
return SIMPLE_ERR_BAD_RESP; |
return SIMPLE_ERR_BAD_RESP; |
Line 2325 int scsiSetControlGLTSD(scsi_device * device, int enab
|
Line 2667 int scsiSetControlGLTSD(scsi_device * device, int enab
|
return err; |
return err; |
if (0 == (ch_buff[offset + 2] & 2)) |
if (0 == (ch_buff[offset + 2] & 2)) |
return SIMPLE_ERR_BAD_PARAM; /* GLTSD bit not chageable */ |
return SIMPLE_ERR_BAD_PARAM; /* GLTSD bit not chageable */ |
| |
if (10 == modese_len) { |
if (10 == modese_len) { |
resp_len = (buff[0] << 8) + buff[1] + 2; |
resp_len = (buff[0] << 8) + buff[1] + 2; |
buff[3] &= 0xef; /* for disks mask out DPOFUA bit */ |
buff[3] &= 0xef; /* for disks mask out DPOFUA bit */ |
Line 2345 int scsiSetControlGLTSD(scsi_device * device, int enab
|
Line 2687 int scsiSetControlGLTSD(scsi_device * device, int enab
|
return err; |
return err; |
} |
} |
|
|
/* Returns a negative value if failed to fetch Protocol specific port mode | /* Returns a negative value if failed to fetch Protocol specific port mode |
page or it was malformed. Returns transport protocol identifier when |
page or it was malformed. Returns transport protocol identifier when |
value >= 0 . */ |
value >= 0 . */ |
int scsiFetchTransportProtocol(scsi_device * device, int modese_len) | int |
| scsiFetchTransportProtocol(scsi_device * device, int modese_len) |
{ |
{ |
int err, offset; |
int err, offset; |
UINT8 buff[64]; |
UINT8 buff[64]; |
Line 2371 int scsiFetchTransportProtocol(scsi_device * device, i
|
Line 2714 int scsiFetchTransportProtocol(scsi_device * device, i
|
buff, sizeof(buff)); |
buff, sizeof(buff)); |
if (err) |
if (err) |
return -EINVAL; |
return -EINVAL; |
} | } |
offset = scsiModePageOffset(buff, sizeof(buff), modese_len); |
offset = scsiModePageOffset(buff, sizeof(buff), modese_len); |
if ((offset >= 0) && (buff[offset + 1] > 1)) { |
if ((offset >= 0) && (buff[offset + 1] > 1)) { |
if ((0 == (buff[offset] & 0x40)) && /* SPF==0 */ |
if ((0 == (buff[offset] & 0x40)) && /* SPF==0 */ |
(PROTOCOL_SPECIFIC_PORT_PAGE == (buff[offset] & 0x3f))) | (PROTOCOL_SPECIFIC_PORT_PAGE == (buff[offset] & 0x3f))) |
return (buff[offset + 2] & 0xf); |
return (buff[offset + 2] & 0xf); |
} |
} |
return -EINVAL; |
return -EINVAL; |
|
} |
|
|
|
const unsigned char * |
|
sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len, |
|
int desc_type) |
|
{ |
|
int add_sen_len, add_len, desc_len, k; |
|
const unsigned char * descp; |
|
|
|
if ((sense_len < 8) || (0 == (add_sen_len = sensep[7]))) |
|
return NULL; |
|
if ((sensep[0] < 0x72) || (sensep[0] > 0x73)) |
|
return NULL; |
|
add_sen_len = (add_sen_len < (sense_len - 8)) ? |
|
add_sen_len : (sense_len - 8); |
|
descp = &sensep[8]; |
|
for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { |
|
descp += desc_len; |
|
add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; |
|
desc_len = add_len + 2; |
|
if (descp[0] == desc_type) |
|
return descp; |
|
if (add_len < 0) /* short descriptor ?? */ |
|
break; |
|
} |
|
return NULL; |
|
} |
|
|
|
// Convenience function for formatting strings from SCSI identify |
|
void |
|
scsi_format_id_string(char * out, const unsigned char * in, int n) |
|
{ |
|
char tmp[65]; |
|
n = n > 64 ? 64 : n; |
|
strncpy(tmp, (const char *)in, n); |
|
tmp[n] = '\0'; |
|
|
|
// Find the first non-space character (maybe none). |
|
int first = -1; |
|
int i; |
|
for (i = 0; tmp[i]; i++) |
|
if (!isspace((int)tmp[i])) { |
|
first = i; |
|
break; |
|
} |
|
|
|
if (first == -1) { |
|
// There are no non-space characters. |
|
out[0] = '\0'; |
|
return; |
|
} |
|
|
|
// Find the last non-space character. |
|
for (i = strlen(tmp)-1; i >= first && isspace((int)tmp[i]); i--); |
|
int last = i; |
|
|
|
strncpy(out, tmp+first, last-first+1); |
|
out[last-first+1] = '\0'; |
} |
} |