mgh: fix for default HDD DMA mode, that wasn't correctly set
[open-ps2-loader.git] / modules / hdd / hdldsvr / hdldsvr.c
blob1c9ef639e6fd2d7d2f2f25018f8e54ac94883fd2
1 /*
2 Copyright 2010, jimmikaelkael
3 Licenced under Academic Free License version 3.0
4 Review OpenUsbLd README & LICENSE files for further details.
5 */
7 #include <loadcore.h>
8 #include <stdio.h>
9 #include <iomanX.h>
10 #include <ps2ip.h>
11 #include <sysclib.h>
12 #include <thbase.h>
13 #include <thsemap.h>
14 #include <errno.h>
16 #include "smsutils.h"
18 //#define FAKE_WRITES
20 #define MODNAME "hdldsvr"
21 IRX_ID(MODNAME, 1, 1);
23 struct irx_export_table _exp_hdldsvr;
25 #define TCP_SERVER_PORT 45233
26 #define UDP_SERVER_PORT 45233
28 #define CMD_SIZE 16
29 #define CMD_STAT 0x73746174 // 'stat'; get HDD size in KB
30 #define CMD_READ 0x72656164 // 'read'; read sectors from HDD
31 #define CMD_WRIT 0x77726974 // 'writ'; write sectors to HDD
32 #define CMD_WRIS 0x77726973 // 'wris'; get last write status
33 #define CMD_FLSH 0x666c7368 // 'flsh'; flush write buff
34 #define CMD_POWX 0x706f7778 // 'powx'; poweroff system
36 #define HDD_SECTOR_SIZE 512 // HDD sector size in bytes
37 #define NET_NUM_SECTORS 2048 // max # of sectors to move via network
39 #define STATUS_AVAIL 0 // expecting command
40 #define STATUS_BUSY_RESPOND 1 // sending back response (and readen data)
41 #define STATUS_BUSY_WRITE 2 // expecting write data
42 #define STATUS_WRITE_STAT 3 // sending back write stat response
44 #define SETBIT(mask, bit) (mask)[(bit) / 32] |= 1 << ((bit) % 32)
45 #define GETBIT(mask, bit) ((mask)[(bit) / 32] & (1 << ((bit) % 32)))
47 #define APA_DEVCTL_MAX_SECTORS 0x00004801 // max partition size(in sectors)
48 #define APA_DEVCTL_TOTAL_SECTORS 0x00004802
49 #define APA_DEVCTL_IDLE 0x00004803
50 #define APA_DEVCTL_FLUSH_CACHE 0x00004804
51 #define APA_DEVCTL_SWAP_TMP 0x00004805
52 #define APA_DEVCTL_DEV9_SHUTDOWN 0x00004806
53 #define APA_DEVCTL_STATUS 0x00004807
54 #define APA_DEVCTL_FORMAT 0x00004808
55 #define APA_DEVCTL_SMART_STAT 0x00004809
56 #define APA_DEVCTL_GETTIME 0x00006832
57 #define APA_DEVCTL_SET_OSDMBR 0x00006833 // arg = hddSetOsdMBR_t
58 #define APA_DEVCTL_GET_SECTOR_ERROR 0x00006834
59 #define APA_DEVCTL_GET_ERROR_PART_NAME 0x00006835 // bufp = namebuffer[0x20]
60 #define APA_DEVCTL_ATA_READ 0x00006836 // arg = hddAtaTransfer_t
61 #define APA_DEVCTL_ATA_WRITE 0x00006837 // arg = hddAtaTransfer_t
62 #define APA_DEVCTL_SCE_IDENTIFY_DRIVE 0x00006838 // bufp = buffer for atadSceIdentifyDrive
63 #define APA_DEVCTL_IS_48BIT 0x00006840
64 #define APA_DEVCTL_SET_TRANSFER_MODE 0x00006841
65 #define APA_DEVCTL_ATA_IOP_WRITE 0x00006842
68 void tcp_server_thread(void *args);
69 void udp_server_thread(void *args);
71 static int tcp_server_tid, udp_server_tid;
72 static int udp_mutex = -1;
74 static u8 tcp_buf[CMD_SIZE + HDD_SECTOR_SIZE*2] __attribute__((aligned(64)));
75 static u8 udp_buf[8 + HDD_SECTOR_SIZE*2] __attribute__((aligned(64)));
77 struct tcp_packet_header {
78 u32 command;
79 u32 start_sector;
80 u32 num_sectors;
81 u32 result;
82 } __attribute__((packed));
84 typedef struct {
85 struct tcp_packet_header hdr;
86 u8 data[HDD_SECTOR_SIZE*2];
87 } tcp_packet_t __attribute__((packed));
89 typedef struct {
90 u8 data[HDD_SECTOR_SIZE * 2];
91 u32 command;
92 u32 start_sector;
93 } udp_packet_t __attribute__((packed));
95 struct stats {
96 int status;
97 u32 command;
98 u32 start_sector;
99 u32 num_sectors;
100 u8 *data;
101 u32 bitmask[(NET_NUM_SECTORS + 31) / 32];
102 u32 bitmask_copy[(NET_NUM_SECTORS + 31) / 32]; // endian-neutral
103 u8 buffer[HDD_SECTOR_SIZE * (NET_NUM_SECTORS + 1)]; // 1MB on IOP !!! Huge !
106 static struct stats gstats __attribute__((aligned(64)));
108 //-------------------------------------------------------------------------
109 int _start(int argc, char** argv)
111 iop_thread_t thread_param;
113 // register exports
114 RegisterLibraryEntries(&_exp_hdldsvr);
116 // create a locked udp mutex
117 udp_mutex = CreateMutex(IOP_MUTEX_LOCKED);
119 // create & start the tcp thread
120 thread_param.attr = TH_C;
121 thread_param.thread = (void *)tcp_server_thread;
122 thread_param.priority = 0x64;
123 thread_param.stacksize = 0x1000;
124 thread_param.option = 0;
126 tcp_server_tid = CreateThread(&thread_param);
128 StartThread(tcp_server_tid, 0);
130 // create & start the udp thread
131 thread_param.attr = TH_C;
132 thread_param.thread = (void *)udp_server_thread;
133 thread_param.priority = 0x64;
134 thread_param.stacksize = 0x1000;
135 thread_param.option = 0;
137 udp_server_tid = CreateThread(&thread_param);
139 StartThread(udp_server_tid, 0);
141 return MODULE_RESIDENT_END;
144 //-------------------------------------------------------------------------
145 int _shutdown(void)
147 // delete threads
148 DeleteThread(tcp_server_tid);
149 DeleteThread(udp_server_tid);
151 // delete udp mutex
152 DeleteSema(udp_mutex);
154 return 0;
157 //-------------------------------------------------------------------------
158 static int ack_tcp_command(int sock, void *buf, int bsize)
160 register int r;
162 // acknowledge a received command
164 gstats.status = STATUS_BUSY_RESPOND;
166 r = lwip_send(sock, buf, bsize, 0);
168 gstats.status = STATUS_AVAIL;
170 return r;
173 //-------------------------------------------------------------------------
174 static void reject_tcp_command(int sock, char *error_string)
176 // reject a received command
178 gstats.status = STATUS_BUSY_RESPOND;
180 lwip_send(sock, error_string, strlen(error_string), 0);
182 gstats.status = STATUS_AVAIL;
184 devctl("hdd0:", APA_DEVCTL_FLUSH_CACHE, NULL, 0, NULL, 0);
187 //-------------------------------------------------------------------------
188 static int check_datas(u32 command, u32 start_sector, u32 num_sectors)
190 // check if all write data is here
192 register int i, got_all_datas = 1;
194 // wait that udp mutex is unlocked
195 WaitSema(udp_mutex);
197 for (i=0; i<num_sectors; ++i) {
198 if (!GETBIT(gstats.bitmask, i)) {
199 got_all_datas = 0;
200 break;
204 if (!got_all_datas) // some parts are missing; should ask for retransmit
205 return -1;
207 // all data here -- we can commit
208 gstats.command = command;
209 return 0;
212 //-------------------------------------------------------------------------
213 static int handle_tcp_client(int tcp_client_socket)
215 register int r, i, size;
216 u8 args[16];
217 tcp_packet_t *pkt = (tcp_packet_t *)tcp_buf;
219 while (1) {
221 // receive incoming packets
222 size = lwip_recv(tcp_client_socket, &tcp_buf[0], sizeof(tcp_buf), 0);
223 if (size < 0)
224 goto error;
226 // check if valid command size
227 if (size != CMD_SIZE) {
228 reject_tcp_command(tcp_client_socket, "handle_recv: invalid packet received");
229 goto error;
232 // don't accept 'wris' without previous 'writ'
233 if ((gstats.status == STATUS_AVAIL) && (pkt->hdr.command == CMD_WRIS)) {
234 reject_tcp_command(tcp_client_socket, "write stat denied");
235 goto error;
237 else if ((!(gstats.status == STATUS_BUSY_WRITE) && (pkt->hdr.command == CMD_WRIS))) {
238 reject_tcp_command(tcp_client_socket, "busy");
239 goto error;
242 switch (pkt->hdr.command) {
244 // ------------------------------------------------
245 // 'writ' command
246 // ------------------------------------------------
247 case CMD_WRIT:
248 // confirm write
249 pkt->hdr.result = 0;
250 r = ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header));
251 if (r < 0) {
252 reject_tcp_command(tcp_client_socket, "init_write b0rked");
253 goto error;
256 gstats.status = STATUS_BUSY_WRITE;
257 gstats.command = pkt->hdr.command;
258 gstats.start_sector = pkt->hdr.start_sector;
259 gstats.num_sectors = pkt->hdr.num_sectors;
261 // set-up buffer and clear bitmask
262 gstats.data = (u8*)(((long)&gstats.buffer[HDD_SECTOR_SIZE - 1]) & ~(HDD_SECTOR_SIZE - 1));
263 mips_memset (gstats.bitmask, 0, sizeof (gstats.bitmask));
265 break;
268 // ------------------------------------------------
269 // 'wris' command
270 // ------------------------------------------------
271 case CMD_WRIS:
272 if ((pkt->hdr.start_sector != gstats.start_sector) || (pkt->hdr.num_sectors != gstats.num_sectors)) {
273 reject_tcp_command(tcp_client_socket, "invalid write stat");
274 goto error;
276 r = check_datas(pkt->hdr.command, pkt->hdr.start_sector, pkt->hdr.num_sectors);
277 if (r < 0) {
279 // means we need retransmission of some datas so we send bitmask stats to the client
280 u32 *out = gstats.bitmask_copy;
281 for (i=0; i<(NET_NUM_SECTORS+31)/32; ++i)
282 out[i] = gstats.bitmask[i];
284 mips_memcpy(pkt->data, (void *)out, sizeof(gstats.bitmask_copy));
286 pkt->hdr.result = 0;
287 r = ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header)+sizeof(gstats.bitmask));
288 if (r < 0) {
289 reject_tcp_command(tcp_client_socket, "init_write_stat failed");
290 goto error;
294 gstats.status = STATUS_BUSY_WRITE;
296 else {
297 pkt->hdr.result = pkt->hdr.num_sectors;
299 #ifdef FAKE_WRITES
300 // fake write, we read instead
301 *(u32 *)&args[0] = pkt->hdr.start_sector;
302 *(u32 *)&args[4] = pkt->hdr.num_sectors;
303 devctl("hdd0:", APA_DEVCTL_ATA_READ, args, 8, gstats.data, pkt->hdr.num_sectors*HDD_SECTOR_SIZE);
304 #else
305 // !!! real writes !!!
306 *(u32 *)&args[0] = pkt->hdr.start_sector;
307 *(u32 *)&args[4] = pkt->hdr.num_sectors;
308 *(u32 *)&args[8] = (u32)gstats.data;
309 devctl("hdd0:", APA_DEVCTL_ATA_IOP_WRITE, args, 8+(pkt->hdr.num_sectors*HDD_SECTOR_SIZE), NULL, 0);
310 #endif
311 ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header));
313 break;
316 // ------------------------------------------------
317 // 'stat' command
318 // ------------------------------------------------
319 case CMD_STAT:
320 r = devctl("hdd0:", APA_DEVCTL_TOTAL_SECTORS, NULL, 0, NULL, 0);
321 if (r < 0)
322 pkt->hdr.result = -1;
323 else
324 pkt->hdr.result = r >> 1;
325 ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header));
327 break;
330 // ------------------------------------------------
331 // 'read' command
332 // ------------------------------------------------
333 case CMD_READ:
334 // set up buffer
335 gstats.data = (u8 *)(((long)&gstats.buffer + HDD_SECTOR_SIZE - 1) & ~(HDD_SECTOR_SIZE - 1));
337 *(u32 *)&args[0] = pkt->hdr.start_sector;
338 *(u32 *)&args[4] = pkt->hdr.num_sectors;
340 if (pkt->hdr.num_sectors > 2) {
341 r = devctl("hdd0:", APA_DEVCTL_ATA_READ, args, 8, gstats.data, pkt->hdr.num_sectors*HDD_SECTOR_SIZE);
342 if (r < 0)
343 pkt->hdr.result = -1;
344 else
345 pkt->hdr.result = pkt->hdr.num_sectors;
347 ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header));
348 if (r == 0)
349 ack_tcp_command(tcp_client_socket, gstats.data, pkt->hdr.num_sectors*HDD_SECTOR_SIZE);
351 else {
352 r = devctl("hdd0:", APA_DEVCTL_ATA_READ, args, 8, pkt->data, pkt->hdr.num_sectors*HDD_SECTOR_SIZE);
353 if (r < 0)
354 pkt->hdr.result = -1;
355 else
356 pkt->hdr.result = pkt->hdr.num_sectors;
358 ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(tcp_packet_t));
361 break;
364 // ------------------------------------------------
365 // 'flsh' command
366 // ------------------------------------------------
367 case CMD_FLSH:
368 devctl("hdd0:", APA_DEVCTL_FLUSH_CACHE, NULL, 0, NULL, 0);
370 break;
373 // ------------------------------------------------
374 // 'powx' command
375 // ------------------------------------------------
376 case CMD_POWX:
377 devctl("hdd0:", APA_DEVCTL_FLUSH_CACHE, NULL, 0, NULL, 0);
378 devctl("hdd0:", APA_DEVCTL_DEV9_SHUTDOWN, NULL, 0, NULL, 0);
379 *((volatile u8 *)0xbf402017) = 0x00;
380 *((volatile u8 *)0xbf402016) = 0x0f;
382 break;
386 default:
387 reject_tcp_command(tcp_client_socket, "handle_recv: unknown command");
388 goto error;
392 return 0;
394 error:
395 return -1;
398 //-------------------------------------------------------------------------
399 void tcp_server_thread(void *args)
401 int tcp_socket, client_socket = -1;
402 struct sockaddr_in peer;
403 int peerlen;
404 register int r;
406 while (1) {
408 peer.sin_family = AF_INET;
409 peer.sin_port = htons(TCP_SERVER_PORT);
410 peer.sin_addr.s_addr = htonl(INADDR_ANY);
412 // create the socket
413 tcp_socket = lwip_socket(AF_INET, SOCK_STREAM, 0);
414 if (tcp_socket < 0)
415 goto error;
417 // bind the socket
418 r = lwip_bind(tcp_socket, (struct sockaddr *)&peer, sizeof(peer));
419 if (r < 0)
420 goto error;
422 // we want to listen
423 r = lwip_listen(tcp_socket, 3);
424 if (r < 0)
425 goto error;
427 while(1) {
428 peerlen = sizeof(peer);
429 // wait for incoming connection
430 client_socket = lwip_accept(tcp_socket, (struct sockaddr *)&peer, &peerlen);
431 if (client_socket < 0)
432 goto error;
434 // got connection, handle the client
435 r = handle_tcp_client(client_socket);
436 if (r < 0)
437 lwip_close(client_socket);
440 error:
441 // close the socket
442 lwip_close(tcp_socket);
446 //-------------------------------------------------------------------------
447 void udp_server_thread(void *args)
449 int udp_socket;
450 struct sockaddr_in peer;
451 register int r;
452 udp_packet_t *pkt = (udp_packet_t *)udp_buf;
454 while (1) {
456 peer.sin_family = AF_INET;
457 peer.sin_port = htons(UDP_SERVER_PORT);
458 peer.sin_addr.s_addr = htonl(INADDR_ANY);
460 // create the socket
461 udp_socket = lwip_socket(AF_INET, SOCK_DGRAM, 0);
462 if (udp_socket < 0)
463 goto error;
465 // bind the socket
466 r = lwip_bind(udp_socket, (struct sockaddr *)&peer, sizeof(peer));
467 if (r < 0)
468 goto error;
470 while(1) {
472 // wait for packet
473 r = lwip_recv(udp_socket, udp_buf, sizeof(udp_buf), 0);
475 // check to see if it's the command we're expecting
476 if ((r == sizeof (udp_packet_t)) && (pkt->command == gstats.command)) {
478 // check the start sector is valid
479 if ((gstats.start_sector <= pkt->start_sector) && (pkt->start_sector < gstats.start_sector + gstats.num_sectors)) {
481 u32 start_sector = pkt->start_sector - gstats.start_sector;
483 if (!GETBIT(gstats.bitmask, start_sector)) {
484 mips_memcpy(gstats.data + start_sector*HDD_SECTOR_SIZE, pkt, HDD_SECTOR_SIZE*2);
486 SETBIT(gstats.bitmask, start_sector);
487 SETBIT(gstats.bitmask, start_sector + 1);
489 // unlock udp mutex
490 SignalSema(udp_mutex);
496 error:
497 // close the socket
498 lwip_close(udp_socket);