| 864 | /// PMC AacRAID support |
| 865 | |
| 866 | #define SAT_ATA_PASSTHROUGH_12LEN 12 |
| 867 | #define SAT_ATA_PASSTHROUGH_16LEN 16 |
| 868 | |
| 869 | #define DEF_SAT_ATA_PASSTHRU_SIZE 16 |
| 870 | #define ATA_RETURN_DESCRIPTOR 9 |
| 871 | |
| 872 | class linux_aacraid_device |
| 873 | :public scsi_device, |
| 874 | public /*extends */ linux_smart_device |
| 875 | { |
| 876 | public: |
| 877 | linux_aacraid_device(smart_interface *intf, const char *name, |
| 878 | unsigned int channel, unsigned int device); |
| 879 | |
| 880 | virtual ~linux_aacraid_device() throw(); |
| 881 | |
| 882 | virtual smart_device *autodetect_open(); |
| 883 | |
| 884 | virtual bool open(); |
| 885 | virtual bool close(); |
| 886 | |
| 887 | virtual bool scsi_pass_through(scsi_cmnd_io *iop); |
| 888 | private: |
| 889 | int afd; |
| 890 | |
| 891 | //Id of the device |
| 892 | int aId; |
| 893 | |
| 894 | //Channel(Lun) of the device |
| 895 | int aLun; |
| 896 | }; |
| 897 | |
| 898 | linux_aacraid_device::linux_aacraid_device(smart_interface *intf, |
| 899 | const char *dev_name ,unsigned int channel,unsigned int device) |
| 900 | : smart_device(intf,dev_name,"aacraid","aacraid"), |
| 901 | linux_smart_device(O_RDWR|O_NONBLOCK), |
| 902 | afd(-1) |
| 903 | { |
| 904 | |
| 905 | aLun = channel; |
| 906 | aId = device; |
| 907 | set_info().info_name=strprintf("%s [aacraid_disk_%02d_%d]",dev_name,channel,device); |
| 908 | set_info().dev_type = strprintf("aacraid,%d,%d",channel,device); |
| 909 | |
| 910 | } |
| 911 | |
| 912 | linux_aacraid_device::~linux_aacraid_device() throw() |
| 913 | { |
| 914 | if(afd >=0) |
| 915 | ::close(afd); |
| 916 | } |
| 917 | |
| 918 | smart_device * linux_aacraid_device::autodetect_open() |
| 919 | { |
| 920 | int report = scsi_debugmode; |
| 921 | |
| 922 | if(!open()) |
| 923 | return this; |
| 924 | |
| 925 | if(strcmp(get_req_type(),"aacraid")) |
| 926 | return this; |
| 927 | |
| 928 | unsigned char req_buff[64] = {0,}; |
| 929 | int req_len = 36; |
| 930 | if(scsiStdInquiry(this,req_buff,req_len)){ |
| 931 | close(); |
| 932 | set_err(EIO,"INQUIRY failed"); |
| 933 | } |
| 934 | |
| 935 | int avail_len = req_buff[4]+5; |
| 936 | int len = (avail_len < req_len?avail_len:req_len); |
| 937 | if (len<36) |
| 938 | return this; |
| 939 | |
| 940 | if(report) |
| 941 | pout("Got AACRaid inquiry ..%s\n",req_buff); |
| 942 | |
| 943 | //Use INQUIRY to detect the type of the device |
| 944 | { |
| 945 | ata_device * newdev = smi()->autodetect_sat_device(this,req_buff,len); |
| 946 | if(newdev){ |
| 947 | return newdev; |
| 948 | } |
| 949 | } |
| 950 | |
| 951 | return this; |
| 952 | } |
| 953 | |
| 954 | bool linux_aacraid_device::open() |
| 955 | { |
| 956 | int report =scsi_debugmode; |
| 957 | |
| 958 | int err; |
| 959 | char line[128]; |
| 960 | int mjr; |
| 961 | FILE *fp =fopen("/proc/devices","r"); |
| 962 | |
| 963 | while(fgets(line,sizeof(line),fp) !=NULL) |
| 964 | { |
| 965 | int a=0; |
| 966 | if(strstr(line,"aac")!=NULL && sscanf(line,"%d aac%n",&mjr,&a) ==1) |
| 967 | { |
| 968 | //Create misc device file in /dev/ used for communication with driver |
| 969 | a = mknod("/dev/aac",S_IFCHR,makedev(mjr,0)); |
| 970 | if(report > 0) |
| 971 | pout("Creating /dev/aac = %d\n",(a >= 0 ? 0 :errno)); |
| 972 | if(a>=0||errno ==EEXIST) |
| 973 | break; |
| 974 | } |
| 975 | } |
| 976 | if( (afd = ::open("/dev/aac",O_RDWR)) >=0 ) { |
| 977 | set_fd(afd); |
| 978 | return true; |
| 979 | } |
| 980 | |
| 981 | err = errno; |
| 982 | linux_smart_device::close(); |
| 983 | return set_err(err,"cannot open /dev/aac"); |
| 984 | } |
| 985 | |
| 986 | bool linux_aacraid_device::close() |
| 987 | { |
| 988 | |
| 989 | if(afd >= 0) |
| 990 | ::close(afd); |
| 991 | |
| 992 | afd = -1; |
| 993 | set_fd(afd); |
| 994 | |
| 995 | return true; |
| 996 | } |
| 997 | |
| 998 | bool linux_aacraid_device::scsi_pass_through(scsi_cmnd_io *iop) |
| 999 | { |
| 1000 | |
| 1001 | int report = scsi_debugmode; |
| 1002 | |
| 1003 | if (report > 0) { |
| 1004 | int k, j; |
| 1005 | const unsigned char * ucp = iop->cmnd; |
| 1006 | const char * np; |
| 1007 | char buff[256]; |
| 1008 | const int sz = (int)sizeof(buff); |
| 1009 | |
| 1010 | np = scsi_get_opcode_name(ucp[0]); |
| 1011 | j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); |
| 1012 | for (k = 0; k < (int)iop->cmnd_len; ++k) |
| 1013 | j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); |
| 1014 | if ((report > 1) && |
| 1015 | (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { |
| 1016 | int trunc = (iop->dxfer_len > 256) ? 1 : 0; |
| 1017 | |
| 1018 | j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " |
| 1019 | "data, len=%d%s:\n", (int)iop->dxfer_len, |
| 1020 | (trunc ? " [only first 256 bytes shown]" : "")); |
| 1021 | dStrHex((const char *)iop->dxferp, |
| 1022 | (trunc ? 256 : iop->dxfer_len) , 1); |
| 1023 | } |
| 1024 | else |
| 1025 | j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); |
| 1026 | pout("%s", buff); |
| 1027 | } |
| 1028 | |
| 1029 | |
| 1030 | int rc; |
| 1031 | user_aac_reply *pReply; |
| 1032 | |
| 1033 | //return test commands |
| 1034 | if (iop->cmnd[0] == 0x00) |
| 1035 | return true; |
| 1036 | |
| 1037 | #ifdef ENVIRONMENT64 |
| 1038 | // Create user 64 bit request |
| 1039 | user_aac_srb64 *pSrb; |
| 1040 | uint8_t *pMalloc = (uint8_t *)malloc(sizeof(user_aac_srb64) + sizeof(user_aac_reply)); |
| 1041 | |
| 1042 | pSrb = (user_aac_srb64*)(pMalloc); |
| 1043 | pReply = (user_aac_reply*)(pMalloc+sizeof(user_aac_srb64)); |
| 1044 | |
| 1045 | #elif defined(ENVIRONMENT32) |
| 1046 | //Create user 32 bit request |
| 1047 | user_aac_srb32 *pSrb; |
| 1048 | uint8_t *pMalloc = (uint8_t *)malloc(sizeof(user_aac_srb32) + sizeof(user_aac_reply)); |
| 1049 | |
| 1050 | pSrb = (user_aac_srb32*)(pMalloc); |
| 1051 | pReply = (user_aac_reply*)(pMalloc+sizeof(user_aac_srb32)); |
| 1052 | #endif |
| 1053 | |
| 1054 | |
| 1055 | memset(pSrb,0,sizeof(pSrb)); |
| 1056 | memset(pReply,0,sizeof(pReply)); |
| 1057 | |
| 1058 | pSrb->function = SRB_FUNCTION_EXECUTE_SCSI; |
| 1059 | //channel is 0 always |
| 1060 | pSrb->channel = 0; |
| 1061 | pSrb->id = aId; |
| 1062 | pSrb->lun = aLun; |
| 1063 | pSrb->timeout = 0; |
| 1064 | |
| 1065 | pSrb->retry_limit = 0; |
| 1066 | pSrb->cdb_size = iop->cmnd_len; |
| 1067 | |
| 1068 | switch(iop->dxfer_dir){ |
| 1069 | case DXFER_NONE: |
| 1070 | pSrb->flags = SRB_NoDataXfer; |
| 1071 | break; |
| 1072 | case DXFER_FROM_DEVICE: |
| 1073 | pSrb->flags = SRB_DataIn; |
| 1074 | break; |
| 1075 | case DXFER_TO_DEVICE: |
| 1076 | pSrb->flags = SRB_DataOut; |
| 1077 | break; |
| 1078 | default: |
| 1079 | pout("aacraid: bad dxfer_dir\n"); |
| 1080 | return set_err(EINVAL, "aacraid: bad dxfer_dir\n"); |
| 1081 | } |
| 1082 | |
| 1083 | if(iop->dxfer_len > 0){ |
| 1084 | |
| 1085 | #ifdef ENVIRONMENT64 |
| 1086 | pSrb->sg64.count = 1; |
| 1087 | pSrb->sg64.sg64[0].addr64.lo32 = ((intptr_t)iop->dxferp) & 0x00000000ffffffff; |
| 1088 | pSrb->sg64.sg64[0].addr64.hi32 = ((intptr_t)iop->dxferp) >> 32; |
| 1089 | pSrb->sg64.sg64[0].length = (uint32_t)iop->dxfer_len; |
| 1090 | pSrb->count = sizeof(user_aac_srb64) + (sizeof(user_sgentry64)*(pSrb->sg64.count-1)); |
| 1091 | #elif defined(ENVIRONMENT32) |
| 1092 | pSrb->sg32.count =1; |
| 1093 | pSrb->sg32.sg32[0].addr32 = (intptr_t)iop->dxferp; |
| 1094 | pSrb->sg32.sg32[0].length = (uint32_t)iop->dxfer_len; |
| 1095 | pSrb->count = sizeof(user_aac_srb32) + (sizeof(user_sgentry32)*(pSrb->sg32.count-1)); |
| 1096 | #endif |
| 1097 | } |
| 1098 | |
| 1099 | memcpy(pSrb->cdb,iop->cmnd,iop->cmnd_len); |
| 1100 | |
| 1101 | rc=0; |
| 1102 | errno=0; |
| 1103 | rc=ioctl(afd,FSACTL_SEND_RAW_SRB,pSrb); |
| 1104 | if(rc!=0 || pReply->srb_status != 0x01){ |
| 1105 | if(pReply->srb_status == 0x08){ |
| 1106 | return set_err(EIO, "aacraid: Device %d %d does not exist\n" ,aLun,aId ); |
| 1107 | } |
| 1108 | return set_err((errno ? errno : EIO), "aacraid result: %d.%d = %d/%d", |
| 1109 | aLun, aId, errno, |
| 1110 | pReply->srb_status); |
| 1111 | } |
| 1112 | |
| 1113 | return true; |
| 1114 | } |
| 1115 | |
| 1116 | |
| 1117 | ///////////////////////////////////////////////////////////////////////////// |