2 * JMraidcon - A console interface to the JMicron JMB394 H/W RAID controller
3 * Copyright (C) 2010 Werner Johansson, <wj@xnk.nu>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include <sys/ioctl.h>
29 #include <asm/byteorder.h> // For __le32_to_cpu etc
31 #define SECTORSIZE (512)
32 #define READ_CMD (0x28)
33 #define WRITE_CMD (0x2a)
34 #define RW_CMD_LEN (10)
36 // First 4 bytes are always the same for all the scrambled commands, next 4 bytes forms an incrementing command id
37 const uint8_t probe6[]={ 0x22, 0x03, 0x7b, 0x19, 0x06,0x00,0x00,0x00, 0x00, 0x01, 0x02, 0xff, 0x01 }; // This returns very little info (at the end)?
38 const uint8_t probe7[]={ 0x22, 0x03, 0x7b, 0x19, 0x0b,0x00,0x00,0x00, 0x00, 0x01, 0x01, 0xff }; // This cmd returns the "RAID Manager" name
39 const uint8_t probe8[]={ 0x22, 0x03, 0x7b, 0x19, 0x0c,0x00,0x00,0x00, 0x00, 0x01, 0x02, 0xff, 0x0a };
40 const uint8_t probe9[]={ 0x22, 0x03, 0x7b, 0x19, 0x0e,0x00,0x00,0x00, 0x00, 0x02, 0x01, 0xff }; // This returns the names of disks attached (or in a specific RAID volume?)
41 const uint8_t probe11[]={ 0x22, 0x03, 0x7b, 0x19, 0x10,0x00,0x00,0x00, 0x00, 0x02, 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Identify disk0?
42 const uint8_t probe12[]={ 0x22, 0x03, 0x7b, 0x19, 0x11,0x00,0x00,0x00, 0x00, 0x02, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01 }; // Identify disk1?
43 const uint8_t probe13[]={ 0x22, 0x03, 0x7b, 0x19, 0x12,0x00,0x00,0x00, 0x00, 0x02, 0x02, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02 }; // Identify disk2?
44 const uint8_t probe14[]={ 0x22, 0x03, 0x7b, 0x19, 0x13,0x00,0x00,0x00, 0x00, 0x02, 0x02, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03 }; // Identify disk3?
45 const uint8_t probe15[]={ 0x22, 0x03, 0x7b, 0x19, 0x14,0x00,0x00,0x00, 0x00, 0x02, 0x02, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04 }; // Identify disk4?
46 const uint8_t probe16[]={ 0x22, 0x03, 0x7b, 0x19, 0x15,0x00,0x00,0x00, 0x00, 0x03, 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }; // AWARD I5, wtf??
47 const uint8_t probe17[]={ 0x22, 0x03, 0x7b, 0x19, 0x16,0x00,0x00,0x00, 0x00, 0x03, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01 }; // ??
48 const uint8_t probe18[]={ 0x22, 0x03, 0x7b, 0x19, 0x17,0x00,0x00,0x00, 0x00, 0x03, 0x02, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02 }; // ??
49 const uint8_t probe19[]={ 0x22, 0x03, 0x7b, 0x19, 0x18,0x00,0x00,0x00, 0x00, 0x03, 0x02, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03 }; // ??
50 const uint8_t probe20[]={ 0x22, 0x03, 0x7b, 0x19, 0x19,0x00,0x00,0x00, 0x00, 0x03, 0x02, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04 }; // ??
51 const uint8_t probe21[]={ 0x22, 0x03, 0x7b, 0x19, 0x1a,0x00,0x00,0x00, 0x00, 0x01, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; // Returns nothing?
52 const uint8_t probe23[]={ 0x22, 0x03, 0x7b, 0x19, 0x1c,0x00,0x00,0x00, 0x00, 0x02, 0x03, 0xff, 0x00, 0x02, 0x00, 0xe0, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0 }; // SMART data disk0?
53 const uint8_t probe24[]={ 0x22, 0x03, 0x7b, 0x19, 0x1d,0x00,0x00,0x00, 0x00, 0x02, 0x03, 0xff, 0x00, 0x02, 0x00, 0xe0, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0 }; // SMART data disk0 part2?
54 const uint8_t probe25[]={ 0x22, 0x03, 0x7b, 0x19, 0x1e,0x00,0x00,0x00, 0x00, 0x02, 0x03, 0xff, 0x01, 0x02, 0x00, 0xe0, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0 }; // SMART data disk1?
55 const uint8_t probe26[]={ 0x22, 0x03, 0x7b, 0x19, 0x1f,0x00,0x00,0x00, 0x00, 0x02, 0x03, 0xff, 0x01, 0x02, 0x00, 0xe0, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0 }; // SMART data disk1 part2?
56 const uint8_t probe27[]={ 0x22, 0x03, 0x7b, 0x19, 0x20,0x00,0x00,0x00, 0x00, 0x02, 0x03, 0xff, 0x02, 0x02, 0x00, 0xe0, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0 }; // SMART data disk2?
57 const uint8_t probe28[]={ 0x22, 0x03, 0x7b, 0x19, 0x21,0x00,0x00,0x00, 0x00, 0x02, 0x03, 0xff, 0x02, 0x02, 0x00, 0xe0, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0 }; // SMART data disk2 part2?
60 #warning FIXME: Should not use a hard-coded sector number (0x21), even though it is backed up and restored afterwards
61 uint8_t rwCmdBlk[RW_CMD_LEN] =
62 {READ_CMD, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x01, 0x00}; // SECTOR NUMBER 0x21!!!!!!
64 uint32_t Do_JM_Cmd( int theFD, uint32_t* theCmd, uint32_t* theResp ) {
67 // Calculate CRC for the request
68 uint32_t myCRC = JM_CRC( theCmd, 0x7f );
70 // Stash the CRC at the end
71 theCmd[0x7f] = __cpu_to_le32( myCRC );
72 // printf("Command CRC: 0x%08x\n", myCRC);
74 // Make the data look really 31337 (or not)
77 io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
78 rwCmdBlk[0] = WRITE_CMD;
79 io_hdr.dxferp = theCmd;
80 ioctl(theFD, SG_IO, &io_hdr);
82 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
83 rwCmdBlk[0] = READ_CMD;
84 io_hdr.dxferp = theResp;
85 ioctl(theFD, SG_IO, &io_hdr);
87 // Make the 31337-looking response sane
90 myCRC = JM_CRC( theResp, 0x7f);
91 if( myCRC != __le32_to_cpu( theResp[0x7f] ) ) {
92 printf( "Warning: Response CRC 0x%08x does not match the calculated 0x%08x!!\n", __le32_to_cpu( theResp[0x7f] ), myCRC );
98 static void hexdump(uint8_t* thePtr, uint32_t theLen) {
100 for(looper=0; looper<theLen; looper++) {
101 printf("0x%02x, ", thePtr[looper]);
102 if((looper&0x0f)==0x0f) {
104 for(asc=looper-0x0f; asc<looper; asc++) {
105 uint8_t theOut=thePtr[asc];
106 if(theOut<0x20 || theOut>0x7f) theOut='.';
115 static void TestCmd( int theFD, uint8_t* theCmd, uint32_t theLen) {
116 uint8_t tempBuf1[SECTORSIZE];
117 uint8_t tempBuf2[SECTORSIZE];
119 // Entire sector is always sent, so zero fill cmd
120 memset( tempBuf1, 0, SECTORSIZE );
121 memcpy( tempBuf1, theCmd, theLen );
123 printf( "Sending command:\n");
124 hexdump( tempBuf1, (theLen+0x0f)&0x1f0 );
125 Do_JM_Cmd( theFD, (uint32_t*)tempBuf1, (uint32_t*)tempBuf2 );
126 printf( "Response:\n");
127 hexdump(tempBuf2, SECTORSIZE);
130 int main(int argc, char * argv[])
133 uint8_t saveBuf[SECTORSIZE];
134 uint8_t probeBuf[SECTORSIZE];
135 uint8_t sense_buffer[32];
137 printf("JMraidcon version x, Copyright (C) 2010 Werner Johansson\n" \
138 "JMraidcon comes with ABSOLUTELY NO WARRANTY.\n" \
139 "This is free software, and you are welcome\n" \
140 "to redistribute it under certain conditions.\n\n" );
143 printf("Usage : JMraidcon /dev/sd<X>\n");
147 if ((sg_fd = open(argv[1], O_RDWR)) < 0) {
148 printf("Cannot open device");
152 // Check if the opened device looks like a sg one.
153 // Inspired by the sg_simple0 example
154 if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
155 printf("%s is not an sg device, or old sg driver\n", argv[1]);
159 // Setup the ioctl struct
160 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
161 io_hdr.interface_id = 'S';
162 io_hdr.cmd_len = sizeof(rwCmdBlk);
163 io_hdr.mx_sb_len = sizeof(sense_buffer);
164 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
165 io_hdr.dxfer_len = SECTORSIZE;
166 io_hdr.dxferp = saveBuf;
167 io_hdr.cmdp = rwCmdBlk;
168 io_hdr.sbp = sense_buffer;
169 io_hdr.timeout = 3000;
171 // Add more error handling like this later
172 if( ioctl( sg_fd, SG_IO, &io_hdr ) < 0 ) {
173 printf("ioctl SG_IO failed");
177 // Generate and send the initial "wakeup" data
178 // No idea what the second dword represents at this point
179 // Note that these (and all other writes) should be directed to an unused sector!!
180 memset( probeBuf, 0, SECTORSIZE );
183 uint32_t* probeBuf32 = (uint32_t*)probeBuf;
185 // Populate with the static data
186 probeBuf32[0 >> 2] = __cpu_to_le32( 0x197b0325 );
187 probeBuf32[0x1f8 >> 2] = __cpu_to_le32( 0x10eca1db );
188 for( uint32_t i=0x10; i<0x1f8; i++ ) {
189 probeBuf[i] = i&0xff;
192 io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
193 rwCmdBlk[0] = WRITE_CMD;
194 io_hdr.dxferp = probeBuf;
196 // The only value (except the CRC at the end) that changes between the 4 wakeup sectors
197 probeBuf32[4 >> 2] = __cpu_to_le32( 0x3c75a80b );
198 uint32_t myCRC = JM_CRC( probeBuf32, 0x1fc >> 2 );
199 probeBuf32[0x1fc >> 2] = __cpu_to_le32( myCRC );
200 ioctl(sg_fd, SG_IO, &io_hdr);
202 probeBuf32[4 >> 2] = __cpu_to_le32( 0x0388e337 );
203 myCRC = JM_CRC( probeBuf32, 0x1fc >> 2 );
204 probeBuf32[0x1fc >> 2] = __cpu_to_le32( myCRC );
205 ioctl(sg_fd, SG_IO, &io_hdr);
207 probeBuf32[4 >> 2] = __cpu_to_le32( 0x689705f3 );
208 myCRC = JM_CRC( probeBuf32, 0x1fc >> 2 );
209 probeBuf32[0x1fc >> 2] = __cpu_to_le32( myCRC );
210 ioctl(sg_fd, SG_IO, &io_hdr);
212 probeBuf32[4 >> 2] = __cpu_to_le32( 0xe00c523a );
213 myCRC = JM_CRC( probeBuf32, 0x1fc >> 2 );
214 probeBuf32[0x1fc >> 2] = __cpu_to_le32( myCRC );
215 ioctl(sg_fd, SG_IO, &io_hdr);
217 // Initial probe complete, now send scrambled commands to the same sector
219 TestCmd( sg_fd, (uint8_t*)probe6, sizeof(probe6) );
220 TestCmd( sg_fd, (uint8_t*)probe7, sizeof(probe7) );
221 TestCmd( sg_fd, (uint8_t*)probe8, sizeof(probe8) );
222 TestCmd( sg_fd, (uint8_t*)probe9, sizeof(probe9) );
223 TestCmd( sg_fd, (uint8_t*)probe11, sizeof(probe11) );
224 TestCmd( sg_fd, (uint8_t*)probe12, sizeof(probe12) );
225 TestCmd( sg_fd, (uint8_t*)probe13, sizeof(probe13) );
226 TestCmd( sg_fd, (uint8_t*)probe14, sizeof(probe14) );
227 TestCmd( sg_fd, (uint8_t*)probe15, sizeof(probe15) );
228 TestCmd( sg_fd, (uint8_t*)probe16, sizeof(probe16) );
229 TestCmd( sg_fd, (uint8_t*)probe17, sizeof(probe17) );
230 TestCmd( sg_fd, (uint8_t*)probe18, sizeof(probe18) );
231 TestCmd( sg_fd, (uint8_t*)probe19, sizeof(probe19) );
232 TestCmd( sg_fd, (uint8_t*)probe20, sizeof(probe20) );
233 TestCmd( sg_fd, (uint8_t*)probe21, sizeof(probe21) );
234 TestCmd( sg_fd, (uint8_t*)probe23, sizeof(probe23) );
235 TestCmd( sg_fd, (uint8_t*)probe24, sizeof(probe24) );
236 TestCmd( sg_fd, (uint8_t*)probe25, sizeof(probe25) );
237 TestCmd( sg_fd, (uint8_t*)probe26, sizeof(probe26) );
238 TestCmd( sg_fd, (uint8_t*)probe27, sizeof(probe27) );
239 TestCmd( sg_fd, (uint8_t*)probe28, sizeof(probe28) );
241 // Restore the original data to the sector
242 io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
243 rwCmdBlk[0] = WRITE_CMD;
244 io_hdr.dxferp = saveBuf;
245 ioctl(sg_fd, SG_IO, &io_hdr);