Fix terrible performance
[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 "led.h"\r
20 \r
21 #include "scsi.h"\r
22 #include "scsiPhy.h"\r
23 #include "sd.h"\r
24 #include "disk.h"\r
25 #include "trace.h"\r
26 #include "bootloader.h"\r
27 #include "bsp.h"\r
28 \r
29 #include "../../include/scsi2sd.h"\r
30 #include "../../include/hidpacket.h"\r
31 \r
32 #include "usb_device/usb_device.h"\r
33 #include "usb_device/usbd_hid.h"\r
34 #include "usb_device/usbd_composite.h"\r
35 #include "bsp_driver_sd.h"\r
36 \r
37 \r
38 #include <string.h>\r
39 \r
40 static const uint16_t FIRMWARE_VERSION = 0x0606;\r
41 \r
42 // 1 flash row\r
43 static const uint8_t DEFAULT_CONFIG[128] =\r
44 {\r
45         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00,\r
46         0x00, 0x02, 0x3F, 0x00, 0xFF, 0x00, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x73,\r
47         0x72, 0x63, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,\r
48         0x43, 0x53, 0x49, 0x32, 0x53, 0x44, 0x20, 0x31, 0x2E, 0x30, 0x31, 0x32,\r
49         0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,\r
50         0x37, 0x38, 0x00, 0x00\r
51 };\r
52 \r
53 \r
54 static uint8_t s2s_cfg[S2S_CFG_SIZE] S2S_DMA_ALIGN;\r
55 \r
56 \r
57 enum USB_STATE\r
58 {\r
59         USB_IDLE,\r
60         USB_DATA_SENT\r
61 };\r
62 \r
63 \r
64 static int usbInEpState;\r
65 #if 0\r
66 static int usbDebugEpState;\r
67 #endif\r
68 static int usbReady; // TODO MM REMOVE. Unused ?\r
69 \r
70 void s2s_configInit(S2S_BoardCfg* config)\r
71 {\r
72 \r
73         usbInEpState = USB_IDLE;\r
74         usbReady = 0; // We don't know if host is connected yet.\r
75 \r
76 \r
77         if ((blockDev.state & DISK_PRESENT) && sdDev.capacity)\r
78         {\r
79                 int cfgSectors = (S2S_CFG_SIZE + 511) / 512;\r
80                 BSP_SD_ReadBlocks_DMA(\r
81                         (uint32_t*) &s2s_cfg[0],\r
82                         (sdDev.capacity - cfgSectors) * 512ll,\r
83                         512,\r
84                         cfgSectors);\r
85 \r
86                 memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
87 \r
88                 if (memcmp(config->magic, "BCFG", 4))\r
89                 {\r
90                         // Invalid SD card config, use default.\r
91                         memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);\r
92                         memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
93                         memcpy(config->magic, "BCFG", 4);\r
94                         config->selectionDelay = 255; // auto\r
95                         config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
96 \r
97                         memcpy(\r
98                                 &s2s_cfg[0] + sizeof(S2S_BoardCfg),\r
99                                 DEFAULT_CONFIG,\r
100                                 sizeof(S2S_TargetCfg));\r
101                 }\r
102         }\r
103         else\r
104         {\r
105                 // No SD card, use existing config if valid\r
106                 if (memcmp(config->magic, "BCFG", 4))\r
107                 {\r
108                         // Not valid, use empty config with no disks.\r
109                         memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);\r
110                         memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
111                         config->selectionDelay = 255; // auto\r
112                         config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
113                 }\r
114         }\r
115 \r
116 }\r
117 \r
118 \r
119 static void\r
120 pingCommand()\r
121 {\r
122         uint8_t response[] =\r
123         {\r
124                 S2S_CFG_STATUS_GOOD\r
125         };\r
126         hidPacket_send(response, sizeof(response));\r
127 }\r
128 \r
129 static void\r
130 sdInfoCommand()\r
131 {\r
132         uint8_t response[sizeof(sdDev.csd) + sizeof(sdDev.cid)];\r
133         memcpy(response, sdDev.csd, sizeof(sdDev.csd));\r
134         memcpy(response + sizeof(sdDev.csd), sdDev.cid, sizeof(sdDev.cid));\r
135 \r
136         hidPacket_send(response, sizeof(response));\r
137 }\r
138 \r
139 \r
140 static void\r
141 scsiTestCommand()\r
142 {\r
143         int resultCode = scsiSelfTest();\r
144         uint8_t response[] =\r
145         {\r
146                 resultCode == 0 ? S2S_CFG_STATUS_GOOD : S2S_CFG_STATUS_ERR,\r
147                 resultCode\r
148         };\r
149         hidPacket_send(response, sizeof(response));\r
150 }\r
151 \r
152 static void\r
153 scsiDevInfoCommand()\r
154 {\r
155         uint8_t response[] =\r
156         {\r
157                 FIRMWARE_VERSION >> 8,\r
158                 FIRMWARE_VERSION & 0xff,\r
159                 sdDev.capacity >> 24,\r
160                 sdDev.capacity >> 16,\r
161                 sdDev.capacity >> 8,\r
162                 sdDev.capacity\r
163         };\r
164         hidPacket_send(response, sizeof(response));\r
165 }\r
166 \r
167 static void\r
168 debugCommand()\r
169 {\r
170         uint8_t response[32];\r
171         memcpy(&response, &scsiDev.cdb, 12);\r
172         response[12] = scsiDev.msgIn;\r
173         response[13] = scsiDev.msgOut;\r
174         response[14] = scsiDev.lastStatus;\r
175         response[15] = scsiDev.lastSense;\r
176         response[16] = scsiDev.phase;\r
177         response[17] = scsiStatusBSY();\r
178         response[18] = scsiStatusSEL();\r
179         response[19] = scsiStatusATN();\r
180         response[20] = scsiStatusRST();\r
181         response[21] = scsiDev.rstCount;\r
182         response[22] = scsiDev.selCount;\r
183         response[23] = scsiDev.msgCount;\r
184         response[24] = scsiDev.cmdCount;\r
185         response[25] = scsiDev.watchdogTick;\r
186         response[26] = blockDev.state;\r
187         response[27] = scsiDev.lastSenseASC >> 8;\r
188         response[28] = scsiDev.lastSenseASC;\r
189         response[29] = *SCSI_STS_DBX;\r
190         response[30] = LastTrace;\r
191         response[31] = scsiStatusACK();\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 \r
334 \r
335 // Public method for storing MODE SELECT results.\r
336 void s2s_configSave(int scsiId, uint16_t bytesPerSector)\r
337 {\r
338         S2S_TargetCfg* cfg = (S2S_TargetCfg*) s2s_getConfigById(scsiId);\r
339         cfg->bytesPerSector = bytesPerSector;\r
340 \r
341         BSP_SD_WriteBlocks_DMA(\r
342                 (uint32_t*) &s2s_cfg[0],\r
343                 (sdDev.capacity - S2S_CFG_SIZE) * 512ll,\r
344                 512,\r
345                 (S2S_CFG_SIZE + 511) / 512);\r
346 }\r
347 \r
348 \r
349 const S2S_TargetCfg* s2s_getConfigByIndex(int i)\r
350 {\r
351         return (const S2S_TargetCfg*)\r
352                 (s2s_cfg + sizeof(S2S_BoardCfg) + (i * sizeof(S2S_TargetCfg)));\r
353 }\r
354 \r
355 const S2S_TargetCfg* s2s_getConfigById(int scsiId)\r
356 {\r
357         int i;\r
358         for (i = 0; i < S2S_MAX_TARGETS; ++i)\r
359         {\r
360                 const S2S_TargetCfg* tgt = s2s_getConfigByIndex(i);\r
361                 if ((tgt->scsiId & S2S_CFG_TARGET_ID_BITS) == scsiId)\r
362                 {\r
363                         return tgt;\r
364                 }\r
365         }\r
366         return NULL;\r
367 \r
368 }\r
369 \r