mirror of
https://git.proxmox.com/git/mirror_smartmontools-debian
synced 2025-04-30 15:50:58 +00:00

Downloaded source from https://sourceforge.net/projects/smartmontools/files/smartmontools/7.0/ and imported here to git. Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
543 lines
21 KiB
C++
543 lines
21 KiB
C++
/*
|
|
* os_qnxnto.cpp
|
|
*
|
|
* Home page of code is: http://www.smartmontools.org
|
|
*
|
|
* Copyright (C) 2007 Joerg Hering
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
// This is needed for the various HAVE_* macros and PROJECT_* macros.
|
|
#include "config.h"
|
|
|
|
// These are needed to define prototypes and structures for the
|
|
// functions defined below
|
|
#include "atacmds.h"
|
|
#include "scsicmds.h"
|
|
#include "utility.h"
|
|
|
|
// This is to include whatever structures and prototypes you define in
|
|
// os_generic.h
|
|
#include "os_qnxnto.h"
|
|
#include <errno.h>
|
|
|
|
// Needed by '-V' option (CVS versioning) of smartd/smartctl. You
|
|
// should have one *_H_CVSID macro appearing below for each file
|
|
// appearing with #include "*.h" above. Please list these (below) in
|
|
// alphabetic/dictionary order.
|
|
const char *os_XXXX_c_cvsid="$Id: os_qnxnto.cpp 4842 2018-12-02 16:07:26Z chrfranke $" \
|
|
ATACMDS_H_CVSID CONFIG_H_CVSID OS_QNXNTO_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
|
|
|
|
|
|
// This is here to prevent compiler warnings for unused arguments of
|
|
// functions.
|
|
#define ARGUSED(x) ((void)(x))
|
|
|
|
//----------------------------------------------------------------------------------------------
|
|
// private Functions
|
|
static int ata_sense_data(void *sdata,int *error,int *key,int *asc,int *ascq);
|
|
static int ata_interpret_sense(struct cam_pass_thru *cpt,void *sense,int *status,int rcount);
|
|
static int ata_pass_thru(int fd,struct cam_pass_thru *pcpt);
|
|
|
|
// print examples for smartctl. You should modify this function so
|
|
// that the device paths are sensible for your OS, and to eliminate
|
|
// unsupported commands (eg, 3ware controllers).
|
|
void print_smartctl_examples(){
|
|
printf("=================================================== SMARTCTL EXAMPLES =====\n\n"
|
|
" smartctl -a /dev/hd0 (Prints all SMART information)\n\n"
|
|
" smartctl --smart=on --offlineauto=on --saveauto=on /dev/hd0\n"
|
|
" (Enables SMART on first disk)\n\n"
|
|
" smartctl -t long /dev/hd0 (Executes extended disk self-test)\n\n"
|
|
" smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hd0\n"
|
|
" (Prints Self-Test & Attribute errors)\n"
|
|
" smartctl -a --device=3ware,2 /dev/sda\n"
|
|
" (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n"
|
|
);
|
|
return;
|
|
}
|
|
|
|
// tries to guess device type given the name (a path). See utility.h
|
|
// for return values.
|
|
static const char *net_dev_prefix = "/dev/";
|
|
static const char *net_dev_ata_disk = "hd";
|
|
|
|
int guess_device_type (const char* dev_name)
|
|
{
|
|
int len,dev_prefix_len;
|
|
dev_prefix_len=strlen(net_dev_prefix);
|
|
if(!dev_name||!(len=strlen(dev_name)))
|
|
return(CONTROLLER_UNKNOWN);
|
|
if (!strncmp(net_dev_prefix,dev_name,dev_prefix_len))
|
|
{
|
|
if(len<=dev_prefix_len)
|
|
return(CONTROLLER_UNKNOWN);
|
|
else
|
|
dev_name += dev_prefix_len;
|
|
}
|
|
if(!strncmp(net_dev_ata_disk,dev_name,strlen(net_dev_ata_disk)))
|
|
return(CONTROLLER_ATA);
|
|
return(CONTROLLER_UNKNOWN);
|
|
}
|
|
|
|
// makes a list of ATA or SCSI devices for the DEVICESCAN directive of
|
|
// smartd. Returns number N of devices, or -1 if out of
|
|
// memory. Allocates N+1 arrays: one of N pointers (devlist); the
|
|
// other N arrays each contain null-terminated character strings. In
|
|
// the case N==0, no arrays are allocated because the array of 0
|
|
// pointers has zero length, equivalent to calling malloc(0).
|
|
int make_device_names (char*** devlist, const char* name) {
|
|
ARGUSED(devlist);
|
|
ARGUSED(name);
|
|
return 0;
|
|
}
|
|
|
|
// Like open(). Return non-negative integer handle, only used by the
|
|
// functions below. type=="ATA" or "SCSI". If you need to store
|
|
// extra information about your devices, create a private internal
|
|
// array within this file (see os_freebsd.cpp for an example). If you
|
|
// can not open the device (permission denied, does not exist, etc)
|
|
// set errno as open() does and return <0.
|
|
int deviceopen(const char *pathname, char *type)
|
|
{
|
|
if(!strcmp(type, "ATA"))
|
|
return(open(pathname,O_RDWR|O_NONBLOCK));
|
|
else
|
|
return(-1);
|
|
}
|
|
|
|
// Like close(). Acts only on integer handles returned by
|
|
// deviceopen() above.
|
|
int deviceclose(int fd)
|
|
{
|
|
return(close(fd));
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|
|
// Interface to ATA devices. See os_linux.cpp for the canonical example.
|
|
// DETAILED DESCRIPTION OF ARGUMENTS
|
|
// device: is the integer handle provided by deviceopen()
|
|
// command: defines the different operations, see atacmds.h
|
|
// select: additional input data IF NEEDED (which log, which type of
|
|
// self-test).
|
|
// data: location to write output data, IF NEEDED (1 or 512 bytes).
|
|
// Note: not all commands use all arguments.
|
|
// RETURN VALUES (for all commands BUT command==STATUS_CHECK)
|
|
// -1 if the command failed
|
|
// 0 if the command succeeded,
|
|
// RETURN VALUES if command==STATUS_CHECK
|
|
// -1 if the command failed OR the disk SMART status can't be determined
|
|
// 0 if the command succeeded and disk SMART status is "OK"
|
|
// 1 if the command succeeded and disk SMART status is "FAILING"
|
|
int ata_command_interface(int fd,smart_command_set command,int select,char *data)
|
|
{
|
|
struct cam_pass_thru cpt;
|
|
ATA_SENSE sense;
|
|
CDB *cdb;
|
|
int status,rc;
|
|
memset(&cpt,0x00,sizeof(struct cam_pass_thru));
|
|
cdb=(CDB *)cpt.cam_cdb;
|
|
rc=-1;
|
|
switch(command)
|
|
{
|
|
case READ_VALUES:
|
|
cpt.cam_flags = CAM_DIR_IN;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_dxfer_len = 512;
|
|
cpt.cam_data_ptr = (uint32_t)data;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN;
|
|
cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU;
|
|
cdb->ata_pass_thru.command = ATA_SMART_CMD;
|
|
cdb->ata_pass_thru.features = ATA_SMART_READ_VALUES;
|
|
cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG;
|
|
cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG;
|
|
break;
|
|
case READ_THRESHOLDS:
|
|
cpt.cam_flags = CAM_DIR_IN;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_dxfer_len = 512;
|
|
cpt.cam_data_ptr = (uint32_t)data;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN;
|
|
cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU;
|
|
cdb->ata_pass_thru.command = ATA_SMART_CMD;
|
|
cdb->ata_pass_thru.features = ATA_SMART_READ_THRESHOLDS;
|
|
cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG;
|
|
cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG;
|
|
break;
|
|
case READ_LOG:
|
|
cpt.cam_flags = CAM_DIR_IN;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_dxfer_len = 512;
|
|
cpt.cam_data_ptr = (uint32_t)data;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN;
|
|
cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU;
|
|
cdb->ata_pass_thru.command = ATA_SMART_CMD;
|
|
cdb->ata_pass_thru.features = ATA_SMART_READ_LOG_SECTOR;
|
|
cdb->ata_pass_thru.sector_count= 1;
|
|
cdb->ata_pass_thru.lba_low = select;
|
|
cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG;
|
|
cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG;
|
|
break;
|
|
case WRITE_LOG:
|
|
return(-1);
|
|
break;
|
|
case IDENTIFY:
|
|
cpt.cam_flags = CAM_DIR_IN;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_dxfer_len = 512;
|
|
cpt.cam_data_ptr = (uint32_t)data;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN;
|
|
cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU;
|
|
cdb->ata_pass_thru.command = ATA_IDENTIFY_DEVICE;
|
|
break;
|
|
case PIDENTIFY:
|
|
cpt.cam_flags = CAM_DIR_IN;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_dxfer_len = 512;
|
|
cpt.cam_data_ptr = (uint32_t)data;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN;
|
|
cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU;
|
|
cdb->ata_pass_thru.command = ATA_IDENTIFY_PACKET_DEVICE;
|
|
break;
|
|
case ENABLE:
|
|
cpt.cam_flags = CAM_DIR_NONE;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE;
|
|
cdb->ata_pass_thru.command = ATA_SMART_CMD;
|
|
cdb->ata_pass_thru.features = ATA_SMART_ENABLE;
|
|
cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG;
|
|
cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG;
|
|
break;
|
|
case DISABLE:
|
|
cpt.cam_flags = CAM_DIR_NONE;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE;
|
|
cdb->ata_pass_thru.command = ATA_SMART_CMD;
|
|
cdb->ata_pass_thru.features = ATA_SMART_DISABLE;
|
|
cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG;
|
|
cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG;
|
|
break;
|
|
case AUTO_OFFLINE:
|
|
// NOTE: According to ATAPI 4 and UP, this command is obsolete
|
|
cpt.cam_flags = CAM_DIR_NONE;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE;
|
|
cdb->ata_pass_thru.command = ATA_SMART_CMD;
|
|
cdb->ata_pass_thru.features = ATA_SMART_AUTO_OFFLINE;
|
|
cdb->ata_pass_thru.lba_low = select;
|
|
cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG;
|
|
cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG;
|
|
break;
|
|
case AUTOSAVE:
|
|
cpt.cam_flags = CAM_DIR_NONE;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE;
|
|
cdb->ata_pass_thru.command = ATA_SMART_CMD;
|
|
cdb->ata_pass_thru.features = ATA_SMART_AUTOSAVE;
|
|
cdb->ata_pass_thru.sector_count= select;
|
|
cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG;
|
|
cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG;
|
|
break;
|
|
case IMMEDIATE_OFFLINE:
|
|
// NOTE: According to ATAPI 4 and UP, this command is obsolete
|
|
cpt.cam_flags = CAM_DIR_NONE;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE;
|
|
cdb->ata_pass_thru.command = ATA_SMART_CMD;
|
|
cdb->ata_pass_thru.features = ATA_SMART_IMMEDIATE_OFFLINE;
|
|
cdb->ata_pass_thru.lba_low = select;
|
|
cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG;
|
|
cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG;
|
|
break;
|
|
case STATUS_CHECK:
|
|
// same command, no HDIO in NetBSD
|
|
case STATUS:
|
|
cpt.cam_flags = CAM_DIR_NONE;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE;
|
|
cdb->ata_pass_thru.flags = ATA_FLG_CK_COND;
|
|
cdb->ata_pass_thru.command = ATA_SMART_CMD;
|
|
cdb->ata_pass_thru.features = ATA_SMART_STATUS;
|
|
cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG;
|
|
cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG;
|
|
break;
|
|
case CHECK_POWER_MODE:
|
|
cpt.cam_flags = CAM_DIR_NONE;
|
|
cpt.cam_cdb_len = 16;
|
|
cpt.cam_sense_len = sizeof(sense);
|
|
cpt.cam_sense_ptr = (uint32_t)&sense;
|
|
cdb->ata_pass_thru.opcode = SC_ATA_PT16;
|
|
cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE;
|
|
cdb->ata_pass_thru.flags = ATA_FLG_CK_COND;
|
|
cdb->ata_pass_thru.command = ATA_CHECK_POWER_MODE;
|
|
break;
|
|
default:
|
|
pout("Unrecognized command %d in ata_command_interface()\n", command);
|
|
errno=ENOSYS;
|
|
return(-1);
|
|
}
|
|
// execute now
|
|
if((status=ata_pass_thru(fd,&cpt))==EOK)
|
|
{
|
|
rc=status==EOK?0:-1;
|
|
if(cpt.cam_status!=CAM_REQ_CMP)
|
|
{
|
|
ata_interpret_sense(&cpt,&sense,&status,0);
|
|
if(command==STATUS||command==STATUS_CHECK)
|
|
rc=((sense.desc.lba_high<<8)|sense.desc.lba_mid)==ATA_SMART_SIG?0:1;
|
|
}
|
|
}
|
|
if(command==CHECK_POWER_MODE)
|
|
data[0]=cdb->ata_pass_thru.sector_count;
|
|
// finish
|
|
return(rc);
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|
|
// Interface to SCSI devices. See os_linux.c
|
|
int do_scsi_cmnd_io(int fd,struct scsi_cmnd_io * iop,int report)
|
|
{
|
|
ARGUSED(fd);
|
|
ARGUSED(iop);
|
|
ARGUSED(report);
|
|
return -ENOSYS;
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------------------
|
|
static int ata_sense_data(void *sdata,int *error,int *key,int *asc,int *ascq)
|
|
{
|
|
SCSI_SENSE *sf;
|
|
SCSI_SENSE_DESCRIPTOR *sd;
|
|
sf=(SCSI_SENSE *)sdata;
|
|
sd=(SCSI_SENSE_DESCRIPTOR *)sdata;
|
|
*error=sf->error;
|
|
if(*error & SENSE_DATA_FMT_DESCRIPTOR)
|
|
{
|
|
*key=sd->sense & SK_MSK;
|
|
*asc=sd->asc;
|
|
*ascq=sd->ascq;
|
|
}
|
|
else
|
|
{
|
|
*key=sf->sense & SK_MSK;
|
|
*asc=sf->asc;
|
|
*ascq=sf->ascq;
|
|
}
|
|
return(CAM_SUCCESS);
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|
|
static int ata_interpret_sense(struct cam_pass_thru *cpt,void *sense,int *status,int rcount)
|
|
{
|
|
int retry;
|
|
int key;
|
|
int asc;
|
|
int ascq;
|
|
int error;
|
|
*status=EIO;
|
|
retry=CAM_TRUE;
|
|
if(cpt->cam_status&CAM_AUTOSNS_VALID)
|
|
{
|
|
ata_sense_data(sense,&error,&key,&asc,&ascq);
|
|
switch(key)
|
|
{
|
|
case SK_NO_SENSE: // No sense data (no error)
|
|
retry=CAM_FALSE;
|
|
*status=EOK;
|
|
break;
|
|
case SK_RECOVERED: // Recovered error
|
|
switch(asc)
|
|
{
|
|
case ASC_ATA_PASS_THRU:
|
|
switch(ascq)
|
|
{
|
|
case ASCQ_ATA_PASS_THRU_INFO_AVAIL:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
retry=CAM_FALSE;
|
|
*status=EOK;
|
|
break;
|
|
case SK_NOT_RDY: // Device not ready
|
|
*status=EAGAIN;
|
|
switch(asc)
|
|
{
|
|
case ASC_NOT_READY:
|
|
switch(ascq)
|
|
{
|
|
case ASCQ_BECOMING_READY:
|
|
case ASCQ_CAUSE_NOT_REPORTABLE:
|
|
default:
|
|
retry=CAM_FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
case ASC_MEDIA_NOT_PRESENT:
|
|
*status=ENXIO;
|
|
retry=CAM_FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
case SK_MEDIUM: // Medium error
|
|
case SK_HARDWARE: // Hardware error
|
|
retry=CAM_FALSE;
|
|
*status=EIO;
|
|
break;
|
|
case SK_ILLEGAL: // Illegal Request (bad command)
|
|
retry=CAM_FALSE;
|
|
*status=EINVAL;
|
|
break;
|
|
case SK_UNIT_ATN: // Unit Attention
|
|
switch(asc)
|
|
{
|
|
case ASC_MEDIUM_CHANGED:
|
|
*status=ESTALE;
|
|
retry=CAM_FALSE;
|
|
break;
|
|
case ASC_BUS_RESET:
|
|
break;
|
|
}
|
|
break;
|
|
case SK_DATA_PROT: // Data Protect
|
|
retry=CAM_FALSE;
|
|
*status=EROFS;
|
|
break;
|
|
case SK_VENDOR: // Vendor Specific
|
|
case SK_CPY_ABORT: // Copy Aborted
|
|
retry=CAM_FALSE;
|
|
*status=EIO;
|
|
break;
|
|
case SK_CMD_ABORT: // Aborted Command
|
|
retry=CAM_FALSE;
|
|
*status=ECANCELED;
|
|
break;
|
|
case SK_EQUAL: // Equal
|
|
case SK_VOL_OFL: // Volume Overflow
|
|
case SK_MISCMP: // Miscompare
|
|
case SK_RESERVED: // Reserved
|
|
break;
|
|
}
|
|
if(*status==EOK)
|
|
{
|
|
switch(cpt->cam_status&CAM_STATUS_MASK)
|
|
{
|
|
case CAM_REQ_CMP_ERR: // CCB request completed with an err
|
|
retry=CAM_FALSE;
|
|
*status=EIO;
|
|
break;
|
|
case CAM_BUSY: // CAM subsystem is busy
|
|
*status=EAGAIN;
|
|
break;
|
|
case CAM_REQ_INVALID: // CCB request is invalid
|
|
case CAM_PATH_INVALID: // Path ID supplied is invalid
|
|
case CAM_DEV_NOT_THERE: // SCSI device not installed/there
|
|
case CAM_SEL_TIMEOUT: // Target selection timeout
|
|
case CAM_LUN_INVALID: // LUN supplied is invalid
|
|
case CAM_TID_INVALID: // Target ID supplied is invalid
|
|
retry=CAM_FALSE;
|
|
*status=ENXIO;
|
|
break;
|
|
case CAM_CMD_TIMEOUT: // Command timeout
|
|
*status=rcount?EAGAIN:EIO;
|
|
break;
|
|
case CAM_MSG_REJECT_REC: // Message reject received
|
|
case CAM_SCSI_BUS_RESET: // SCSI bus reset sent/received
|
|
case CAM_UNCOR_PARITY: // Uncorrectable parity err occurred
|
|
case CAM_AUTOSENSE_FAIL: // Autosense: Request sense cmd fail
|
|
case CAM_NO_HBA: // No HBA detected Error
|
|
case CAM_DATA_RUN_ERR: // Data overrun/underrun error
|
|
retry=CAM_FALSE;
|
|
*status=EIO;
|
|
break;
|
|
case CAM_UNEXP_BUSFREE: // Unexpected BUS free
|
|
case CAM_SEQUENCE_FAIL: // Target bus phase sequence failure
|
|
*status=EIO;
|
|
break;
|
|
case CAM_PROVIDE_FAIL: // Unable to provide requ. capability
|
|
retry=CAM_FALSE;
|
|
*status=ENOTTY;
|
|
break;
|
|
case CAM_CCB_LEN_ERR: // CCB length supplied is inadequate
|
|
case CAM_BDR_SENT: // A SCSI BDR msg was sent to target
|
|
case CAM_REQ_TERMIO: // CCB request terminated by the host
|
|
case CAM_FUNC_NOTAVAIL: // The requ. func is not available
|
|
case CAM_NO_NEXUS: // Nexus is not established
|
|
case CAM_IID_INVALID: // The initiator ID is invalid
|
|
case CAM_CDB_RECVD: // The SCSI CDB has been received
|
|
retry=CAM_FALSE;
|
|
*status=EIO;
|
|
break;
|
|
case CAM_SCSI_BUSY: // SCSI bus busy
|
|
*status=EAGAIN;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return(retry);
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|
|
static int ata_pass_thru(int fd,struct cam_pass_thru *pcpt)
|
|
{
|
|
int icnt;
|
|
int status;
|
|
iov_t iov[3];
|
|
struct cam_pass_thru cpt;
|
|
cpt=*pcpt;
|
|
icnt=1;
|
|
SETIOV(&iov[0],&cpt,sizeof(cpt));
|
|
cpt.cam_timeout=cpt.cam_timeout?cpt.cam_timeout:CAM_TIME_DEFAULT;
|
|
if(cpt.cam_sense_len)
|
|
{
|
|
SETIOV(&iov[1],(void *)cpt.cam_sense_ptr,cpt.cam_sense_len);
|
|
cpt.cam_sense_ptr=sizeof(cpt);
|
|
icnt++;
|
|
}
|
|
if(cpt.cam_dxfer_len)
|
|
{
|
|
SETIOV(&iov[2],(void *)cpt.cam_data_ptr,cpt.cam_dxfer_len);
|
|
cpt.cam_data_ptr=(paddr_t)sizeof(cpt)+cpt.cam_sense_len;
|
|
icnt++;
|
|
}
|
|
if((status=devctlv(fd,DCMD_CAM_PASS_THRU,icnt,icnt,iov,iov,NULL)))
|
|
pout("ata_pass_thru devctl: %s\n",strerror(status));
|
|
pcpt->cam_status=cpt.cam_status;
|
|
pcpt->cam_scsi_status=cpt.cam_scsi_status;
|
|
return(status);
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|