use libc::{c_void, memcpy};
use cam::{*, bindings::*};
use Direction;
use scsi::SCSIDevice;
use std::io;
impl SCSIDevice {
pub(crate) fn do_platform_cmd(&self, cmd: &[u8], dir: Direction, sense_len: usize, data_len: usize)-> Result<(Vec<u8>, Vec<u8>), io::Error> {
let mut sense = vec![0; sense_len];
let mut data = vec![0; data_len];
let timeout = 10;
let dev = &self.device.dev;
let ccb: CCB = CCB::new(dev);
unsafe {
let csio = ccb.csio();
csio.ccb_h.func_code = xpt_opcode_XPT_SCSI_IO;
csio.ccb_h.flags = {
use self::Direction::*;
match dir {
From => ccb_flags_CAM_DIR_IN,
To => unimplemented!(), Both => unimplemented!(), None => ccb_flags_CAM_DIR_NONE,
}
};
csio.ccb_h.xflags = 0;
csio.ccb_h.retry_count = 1;
csio.ccb_h.timeout = timeout*1000;
csio.data_ptr = data.as_mut_ptr();
csio.dxfer_len = data.capacity() as u32;
csio.sense_len = sense.capacity() as u8;
csio.tag_action = MSG_SIMPLE_Q_TAG as u8;
#[allow(trivial_casts)] memcpy(
&mut csio.cdb_io.cdb_bytes as *mut _ as *mut c_void,
cmd.as_ptr() as *const c_void,
cmd.len(),
);
csio.cdb_len = cmd.len() as u8; }
dev.send_ccb(&ccb)?;
let status = ccb.get_status();
if !(status == cam_status_CAM_REQ_CMP || status == cam_status_CAM_SCSI_STATUS_ERROR) {
Err(error::from_status(dev, &ccb))?
}
let sense_len =
if (ccb.get_status_flags() & cam_status_CAM_AUTOSNS_VALID) != 0 {
unsafe {
let csio = ccb.csio();
#[allow(trivial_casts)] memcpy(
sense.as_mut_ptr() as *mut c_void,
&csio.sense_data as *const _ as *const c_void,
sense.capacity(),
);
csio.sense_len - csio.sense_resid
}
} else {
0 };
let data_len = unsafe {
ccb.csio().dxfer_len - ccb.csio().resid
};
Ok((
sense[ .. sense_len as usize].to_vec(),
data[ .. data_len as usize].to_vec(),
))
}
}