scsi_LnxSG Class Reference
[SCSI Library]

#include <scsi_lnxsg.h>

Inheritance diagram for scsi_LnxSG:

Inheritance graph
[legend]
Collaboration diagram for scsi_LnxSG:

Collaboration graph
[legend]

List of all members.


Detailed Description

Implementation of scsi_IO interface using Linux SCSI Generic (sg) driver.

Author:
Matej Kenda

Definition at line 28 of file scsi_lnxsg.h.


Public Member Functions

 scsi_LnxSG (const string &a_deviceID)
virtual ~scsi_LnxSG ()
virtual bool IsOpen ()
virtual void Close ()

Protected Member Functions

virtual void OpenByDeviceName ()
 Open SCSI device by its (platform specific!) name.
virtual void OpenBySCSIID ()
 Open SCSI device by its (current) SCSI ID.
virtual void OpenBySerialNumber ()
 Open SCSI device by its unique identification.
virtual void InqSCSIID ()
 Get SCSI ID of the currently opened device.
int DoIOCtl (const scsi_CDB &a_cdb, UInt32_t a_timeout)
 Function to actually execute CDB commands.
virtual scsi_Status_e GetCDBStatus ()
virtual void CheckDriverStatus (UInt8_t a_cdbCode)
 Checks the status of the driver after the execution of CDB.
virtual void CheckHostStatus (UInt8_t a_cdbCode)
 Checks the status of the host (if available) after the execution of CDB.
virtual bool IsSenseValid ()

Private Member Functions

void SGOpen (bool a_readOnly=false, bool a_excl=false)
bool Reset (int what)

Private Attributes

 log_CLASSID_m
int m_handle
sg_io_hdr_t m_ioHdr

Constructor & Destructor Documentation

scsi_LnxSG::scsi_LnxSG ( const string &  a_deviceID  ) 

Definition at line 43 of file scsi_lnxsg.cpp.

References log_FUNC_m.

00044     : scsi_IO(a_DeviceID),
00045       m_handle(-1) {
00046 
00047     log_FUNC_m(scsi_LnxSG);
00048 }

scsi_LnxSG::~scsi_LnxSG (  )  [virtual]

Definition at line 54 of file scsi_lnxsg.cpp.

References Close(), IsOpen(), log_FUNC_m, log_WRN_m, and scsi_IO::m_deviceName.

00054                         {
00055     log_FUNC_m(~scsi_LnxSG);
00056 
00057     if (IsOpen()) {
00058         log_WRN_m("Device not yet closed! Closing device " << m_deviceName);
00059         Close();
00060     }
00061 }

Here is the call graph for this function:


Member Function Documentation

bool scsi_LnxSG::IsOpen (  )  [virtual]

Implements scsi_IO.

Definition at line 50 of file scsi_lnxsg.cpp.

References m_handle.

Referenced by ~scsi_LnxSG().

00050                         {
00051     return (m_handle >= 0);
00052 }

Here is the caller graph for this function:

void scsi_LnxSG::Close (  )  [virtual]

Implements scsi_IO.

Definition at line 173 of file scsi_lnxsg.cpp.

References dbg_LOW, ie_SCSI_CLOSE, ivd_Error, log_DBG_m, log_FUNC_m, log_MARKLINE_m, scsi_IO::m_deviceID, and m_handle.

Referenced by ~scsi_LnxSG().

00173                       {
00174     log_FUNC_m(Close);
00175 
00176     log_DBG_m(dbg_LOW, "Closing device ID: " << m_deviceID);
00177 
00178     if (m_handle < 0) {
00179         log_MARKLINE_m;
00180         throw ivd_Error(ie_SCSI_CLOSE);
00181     }
00182     close(m_handle);
00183     m_handle = -1;
00184 }

Here is the caller graph for this function:

void scsi_LnxSG::OpenByDeviceName (  )  [protected, virtual]

Open SCSI device by its (platform specific!) name.

Implements scsi_IO.

Definition at line 63 of file scsi_lnxsg.cpp.

References dbg_LOW, InqSCSIID(), scsi_IO::InqSerialNumber(), scsi_IO::InqStandard(), log_DBG_m, log_FUNC_m, scsi_IO::m_deviceName, and SGOpen().

00063                                  {
00064     log_FUNC_m(OpenByDeviceName);
00065 
00066     log_DBG_m(dbg_LOW, "Opening device file: " << m_deviceName);
00067 
00068     SGOpen(false, true);
00069 
00070     InqSCSIID();
00071     InqStandard();
00072     InqSerialNumber();
00073 }

Here is the call graph for this function:

void scsi_LnxSG::OpenBySCSIID (  )  [protected, virtual]

Open SCSI device by its (current) SCSI ID.

Warning:
Implementations must take care to close the device if an error occurs.

Implements scsi_IO.

Definition at line 75 of file scsi_lnxsg.cpp.

References dbg_LOW, log_DBG_m, log_FUNC_m, scsi_IO::m_channel, scsi_IO::m_id, scsi_IO::m_lun, and scsi_IO::m_port.

00075                               {
00076     log_FUNC_m(OpenBySCSIID);
00077 
00078     log_DBG_m(dbg_LOW,
00079         "Opening SCSI ID: " <<
00080         m_port << ":" <<
00081         m_channel << ":" <<
00082         m_id << ":" <<
00083         m_lun);
00084 
00085 }

void scsi_LnxSG::OpenBySerialNumber (  )  [protected, virtual]

Open SCSI device by its unique identification.

Warning:
Implementations must take care to close the device if an error occurs.

Implements scsi_IO.

Definition at line 87 of file scsi_lnxsg.cpp.

References dbg_LOW, log_DBG_m, log_FUNC_m, scsi_IO::m_productID, scsi_IO::m_productSerialNumber, and scsi_IO::m_vendorID.

00087                                     {
00088     log_FUNC_m(OpenBySerialNumber);
00089 
00090     log_DBG_m(dbg_LOW,
00091         "Opening SCSI Serial #: " <<
00092         m_vendorID << ":" <<
00093         m_productID << ":" <<
00094         m_productSerialNumber);
00095 
00096 }

void scsi_LnxSG::InqSCSIID (  )  [protected, virtual]

Get SCSI ID of the currently opened device.

Implements scsi_IO.

Definition at line 291 of file scsi_lnxsg.cpp.

References dbg_EXTAPI, errno, scsi_IO::GetSCSIID(), log_DBG_m, log_FUNC_m, log_MARKLINE_m, scsi_IO::m_channel, m_handle, scsi_IO::m_id, scsi_IO::m_lun, scsi_IO::m_port, and scsi_IO::m_strSCSIID.

Referenced by OpenByDeviceName().

00291                            {
00292     log_FUNC_m(InqSCSIID);
00293 
00294     struct sg_scsi_id   scsiID;
00295 
00296     log_DBG_m(dbg_EXTAPI, "ioctl(.., SG_GET_SCSI_ID, ..)")
00297     int result = ioctl(m_handle, SG_GET_SCSI_ID, (void*)(&scsiID));
00298     if (result != 0) {
00299         log_MARKLINE_m;
00300         throw ivd_SysError(errno,
00301             "ioctl(.., SG_GET_SCSI_ID, ..) returned error");
00302     }
00303 
00304     m_port = scsiID.host_no;
00305     m_channel = scsiID.channel;
00306     m_id = scsiID.scsi_id;
00307     m_lun = scsiID.lun;
00308 
00309     m_strSCSIID = GetSCSIID();
00310 }

Here is the call graph for this function:

Here is the caller graph for this function:

int scsi_LnxSG::DoIOCtl ( const scsi_CDB a_cdb,
UInt32_t  a_timeout 
) [protected, virtual]

Function to actually execute CDB commands.

Returns:
result code of platform specific ioctl command.

Implements scsi_IO.

Definition at line 186 of file scsi_lnxsg.cpp.

References dbg_DETAIL, dbg_EXTAPI, errno, scsi_CDB::GetBufferPointer(), scsi_CDB::GetBufferSize(), scsi_CDB::GetCmdPointer(), scsi_CDB::GetCmdSize(), scsi_IO::GetSense(), scsi_IO::GetSenseSize(), scsi_CDB::GetTransferDirection(), log_DBG_m, log_FUNC_m, m_handle, m_ioHdr, scsi_IO::m_pdDirectMode, MIN_DIRECT_BUFFER_SIZE, op_READ_10, op_READ_6, op_WRITE_10, and op_WRITE_6.

00186                                                                  {
00187     log_FUNC_m(DoIOCtl);
00188 
00189     memset(&m_ioHdr, 0, sizeof(m_ioHdr));
00190     m_ioHdr.interface_id = static_cast<int>('S');
00191     m_ioHdr.dxfer_direction = a_cdb.GetTransferDirection();
00192 
00193     m_ioHdr.cmdp = const_cast<unsigned char*>(a_cdb.GetCmdPointer());
00194     m_ioHdr.cmd_len = a_cdb.GetCmdSize();
00195 
00196     // Don't use scatter-gather, we use direct IO, so set this to 0.
00197     m_ioHdr.iovec_count = 0;
00198 
00199     m_ioHdr.dxfer_len =
00200         static_cast<const unsigned int>(a_cdb.GetBufferSize());
00201 
00202     m_ioHdr.dxferp =
00203         reinterpret_cast<unsigned char *>(a_cdb.GetBufferPointer());
00204 
00205     // Set pointers to sense structure
00206     m_ioHdr.mx_sb_len = GetSenseSize();
00207     m_ioHdr.sbp =
00208         reinterpret_cast<UInt8_t*>(const_cast<data_Sense_t*>(GetSense()));
00209 
00210     UInt8_t cdbCode = a_cdb.GetCmdPointer()[0];
00211 
00212     if (cdbCode == op_READ_6 || cdbCode == op_READ_10 ||
00213         cdbCode == op_WRITE_6 || cdbCode == op_WRITE_10) {
00214         //
00215         // Do not transfer buffers from user space to kernel
00216         // space for larger blocks of data when doing read/write operations
00217         // (use direct IO instead).
00218         //
00219         // Direct IO can also be disabled via env variable SG_NO_DIO!
00220         //
00221         if (m_ioHdr.dxfer_len > MIN_DIRECT_BUFFER_SIZE && m_pdDirectMode) {
00222             m_ioHdr.flags |= SG_FLAG_DIRECT_IO;
00223         }
00224     };
00225 
00226     m_ioHdr.timeout = a_timeout;
00227 
00228     log_DBG_m(dbg_EXTAPI, "ioctl(.., SG_IO, ..)")
00229     int result = ioctl(m_handle, SG_IO, &m_ioHdr);
00230     if (result == -1) {
00231         log_DBG_m(dbg_DETAIL, "Return errno: " << errno)
00232         return errno;
00233     }
00234     else {
00235         log_DBG_m(dbg_DETAIL , "Return result: " << result)
00236         return result;
00237     }
00238 }

Here is the call graph for this function:

virtual scsi_Status_e scsi_LnxSG::GetCDBStatus (  )  [inline, protected, virtual]

Implements scsi_IO.

Definition at line 47 of file scsi_lnxsg.h.

References m_ioHdr, and st_STATUS_MASK.

Referenced by IsSenseValid().

00047                                          {
00048         return (scsi_Status_e)(m_ioHdr.status & st_STATUS_MASK);
00049     }

Here is the caller graph for this function:

void scsi_LnxSG::CheckDriverStatus ( UInt8_t  a_cdbCode  )  [protected, virtual]

Checks the status of the driver after the execution of CDB.

Reimplemented from scsi_IO.

Definition at line 240 of file scsi_lnxsg.cpp.

References dbg_NORM, DRIVER_MASK, evt_ERROR, ie_SCSI_DRIVER, ivd_Error, log_DBG_m, log_FUNC_m, log_MARKLINE_m, log_WriteEvent(), m_ioHdr, scsi_IO::m_strSCSIID, scsi_CommandSize(), scsi_GetOpcodeText(), SG_ERR_DRIVER_OK, and SG_ERR_DRIVER_SENSE.

00240                                                     {
00241     if ( m_ioHdr.driver_status                  == SG_ERR_DRIVER_OK   ||
00242         (m_ioHdr.driver_status & DRIVER_MASK)   == SG_ERR_DRIVER_SENSE) {
00243         return;
00244     }
00245     log_FUNC_m(CheckDriverStatus);
00246 
00247     ostringstream sstr;
00248     sstr
00249         << "Driver status code: "
00250         << hex << m_ioHdr.driver_status << dec
00251         << " CDB: " << scsi_GetOpcodeText(a_cdbCode);
00252 
00253     // Some Linux drivers report that they don't support large CDBs in
00254     // driver status.
00255     if (scsi_CommandSize(a_cdbCode) >= 16) {
00256         log_DBG_m(dbg_NORM, "Large CDB: " << sstr.str());
00257     }
00258     else {
00259         log_WriteEvent(evt_ERROR, sstr.str(), "SCSI", 0, m_strSCSIID);
00260     }
00261 
00262     log_MARKLINE_m;
00263     throw ivd_Error(ie_SCSI_DRIVER, sstr.str());
00264 }

Here is the call graph for this function:

void scsi_LnxSG::CheckHostStatus ( UInt8_t  a_cdbCode  )  [protected, virtual]

Checks the status of the host (if available) after the execution of CDB.

Reimplemented from scsi_IO.

Definition at line 266 of file scsi_lnxsg.cpp.

References dbg_NORM, evt_ERROR, ie_SCSI_HOST, ivd_Error, log_DBG_m, log_FUNC_m, log_MARKLINE_m, log_WriteEvent(), m_ioHdr, scsi_IO::m_strSCSIID, scsi_CommandSize(), scsi_GetOpcodeText(), and SG_ERR_DID_OK.

00266                                                   {
00267     if (m_ioHdr.host_status == SG_ERR_DID_OK) {
00268         return;
00269     }
00270     log_FUNC_m(CheckHostStatus);
00271 
00272     ostringstream sstr;
00273     sstr
00274         << "SCSI host status code: "
00275         << hex << m_ioHdr.host_status << dec
00276         << " CDB: " << scsi_GetOpcodeText(a_cdbCode);
00277 
00278     // Some Linux drivers report that they don't support large CDBs in
00279     // host status.
00280     if (scsi_CommandSize(a_cdbCode) >= 16) {
00281         log_DBG_m(dbg_NORM, "Large CDB: " << sstr.str());
00282     }
00283     else {
00284         log_WriteEvent(evt_ERROR, sstr.str(), "SCSI", 0, m_strSCSIID);
00285     }
00286 
00287     log_MARKLINE_m;
00288     throw ivd_Error(ie_SCSI_HOST, sstr.str());
00289 }

Here is the call graph for this function:

virtual bool scsi_LnxSG::IsSenseValid (  )  [inline, protected, virtual]

Implements scsi_IO.

Definition at line 53 of file scsi_lnxsg.h.

References GetCDBStatus(), m_ioHdr, SG_ERR_DRIVER_SENSE, st_BUSY, st_CHECK_CONDITION, and st_COMMAND_TERMINATED.

00053                                 {
00054         scsi_Status_e status    = GetCDBStatus();
00055         int           drvStatus = m_ioHdr.driver_status;
00056 
00057         if (status == st_CHECK_CONDITION ||
00058             status == st_COMMAND_TERMINATED ||
00059             status == st_BUSY ||
00060             drvStatus & SG_ERR_DRIVER_SENSE) {
00061             return true;
00062         }
00063         else {
00064             return false;
00065         }
00066     }

Here is the call graph for this function:

void scsi_LnxSG::SGOpen ( bool  a_readOnly = false,
bool  a_excl = false 
) [private]

Definition at line 98 of file scsi_lnxsg.cpp.

References dbg_DETAIL, dbg_EXTAPI, dbg_LOW, errno, ie_SCSI_OPEN, ivd_Error, ivd_Sleep, log_DBG_m, log_FUNC_m, log_MARKLINE_m, scsi_IO::m_deviceName, and m_handle.

Referenced by OpenByDeviceName().

00098                                                    {
00099     log_FUNC_m(SGOpen);
00100 
00101     if (m_handle >= 0) {
00102         //device already opened
00103         log_MARKLINE_m;
00104         throw ivd_Error(ie_SCSI_OPEN);
00105     }
00106 
00107     // Retry open 5 times
00108     for (int i = 5; i > 0; i--) {
00109         log_DBG_m(dbg_EXTAPI, "open(" << m_deviceName << ")");
00110 
00111         m_handle = open(
00112             m_deviceName.c_str(),
00113               (a_readOnly ? O_RDONLY : O_RDWR)
00114             | (a_excl ? O_EXCL : 0)
00115             | O_NONBLOCK);
00116 
00117         if (m_handle < 0) {
00118             if (errno == EBUSY || errno == EINTR /*|| errno == ENXIO*/) {
00119                 if (i == 1) {
00120                     log_MARKLINE_m;
00121                     throw ivd_SysError(errno, "open(" + m_deviceName + "...)");
00122                 }
00123                 log_DBG_m(dbg_DETAIL,
00124                     "open() failed. Retrying. Error: " << strerror(errno));
00125                 ivd_Sleep(1);
00126                 continue;
00127             }
00128             else {
00129                 log_MARKLINE_m;
00130                 throw ivd_SysError(errno, "open(" + m_deviceName + "...)");
00131             }
00132         }
00133         // open() successful. Break the loop.
00134         break;
00135     }
00136     log_DBG_m(dbg_LOW, "SCSI device handle: " << m_handle);
00137 
00138     // It seems that the kernel needs some patch to support SCSI reset.
00139 /*
00140     Reset(SG_SCSI_RESET_DEVICE);
00141     Reset(SG_SCSI_RESET_BUS);
00142     Reset(SG_SCSI_RESET_HOST);
00143 */
00144 
00145     log_DBG_m(dbg_DETAIL,
00146         "Will try to read any garbage from previous usage of the device.");
00147 
00148     {
00149         // defining local struct
00150         struct sg_rep {
00151             struct sg_header    hd;
00152             unsigned char       rbuf[100];
00153         } sg_rep;
00154 
00155         int flags;
00156 
00157         flags = fcntl(m_handle, F_GETFL); /* Be very proper about this */
00158         fcntl(m_handle, F_SETFL, flags|O_NONBLOCK);
00159         // TODO: Do additional checks of return value and errno!!
00160 
00161         memset(&sg_rep, 0, sizeof(struct sg_header));
00162         sg_rep.hd.reply_len = sizeof(struct sg_header);
00163 
00164         while (read(m_handle, &sg_rep, sizeof(sg_rep)) >= 0 ||
00165                errno != EAGAIN) {
00166             // NULL BODY
00167         };
00168 
00169         fcntl(m_handle, F_SETFL, flags);
00170     }
00171 }

Here is the caller graph for this function:

bool scsi_LnxSG::Reset ( int  what  )  [private]

Definition at line 313 of file scsi_lnxsg.cpp.

00313                                {
00314 /*
00315     int k;
00316     int res;
00317 
00318     k = what;
00319     res = ioctl(m_handle, SG_SCSI_RESET, &k);
00320     if (res < 0) {
00321         if (EBUSY == errno)
00322             printf("sg_reset: BUSY, may be resetting now\n");
00323         else if (EIO == errno)
00324             printf("sg_reset: requested type of reset may not be available\n");
00325         else if (EACCES == errno)
00326             printf("sg_reset: to do a reset needs root permission\n");
00327         else
00328             printf("sg_reset: SG_SCSI_RESET not supported\n");
00329         return false;
00330     }
00331     if (SG_SCSI_RESET_NOTHING == k)
00332         printf("sg_reset: did nothing, device is normal mode\n");
00333     else {
00334         if (SG_SCSI_RESET_DEVICE == k)
00335             printf("sg_reset: started device reset\n");
00336         else if (SG_SCSI_RESET_BUS == k)
00337             printf("sg_reset: started bus reset\n");
00338         else if (SG_SCSI_RESET_HOST == k)
00339             printf("sg_reset: started host reset\n");
00340 
00341         printf("waiting for the reset to complete...\n");
00342         int j = 0;
00343         k = SG_SCSI_RESET_NOTHING;
00344         do {
00345             if (0 != j)
00346                 sleep(1);
00347             res = ioctl(m_handle, SG_SCSI_RESET, &k);
00348             ++j;
00349         } while ((res < 0) && (EBUSY == errno));
00350         printf("  ... reset seemingly completed\n");
00351     }
00352 */
00353     return true;
00354 
00355 }


Member Data Documentation

Reimplemented from scsi_IO.

Definition at line 69 of file scsi_lnxsg.h.

int scsi_LnxSG::m_handle [private]

Definition at line 71 of file scsi_lnxsg.h.

Referenced by Close(), DoIOCtl(), InqSCSIID(), IsOpen(), and SGOpen().

sg_io_hdr_t scsi_LnxSG::m_ioHdr [private]

Definition at line 73 of file scsi_lnxsg.h.

Referenced by CheckDriverStatus(), CheckHostStatus(), DoIOCtl(), GetCDBStatus(), and IsSenseValid().


The documentation for this class was generated from the following files:

Generated on Mon Feb 27 19:50:16 2012 for OPENARCHIVE by  doxygen 1.5.6