Annotation of embedaddon/smartmontools/dev_areca.cpp, revision 1.1

1.1     ! misho       1: /*
        !             2:  * dev_areca.cpp
        !             3:  *
        !             4:  * Home page of code is: http://smartmontools.sourceforge.net
        !             5:  *
        !             6:  * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
        !             7:  *
        !             8:  * This program is free software; you can redistribute it and/or modify
        !             9:  * it under the terms of the GNU General Public License as published by
        !            10:  * the Free Software Foundation; either version 2, or (at your option)
        !            11:  * any later version.
        !            12:  *
        !            13:  * You should have received a copy of the GNU General Public License
        !            14:  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
        !            15:  *
        !            16:  */
        !            17: 
        !            18: #include "config.h"
        !            19: #include "int64.h"
        !            20: 
        !            21: #include "dev_interface.h"
        !            22: #include "dev_areca.h"
        !            23: 
        !            24: const char * dev_areca_cpp_cvsid = "$Id: dev_areca.cpp 3664 2012-10-24 21:07:11Z chrfranke $"
        !            25:   DEV_ARECA_H_CVSID;
        !            26: 
        !            27: #include "atacmds.h"
        !            28: #include "scsicmds.h"
        !            29: 
        !            30: #include <errno.h>
        !            31: 
        !            32: #if 0 // For debugging areca code
        !            33: static void dumpdata(unsigned char *block, int len)
        !            34: {
        !            35:   int ln = (len / 16) + 1;   // total line#
        !            36:   unsigned char c;
        !            37:   int pos = 0;
        !            38: 
        !            39:   printf(" Address = %p, Length = (0x%x)%d\n", block, len, len);
        !            40:   printf("      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      ASCII      \n");
        !            41:   printf("=====================================================================\n");
        !            42: 
        !            43:   for ( int l = 0; l < ln && len; l++ )
        !            44:   {
        !            45:     // printf the line# and the HEX data
        !            46:     // if a line data length < 16 then append the space to the tail of line to reach 16 chars
        !            47:     printf("%02X | ", l);
        !            48:     for ( pos = 0; pos < 16 && len; pos++, len-- )
        !            49:     {
        !            50:       c = block[l*16+pos];
        !            51:       printf("%02X ", c);
        !            52:     }
        !            53: 
        !            54:     if ( pos < 16 )
        !            55:     {
        !            56:       for ( int loop = pos; loop < 16; loop++ )
        !            57:       {
        !            58:         printf("   ");
        !            59:       }
        !            60:     }
        !            61: 
        !            62:     // print ASCII char
        !            63:     for ( int loop = 0; loop < pos; loop++ )
        !            64:     {
        !            65:       c = block[l*16+loop];
        !            66:       if ( c >= 0x20 && c <= 0x7F )
        !            67:       {
        !            68:         printf("%c", c);
        !            69:       }
        !            70:       else
        !            71:       {
        !            72:         printf(".");
        !            73:       }
        !            74:     }
        !            75:     printf("\n");
        !            76:   }
        !            77:   printf("=====================================================================\n");
        !            78: }
        !            79: #endif
        !            80: 
        !            81: generic_areca_device::generic_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
        !            82: : smart_device(intf, dev_name, "areca", "areca"),
        !            83:   m_disknum(disknum),
        !            84:   m_encnum(encnum)
        !            85: {
        !            86:   set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
        !            87: }
        !            88: 
        !            89: generic_areca_device::~generic_areca_device() throw()
        !            90: {
        !            91: 
        !            92: }
        !            93: 
        !            94: // PURPOSE
        !            95: //   This is an interface routine meant to isolate the OS dependent
        !            96: //   parts of the code, and to provide a debugging interface.  Each
        !            97: //   different port and OS needs to provide it's own interface.  This
        !            98: //   is the Windows interface to the Areca "arcmsr" driver.  It allows ATA
        !            99: //   commands to be passed through the SCSI driver.
        !           100: // DETAILED DESCRIPTION OF ARGUMENTS
        !           101: //   fd: is the file descriptor provided by open()
        !           102: //   disknum is the disk number (0 to 127) in the RAID array
        !           103: //   command: defines the different operations.
        !           104: //   select: additional input data if needed (which log, which type of
        !           105: //           self-test).
        !           106: //   data:   location to write output data, if needed (512 bytes).
        !           107: //   Note: not all commands use all arguments.
        !           108: // RETURN VALUES
        !           109: //  -1 if the command failed
        !           110: //   0 if the command succeeded,
        !           111: //   STATUS_CHECK routine:
        !           112: //  -1 if the command failed
        !           113: //   0 if the command succeeded and disk SMART status is "OK"
        !           114: //   1 if the command succeeded and disk SMART status is "FAILING"
        !           115: int generic_areca_device::arcmsr_command_handler(unsigned long arcmsr_cmd, unsigned char *data, int data_len)
        !           116: {
        !           117:   unsigned int cmds[] =
        !           118:   {
        !           119:     ARCMSR_IOCTL_READ_RQBUFFER,
        !           120:     ARCMSR_IOCTL_WRITE_WQBUFFER,
        !           121:     ARCMSR_IOCTL_CLEAR_RQBUFFER,
        !           122:     ARCMSR_IOCTL_CLEAR_WQBUFFER,
        !           123:     ARCMSR_IOCTL_RETURN_CODE_3F
        !           124:   };
        !           125: 
        !           126:   int ioctlreturn = 0;
        !           127:   sSRB_BUFFER sBuf;
        !           128:   struct scsi_cmnd_io iop;
        !           129:   int dir = DXFER_TO_DEVICE;
        !           130: 
        !           131:   UINT8 cdb[10]={0};
        !           132:   UINT8 sense[32]={0};
        !           133: 
        !           134:   unsigned char *areca_return_packet;
        !           135:   int total = 0;
        !           136:   int expected = -1;
        !           137:   unsigned char return_buff[2048]={0};
        !           138:   unsigned char *ptr = &return_buff[0];
        !           139: 
        !           140:   memset((unsigned char *)&sBuf, 0, sizeof(sBuf));
        !           141:   memset(&iop, 0, sizeof(iop));
        !           142: 
        !           143:   sBuf.srbioctl.HeaderLength = sizeof(sARCMSR_IO_HDR);
        !           144:   memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR));
        !           145:   sBuf.srbioctl.Timeout = 10000;
        !           146:   sBuf.srbioctl.ControlCode = cmds[arcmsr_cmd];
        !           147: 
        !           148:   if(arcmsr_cmd >= ARCMSR_CMD_TOTAL)
        !           149:   {
        !           150:       return -1;
        !           151:   }
        !           152: 
        !           153:   switch ( arcmsr_cmd )
        !           154:   {
        !           155:   // command for writing data to driver
        !           156:   case ARCMSR_WRITE_WQBUFFER:
        !           157:     if ( data && data_len )
        !           158:     {
        !           159:       sBuf.srbioctl.Length = data_len;
        !           160:       memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len);
        !           161:     }
        !           162:     // commands for clearing related buffer of driver
        !           163:   case ARCMSR_CLEAR_RQBUFFER:
        !           164:   case ARCMSR_CLEAR_WQBUFFER:
        !           165:     cdb[0] = 0x3B; //SCSI_WRITE_BUF command;
        !           166:     break;
        !           167:   // command for reading data from driver
        !           168:   case ARCMSR_READ_RQBUFFER:
        !           169:   // command for identifying driver
        !           170:   case ARCMSR_RETURN_CODE_3F:
        !           171:     cdb[0] = 0x3C; //SCSI_READ_BUF command;
        !           172:     dir = DXFER_FROM_DEVICE;
        !           173:     break;
        !           174:   default:
        !           175:     // unknown arcmsr commands
        !           176:     return -1;
        !           177:   }
        !           178: 
        !           179:   cdb[1] = 0x01;
        !           180:   cdb[2] = 0xf0;
        !           181:   cdb[5] = cmds[arcmsr_cmd] >> 24;
        !           182:   cdb[6] = cmds[arcmsr_cmd] >> 16;
        !           183:   cdb[7] = cmds[arcmsr_cmd] >> 8;
        !           184:   cdb[8] = cmds[arcmsr_cmd] & 0x0F;
        !           185: 
        !           186:   iop.dxfer_dir = dir;
        !           187:   iop.dxfer_len = sizeof(sBuf);
        !           188:   iop.dxferp = (unsigned char *)&sBuf;
        !           189:   iop.cmnd = cdb;
        !           190:   iop.cmnd_len = sizeof(cdb);
        !           191:   iop.sensep = sense;
        !           192:   iop.max_sense_len = sizeof(sense);
        !           193:   iop.timeout = SCSI_TIMEOUT_DEFAULT;
        !           194: 
        !           195:   while ( 1 )
        !           196:   {
        !           197:     ioctlreturn = arcmsr_do_scsi_io(&iop);
        !           198:     if(ioctlreturn || iop.scsi_status)
        !           199:     {
        !           200:       break;
        !           201:     }
        !           202: 
        !           203:     if ( arcmsr_cmd != ARCMSR_READ_RQBUFFER )
        !           204:     {
        !           205:       // if succeeded, just returns the length of outgoing data
        !           206:       return data_len;
        !           207:     }
        !           208: 
        !           209:     if ( sBuf.srbioctl.Length )
        !           210:     {
        !           211:       memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
        !           212:       ptr += sBuf.srbioctl.Length;
        !           213:       total += sBuf.srbioctl.Length;
        !           214:       // the returned bytes enough to compute payload length ?
        !           215:       if ( expected < 0 && total >= 5 )
        !           216:       {
        !           217:         areca_return_packet = (unsigned char *)&return_buff[0];
        !           218:         if ( areca_return_packet[0] == 0x5E &&
        !           219:            areca_return_packet[1] == 0x01 &&
        !           220:            areca_return_packet[2] == 0x61 )
        !           221:         {
        !           222:           // valid header, let's compute the returned payload length,
        !           223:           // we expected the total length is
        !           224:           // payload + 3 bytes header + 2 bytes length + 1 byte checksum
        !           225:           expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6;
        !           226:         }
        !           227:       }
        !           228: 
        !           229:       if ( total >= 7 && total >= expected )
        !           230:       {
        !           231:         //printf("total bytes received = %d, expected length = %d\n", total, expected);
        !           232: 
        !           233:         // ------ Okay! we received enough --------
        !           234:         break;
        !           235:       }
        !           236:     }
        !           237:   }
        !           238: 
        !           239:   // Deal with the different error cases
        !           240:   if ( arcmsr_cmd == ARCMSR_RETURN_CODE_3F )
        !           241:   {
        !           242:     // Silence the ARCMSR_IOCTL_RETURN_CODE_3F's error, no pout(...)
        !           243:     return -4;
        !           244:   }
        !           245: 
        !           246:   if ( ioctlreturn )
        !           247:   {
        !           248:     pout("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn);
        !           249:     return -2;
        !           250:   }
        !           251: 
        !           252:   if ( iop.scsi_status )
        !           253:   {
        !           254:     pout("io_hdr.scsi_status with write buffer failed code = %x\n", iop.scsi_status);
        !           255:     return -3;
        !           256:   }
        !           257: 
        !           258:   if ( data )
        !           259:   {
        !           260:     memcpy(data, return_buff, total);
        !           261:   }
        !           262: 
        !           263:   return total;
        !           264: }
        !           265: 
        !           266: bool generic_areca_device::arcmsr_probe()
        !           267: {
        !           268:   if(!is_open())
        !           269:   {
        !           270:     open();
        !           271:   }
        !           272: 
        !           273:   if(arcmsr_command_handler(ARCMSR_RETURN_CODE_3F, NULL, 0) != 0)
        !           274:   {
        !           275:     return false;
        !           276:   }
        !           277:   return true;
        !           278: }
        !           279: 
        !           280: int generic_areca_device::arcmsr_ui_handler(unsigned char *areca_packet, int areca_packet_len, unsigned char *result)
        !           281: {
        !           282:   int expected = 0;
        !           283:   unsigned char return_buff[2048];
        !           284:   unsigned char cs = 0;
        !           285:   int cs_pos = 0;
        !           286: 
        !           287:   // ----- ADD CHECKSUM -----
        !           288:   cs_pos = areca_packet_len - 1;
        !           289:   for(int i = 3; i < cs_pos; i++)
        !           290:   {
        !           291:       areca_packet[cs_pos] += areca_packet[i];
        !           292:   }
        !           293: 
        !           294:   if(!arcmsr_lock())
        !           295:   {
        !           296:     return -1;
        !           297:   }
        !           298:   expected = arcmsr_command_handler(ARCMSR_CLEAR_RQBUFFER, NULL, 0);
        !           299:   if (expected==-3) {
        !           300:     return set_err(EIO);
        !           301:   }
        !           302:   expected = arcmsr_command_handler(ARCMSR_CLEAR_WQBUFFER, NULL, 0);
        !           303:   expected = arcmsr_command_handler(ARCMSR_WRITE_WQBUFFER, areca_packet, areca_packet_len);
        !           304:   if ( expected > 0 )
        !           305:   {
        !           306:     expected = arcmsr_command_handler(ARCMSR_READ_RQBUFFER, return_buff, sizeof(return_buff));
        !           307:   }
        !           308: 
        !           309:   if ( expected < 0 )
        !           310:   {
        !           311:     return -1;
        !           312:   }
        !           313: 
        !           314:   if(!arcmsr_unlock())
        !           315:   {
        !           316:     return -1;
        !           317:   }
        !           318: 
        !           319:   // ----- VERIFY THE CHECKSUM -----
        !           320:   cs = 0;
        !           321:   for ( int loop = 3; loop < expected - 1; loop++ )
        !           322:   {
        !           323:       cs += return_buff[loop];
        !           324:   }
        !           325: 
        !           326:   if ( return_buff[expected - 1] != cs )
        !           327:   {
        !           328:     return -1;
        !           329:   }
        !           330: 
        !           331:   memcpy(result, return_buff, expected);
        !           332: 
        !           333:   return expected;
        !           334: }
        !           335: 
        !           336: int generic_areca_device::arcmsr_get_controller_type()
        !           337: {
        !           338:   int expected = 0;
        !           339:   unsigned char return_buff[2048];
        !           340:   unsigned char areca_packet[] = {0x5E, 0x01, 0x61, 0x01, 0x00, 0x23, 0x00};
        !           341: 
        !           342:   memset(return_buff, 0, sizeof(return_buff));
        !           343:   expected = arcmsr_ui_handler(areca_packet, sizeof(areca_packet), return_buff);
        !           344:   if ( expected < 0 )
        !           345:   {
        !           346:     return -1;
        !           347:   }
        !           348: 
        !           349:   return return_buff[0xc2];
        !           350: }
        !           351: 
        !           352: int generic_areca_device::arcmsr_get_dev_type()
        !           353: {
        !           354:   int expected = 0;
        !           355:   unsigned char return_buff[2048];
        !           356:   int ctlr_type = -1;
        !           357:   int encnum = get_encnum();
        !           358:   int disknum = get_disknum();
        !           359:   unsigned char areca_packet[] = {0x5E, 0x01, 0x61, 0x03, 0x00, 0x22, disknum - 1, encnum - 1, 0x00};
        !           360: 
        !           361:   memset(return_buff, 0, sizeof(return_buff));
        !           362:   expected = arcmsr_ui_handler(areca_packet, sizeof(areca_packet), return_buff);
        !           363:   if ( expected < 0 )
        !           364:   {
        !           365:     return -1;
        !           366:   }
        !           367: 
        !           368:   ctlr_type = arcmsr_get_controller_type();
        !           369: 
        !           370:   if( ctlr_type < 0 )
        !           371:   {
        !           372:     return ctlr_type;
        !           373:   }
        !           374: 
        !           375:   if( ctlr_type == 0x02/* SATA Controllers */ ||
        !           376:      (ctlr_type == 0x03 /* SAS Controllers */ && return_buff[0x52] & 0x01 /* SATA devices behind SAS Controller */) )
        !           377:   {
        !           378:     // SATA device
        !           379:     return 1;
        !           380:   }
        !           381: 
        !           382:   // SAS device
        !           383:   return 0;
        !           384: }
        !           385: 
        !           386: bool generic_areca_device::arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
        !           387: {
        !           388:   // ATA input registers
        !           389:   typedef struct _ATA_INPUT_REGISTERS
        !           390:   {
        !           391:     unsigned char features;
        !           392:     unsigned char sector_count;
        !           393:     unsigned char sector_number;
        !           394:     unsigned char cylinder_low;
        !           395:     unsigned char cylinder_high;
        !           396:     unsigned char device_head;
        !           397:     unsigned char command;
        !           398:     unsigned char reserved[8];
        !           399:     unsigned char data[512]; // [in/out] buffer for outgoing/incoming data
        !           400:   } sATA_INPUT_REGISTERS;
        !           401: 
        !           402:   // ATA output registers
        !           403:   // Note: The output registers is re-sorted for areca internal use only
        !           404:   typedef struct _ATA_OUTPUT_REGISTERS
        !           405:   {
        !           406:     unsigned char error;
        !           407:     unsigned char status;
        !           408:     unsigned char sector_count;
        !           409:     unsigned char sector_number;
        !           410:     unsigned char cylinder_low;
        !           411:     unsigned char cylinder_high;
        !           412:   } sATA_OUTPUT_REGISTERS;
        !           413: 
        !           414:   // Areca packet format for outgoing:
        !           415:   // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
        !           416:   // B[3~4] : 2 bytes command length + variant data length, little endian
        !           417:   // B[5]   : 1 bytes areca defined command code, ATA passthrough command code is 0x1c
        !           418:   // B[6~last-1] : variant bytes payload data
        !           419:   // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
        !           420:   //
        !           421:   //
        !           422:   //   header 3 bytes  length 2 bytes   cmd 1 byte    payload data x bytes  cs 1 byte
        !           423:   // +--------------------------------------------------------------------------------+
        !           424:   // + 0x5E 0x01 0x61 |   0x00 0x00   |     0x1c   | .................... |   0x00    |
        !           425:   // +--------------------------------------------------------------------------------+
        !           426:   //
        !           427: 
        !           428:   //Areca packet format for incoming:
        !           429:   // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
        !           430:   // B[3~4] : 2 bytes payload length, little endian
        !           431:   // B[5~last-1] : variant bytes returned payload data
        !           432:   // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
        !           433:   //
        !           434:   //
        !           435:   //   header 3 bytes  length 2 bytes   payload data x bytes  cs 1 byte
        !           436:   // +-------------------------------------------------------------------+
        !           437:   // + 0x5E 0x01 0x61 |   0x00 0x00   | .................... |   0x00    |
        !           438:   // +-------------------------------------------------------------------+
        !           439:   unsigned char    areca_packet[640];
        !           440:   int areca_packet_len = sizeof(areca_packet);
        !           441:   unsigned char return_buff[2048];
        !           442:   int expected = 0;
        !           443: 
        !           444:   sATA_INPUT_REGISTERS *ata_cmd;
        !           445: 
        !           446:   // For debugging
        !           447: #if 0
        !           448:   memset(sInq, 0, sizeof(sInq));
        !           449:   scsiStdInquiry(fd, (unsigned char *)sInq, (int)sizeof(sInq));
        !           450:   dumpdata((unsigned char *)sInq, sizeof(sInq));
        !           451: #endif
        !           452:   memset(areca_packet, 0, areca_packet_len);
        !           453: 
        !           454:   // ----- BEGIN TO SETUP HEADERS -------
        !           455:   areca_packet[0] = 0x5E;
        !           456:   areca_packet[1] = 0x01;
        !           457:   areca_packet[2] = 0x61;
        !           458:   areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff);
        !           459:   areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff);
        !           460:   areca_packet[5] = 0x1c;  // areca defined code for ATA passthrough command
        !           461: 
        !           462:   // ----- BEGIN TO SETUP PAYLOAD DATA -----
        !           463:   memcpy(&areca_packet[7], "SmrT", 4);  // areca defined password
        !           464:   ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12];
        !           465: 
        !           466:   // Set registers
        !           467:   {
        !           468:     const ata_in_regs & r = in.in_regs;
        !           469:     ata_cmd->features      = r.features;
        !           470:     ata_cmd->sector_count  = r.sector_count;
        !           471:     ata_cmd->sector_number = r.lba_low;
        !           472:     ata_cmd->cylinder_low  = r.lba_mid;
        !           473:     ata_cmd->cylinder_high = r.lba_high;
        !           474:     ata_cmd->device_head   = r.device;
        !           475:     ata_cmd->command       = r.command;
        !           476:   }
        !           477:   bool readdata = false;
        !           478:   if (in.direction == ata_cmd_in::data_in) {
        !           479:       readdata = true;
        !           480:       // the command will read data
        !           481:       areca_packet[6] = 0x13;
        !           482:   }
        !           483:   else if ( in.direction == ata_cmd_in::no_data )
        !           484:   {
        !           485:     // the commands will return no data
        !           486:     areca_packet[6] = 0x15;
        !           487:   }
        !           488:   else if (in.direction == ata_cmd_in::data_out)
        !           489:   {
        !           490:     // the commands will write data
        !           491:     memcpy(ata_cmd->data, in.buffer, in.size);
        !           492:     areca_packet[6] = 0x14;
        !           493:   }
        !           494:   else {
        !           495:       // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE
        !           496:       return set_err(ENOSYS);
        !           497:   }
        !           498: 
        !           499:   areca_packet[11] = get_disknum() - 1;  // disk#
        !           500:   areca_packet[19] = get_encnum() - 1;   // enc#
        !           501: 
        !           502:   // ----- BEGIN TO SEND TO ARECA DRIVER ------
        !           503:   expected = arcmsr_ui_handler(areca_packet, areca_packet_len, return_buff);
        !           504:   if ( expected < 0 )
        !           505:   {
        !           506:     return set_err(EIO);
        !           507:   }
        !           508: 
        !           509:   sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5] ;
        !           510:   if ( ata_out->status )
        !           511:   {
        !           512:     if ( in.in_regs.command == ATA_IDENTIFY_DEVICE
        !           513:      && !nonempty((unsigned char *)in.buffer, in.size))
        !           514:      {
        !           515:         return set_err(ENODEV, "No drive on port %d", get_disknum());
        !           516:      }
        !           517:   }
        !           518: 
        !           519:   // returns with data
        !           520:   if (readdata)
        !           521:   {
        !           522:     memcpy(in.buffer, &return_buff[7], in.size);
        !           523:   }
        !           524: 
        !           525:   // Return register values
        !           526:   {
        !           527:     ata_out_regs & r = out.out_regs;
        !           528:     r.error          = ata_out->error;
        !           529:     r.sector_count   = ata_out->sector_count;
        !           530:     r.lba_low        = ata_out->sector_number;
        !           531:     r.lba_mid        = ata_out->cylinder_low;
        !           532:     r.lba_high       = ata_out->cylinder_high;
        !           533:     r.status         = ata_out->status;
        !           534:   }
        !           535:   return true;
        !           536: }
        !           537: 
        !           538: bool generic_areca_device::arcmsr_scsi_pass_through(struct scsi_cmnd_io * iop)
        !           539: {
        !           540:   // Areca packet format for outgoing:
        !           541:   // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
        !           542:   // B[3~4] : 2 bytes command length + variant data length, little endian
        !           543:   // B[5]   : 1 bytes areca defined command code
        !           544:   // B[6~last-1] : variant bytes payload data
        !           545:   // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
        !           546:   //
        !           547:   //
        !           548:   //   header 3 bytes  length 2 bytes   cmd 1 byte    payload data x bytes  cs 1 byte
        !           549:   // +--------------------------------------------------------------------------------+
        !           550:   // + 0x5E 0x01 0x61 |   0x00 0x00   |     0x1c   | .................... |   0x00    |
        !           551:   // +--------------------------------------------------------------------------------+
        !           552:   //
        !           553: 
        !           554:   //Areca packet format for incoming:
        !           555:   // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
        !           556:   // B[3~4] : 2 bytes payload length, little endian
        !           557:   // B[5~last-1] : variant bytes returned payload data
        !           558:   // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
        !           559:   //
        !           560:   //
        !           561:   //   header 3 bytes  length 2 bytes   payload data x bytes  cs 1 byte
        !           562:   // +-------------------------------------------------------------------+
        !           563:   // + 0x5E 0x01 0x61 |   0x00 0x00   | .................... |   0x00    |
        !           564:   // +-------------------------------------------------------------------+
        !           565:   unsigned char    areca_packet[640];
        !           566:   int areca_packet_len = sizeof(areca_packet);
        !           567:   unsigned char return_buff[2048];
        !           568:   int expected = 0;
        !           569: 
        !           570:   if (iop->cmnd_len > 16) {
        !           571:     set_err(EINVAL, "cmnd_len too large");
        !           572:     return false;
        !           573:   }
        !           574: 
        !           575:   memset(areca_packet, 0, areca_packet_len);
        !           576: 
        !           577:   // ----- BEGIN TO SETUP HEADERS -------
        !           578:   areca_packet[0] = 0x5E;
        !           579:   areca_packet[1] = 0x01;
        !           580:   areca_packet[2] = 0x61;
        !           581:   areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff);
        !           582:   areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff);
        !           583:   areca_packet[5] = 0x1c;
        !           584: 
        !           585:   // ----- BEGIN TO SETUP PAYLOAD DATA -----
        !           586:   areca_packet[6] = 0x16; // scsi pass through
        !           587:   memcpy(&areca_packet[7], "SmrT", 4);  // areca defined password
        !           588:   areca_packet[12] = iop->cmnd_len; // cdb length
        !           589:   memcpy( &areca_packet[35], iop->cmnd, iop->cmnd_len); // cdb
        !           590:   areca_packet[15] = (unsigned char)iop->dxfer_len; // 15(LSB) ~ 18(MSB): data length ( max=512 bytes)
        !           591:   areca_packet[16] = (unsigned char)(iop->dxfer_len >> 8);
        !           592:   areca_packet[17] = (unsigned char)(iop->dxfer_len >> 16);
        !           593:   areca_packet[18] = (unsigned char)(iop->dxfer_len >> 24);
        !           594:   if(iop->dxfer_dir == DXFER_TO_DEVICE)
        !           595:   {
        !           596:     areca_packet[13] |= 0x01;
        !           597:     memcpy(&areca_packet[67], iop->dxferp, iop->dxfer_len);
        !           598:   }
        !           599:   else if (iop->dxfer_dir == DXFER_FROM_DEVICE)
        !           600:   {
        !           601:   }
        !           602:   else if( iop->dxfer_dir == DXFER_NONE)
        !           603:   {
        !           604:   }
        !           605:   else {
        !           606:     // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE
        !           607:     return set_err(ENOSYS);
        !           608:   }
        !           609: 
        !           610:   areca_packet[11] = get_disknum() - 1;  // disk#
        !           611:   areca_packet[19] = get_encnum() - 1;   // enc#
        !           612: 
        !           613:   // ----- BEGIN TO SEND TO ARECA DRIVER ------
        !           614:   expected = arcmsr_ui_handler(areca_packet, areca_packet_len, return_buff);
        !           615:   if ( expected < 0 )
        !           616:   {
        !           617:     return set_err(EIO);
        !           618:   }
        !           619: 
        !           620:   int scsi_status = return_buff[5];
        !           621:   int in_data_len = return_buff[11] | return_buff[12] << 8 | return_buff[13] << 16 | return_buff[14] << 24;
        !           622: 
        !           623:   if (iop->dxfer_dir == DXFER_FROM_DEVICE)
        !           624:   {
        !           625:     memset(iop->dxferp, 0, iop->dxfer_len); // need?
        !           626:     memcpy(iop->dxferp, &return_buff[15], in_data_len);
        !           627:   }
        !           628: 
        !           629:   if(scsi_status == 0xE1 /* Underrun, actual data length < requested data length */)
        !           630:   {
        !           631:       // don't care, just ignore
        !           632:       scsi_status = 0x0;
        !           633:   }
        !           634: 
        !           635:   if(scsi_status != 0x00 && scsi_status != SCSI_STATUS_CHECK_CONDITION)
        !           636:   {
        !           637:     return set_err(EIO);
        !           638:   }
        !           639: 
        !           640:   if(scsi_status == SCSI_STATUS_CHECK_CONDITION)
        !           641:   {
        !           642:     // check condition
        !           643:     iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
        !           644:     iop->resp_sense_len = 4;
        !           645:     iop->sensep[0] = return_buff[7];
        !           646:     iop->sensep[1] = return_buff[8];
        !           647:     iop->sensep[2] = return_buff[9];
        !           648:     iop->sensep[3] = return_buff[10];
        !           649:   }
        !           650: 
        !           651:   return true;
        !           652: }
        !           653: 
        !           654: /////////////////////////////////////////////////////////////
        !           655: areca_ata_device::areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
        !           656: : smart_device(intf, dev_name, "areca", "areca")
        !           657: {
        !           658:   set_encnum(encnum);
        !           659:   set_disknum(disknum);
        !           660:   set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
        !           661: }
        !           662: 
        !           663: areca_ata_device::~areca_ata_device() throw()
        !           664: {
        !           665: 
        !           666: }
        !           667: 
        !           668: bool areca_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
        !           669: {
        !           670:   if (!ata_cmd_is_supported(in,
        !           671:     ata_device::supports_data_out |
        !           672:     ata_device::supports_output_regs |
        !           673:   //ata_device::supports_multi_sector | // TODO
        !           674:     ata_device::supports_48bit_hi_null,
        !           675:     "Areca")
        !           676:   )
        !           677:     return false;
        !           678: 
        !           679:   return arcmsr_ata_pass_through(in, out);
        !           680: }
        !           681: 
        !           682: /////////////////////////////////////////////////////////////
        !           683: areca_scsi_device::areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
        !           684: : smart_device(intf, dev_name, "areca", "areca")
        !           685: {
        !           686:   set_encnum(encnum);
        !           687:   set_disknum(disknum);
        !           688:   set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
        !           689: }
        !           690: 
        !           691: areca_scsi_device::~areca_scsi_device() throw()
        !           692: {
        !           693: 
        !           694: }
        !           695: 
        !           696: bool areca_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop)
        !           697: {
        !           698:   return arcmsr_scsi_pass_through(iop);
        !           699: }
        !           700: 
        !           701: 
        !           702: 
        !           703: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>