smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
dev_areca.cpp
Go to the documentation of this file.
00001 /*
00002  * dev_areca.cpp
00003  *
00004  * Home page of code is: http://smartmontools.sourceforge.net
00005  *
00006  * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
00015  *
00016  */
00017 
00018 #include "config.h"
00019 #include "int64.h"
00020 
00021 #include "dev_interface.h"
00022 #include "dev_areca.h"
00023 
00024 const char * dev_areca_cpp_cvsid = "$Id: dev_areca.cpp 3872 2014-02-03 21:07:51Z chrfranke $"
00025   DEV_ARECA_H_CVSID;
00026 
00027 #include "atacmds.h"
00028 #include "scsicmds.h"
00029 
00030 #include <errno.h>
00031 
00032 #if 0 // For debugging areca code
00033 static void dumpdata(unsigned char *block, int len)
00034 {
00035   int ln = (len / 16) + 1;   // total line#
00036   unsigned char c;
00037   int pos = 0;
00038 
00039   printf(" Address = %p, Length = (0x%x)%d\n", block, len, len);
00040   printf("      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      ASCII      \n");
00041   printf("=====================================================================\n");
00042 
00043   for ( int l = 0; l < ln && len; l++ )
00044   {
00045     // printf the line# and the HEX data
00046     // if a line data length < 16 then append the space to the tail of line to reach 16 chars
00047     printf("%02X | ", l);
00048     for ( pos = 0; pos < 16 && len; pos++, len-- )
00049     {
00050       c = block[l*16+pos];
00051       printf("%02X ", c);
00052     }
00053 
00054     if ( pos < 16 )
00055     {
00056       for ( int loop = pos; loop < 16; loop++ )
00057       {
00058         printf("   ");
00059       }
00060     }
00061 
00062     // print ASCII char
00063     for ( int loop = 0; loop < pos; loop++ )
00064     {
00065       c = block[l*16+loop];
00066       if ( c >= 0x20 && c <= 0x7F )
00067       {
00068         printf("%c", c);
00069       }
00070       else
00071       {
00072         printf(".");
00073       }
00074     }
00075     printf("\n");
00076   }
00077   printf("=====================================================================\n");
00078 }
00079 #endif
00080 
00081 generic_areca_device::generic_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
00082 : smart_device(intf, dev_name, "areca", "areca"),
00083   m_disknum(disknum),
00084   m_encnum(encnum)
00085 {
00086   set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
00087 }
00088 
00089 generic_areca_device::~generic_areca_device() throw()
00090 {
00091 
00092 }
00093 
00094 // PURPOSE
00095 //   This is an interface routine meant to isolate the OS dependent
00096 //   parts of the code, and to provide a debugging interface.  Each
00097 //   different port and OS needs to provide it's own interface.  This
00098 //   is the Windows interface to the Areca "arcmsr" driver.  It allows ATA
00099 //   commands to be passed through the SCSI driver.
00100 // DETAILED DESCRIPTION OF ARGUMENTS
00101 //   fd: is the file descriptor provided by open()
00102 //   disknum is the disk number (0 to 127) in the RAID array
00103 //   command: defines the different operations.
00104 //   select: additional input data if needed (which log, which type of
00105 //           self-test).
00106 //   data:   location to write output data, if needed (512 bytes).
00107 //   Note: not all commands use all arguments.
00108 // RETURN VALUES
00109 //  -1 if the command failed
00110 //   0 if the command succeeded,
00111 //   STATUS_CHECK routine:
00112 //  -1 if the command failed
00113 //   0 if the command succeeded and disk SMART status is "OK"
00114 //   1 if the command succeeded and disk SMART status is "FAILING"
00115 int generic_areca_device::arcmsr_command_handler(unsigned long arcmsr_cmd, unsigned char *data, int data_len)
00116 {
00117   if (arcmsr_cmd >= ARCMSR_CMD_TOTAL)
00118     return -1;
00119 
00120   static const unsigned int cmds[ARCMSR_CMD_TOTAL] =
00121   {
00122     ARCMSR_IOCTL_READ_RQBUFFER,
00123     ARCMSR_IOCTL_WRITE_WQBUFFER,
00124     ARCMSR_IOCTL_CLEAR_RQBUFFER,
00125     ARCMSR_IOCTL_CLEAR_WQBUFFER,
00126     ARCMSR_IOCTL_RETURN_CODE_3F
00127   };
00128 
00129   int ioctlreturn = 0;
00130   sSRB_BUFFER sBuf;
00131   struct scsi_cmnd_io iop;
00132   int dir = DXFER_TO_DEVICE;
00133 
00134   UINT8 cdb[10]={0};
00135   UINT8 sense[32]={0};
00136 
00137   unsigned char *areca_return_packet;
00138   int total = 0;
00139   int expected = -1;
00140   unsigned char return_buff[2048]={0};
00141   unsigned char *ptr = &return_buff[0];
00142 
00143   memset((unsigned char *)&sBuf, 0, sizeof(sBuf));
00144   memset(&iop, 0, sizeof(iop));
00145 
00146   sBuf.srbioctl.HeaderLength = sizeof(sARCMSR_IO_HDR);
00147   memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR));
00148   sBuf.srbioctl.Timeout = 10000;
00149   sBuf.srbioctl.ControlCode = cmds[arcmsr_cmd];
00150 
00151   switch ( arcmsr_cmd )
00152   {
00153   // command for writing data to driver
00154   case ARCMSR_WRITE_WQBUFFER:
00155     if ( data && data_len )
00156     {
00157       sBuf.srbioctl.Length = data_len;
00158       memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len);
00159     }
00160     // commands for clearing related buffer of driver
00161   case ARCMSR_CLEAR_RQBUFFER:
00162   case ARCMSR_CLEAR_WQBUFFER:
00163     cdb[0] = 0x3B; //SCSI_WRITE_BUF command;
00164     break;
00165   // command for reading data from driver
00166   case ARCMSR_READ_RQBUFFER:
00167   // command for identifying driver
00168   case ARCMSR_RETURN_CODE_3F:
00169     cdb[0] = 0x3C; //SCSI_READ_BUF command;
00170     dir = DXFER_FROM_DEVICE;
00171     break;
00172   default:
00173     // unknown arcmsr commands
00174     return -1;
00175   }
00176 
00177   cdb[1] = 0x01;
00178   cdb[2] = 0xf0;
00179   cdb[5] = cmds[arcmsr_cmd] >> 24;
00180   cdb[6] = cmds[arcmsr_cmd] >> 16;
00181   cdb[7] = cmds[arcmsr_cmd] >> 8;
00182   cdb[8] = cmds[arcmsr_cmd] & 0x0F;
00183 
00184   iop.dxfer_dir = dir;
00185   iop.dxfer_len = sizeof(sBuf);
00186   iop.dxferp = (unsigned char *)&sBuf;
00187   iop.cmnd = cdb;
00188   iop.cmnd_len = sizeof(cdb);
00189   iop.sensep = sense;
00190   iop.max_sense_len = sizeof(sense);
00191   iop.timeout = SCSI_TIMEOUT_DEFAULT;
00192 
00193   while ( 1 )
00194   {
00195     ioctlreturn = arcmsr_do_scsi_io(&iop);
00196     if(ioctlreturn || iop.scsi_status)
00197     {
00198       break;
00199     }
00200 
00201     if ( arcmsr_cmd != ARCMSR_READ_RQBUFFER )
00202     {
00203       // if succeeded, just returns the length of outgoing data
00204       return data_len;
00205     }
00206 
00207     if ( sBuf.srbioctl.Length )
00208     {
00209       memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
00210       ptr += sBuf.srbioctl.Length;
00211       total += sBuf.srbioctl.Length;
00212       // the returned bytes enough to compute payload length ?
00213       if ( expected < 0 && total >= 5 )
00214       {
00215         areca_return_packet = (unsigned char *)&return_buff[0];
00216         if ( areca_return_packet[0] == 0x5E &&
00217            areca_return_packet[1] == 0x01 &&
00218            areca_return_packet[2] == 0x61 )
00219         {
00220           // valid header, let's compute the returned payload length,
00221           // we expected the total length is
00222           // payload + 3 bytes header + 2 bytes length + 1 byte checksum
00223           expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6;
00224         }
00225       }
00226 
00227       if ( total >= 7 && total >= expected )
00228       {
00229         //printf("total bytes received = %d, expected length = %d\n", total, expected);
00230 
00231         // ------ Okay! we received enough --------
00232         break;
00233       }
00234     }
00235   }
00236 
00237   // Deal with the different error cases
00238   if ( arcmsr_cmd == ARCMSR_RETURN_CODE_3F )
00239   {
00240     // Silence the ARCMSR_IOCTL_RETURN_CODE_3F's error, no pout(...)
00241     return -4;
00242   }
00243 
00244   if ( ioctlreturn )
00245   {
00246     pout("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn);
00247     return -2;
00248   }
00249 
00250   if ( iop.scsi_status )
00251   {
00252     pout("io_hdr.scsi_status with write buffer failed code = %x\n", iop.scsi_status);
00253     return -3;
00254   }
00255 
00256   if ( data )
00257   {
00258     memcpy(data, return_buff, total);
00259   }
00260 
00261   return total;
00262 }
00263 
00264 bool generic_areca_device::arcmsr_probe()
00265 {
00266   if(!is_open())
00267   {
00268     open();
00269   }
00270 
00271   if(arcmsr_command_handler(ARCMSR_RETURN_CODE_3F, NULL, 0) != 0)
00272   {
00273     return false;
00274   }
00275   return true;
00276 }
00277 
00278 int generic_areca_device::arcmsr_ui_handler(unsigned char *areca_packet, int areca_packet_len, unsigned char *result)
00279 {
00280   int expected = 0;
00281   unsigned char return_buff[2048];
00282   unsigned char cs = 0;
00283   int cs_pos = 0;
00284 
00285   // ----- ADD CHECKSUM -----
00286   cs_pos = areca_packet_len - 1;
00287   for(int i = 3; i < cs_pos; i++)
00288   {
00289       areca_packet[cs_pos] += areca_packet[i];
00290   }
00291 
00292   if(!arcmsr_lock())
00293   {
00294     return -1;
00295   }
00296   expected = arcmsr_command_handler(ARCMSR_CLEAR_RQBUFFER, NULL, 0);
00297   if (expected==-3) {
00298     return set_err(EIO);
00299   }
00300   expected = arcmsr_command_handler(ARCMSR_CLEAR_WQBUFFER, NULL, 0);
00301   expected = arcmsr_command_handler(ARCMSR_WRITE_WQBUFFER, areca_packet, areca_packet_len);
00302   if ( expected > 0 )
00303   {
00304     expected = arcmsr_command_handler(ARCMSR_READ_RQBUFFER, return_buff, sizeof(return_buff));
00305   }
00306 
00307   if ( expected < 0 )
00308   {
00309     return -1;
00310   }
00311 
00312   if(!arcmsr_unlock())
00313   {
00314     return -1;
00315   }
00316 
00317   // ----- VERIFY THE CHECKSUM -----
00318   cs = 0;
00319   for ( int loop = 3; loop < expected - 1; loop++ )
00320   {
00321       cs += return_buff[loop];
00322   }
00323 
00324   if ( return_buff[expected - 1] != cs )
00325   {
00326     return -1;
00327   }
00328 
00329   memcpy(result, return_buff, expected);
00330 
00331   return expected;
00332 }
00333 
00334 int generic_areca_device::arcmsr_get_controller_type()
00335 {
00336   int expected = 0;
00337   unsigned char return_buff[2048];
00338   unsigned char areca_packet[] = {0x5E, 0x01, 0x61, 0x01, 0x00, 0x23, 0x00};
00339 
00340   memset(return_buff, 0, sizeof(return_buff));
00341   expected = arcmsr_ui_handler(areca_packet, sizeof(areca_packet), return_buff);
00342   if ( expected < 0 )
00343   {
00344     return -1;
00345   }
00346 
00347   return return_buff[0xc2];
00348 }
00349 
00350 int generic_areca_device::arcmsr_get_dev_type()
00351 {
00352   int expected = 0;
00353   unsigned char return_buff[2048];
00354   int ctlr_type = -1;
00355   int encnum = get_encnum();
00356   int disknum = get_disknum();
00357   unsigned char areca_packet[] = {0x5E, 0x01, 0x61, 0x03, 0x00, 0x22,
00358     (unsigned char)(disknum - 1), (unsigned char)(encnum - 1), 0x00};
00359 
00360   memset(return_buff, 0, sizeof(return_buff));
00361   expected = arcmsr_ui_handler(areca_packet, sizeof(areca_packet), return_buff);
00362   if ( expected < 0 )
00363   {
00364     return -1;
00365   }
00366 
00367   ctlr_type = arcmsr_get_controller_type();
00368 
00369   if( ctlr_type < 0 )
00370   {
00371     return ctlr_type;
00372   }
00373 
00374   if( ctlr_type == 0x02/* SATA Controllers */ ||
00375      (ctlr_type == 0x03 /* SAS Controllers */ && return_buff[0x52] & 0x01 /* SATA devices behind SAS Controller */) )
00376   {
00377     // SATA device
00378     return 1;
00379   }
00380 
00381   // SAS device
00382   return 0;
00383 }
00384 
00385 bool generic_areca_device::arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
00386 {
00387   // ATA input registers
00388   typedef struct _ATA_INPUT_REGISTERS
00389   {
00390     unsigned char features;
00391     unsigned char sector_count;
00392     unsigned char sector_number;
00393     unsigned char cylinder_low;
00394     unsigned char cylinder_high;
00395     unsigned char device_head;
00396     unsigned char command;
00397     unsigned char reserved[8];
00398     unsigned char data[512]; // [in/out] buffer for outgoing/incoming data
00399   } sATA_INPUT_REGISTERS;
00400 
00401   // ATA output registers
00402   // Note: The output registers is re-sorted for areca internal use only
00403   typedef struct _ATA_OUTPUT_REGISTERS
00404   {
00405     unsigned char error;
00406     unsigned char status;
00407     unsigned char sector_count;
00408     unsigned char sector_number;
00409     unsigned char cylinder_low;
00410     unsigned char cylinder_high;
00411   } sATA_OUTPUT_REGISTERS;
00412 
00413   // Areca packet format for outgoing:
00414   // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
00415   // B[3~4] : 2 bytes command length + variant data length, little endian
00416   // B[5]   : 1 bytes areca defined command code, ATA passthrough command code is 0x1c
00417   // B[6~last-1] : variant bytes payload data
00418   // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
00419   //
00420   //
00421   //   header 3 bytes  length 2 bytes   cmd 1 byte    payload data x bytes  cs 1 byte
00422   // +--------------------------------------------------------------------------------+
00423   // + 0x5E 0x01 0x61 |   0x00 0x00   |     0x1c   | .................... |   0x00    |
00424   // +--------------------------------------------------------------------------------+
00425   //
00426 
00427   //Areca packet format for incoming:
00428   // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
00429   // B[3~4] : 2 bytes payload length, little endian
00430   // B[5~last-1] : variant bytes returned payload data
00431   // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
00432   //
00433   //
00434   //   header 3 bytes  length 2 bytes   payload data x bytes  cs 1 byte
00435   // +-------------------------------------------------------------------+
00436   // + 0x5E 0x01 0x61 |   0x00 0x00   | .................... |   0x00    |
00437   // +-------------------------------------------------------------------+
00438   unsigned char    areca_packet[640];
00439   int areca_packet_len = sizeof(areca_packet);
00440   unsigned char return_buff[2048];
00441   int expected = 0;
00442 
00443   sATA_INPUT_REGISTERS *ata_cmd;
00444 
00445   // For debugging
00446 #if 0
00447   memset(sInq, 0, sizeof(sInq));
00448   scsiStdInquiry(fd, (unsigned char *)sInq, (int)sizeof(sInq));
00449   dumpdata((unsigned char *)sInq, sizeof(sInq));
00450 #endif
00451   memset(areca_packet, 0, areca_packet_len);
00452 
00453   // ----- BEGIN TO SETUP HEADERS -------
00454   areca_packet[0] = 0x5E;
00455   areca_packet[1] = 0x01;
00456   areca_packet[2] = 0x61;
00457   areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff);
00458   areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff);
00459   areca_packet[5] = 0x1c;  // areca defined code for ATA passthrough command
00460 
00461   // ----- BEGIN TO SETUP PAYLOAD DATA -----
00462   memcpy(&areca_packet[7], "SmrT", 4);  // areca defined password
00463   ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12];
00464 
00465   // Set registers
00466   {
00467     const ata_in_regs & r = in.in_regs;
00468     ata_cmd->features      = r.features;
00469     ata_cmd->sector_count  = r.sector_count;
00470     ata_cmd->sector_number = r.lba_low;
00471     ata_cmd->cylinder_low  = r.lba_mid;
00472     ata_cmd->cylinder_high = r.lba_high;
00473     ata_cmd->device_head   = r.device;
00474     ata_cmd->command       = r.command;
00475   }
00476   bool readdata = false;
00477   if (in.direction == ata_cmd_in::data_in) {
00478       readdata = true;
00479       // the command will read data
00480       areca_packet[6] = 0x13;
00481   }
00482   else if ( in.direction == ata_cmd_in::no_data )
00483   {
00484     // the commands will return no data
00485     areca_packet[6] = 0x15;
00486   }
00487   else if (in.direction == ata_cmd_in::data_out)
00488   {
00489     // the commands will write data
00490     memcpy(ata_cmd->data, in.buffer, in.size);
00491     areca_packet[6] = 0x14;
00492   }
00493   else {
00494       // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE
00495       return set_err(ENOSYS);
00496   }
00497 
00498   areca_packet[11] = get_disknum() - 1;  // disk#
00499   areca_packet[19] = get_encnum() - 1;   // enc#
00500 
00501   // ----- BEGIN TO SEND TO ARECA DRIVER ------
00502   expected = arcmsr_ui_handler(areca_packet, areca_packet_len, return_buff);
00503   if ( expected < 0 )
00504   {
00505     return set_err(EIO);
00506   }
00507 
00508   sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5] ;
00509   if ( ata_out->status )
00510   {
00511     if ( in.in_regs.command == ATA_IDENTIFY_DEVICE
00512      && !nonempty((unsigned char *)in.buffer, in.size))
00513      {
00514         return set_err(ENODEV, "No drive on port %d", get_disknum());
00515      }
00516   }
00517 
00518   // returns with data
00519   if (readdata)
00520   {
00521     memcpy(in.buffer, &return_buff[7], in.size);
00522   }
00523 
00524   // Return register values
00525   {
00526     ata_out_regs & r = out.out_regs;
00527     r.error          = ata_out->error;
00528     r.sector_count   = ata_out->sector_count;
00529     r.lba_low        = ata_out->sector_number;
00530     r.lba_mid        = ata_out->cylinder_low;
00531     r.lba_high       = ata_out->cylinder_high;
00532     r.status         = ata_out->status;
00533   }
00534   return true;
00535 }
00536 
00537 bool generic_areca_device::arcmsr_scsi_pass_through(struct scsi_cmnd_io * iop)
00538 {
00539   // Areca packet format for outgoing:
00540   // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
00541   // B[3~4] : 2 bytes command length + variant data length, little endian
00542   // B[5]   : 1 bytes areca defined command code
00543   // B[6~last-1] : variant bytes payload data
00544   // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
00545   //
00546   //
00547   //   header 3 bytes  length 2 bytes   cmd 1 byte    payload data x bytes  cs 1 byte
00548   // +--------------------------------------------------------------------------------+
00549   // + 0x5E 0x01 0x61 |   0x00 0x00   |     0x1c   | .................... |   0x00    |
00550   // +--------------------------------------------------------------------------------+
00551   //
00552 
00553   //Areca packet format for incoming:
00554   // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
00555   // B[3~4] : 2 bytes payload length, little endian
00556   // B[5~last-1] : variant bytes returned payload data
00557   // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
00558   //
00559   //
00560   //   header 3 bytes  length 2 bytes   payload data x bytes  cs 1 byte
00561   // +-------------------------------------------------------------------+
00562   // + 0x5E 0x01 0x61 |   0x00 0x00   | .................... |   0x00    |
00563   // +-------------------------------------------------------------------+
00564   unsigned char    areca_packet[640];
00565   int areca_packet_len = sizeof(areca_packet);
00566   unsigned char return_buff[2048];
00567   int expected = 0;
00568 
00569   if (iop->cmnd_len > 16) {
00570     set_err(EINVAL, "cmnd_len too large");
00571     return false;
00572   }
00573 
00574   memset(areca_packet, 0, areca_packet_len);
00575 
00576   // ----- BEGIN TO SETUP HEADERS -------
00577   areca_packet[0] = 0x5E;
00578   areca_packet[1] = 0x01;
00579   areca_packet[2] = 0x61;
00580   areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff);
00581   areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff);
00582   areca_packet[5] = 0x1c;
00583 
00584   // ----- BEGIN TO SETUP PAYLOAD DATA -----
00585   areca_packet[6] = 0x16; // scsi pass through
00586   memcpy(&areca_packet[7], "SmrT", 4);  // areca defined password
00587   areca_packet[12] = iop->cmnd_len; // cdb length
00588   memcpy( &areca_packet[35], iop->cmnd, iop->cmnd_len); // cdb
00589   areca_packet[15] = (unsigned char)iop->dxfer_len; // 15(LSB) ~ 18(MSB): data length ( max=512 bytes)
00590   areca_packet[16] = (unsigned char)(iop->dxfer_len >> 8);
00591   areca_packet[17] = (unsigned char)(iop->dxfer_len >> 16);
00592   areca_packet[18] = (unsigned char)(iop->dxfer_len >> 24);
00593   if(iop->dxfer_dir == DXFER_TO_DEVICE)
00594   {
00595     areca_packet[13] |= 0x01;
00596     memcpy(&areca_packet[67], iop->dxferp, iop->dxfer_len);
00597   }
00598   else if (iop->dxfer_dir == DXFER_FROM_DEVICE)
00599   {
00600   }
00601   else if( iop->dxfer_dir == DXFER_NONE)
00602   {
00603   }
00604   else {
00605     // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE
00606     return set_err(ENOSYS);
00607   }
00608 
00609   areca_packet[11] = get_disknum() - 1;  // disk#
00610   areca_packet[19] = get_encnum() - 1;   // enc#
00611 
00612   // ----- BEGIN TO SEND TO ARECA DRIVER ------
00613   expected = arcmsr_ui_handler(areca_packet, areca_packet_len, return_buff);
00614 
00615   if (expected < 0)
00616     return set_err(EIO, "arcmsr_scsi_pass_through: I/O error");
00617   if (expected < 15) // 7 bytes if port is empty
00618     return set_err(EIO, "arcmsr_scsi_pass_through: missing data (%d bytes, expected %d)", expected, 15);
00619 
00620   int scsi_status = return_buff[5];
00621   int in_data_len = return_buff[11] | return_buff[12] << 8 | return_buff[13] << 16 | return_buff[14] << 24;
00622 
00623   if (iop->dxfer_dir == DXFER_FROM_DEVICE)
00624   {
00625     memset(iop->dxferp, 0, iop->dxfer_len); // need?
00626     memcpy(iop->dxferp, &return_buff[15], in_data_len);
00627   }
00628 
00629   if(scsi_status == 0xE1 /* Underrun, actual data length < requested data length */)
00630   {
00631       // don't care, just ignore
00632       scsi_status = 0x0;
00633   }
00634 
00635   if(scsi_status != 0x00 && scsi_status != SCSI_STATUS_CHECK_CONDITION)
00636   {
00637     return set_err(EIO);
00638   }
00639 
00640   if(scsi_status == SCSI_STATUS_CHECK_CONDITION)
00641   {
00642     // check condition
00643     iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
00644     iop->resp_sense_len = 4;
00645     iop->sensep[0] = return_buff[7];
00646     iop->sensep[1] = return_buff[8];
00647     iop->sensep[2] = return_buff[9];
00648     iop->sensep[3] = return_buff[10];
00649   }
00650 
00651   return true;
00652 }
00653 
00654 /////////////////////////////////////////////////////////////
00655 areca_ata_device::areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
00656 : smart_device(intf, dev_name, "areca", "areca")
00657 {
00658   set_encnum(encnum);
00659   set_disknum(disknum);
00660   set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
00661 }
00662 
00663 areca_ata_device::~areca_ata_device() throw()
00664 {
00665 
00666 }
00667 
00668 bool areca_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
00669 {
00670   if (!ata_cmd_is_supported(in,
00671     ata_device::supports_data_out |
00672     ata_device::supports_output_regs |
00673   //ata_device::supports_multi_sector | // TODO
00674     ata_device::supports_48bit_hi_null,
00675     "Areca")
00676   )
00677     return false;
00678 
00679   return arcmsr_ata_pass_through(in, out);
00680 }
00681 
00682 /////////////////////////////////////////////////////////////
00683 areca_scsi_device::areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
00684 : smart_device(intf, dev_name, "areca", "areca")
00685 {
00686   set_encnum(encnum);
00687   set_disknum(disknum);
00688   set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
00689 }
00690 
00691 areca_scsi_device::~areca_scsi_device() throw()
00692 {
00693 
00694 }
00695 
00696 bool areca_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop)
00697 {
00698   return arcmsr_scsi_pass_through(iop);
00699 }
00700 
00701 
00702 
00703