SD hotswap, SD fixes, SCSI interface fixes, performance improvements.
[SCSI2SD-V6.git] / src / firmware / config.c
1 //      Copyright (C) 2014 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\r
5 //      SCSI2SD is free software: you can redistribute it and/or modify\r
6 //      it under the terms of the GNU General Public License as published by\r
7 //      the Free Software Foundation, either version 3 of the License, or\r
8 //      (at your option) any later version.\r
9 //\r
10 //      SCSI2SD is distributed in the hope that it will be useful,\r
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 //      GNU General Public License for more details.\r
14 //\r
15 //      You should have received a copy of the GNU General Public License\r
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 #include "config.h"\r
19 #include "debug.h"\r
20 #include "led.h"\r
21 \r
22 #include "scsi.h"\r
23 #include "scsiPhy.h"\r
24 #include "sd.h"\r
25 #include "disk.h"\r
26 #include "trace.h"\r
27 #include "bootloader.h"\r
28 #include "bsp.h"\r
29 \r
30 #include "../../include/scsi2sd.h"\r
31 #include "../../include/hidpacket.h"\r
32 \r
33 #include "usb_device/usb_device.h"\r
34 #include "usb_device/usbd_hid.h"\r
35 #include "usb_device/usbd_composite.h"\r
36 #include "bsp_driver_sd.h"\r
37 \r
38 \r
39 #include <string.h>\r
40 \r
41 static const uint16_t FIRMWARE_VERSION = 0x0601;\r
42 \r
43 // 1 flash row\r
44 static const uint8_t DEFAULT_CONFIG[128] =\r
45 {\r
46         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00,\r
47         0x00, 0x02, 0x3F, 0x00, 0xFF, 0x00, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x73,\r
48         0x72, 0x63, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,\r
49         0x43, 0x53, 0x49, 0x32, 0x53, 0x44, 0x20, 0x31, 0x2E, 0x30, 0x31, 0x32,\r
50         0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,\r
51         0x37, 0x38, 0x00, 0x00\r
52 };\r
53 \r
54 \r
55 static uint8_t s2s_cfg[S2S_CFG_SIZE] S2S_DMA_ALIGN;\r
56 \r
57 \r
58 enum USB_STATE\r
59 {\r
60         USB_IDLE,\r
61         USB_DATA_SENT\r
62 };\r
63 \r
64 \r
65 static int usbInEpState;\r
66 #if 0\r
67 static int usbDebugEpState;\r
68 #endif\r
69 static int usbReady; // TODO MM REMOVE. Unused ?\r
70 \r
71 void s2s_configInit(S2S_BoardCfg* config)\r
72 {\r
73 \r
74         usbInEpState = USB_IDLE;\r
75         usbReady = 0; // We don't know if host is connected yet.\r
76 \r
77 \r
78         if ((blockDev.state & DISK_PRESENT) && sdDev.capacity)\r
79         {\r
80                 int cfgSectors = (S2S_CFG_SIZE + 511) / 512;\r
81                 BSP_SD_ReadBlocks_DMA(\r
82                         (uint32_t*) &s2s_cfg[0],\r
83                         (sdDev.capacity - cfgSectors) * 512ll,\r
84                         512,\r
85                         cfgSectors);\r
86 \r
87                 memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
88 \r
89                 if (memcmp(config->magic, "BCFG", 4))\r
90                 {\r
91                         // Invalid SD card config, use default.\r
92                         memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);\r
93                         memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
94                         memcpy(config->magic, "BCFG", 4);\r
95                         config->selectionDelay = 255; // auto\r
96                         config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
97 \r
98                         memcpy(\r
99                                 &s2s_cfg[0] + sizeof(S2S_BoardCfg),\r
100                                 DEFAULT_CONFIG,\r
101                                 sizeof(S2S_TargetCfg));\r
102                 }\r
103         }\r
104         else\r
105         {\r
106                 // No SD card, use existing config if valid\r
107                 if (memcmp(config->magic, "BCFG", 4))\r
108                 {\r
109                         // Not valid, use empty config with no disks.\r
110                         memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);\r
111                         memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
112                         config->selectionDelay = 255; // auto\r
113                         config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
114                 }\r
115         }\r
116 \r
117 }\r
118 \r
119 \r
120 static void\r
121 pingCommand()\r
122 {\r
123         uint8_t response[] =\r
124         {\r
125                 S2S_CFG_STATUS_GOOD\r
126         };\r
127         hidPacket_send(response, sizeof(response));\r
128 }\r
129 \r
130 static void\r
131 sdInfoCommand()\r
132 {\r
133         uint8_t response[sizeof(sdDev.csd) + sizeof(sdDev.cid)];\r
134         memcpy(response, sdDev.csd, sizeof(sdDev.csd));\r
135         memcpy(response + sizeof(sdDev.csd), sdDev.cid, sizeof(sdDev.cid));\r
136 \r
137         hidPacket_send(response, sizeof(response));\r
138 }\r
139 \r
140 \r
141 static void\r
142 scsiTestCommand()\r
143 {\r
144         int resultCode = 0; // TODO scsiSelfTest();\r
145         uint8_t response[] =\r
146         {\r
147                 resultCode == 0 ? S2S_CFG_STATUS_GOOD : S2S_CFG_STATUS_ERR,\r
148                 resultCode\r
149         };\r
150         hidPacket_send(response, sizeof(response));\r
151 }\r
152 \r
153 static void\r
154 scsiDevInfoCommand()\r
155 {\r
156         uint8_t response[] =\r
157         {\r
158                 FIRMWARE_VERSION >> 8,\r
159                 FIRMWARE_VERSION & 0xff,\r
160                 sdDev.capacity >> 24,\r
161                 sdDev.capacity >> 16,\r
162                 sdDev.capacity >> 8,\r
163                 sdDev.capacity\r
164         };\r
165         hidPacket_send(response, sizeof(response));\r
166 }\r
167 \r
168 static void\r
169 debugCommand()\r
170 {\r
171         uint8_t response[32];\r
172         memcpy(&response, &scsiDev.cdb, 12);\r
173         response[12] = scsiDev.msgIn;\r
174         response[13] = scsiDev.msgOut;\r
175         response[14] = scsiDev.lastStatus;\r
176         response[15] = scsiDev.lastSense;\r
177         response[16] = scsiDev.phase;\r
178         response[17] = scsiStatusBSY();\r
179         response[18] = *SCSI_STS_SELECTED;\r
180         response[19] = scsiStatusATN();\r
181         response[20] = scsiStatusRST();\r
182         response[21] = scsiDev.rstCount;\r
183         response[22] = scsiDev.selCount;\r
184         response[23] = scsiDev.msgCount;\r
185         response[24] = scsiDev.cmdCount;\r
186         response[25] = scsiDev.watchdogTick;\r
187         response[26] = blockDev.state;\r
188         response[27] = scsiDev.lastSenseASC >> 8;\r
189         response[28] = scsiDev.lastSenseASC;\r
190         response[29] = *SCSI_STS_DBX;\r
191         response[30] = LastTrace;\r
192         hidPacket_send(response, sizeof(response));\r
193 }\r
194 \r
195 static void\r
196 sdWriteCommand(const uint8_t* cmd, size_t cmdSize)\r
197 {\r
198         if (cmdSize < 517)\r
199         {\r
200                 return; // ignore.\r
201         }\r
202         uint32_t lba =\r
203                 (((uint32_t)cmd[1]) << 24) |\r
204                 (((uint32_t)cmd[2]) << 16) |\r
205                 (((uint32_t)cmd[3]) << 8) |\r
206                 ((uint32_t)cmd[4]);\r
207 \r
208         // Must be aligned.\r
209         uint8_t buf[512] S2S_DMA_ALIGN;\r
210         memcpy(buf, &cmd[5], 512);\r
211         BSP_SD_WriteBlocks_DMA((uint32_t*) buf, lba * 512ll, 512, 1);\r
212 \r
213         uint8_t response[] =\r
214         {\r
215                 S2S_CFG_STATUS_GOOD\r
216         };\r
217         hidPacket_send(response, sizeof(response));\r
218 }\r
219 \r
220 static void\r
221 sdReadCommand(const uint8_t* cmd, size_t cmdSize)\r
222 {\r
223         if (cmdSize < 5)\r
224         {\r
225                 return; // ignore.\r
226         }\r
227         uint32_t lba =\r
228                 (((uint32_t)cmd[1]) << 24) |\r
229                 (((uint32_t)cmd[2]) << 16) |\r
230                 (((uint32_t)cmd[3]) << 8) |\r
231                 ((uint32_t)cmd[4]);\r
232 \r
233         BSP_SD_ReadBlocks_DMA((uint32_t*) cmd, lba * 512ll, 512, 1);\r
234         hidPacket_send(cmd, 512);\r
235 }\r
236 \r
237 static void\r
238 processCommand(const uint8_t* cmd, size_t cmdSize)\r
239 {\r
240         switch (cmd[0])\r
241         {\r
242         case S2S_CMD_PING:\r
243                 pingCommand();\r
244                 break;\r
245 \r
246         case S2S_CMD_REBOOT:\r
247                 s2s_enterBootloader();\r
248                 break;\r
249 \r
250         case S2S_CMD_SDINFO:\r
251                 sdInfoCommand();\r
252                 break;\r
253 \r
254         case S2S_CMD_SCSITEST:\r
255                 scsiTestCommand();\r
256                 break;\r
257 \r
258         case S2S_CMD_DEVINFO:\r
259                 scsiDevInfoCommand();\r
260                 break;\r
261 \r
262         case S2S_CMD_SD_WRITE:\r
263                 sdWriteCommand(cmd, cmdSize);\r
264                 break;\r
265 \r
266         case S2S_CMD_SD_READ:\r
267                 sdReadCommand(cmd, cmdSize);\r
268                 break;\r
269 \r
270         case S2S_CMD_DEBUG:\r
271                 debugCommand();\r
272                 break;\r
273 \r
274         case S2S_CMD_NONE: // invalid\r
275         default:\r
276                 break;\r
277         }\r
278 }\r
279 \r
280 void s2s_configPoll()\r
281 {\r
282         if (!USBD_Composite_IsConfigured(&hUsbDeviceFS))\r
283         {\r
284                 usbInEpState = USB_IDLE;\r
285                 return;\r
286         }\r
287 \r
288         if (USBD_HID_IsReportReady(&hUsbDeviceFS))\r
289         {\r
290                 s2s_ledOn();\r
291 \r
292                 // The host sent us some data!\r
293                 uint8_t hidBuffer[USBHID_LEN];\r
294                 int byteCount = USBD_HID_GetReport(&hUsbDeviceFS, hidBuffer, sizeof(hidBuffer));\r
295                 hidPacket_recv(hidBuffer, byteCount);\r
296 \r
297                 size_t cmdSize;\r
298                 const uint8_t* cmd = hidPacket_getPacket(&cmdSize);\r
299                 if (cmd && (cmdSize > 0))\r
300                 {\r
301                         processCommand(cmd, cmdSize);\r
302                 }\r
303 \r
304                 s2s_ledOff();\r
305         }\r
306 \r
307         switch (usbInEpState)\r
308         {\r
309         case USB_IDLE:\r
310                 {\r
311                         uint8_t hidBuffer[USBHID_LEN];\r
312                         const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);\r
313 \r
314                         if (nextChunk)\r
315                         {\r
316                                 USBD_HID_SendReport (&hUsbDeviceFS, nextChunk, sizeof(hidBuffer));\r
317                                 usbInEpState = USB_DATA_SENT;\r
318                         }\r
319                 }\r
320                 break;\r
321 \r
322         case USB_DATA_SENT:\r
323                 if (!USBD_HID_IsBusy(&hUsbDeviceFS))\r
324                 {\r
325                         // Data accepted.\r
326                         usbInEpState = USB_IDLE;\r
327                 }\r
328                 break;\r
329         }\r
330 \r
331 }\r
332 \r
333 void debugPoll()\r
334 {\r
335 #if 0\r
336         if (!usbReady)\r
337         {\r
338                 return;\r
339         }\r
340 \r
341         if(USBFS_GetEPState(USB_EP_COMMAND) == USBFS_OUT_BUFFER_FULL)\r
342         {\r
343                 // The host sent us some data!\r
344                 int byteCount = USBFS_GetEPCount(USB_EP_COMMAND);\r
345                 USBFS_ReadOutEP(USB_EP_COMMAND, (uint8 *)&hidBuffer, byteCount);\r
346 \r
347                 if (byteCount >= 1 &&\r
348                         hidBuffer[0] == 0x01)\r
349                 {\r
350                         // Reboot command.\r
351                         Bootloadable_1_Load();\r
352                 }\r
353 \r
354                 // Allow the host to send us another command.\r
355                 // (assuming we didn't reboot outselves)\r
356                 USBFS_EnableOutEP(USB_EP_COMMAND);\r
357         }\r
358 \r
359         switch (usbDebugEpState)\r
360         {\r
361         case USB_IDLE:\r
362                 memcpy(&hidBuffer, &scsiDev.cdb, 12);\r
363                 hidBuffer[12] = scsiDev.msgIn;\r
364                 hidBuffer[13] = scsiDev.msgOut;\r
365                 hidBuffer[14] = scsiDev.lastStatus;\r
366                 hidBuffer[15] = scsiDev.lastSense;\r
367                 hidBuffer[16] = scsiDev.phase;\r
368                 hidBuffer[17] = SCSI_ReadFilt(SCSI_Filt_BSY);\r
369                 hidBuffer[18] = SCSI_ReadFilt(SCSI_Filt_SEL);\r
370                 hidBuffer[19] = SCSI_ReadFilt(SCSI_Filt_ATN);\r
371                 hidBuffer[20] = SCSI_ReadFilt(SCSI_Filt_RST);\r
372                 hidBuffer[21] = scsiDev.rstCount;\r
373                 hidBuffer[22] = scsiDev.selCount;\r
374                 hidBuffer[23] = scsiDev.msgCount;\r
375                 hidBuffer[24] = scsiDev.cmdCount;\r
376                 hidBuffer[25] = scsiDev.watchdogTick;\r
377                 hidBuffer[26] = blockDev.state;\r
378                 hidBuffer[27] = scsiDev.lastSenseASC >> 8;\r
379                 hidBuffer[28] = scsiDev.lastSenseASC;\r
380                 hidBuffer[29] = scsiReadDBxPins();\r
381                 hidBuffer[30] = LastTrace;\r
382 \r
383                 hidBuffer[58] = sdDev.capacity >> 24;\r
384                 hidBuffer[59] = sdDev.capacity >> 16;\r
385                 hidBuffer[60] = sdDev.capacity >> 8;\r
386                 hidBuffer[61] = sdDev.capacity;\r
387 \r
388                 hidBuffer[62] = FIRMWARE_VERSION >> 8;\r
389                 hidBuffer[63] = FIRMWARE_VERSION;\r
390 \r
391                 USBFS_LoadInEP(USB_EP_DEBUG, (uint8 *)&hidBuffer, sizeof(hidBuffer));\r
392                 usbDebugEpState = USB_DATA_SENT;\r
393                 break;\r
394 \r
395         case USB_DATA_SENT:\r
396                 if (USBFS_bGetEPAckState(USB_EP_DEBUG))\r
397                 {\r
398                         // Data accepted.\r
399                         usbDebugEpState = USB_IDLE;\r
400                 }\r
401                 break;\r
402         }\r
403 #endif\r
404 }\r
405 \r
406 #if 0\r
407 CY_ISR(debugTimerISR)\r
408 {\r
409         Debug_Timer_ReadStatusRegister();\r
410         Debug_Timer_Interrupt_ClearPending();\r
411         uint8 savedIntrStatus = CyEnterCriticalSection();\r
412         debugPoll();\r
413         CyExitCriticalSection(savedIntrStatus);\r
414 }\r
415 #endif\r
416 \r
417 void s2s_debugInit()\r
418 {\r
419 #if 0\r
420         Debug_Timer_Interrupt_StartEx(debugTimerISR);\r
421         Debug_Timer_Start();\r
422 #endif\r
423 }\r
424 \r
425 void debugPause()\r
426 {\r
427 #if 0\r
428         Debug_Timer_Stop();\r
429 #endif\r
430 }\r
431 \r
432 void debugResume()\r
433 {\r
434 #if 0\r
435         Debug_Timer_Start();\r
436 #endif\r
437 }\r
438 \r
439 int isDebugEnabled()\r
440 {\r
441         return usbReady;\r
442 }\r
443 \r
444 // Public method for storing MODE SELECT results.\r
445 void s2s_configSave(int scsiId, uint16_t bytesPerSector)\r
446 {\r
447         S2S_TargetCfg* cfg = (S2S_TargetCfg*) s2s_getConfigById(scsiId);\r
448         cfg->bytesPerSector = bytesPerSector;\r
449 \r
450         BSP_SD_WriteBlocks_DMA(\r
451                 (uint32_t*) &s2s_cfg[0],\r
452                 (sdDev.capacity - S2S_CFG_SIZE) * 512ll,\r
453                 512,\r
454                 (S2S_CFG_SIZE + 511) / 512);\r
455 }\r
456 \r
457 \r
458 const S2S_TargetCfg* s2s_getConfigByIndex(int i)\r
459 {\r
460         return (const S2S_TargetCfg*)\r
461                 (s2s_cfg + sizeof(S2S_BoardCfg) + (i * sizeof(S2S_TargetCfg)));\r
462 }\r
463 \r
464 const S2S_TargetCfg* s2s_getConfigById(int scsiId)\r
465 {\r
466         int i;\r
467         for (i = 0; i < S2S_MAX_TARGETS; ++i)\r
468         {\r
469                 const S2S_TargetCfg* tgt = s2s_getConfigByIndex(i);\r
470                 if ((tgt->scsiId & S2S_CFG_TARGET_ID_BITS) == scsiId)\r
471                 {\r
472                         return tgt;\r
473                 }\r
474         }\r
475         return NULL;\r
476 \r
477 }\r
478 \r