summaryrefslogtreecommitdiffstats
path: root/os_qnxnto.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--os_qnxnto.cpp542
1 files changed, 542 insertions, 0 deletions
diff --git a/os_qnxnto.cpp b/os_qnxnto.cpp
new file mode 100644
index 0000000..677e559
--- /dev/null
+++ b/os_qnxnto.cpp
@@ -0,0 +1,542 @@
+/*
+ * 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);
+}
+//----------------------------------------------------------------------------------------------