⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsicmds.cpp

📁 硬盘各项性能的测试,如温度容量版本健康度型号
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/* * scsicmds.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * * Additional SCSI work: * Copyright (C) 2003-8 Douglas Gilbert <dougg@torque.net> * * 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. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * at the Concurrent Systems Laboratory (now part of the Storage Systems * Research Center), Jack Baskin School of Engineering, University of * California, Santa Cruz. http://ssrc.soe.ucsc.edu/ * * * In the SCSI world "SMART" is a dead or withdrawn standard. In recent * SCSI standards (since SCSI-3) it goes under the awkward name of * "Informational Exceptions" ["IE" or "IEC" (with the "C" for "control")]. * The relevant information is spread around several SCSI draft * standards available at http://www.t10.org . Reference is made in the * code to the following acronyms: *      - SAM [SCSI Architectural model, versions 2 or 3] *      - SPC [SCSI Primary commands, versions 2 or 3] *      - SBC [SCSI Block commands, versions 2] * * Some SCSI disk vendors have snippets of "SMART" information in their * product manuals. */#include <stdio.h>#include <string.h>#include "config.h"#include "int64.h"#include "extern.h"#include "scsicmds.h"#include "utility.h"const char *scsicmds_c_cvsid="$Id: scsicmds.cpp,v 1.96 2008/03/04 22:09:47 ballen4705 Exp $"CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;/* for passing global control variables */extern smartmonctrl *con;/* output binary in hex and optionally ascii */void dStrHex(const char* str, int len, int no_ascii){    const char* p = str;    unsigned char c;    char buff[82];    int a = 0;    const int bpstart = 5;    const int cpstart = 60;    int cpos = cpstart;    int bpos = bpstart;    int i, k;        if (len <= 0) return;    memset(buff,' ',80);    buff[80]='\0';    k = sprintf(buff + 1, "%.2x", a);    buff[k + 1] = ' ';    if (bpos >= ((bpstart + (9 * 3))))        bpos++;    for(i = 0; i < len; i++)    {        c = *p++;        bpos += 3;        if (bpos == (bpstart + (9 * 3)))            bpos++;        sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);        buff[bpos + 2] = ' ';        if (no_ascii)            buff[cpos++] = ' ';        else {            if ((c < ' ') || (c >= 0x7f))                c='.';            buff[cpos++] = c;        }        if (cpos > (cpstart+15))        {            pout("%s\n", buff);            bpos = bpstart;            cpos = cpstart;            a += 16;            memset(buff,' ',80);            k = sprintf(buff + 1, "%.2x", a);            buff[k + 1] = ' ';        }    }    if (cpos > cpstart)    {        pout("%s\n", buff);    }}struct scsi_opcode_name {    UINT8 opcode;    const char * name;};static struct scsi_opcode_name opcode_name_arr[] = {    /* in ascending opcode order */    {TEST_UNIT_READY, "test unit ready"},       /* 0x00 */    {REQUEST_SENSE, "request sense"},           /* 0x03 */    {INQUIRY, "inquiry"},                       /* 0x12 */    {MODE_SELECT, "mode select(6)"},            /* 0x15 */    {MODE_SENSE, "mode sense(6)"},              /* 0x1a */    {RECEIVE_DIAGNOSTIC, "receive diagnostic"}, /* 0x1c */    {SEND_DIAGNOSTIC, "send diagnostic"},       /* 0x1d */    {READ_DEFECT_10, "read defect list(10)"},   /* 0x37 */    {LOG_SENSE, "log sense"},                   /* 0x4d */    {MODE_SELECT_10, "mode select(10)"},        /* 0x55 */    {MODE_SENSE_10, "mode sense(10)"},          /* 0x5a */    {SAT_ATA_PASSTHROUGH_16, "ata pass-through(16)"}, /* 0x85 */    {SAT_ATA_PASSTHROUGH_12, "ata pass-through(12)"}, /* 0xa1 */};const char * scsi_get_opcode_name(UINT8 opcode){    int k;    int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]);    struct scsi_opcode_name * onp;    for (k = 0; k < len; ++k) {        onp = &opcode_name_arr[k];        if (opcode == onp->opcode)            return onp->name;        else if (opcode < onp->opcode)            return NULL;    }    return NULL;}void scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf,                          struct scsi_sense_disect * out){    int resp_code;    memset(out, 0, sizeof(struct scsi_sense_disect));    if (SCSI_STATUS_CHECK_CONDITION == io_buf->scsi_status) {        resp_code = (io_buf->sensep[0] & 0x7f);        out->error_code = resp_code;        if (resp_code >= 0x72) {            out->sense_key = (io_buf->sensep[1] & 0xf);            out->asc = io_buf->sensep[2];            out->ascq = io_buf->sensep[3];        } else if (resp_code >= 0x70) {            out->sense_key = (io_buf->sensep[2] & 0xf);            if (io_buf->resp_sense_len > 13) {                out->asc = io_buf->sensep[12];                out->ascq = io_buf->sensep[13];            }        }    }}int scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo){    switch (sinfo->sense_key) {    case SCSI_SK_NO_SENSE:    case SCSI_SK_RECOVERED_ERR:        return SIMPLE_NO_ERROR;    case SCSI_SK_NOT_READY:        if (SCSI_ASC_NO_MEDIUM == sinfo->asc)             return SIMPLE_ERR_NO_MEDIUM;        else if (SCSI_ASC_NOT_READY == sinfo->asc) {            if (0x1 == sinfo->ascq)                return SIMPLE_ERR_BECOMING_READY;            else                return SIMPLE_ERR_NOT_READY;        } else            return SIMPLE_ERR_NOT_READY;    case SCSI_SK_MEDIUM_ERROR:    case SCSI_SK_HARDWARE_ERROR:        return SIMPLE_ERR_MEDIUM_HARDWARE;    case SCSI_SK_ILLEGAL_REQUEST:        if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc)            return SIMPLE_ERR_BAD_OPCODE;        else if (SCSI_ASC_UNKNOWN_FIELD == sinfo->asc)            return SIMPLE_ERR_BAD_FIELD;        else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc)            return SIMPLE_ERR_BAD_PARAM;        else            return SIMPLE_ERR_BAD_PARAM;    /* all other illegal request */    case SCSI_SK_UNIT_ATTENTION:        return SIMPLE_ERR_TRY_AGAIN;    case SCSI_SK_ABORTED_COMMAND:        return SIMPLE_ERR_ABORTED_COMMAND;    default:        return SIMPLE_ERR_UNKNOWN;    }}const char * scsiErrString(int scsiErr){    if (scsiErr < 0)        return strerror(-scsiErr);    switch (scsiErr) {        case SIMPLE_NO_ERROR:             return "no error";        case SIMPLE_ERR_NOT_READY:             return "device not ready";        case SIMPLE_ERR_BAD_OPCODE:             return "unsupported scsi opcode";        case SIMPLE_ERR_BAD_FIELD:             return "unsupported field in scsi command";        case SIMPLE_ERR_BAD_PARAM:             return "badly formed scsi parameters";        case SIMPLE_ERR_BAD_RESP:             return "scsi response fails sanity test";        case SIMPLE_ERR_NO_MEDIUM:             return "no medium present";        case SIMPLE_ERR_BECOMING_READY:             return "device will be ready soon";        case SIMPLE_ERR_TRY_AGAIN:             return "unit attention reported, try again";        case SIMPLE_ERR_MEDIUM_HARDWARE:             return "medium or hardware error (serious)";        case SIMPLE_ERR_UNKNOWN:             return "unknown error (unexpected sense key)";        case SIMPLE_ERR_ABORTED_COMMAND:             return "aborted command";        default:            return "unknown error";    }}/* Sends LOG SENSE command. Returns 0 if ok, 1 if device NOT READY, 2 if   command not supported, 3 if field (within command) not supported or   returns negated errno.  SPC-3 sections 6.6 and 7.2 (rec 22a).   N.B. Sets PC==1 to fetch "current cumulative" log pages.   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   first to deduce the response length, then send the same command again   requesting the deduced response length. This protects certain fragile    HBAs. The twin fetch technique should not be used with the TapeAlert   log page since it clears its state flags after each fetch. */int scsiLogSense(int device, int pagenum, int subpagenum, UINT8 *pBuf,                 int bufLen, int known_resp_len){    struct scsi_cmnd_io io_hdr;    struct scsi_sense_disect sinfo;    UINT8 cdb[10];    UINT8 sense[32];    int pageLen;    int status, res;    if (known_resp_len > bufLen)        return -EIO;    if (known_resp_len > 0)        pageLen = known_resp_len;    else {        /* Starting twin fetch strategy: first fetch to find respone length */        pageLen = 4;        if (pageLen > bufLen)            return -EIO;        else            memset(pBuf, 0, pageLen);        memset(&io_hdr, 0, sizeof(io_hdr));        memset(cdb, 0, sizeof(cdb));        io_hdr.dxfer_dir = DXFER_FROM_DEVICE;        io_hdr.dxfer_len = pageLen;        io_hdr.dxferp = pBuf;        cdb[0] = LOG_SENSE;        cdb[2] = 0x40 | (pagenum & 0x3f);  /* Page control (PC)==1 */        cdb[3] = subpagenum;        cdb[7] = (pageLen >> 8) & 0xff;        cdb[8] = pageLen & 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;            status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);        if (0 != status)            return status;        scsi_do_sense_disect(&io_hdr, &sinfo);        if ((res = scsiSimpleSenseFilter(&sinfo)))            return res;        /* sanity check on response */        if ((SUPPORTED_LPAGES != pagenum) && (pBuf[0] != pagenum))            return SIMPLE_ERR_BAD_RESP;        if (0 == ((pBuf[2] << 8) + pBuf[3]))            return SIMPLE_ERR_BAD_RESP;        pageLen = (pBuf[2] << 8) + pBuf[3] + 4;        if (4 == pageLen)  /* why define a lpage with no payload? */            pageLen = 252; /* some IBM tape drives don't like double fetch */        /* some SCSI HBA don't like "odd" length transfers */        if (pageLen % 2)            pageLen += 1;           if (pageLen > bufLen)            pageLen = bufLen;    }    memset(pBuf, 0, 4);    memset(&io_hdr, 0, sizeof(io_hdr));    memset(cdb, 0, sizeof(cdb));    io_hdr.dxfer_dir = DXFER_FROM_DEVICE;    io_hdr.dxfer_len = pageLen;    io_hdr.dxferp = pBuf;    cdb[0] = LOG_SENSE;    cdb[2] = 0x40 | (pagenum & 0x3f);  /* Page control (PC)==1 */    cdb[7] = (pageLen >> 8) & 0xff;    cdb[8] = pageLen & 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;    status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl);    if (0 != status)        return status;    scsi_do_sense_disect(&io_hdr, &sinfo);    status = scsiSimpleSenseFilter(&sinfo);    if (0 != status)        return status;    /* sanity check on response */    if ((SUPPORTED_LPAGES != pagenum) && (pBuf[0] != pagenum))        return SIMPLE_ERR_BAD_RESP;    if (0 == ((pBuf[2] << 8) + pBuf[3]))        return SIMPLE_ERR_BAD_RESP;    return 0;}/* 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), * 3 if field in command not supported or returns negated errno.  * SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -