📄 scsiata.cpp
字号:
/* * scsiata.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2006 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. * * The code in this file is based on the SCSI to ATA Translation (SAT) * draft found at http://www.t10.org . The original draft used for this * code is sat-r08.pdf which is not too far away from becoming a * standard. The SAT commands of interest to smartmontools are the * ATA PASS THROUGH SCSI (16) and ATA PASS THROUGH SCSI (12) defined in * section 12 of that document. * * With more transports "hiding" SATA disks (and other S-ATAPI devices) * behind a SCSI command set, accessing special features like SMART * information becomes a challenge. The SAT standard offers ATA PASS * THROUGH commands for special usages. Note that the SAT layer may * be inside a generic OS layer (e.g. libata in linux), in a host * adapter (HA or HBA) firmware, or somewhere on the interconnect * between the host computer and the SATA devices (e.g. a RAID made * of SATA disks and the RAID talks "SCSI" to the host computer). * Note that in the latter case, this code does not solve the * addressing issue (i.e. which SATA disk to address behind the logical * SCSI (RAID) interface). * */#include <stdio.h>#include <string.h>#include "config.h"#include "int64.h"#include "extern.h"#include "scsicmds.h"#include "scsiata.h"#include "utility.h"const char *scsiata_c_cvsid="$Id: scsiata.cpp,v 1.8 2007/12/03 02:14:20 dpgilbert Exp $"CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID SCSIATA_H_CVSID UTILITY_H_CVSID;/* for passing global control variables */extern smartmonctrl *con;#define DEF_SAT_ATA_PASSTHRU_SIZE 16#define ATA_RETURN_DESCRIPTOR 9// cdb[0]: ATA PASS THROUGH (16) SCSI command opcode byte (0x85)// cdb[1]: multiple_count, protocol + extend// cdb[2]: offline, ck_cond, t_dir, byte_block + t_length// cdb[3]: features (15:8)// cdb[4]: features (7:0)// cdb[5]: sector_count (15:8)// cdb[6]: sector_count (7:0)// cdb[7]: lba_low (15:8)// cdb[8]: lba_low (7:0)// cdb[9]: lba_mid (15:8)// cdb[10]: lba_mid (7:0)// cdb[11]: lba_high (15:8)// cdb[12]: lba_high (7:0)// cdb[13]: device// cdb[14]: (ata) command// cdb[15]: control (SCSI, leave as zero)//// 24 bit lba (from MSB): cdb[12] cdb[10] cdb[8]// 48 bit lba (from MSB): cdb[11] cdb[9] cdb[7] cdb[12] cdb[10] cdb[8]////// cdb[0]: ATA PASS THROUGH (12) SCSI command opcode byte (0xa1)// cdb[1]: multiple_count, protocol + extend// cdb[2]: offline, ck_cond, t_dir, byte_block + t_length// cdb[3]: features (7:0)// cdb[4]: sector_count (7:0)// cdb[5]: lba_low (7:0)// cdb[6]: lba_mid (7:0)// cdb[7]: lba_high (7:0)// cdb[8]: device// cdb[9]: (ata) command// cdb[10]: reserved// cdb[11]: control (SCSI, leave as zero)////// ATA Return Descriptor (component of descriptor sense data)// des[0]: descriptor code (0x9)// des[1]: additional descriptor length (0xc)// des[2]: extend (bit 0)// des[3]: error// des[4]: sector_count (15:8)// des[5]: sector_count (7:0)// des[6]: lba_low (15:8)// des[7]: lba_low (7:0)// des[8]: lba_mid (15:8)// des[9]: lba_mid (7:0)// des[10]: lba_high (15:8)// des[11]: lba_high (7:0)// des[12]: device// des[13]: status// PURPOSE// This interface routine takes ATA SMART commands and packages// them in the SAT-defined ATA PASS THROUGH SCSI commands. There are// two available SCSI commands: a 12 byte and 16 byte variant; the// one used is chosen via con->satpassthrulen .// DETAILED DESCRIPTION OF ARGUMENTS// device: is the file descriptor provided by (a SCSI dvice type) open()// command: defines the different ATA operations.// select: additional input data if needed (which log, which type of// self-test).// data: location to write output data, if needed (512 bytes).// Note: not all commands use all arguments.// RETURN VALUES// -1 if the command failed// 0 if the command succeeded,// STATUS_CHECK routine: // -1 if the command failed// 0 if the command succeeded and disk SMART status is "OK"// 1 if the command succeeded and disk SMART status is "FAILING"int sat_command_interface(int device, smart_command_set command, int select, char *data){ struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; struct sg_scsi_sense_hdr ssh; unsigned char cdb[SAT_ATA_PASSTHROUGH_16LEN]; unsigned char sense[32]; const unsigned char * ardp; int status, ard_len, have_sense; int copydata = 0; int outlen = 0; int extend = 0; int ck_cond = 0; /* set to 1 to read register(s) back */ int protocol = 3; /* non-data */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int t_length = 0; /* 0 -> no data transferred */ int feature = 0; int ata_command = 0; int sector_count = 0; int lba_low = 0; int lba_mid = 0; int lba_high = 0; int passthru_size = DEF_SAT_ATA_PASSTHRU_SIZE; memset(cdb, 0, sizeof(cdb)); memset(sense, 0, sizeof(sense)); ata_command = ATA_SMART_CMD; switch (command) { case CHECK_POWER_MODE: ata_command = ATA_CHECK_POWER_MODE; ck_cond = 1; copydata = 1; break; case READ_VALUES: /* READ DATA */ feature = ATA_SMART_READ_VALUES; sector_count = 1; /* one (512 byte) block */ protocol = 4; /* PIO data-in */ t_length = 2; /* sector count holds count */ copydata = 512; break; case READ_THRESHOLDS: /* obsolete */ feature = ATA_SMART_READ_THRESHOLDS; sector_count = 1; /* one (512 byte) block */ lba_low = 1; protocol = 4; /* PIO data-in */ t_length = 2; /* sector count holds count */ copydata=512; break; case READ_LOG: feature = ATA_SMART_READ_LOG_SECTOR; sector_count = 1; /* one (512 byte) block */ lba_low = select; protocol = 4; /* PIO data-in */ t_length = 2; /* sector count holds count */ copydata = 512; break; case WRITE_LOG: feature = ATA_SMART_WRITE_LOG_SECTOR; sector_count = 1; /* one (512 byte) block */ lba_low = select; protocol = 5; /* PIO data-out */ t_length = 2; /* sector count holds count */ t_dir = 0; /* to device */ outlen = 512; break; case IDENTIFY: ata_command = ATA_IDENTIFY_DEVICE; sector_count = 1; /* one (512 byte) block */ protocol = 4; /* PIO data-in */ t_length = 2; /* sector count holds count */ copydata = 512; break; case PIDENTIFY: ata_command = ATA_IDENTIFY_PACKET_DEVICE; sector_count = 1; /* one (512 byte) block */ protocol = 4; /* PIO data-in */ t_length = 2; /* sector count (7:0) holds count */ copydata = 512; break; case ENABLE: feature = ATA_SMART_ENABLE; lba_low = 1; break; case DISABLE: feature = ATA_SMART_DISABLE; lba_low = 1; break; case STATUS: // this command only says if SMART is working. It could be // replaced with STATUS_CHECK below. feature = ATA_SMART_STATUS; ck_cond = 1; break; case AUTO_OFFLINE:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -