More cleanup of the SMART ATA passthrough commands
[JMraidcon.git] / src / JMraidcon.c
1 /*
2  * JMraidcon - A console interface to the JMicron JMB394 H/W RAID controller
3  * Copyright (C) 2010 Werner Johansson, <wj@xnk.nu>
4  *
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.
9  *
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.
14  *
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.
18  */
19
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <scsi/sg.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <sys/ioctl.h>
26 #include <string.h>
27 #include "jm_crc.h"
28 #include "sata_xor.h"
29 #include <asm/byteorder.h> // For __le32_to_cpu etc
30
31 #define SECTORSIZE (512)
32 #define READ_CMD (0x28)
33 #define WRITE_CMD (0x2a)
34 #define RW_CMD_LEN (10)
35
36 #define JM_RAID_WAKEUP_CMD    ( 0x197b0325 )
37 #define JM_RAID_SCRAMBLED_CMD ( 0x197b0322 )
38
39 // First 4 bytes are always the same for all the scrambled commands, next 4 bytes forms an incrementing command id
40 // (and these 8 bytes are now automatically prepended and no longer listed here)
41 const uint8_t probe6[]={ 0x00, 0x01, 0x02, 0xff, 0x01 }; // This returns very little info (at the end)?
42 const uint8_t probe7[]={ 0x00, 0x01, 0x01, 0xff }; // This cmd returns the "RAID Manager" name
43 const uint8_t probe8[]={ 0x00, 0x01, 0x02, 0xff, 0x0a };
44 const uint8_t probe9[]={ 0x00, 0x02, 0x01, 0xff }; // This returns the names of disks attached (or in a specific RAID volume?)
45
46 // The Identify disk commands does not return the data in the same format as the normal IDENTIFY DEVICE!??
47 const uint8_t probe11[]={ 0x00, 0x02, 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Identify disk0
48 const uint8_t probe12[]={ 0x00, 0x02, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01 }; // Identify disk1
49 const uint8_t probe13[]={ 0x00, 0x02, 0x02, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02 }; // Identify disk2
50 const uint8_t probe14[]={ 0x00, 0x02, 0x02, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03 }; // Identify disk3
51 const uint8_t probe15[]={ 0x00, 0x02, 0x02, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04 }; // Identify disk4
52 const uint8_t probe16[]={ 0x00, 0x03, 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }; // AWARD I5, wtf??
53 const uint8_t probe17[]={ 0x00, 0x03, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01 }; // ??
54 const uint8_t probe18[]={ 0x00, 0x03, 0x02, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02 }; // ??
55 const uint8_t probe19[]={ 0x00, 0x03, 0x02, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03 }; // ??
56 const uint8_t probe20[]={ 0x00, 0x03, 0x02, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04 }; // ??
57 const uint8_t probe21[]={ 0x00, 0x01, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; // Returns nothing?
58 const uint8_t probe23[]={ 0x00, 0x02, 0x03, 0xff, 0x00, 0x02, 0x00, 0xe0, 0x00, 0x00,         // disk0 ata passthrough
59         0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0, 0x00 }; // SMART READ ATTRIBUTE VALUE ata cmd
60
61 const uint8_t probe24[]={ 0x00, 0x02, 0x03, 0xff, 0x00, 0x02, 0x00, 0xe0, 0x00, 0x00,         // disk0 ata passthrough, again
62         0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0, 0x00 }; // SMART READ ATTRIBUTE THRESHOLDS ata cmd
63
64 const uint8_t probe25[]={ 0x00, 0x02, 0x03, 0xff, 0x01, 0x02, 0x00, 0xe0, 0x00, 0x00,         // disk1 ata passthrough
65         0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0, 0x00 }; // SMART READ ATTRIBUTE VALUE ata cmd
66
67 const uint8_t probe26[]={ 0x00, 0x02, 0x03, 0xff, 0x01, 0x02, 0x00, 0xe0, 0x00, 0x00,         // disk1 ata passthrough, again
68         0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0, 0x00 }; // SMART READ ATTRIBUTE THRESHOLDS ata cmd
69
70 const uint8_t probe27[]={ 0x00, 0x02, 0x03, 0xff, 0x02, 0x02, 0x00, 0xe0, 0x00, 0x00,         // disk2 ata passthrough
71         0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0, 0x00 }; // SMART READ ATTRIBUTE VALUE ata cmd
72
73 const uint8_t probe28[]={ 0x00, 0x02, 0x03, 0xff, 0x02, 0x02, 0x00, 0xe0, 0x00, 0x00,         // disk2 ata passthrough, again
74         0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0xc2, 0x00, 0xa0, 0x00, 0xb0, 0x00 }; // SMART READ ATTRIBUTE THRESHOLDS ata cmd
75
76     sg_io_hdr_t io_hdr;
77 #warning FIXME: Should not use a hard-coded sector number (0x21), even though it is backed up and restored afterwards
78     uint8_t rwCmdBlk[RW_CMD_LEN] =
79                     {READ_CMD, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x01, 0x00}; // SECTOR NUMBER 0x21!!!!!!
80
81 uint32_t Do_JM_Cmd( int theFD, uint32_t* theCmd, uint32_t* theResp ) {
82     uint32_t retval=0;
83
84     // Calculate CRC for the request
85     uint32_t myCRC = JM_CRC( theCmd, 0x7f );
86
87     // Stash the CRC at the end
88     theCmd[0x7f] = __cpu_to_le32( myCRC );
89 //    printf("Command CRC: 0x%08x\n", myCRC);
90
91     // Make the data look really 31337 (or not)
92     SATA_XOR( theCmd );
93
94     io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
95     rwCmdBlk[0] = WRITE_CMD;
96     io_hdr.dxferp = theCmd;
97     ioctl(theFD, SG_IO, &io_hdr);
98
99     io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
100     rwCmdBlk[0] = READ_CMD;
101     io_hdr.dxferp = theResp;
102     ioctl(theFD, SG_IO, &io_hdr);
103
104     // Make the 31337-looking response sane
105     SATA_XOR( theResp );
106
107     myCRC = JM_CRC( theResp, 0x7f);
108     if( myCRC != __le32_to_cpu( theResp[0x7f] ) ) {
109         printf( "Warning: Response CRC 0x%08x does not match the calculated 0x%08x!!\n", __le32_to_cpu( theResp[0x7f] ), myCRC );
110         retval=1;
111     }
112     return retval;
113 }
114
115 static void hexdump(uint8_t* thePtr, uint32_t theLen) {
116     int looper;
117     for(looper=0; looper<theLen; looper++) {
118         printf("0x%02x, ", thePtr[looper]);
119         if((looper&0x0f)==0x0f) {
120             int asc;
121             for(asc=looper-0x0f; asc<=looper; asc++) {
122                 uint8_t theOut=thePtr[asc];
123                 if(theOut<0x20 || theOut>0x7f) theOut='.';
124                 printf("%c",theOut);
125             }
126             printf("\n");
127         }
128     }
129     printf("\n");
130 }
131
132 static void TestCmd( int theFD, uint8_t* theCmd, uint32_t theLen) {
133     uint8_t tempBuf1[SECTORSIZE];
134     uint32_t* tempBuf1_32 = (uint32_t*)tempBuf1;
135     uint8_t tempBuf2[SECTORSIZE];
136     static uint32_t cmdNum = 1;
137
138     // Entire sector is always sent, so zero fill cmd
139     memset( tempBuf1, 0, SECTORSIZE );
140     memcpy( tempBuf1+0x08, theCmd, theLen );
141
142     tempBuf1_32[0] = __cpu_to_le32( JM_RAID_SCRAMBLED_CMD );
143     tempBuf1_32[1] = __cpu_to_le32( cmdNum++ );
144     theLen+=0x08; // Adding the SCRAMBLED_CMD and command number
145
146     printf( "Sending command:\n");
147     hexdump( tempBuf1, (theLen+0x0f)&0x1f0 );
148     Do_JM_Cmd( theFD, (uint32_t*)tempBuf1, (uint32_t*)tempBuf2 );
149     printf( "Response:\n");
150     hexdump(tempBuf2, SECTORSIZE);
151 }
152
153 int main(int argc, char * argv[])
154 {
155     int sg_fd, k;
156     uint8_t saveBuf[SECTORSIZE];
157     uint8_t probeBuf[SECTORSIZE];
158     uint8_t sense_buffer[32];
159
160     printf("JMraidcon version x, Copyright (C) 2010 Werner Johansson\n" \
161         "JMraidcon comes with ABSOLUTELY NO WARRANTY.\n" \
162         "This is free software, and you are welcome\n" \
163         "to redistribute it under certain conditions.\n\n" );
164
165     if (2 != argc) {
166         printf("Usage : JMraidcon /dev/sd<X>\n");
167         return 1;
168     }
169
170     if ((sg_fd = open(argv[1], O_RDWR)) < 0) {
171         printf("Cannot open device");
172         return 1;
173     }
174
175     // Check if the opened device looks like a sg one.
176     // Inspired by the sg_simple0 example
177     if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
178         printf("%s is not an sg device, or old sg driver\n", argv[1]);
179         return 1;
180     }
181
182     // Setup the ioctl struct
183     memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
184     io_hdr.interface_id = 'S';
185     io_hdr.cmd_len = sizeof(rwCmdBlk);
186     io_hdr.mx_sb_len = sizeof(sense_buffer);
187     io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
188     io_hdr.dxfer_len = SECTORSIZE;
189     io_hdr.dxferp = saveBuf;
190     io_hdr.cmdp = rwCmdBlk;
191     io_hdr.sbp = sense_buffer;
192     io_hdr.timeout = 3000;
193
194     // Add more error handling like this later
195     if( ioctl( sg_fd, SG_IO, &io_hdr ) < 0 ) {
196         printf("ioctl SG_IO failed");
197         return 1;
198     }
199
200     // Generate and send the initial "wakeup" data
201     // No idea what the second dword represents at this point
202     // Note that these (and all other writes) should be directed to an unused sector!!
203     memset( probeBuf, 0, SECTORSIZE );
204
205     // For wide access
206     uint32_t* probeBuf32 = (uint32_t*)probeBuf;
207
208     // Populate with the static data
209     probeBuf32[0 >> 2] = __cpu_to_le32( JM_RAID_WAKEUP_CMD );
210     probeBuf32[0x1f8 >> 2] = __cpu_to_le32( 0x10eca1db );
211     for( uint32_t i=0x10; i<0x1f8; i++ ) {
212         probeBuf[i] = i&0xff;
213     }
214
215     io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
216     rwCmdBlk[0] = WRITE_CMD;
217     io_hdr.dxferp = probeBuf;
218
219     // The only value (except the CRC at the end) that changes between the 4 wakeup sectors
220     probeBuf32[4 >> 2] = __cpu_to_le32( 0x3c75a80b );
221     uint32_t myCRC = JM_CRC( probeBuf32, 0x1fc >> 2 );
222     probeBuf32[0x1fc >> 2] = __cpu_to_le32( myCRC );
223     ioctl(sg_fd, SG_IO, &io_hdr);
224
225     probeBuf32[4 >> 2] = __cpu_to_le32( 0x0388e337 );
226     myCRC = JM_CRC( probeBuf32, 0x1fc >> 2 );
227     probeBuf32[0x1fc >> 2] = __cpu_to_le32( myCRC );
228     ioctl(sg_fd, SG_IO, &io_hdr);
229
230     probeBuf32[4 >> 2] = __cpu_to_le32( 0x689705f3 );
231     myCRC = JM_CRC( probeBuf32, 0x1fc >> 2 );
232     probeBuf32[0x1fc >> 2] = __cpu_to_le32( myCRC );
233     ioctl(sg_fd, SG_IO, &io_hdr);
234
235     probeBuf32[4 >> 2] = __cpu_to_le32( 0xe00c523a );
236     myCRC = JM_CRC( probeBuf32, 0x1fc >> 2 );
237     probeBuf32[0x1fc >> 2] = __cpu_to_le32( myCRC );
238     ioctl(sg_fd, SG_IO, &io_hdr);
239
240     // Initial probe complete, now send scrambled commands to the same sector
241
242     TestCmd( sg_fd, (uint8_t*)probe6, sizeof(probe6) );
243     TestCmd( sg_fd, (uint8_t*)probe7, sizeof(probe7) );
244     TestCmd( sg_fd, (uint8_t*)probe8, sizeof(probe8) );
245     TestCmd( sg_fd, (uint8_t*)probe9, sizeof(probe9) );
246     TestCmd( sg_fd, (uint8_t*)probe11, sizeof(probe11) );
247     TestCmd( sg_fd, (uint8_t*)probe12, sizeof(probe12) );
248     TestCmd( sg_fd, (uint8_t*)probe13, sizeof(probe13) );
249     TestCmd( sg_fd, (uint8_t*)probe14, sizeof(probe14) );
250     TestCmd( sg_fd, (uint8_t*)probe15, sizeof(probe15) );
251     TestCmd( sg_fd, (uint8_t*)probe16, sizeof(probe16) );
252     TestCmd( sg_fd, (uint8_t*)probe17, sizeof(probe17) );
253     TestCmd( sg_fd, (uint8_t*)probe18, sizeof(probe18) );
254     TestCmd( sg_fd, (uint8_t*)probe19, sizeof(probe19) );
255     TestCmd( sg_fd, (uint8_t*)probe20, sizeof(probe20) );
256     TestCmd( sg_fd, (uint8_t*)probe21, sizeof(probe21) );
257     TestCmd( sg_fd, (uint8_t*)probe23, sizeof(probe23) );
258     TestCmd( sg_fd, (uint8_t*)probe24, sizeof(probe24) );
259     TestCmd( sg_fd, (uint8_t*)probe25, sizeof(probe25) );
260     TestCmd( sg_fd, (uint8_t*)probe26, sizeof(probe26) );
261     TestCmd( sg_fd, (uint8_t*)probe27, sizeof(probe27) );
262     TestCmd( sg_fd, (uint8_t*)probe28, sizeof(probe28) );
263
264     // Restore the original data to the sector
265     io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
266     rwCmdBlk[0] = WRITE_CMD;
267     io_hdr.dxferp = saveBuf;
268     ioctl(sg_fd, SG_IO, &io_hdr);
269
270     close(sg_fd);
271     return 0;
272 }
273