Lots of bug fixing, and 4.7 merges
[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 #include "spinlock.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 = 0x0610;\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 static uint8_t configDmaBuf[512] S2S_DMA_ALIGN; // For SD card writes.\r
57 \r
58 \r
59 enum USB_STATE\r
60 {\r
61         USB_IDLE,\r
62         USB_DATA_SENT\r
63 };\r
64 \r
65 \r
66 static int usbInEpState;\r
67 \r
68 static void s2s_debugTimer();\r
69 \r
70 // Debug timer to log via USB.\r
71 // Timer 6 & 7 is a simple counter with no external IO supported.\r
72 static s2s_lock_t usbDevLock = s2s_lock_init;\r
73 TIM_HandleTypeDef htim7;\r
74 static int debugTimerStarted = 0;\r
75 void TIM7_IRQHandler()\r
76 {\r
77         HAL_TIM_IRQHandler(&htim7);\r
78 }\r
79 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)\r
80 {\r
81         if (s2s_spin_trylock(&usbDevLock)) {\r
82                 s2s_debugTimer();\r
83                 s2s_spin_unlock(&usbDevLock);\r
84         }\r
85 }\r
86 \r
87 void s2s_configInit(S2S_BoardCfg* config)\r
88 {\r
89 \r
90         usbInEpState = USB_IDLE;\r
91 \r
92 \r
93         if ((blockDev.state & DISK_PRESENT) && sdDev.capacity)\r
94         {\r
95                 int cfgSectors = (S2S_CFG_SIZE + 511) / 512;\r
96                 BSP_SD_ReadBlocks_DMA(\r
97                         (uint32_t*) &s2s_cfg[0],\r
98                         (sdDev.capacity - cfgSectors) * 512ll,\r
99                         512,\r
100                         cfgSectors);\r
101 \r
102                 memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
103 \r
104                 if (memcmp(config->magic, "BCFG", 4))\r
105                 {\r
106                         // Invalid SD card config, use default.\r
107                         memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);\r
108                         memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
109                         memcpy(config->magic, "BCFG", 4);\r
110                         config->selectionDelay = 255; // auto\r
111                         config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
112 \r
113                         memcpy(\r
114                                 &s2s_cfg[0] + sizeof(S2S_BoardCfg),\r
115                                 DEFAULT_CONFIG,\r
116                                 sizeof(S2S_TargetCfg));\r
117                 }\r
118         }\r
119         else\r
120         {\r
121                 // No SD card, use existing config if valid\r
122                 if (memcmp(config->magic, "BCFG", 4))\r
123                 {\r
124                         // Not valid, use empty config with no disks.\r
125                         memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);\r
126                         memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));\r
127                         config->selectionDelay = 255; // auto\r
128                         config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
129                 }\r
130         }\r
131 }\r
132 \r
133 static void debugInit(void)\r
134 {\r
135         if (debugTimerStarted == 1) return;\r
136 \r
137         debugTimerStarted = 1;\r
138         // 10ms debug timer to capture logs over USB\r
139         __TIM7_CLK_ENABLE();\r
140         htim7.Instance = TIM7;\r
141         htim7.Init.Prescaler = 10800 - 1; // 16bit. 108MHz down to 10KHz\r
142         htim7.Init.CounterMode = TIM_COUNTERMODE_UP;\r
143         htim7.Init.Period = 100 - 1; // 16bit. 10KHz down to 10ms.\r
144         htim7.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;\r
145         HAL_TIM_Base_Init(&htim7);\r
146         HAL_TIM_Base_Start_IT(&htim7);\r
147 \r
148         HAL_NVIC_SetPriority(TIM7_IRQn, 10, 0);\r
149         HAL_NVIC_EnableIRQ(TIM7_IRQn);\r
150 }\r
151 \r
152 \r
153 static void\r
154 pingCommand()\r
155 {\r
156         uint8_t response[] =\r
157         {\r
158                 S2S_CFG_STATUS_GOOD\r
159         };\r
160         hidPacket_send(response, sizeof(response));\r
161 }\r
162 \r
163 static void\r
164 sdInfoCommand()\r
165 {\r
166         uint8_t response[sizeof(sdDev.csd) + sizeof(sdDev.cid)];\r
167         memcpy(response, sdDev.csd, sizeof(sdDev.csd));\r
168         memcpy(response + sizeof(sdDev.csd), sdDev.cid, sizeof(sdDev.cid));\r
169 \r
170         hidPacket_send(response, sizeof(response));\r
171 }\r
172 \r
173 \r
174 static void\r
175 scsiTestCommand()\r
176 {\r
177         int resultCode = scsiSelfTest();\r
178         uint8_t response[] =\r
179         {\r
180                 resultCode == 0 ? S2S_CFG_STATUS_GOOD : S2S_CFG_STATUS_ERR,\r
181                 resultCode\r
182         };\r
183         hidPacket_send(response, sizeof(response));\r
184 }\r
185 \r
186 static void\r
187 scsiDevInfoCommand()\r
188 {\r
189         uint8_t response[] =\r
190         {\r
191                 FIRMWARE_VERSION >> 8,\r
192                 FIRMWARE_VERSION & 0xff,\r
193                 sdDev.capacity >> 24,\r
194                 sdDev.capacity >> 16,\r
195                 sdDev.capacity >> 8,\r
196                 sdDev.capacity\r
197         };\r
198         hidPacket_send(response, sizeof(response));\r
199 }\r
200 \r
201 static void\r
202 debugCommand()\r
203 {\r
204         uint8_t response[32];\r
205         memcpy(&response, &scsiDev.cdb, 12);\r
206         response[12] = scsiDev.msgIn;\r
207         response[13] = scsiDev.msgOut;\r
208         response[14] = scsiDev.lastStatus;\r
209         response[15] = scsiDev.lastSense;\r
210         response[16] = scsiDev.phase;\r
211         response[17] = *SCSI_STS_SCSI;\r
212         response[18] = scsiDev.target != NULL ? scsiDev.target->syncOffset : 0;\r
213         response[19] = scsiDev.target != NULL ? scsiDev.target->syncPeriod : 0;\r
214         response[20] = scsiDev.minSyncPeriod;\r
215         response[21] = scsiDev.rstCount;\r
216         response[22] = scsiDev.selCount;\r
217         response[23] = scsiDev.msgCount;\r
218         response[24] = scsiDev.cmdCount;\r
219         response[25] = scsiDev.watchdogTick;\r
220         response[26] = blockDev.state;\r
221         response[27] = scsiDev.lastSenseASC >> 8;\r
222         response[28] = scsiDev.lastSenseASC;\r
223         response[29] = *SCSI_STS_DBX & 0xff; // What we've read\r
224         response[30] = LastTrace;\r
225         response[31] = *SCSI_STS_DBX >> 8; // What we're writing\r
226         hidPacket_send(response, sizeof(response));\r
227 }\r
228 \r
229 static void\r
230 sdWriteCommand(const uint8_t* cmd, size_t cmdSize)\r
231 {\r
232         if (cmdSize < 517)\r
233         {\r
234                 return; // ignore.\r
235         }\r
236         uint32_t lba =\r
237                 (((uint32_t)cmd[1]) << 24) |\r
238                 (((uint32_t)cmd[2]) << 16) |\r
239                 (((uint32_t)cmd[3]) << 8) |\r
240                 ((uint32_t)cmd[4]);\r
241 \r
242         memcpy(configDmaBuf, &cmd[5], 512);\r
243         BSP_SD_WriteBlocks_DMA((uint32_t*) configDmaBuf, lba * 512ll, 512, 1);\r
244 \r
245         uint8_t response[] =\r
246         {\r
247                 S2S_CFG_STATUS_GOOD\r
248         };\r
249         hidPacket_send(response, sizeof(response));\r
250 }\r
251 \r
252 static void\r
253 sdReadCommand(const uint8_t* cmd, size_t cmdSize)\r
254 {\r
255         if (cmdSize < 5)\r
256         {\r
257                 return; // ignore.\r
258         }\r
259         uint32_t lba =\r
260                 (((uint32_t)cmd[1]) << 24) |\r
261                 (((uint32_t)cmd[2]) << 16) |\r
262                 (((uint32_t)cmd[3]) << 8) |\r
263                 ((uint32_t)cmd[4]);\r
264 \r
265         BSP_SD_ReadBlocks_DMA((uint32_t*) configDmaBuf, lba * 512ll, 512, 1);\r
266         hidPacket_send(configDmaBuf, 512);\r
267 }\r
268 \r
269 static void\r
270 processCommand(const uint8_t* cmd, size_t cmdSize)\r
271 {\r
272         switch (cmd[0])\r
273         {\r
274         case S2S_CMD_PING:\r
275                 pingCommand();\r
276                 break;\r
277 \r
278         case S2S_CMD_REBOOT:\r
279                 s2s_enterBootloader();\r
280                 break;\r
281 \r
282         case S2S_CMD_SDINFO:\r
283                 sdInfoCommand();\r
284                 break;\r
285 \r
286         case S2S_CMD_SCSITEST:\r
287                 scsiTestCommand();\r
288                 break;\r
289 \r
290         case S2S_CMD_DEVINFO:\r
291                 scsiDevInfoCommand();\r
292                 break;\r
293 \r
294         case S2S_CMD_SD_WRITE:\r
295                 sdWriteCommand(cmd, cmdSize);\r
296                 break;\r
297 \r
298         case S2S_CMD_SD_READ:\r
299                 sdReadCommand(cmd, cmdSize);\r
300                 break;\r
301 \r
302         case S2S_CMD_DEBUG:\r
303                 if (debugTimerStarted == 0) {\r
304                         debugInit();\r
305                 }\r
306                 debugCommand();\r
307                 break;\r
308 \r
309         case S2S_CMD_NONE: // invalid\r
310         default:\r
311                 break;\r
312         }\r
313 }\r
314 \r
315 void s2s_configPoll()\r
316 {\r
317         s2s_spin_lock(&usbDevLock);\r
318 \r
319         if (!USBD_Composite_IsConfigured(&hUsbDeviceFS))\r
320         {\r
321                 usbInEpState = USB_IDLE;\r
322                 goto out;\r
323         }\r
324 \r
325         if (USBD_HID_IsReportReady(&hUsbDeviceFS))\r
326         {\r
327                 s2s_ledOn();\r
328 \r
329                 // The host sent us some data!\r
330                 uint8_t hidBuffer[USBHID_LEN];\r
331                 int byteCount = USBD_HID_GetReport(&hUsbDeviceFS, hidBuffer, sizeof(hidBuffer));\r
332                 hidPacket_recv(hidBuffer, byteCount);\r
333 \r
334                 size_t cmdSize;\r
335                 const uint8_t* cmd = hidPacket_getPacket(&cmdSize);\r
336                 if (cmd && (cmdSize > 0))\r
337                 {\r
338                         processCommand(cmd, cmdSize);\r
339                 }\r
340 \r
341                 s2s_ledOff();\r
342         }\r
343 \r
344         switch (usbInEpState)\r
345         {\r
346         case USB_IDLE:\r
347                 {\r
348                         uint8_t hidBuffer[USBHID_LEN];\r
349                         const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);\r
350 \r
351                         if (nextChunk)\r
352                         {\r
353                                 USBD_HID_SendReport (&hUsbDeviceFS, nextChunk, sizeof(hidBuffer));\r
354                                 usbInEpState = USB_DATA_SENT;\r
355                         }\r
356                 }\r
357                 break;\r
358 \r
359         case USB_DATA_SENT:\r
360                 if (!USBD_HID_IsBusy(&hUsbDeviceFS))\r
361                 {\r
362                         // Data accepted.\r
363                         usbInEpState = USB_IDLE;\r
364                 }\r
365                 break;\r
366         }\r
367 \r
368 out:\r
369         s2s_spin_unlock(&usbDevLock);\r
370 }\r
371 \r
372 void s2s_debugTimer()\r
373 {\r
374         if (!USBD_Composite_IsConfigured(&hUsbDeviceFS))\r
375         {\r
376                 usbInEpState = USB_IDLE;\r
377                 return;\r
378         }\r
379 \r
380         if (USBD_HID_IsReportReady(&hUsbDeviceFS))\r
381         {\r
382                 uint8_t hidBuffer[USBHID_LEN];\r
383                 int byteCount = USBD_HID_GetReport(&hUsbDeviceFS, hidBuffer, sizeof(hidBuffer));\r
384                 hidPacket_recv(hidBuffer, byteCount);\r
385 \r
386                 size_t cmdSize;\r
387                 const uint8_t* cmd = hidPacket_peekPacket(&cmdSize);\r
388                 // This is called from an ISR, only process simple commands.\r
389                 if (cmd && (cmdSize > 0))\r
390                 {\r
391                         if (cmd[0] == S2S_CMD_DEBUG)\r
392                         {\r
393                                 hidPacket_getPacket(&cmdSize);\r
394                                 debugCommand();\r
395                         }\r
396                         else if (cmd[0] == S2S_CMD_PING)\r
397                         {\r
398                                 hidPacket_getPacket(&cmdSize);\r
399                                 pingCommand();\r
400                         }\r
401                 }\r
402         }\r
403 \r
404         switch (usbInEpState)\r
405         {\r
406                 case USB_IDLE:\r
407                 {\r
408                         uint8_t hidBuffer[USBHID_LEN];\r
409                         const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);\r
410 \r
411                         if (nextChunk)\r
412                         {\r
413                                 USBD_HID_SendReport (&hUsbDeviceFS, nextChunk, sizeof(hidBuffer));\r
414                                 usbInEpState = USB_DATA_SENT;\r
415                         }\r
416                 }\r
417                 break;\r
418 \r
419                 case USB_DATA_SENT:\r
420                         if (!USBD_HID_IsBusy(&hUsbDeviceFS))\r
421                         {\r
422                                 // Data accepted.\r
423                                 usbInEpState = USB_IDLE;\r
424                         }\r
425                         break;\r
426         }\r
427 }\r
428 \r
429 \r
430 \r
431 // Public method for storing MODE SELECT results.\r
432 void s2s_configSave(int scsiId, uint16_t bytesPerSector)\r
433 {\r
434         S2S_TargetCfg* cfg = (S2S_TargetCfg*) s2s_getConfigById(scsiId);\r
435         cfg->bytesPerSector = bytesPerSector;\r
436 \r
437         BSP_SD_WriteBlocks_DMA(\r
438                 (uint32_t*) &s2s_cfg[0],\r
439                 (sdDev.capacity - S2S_CFG_SIZE) * 512ll,\r
440                 512,\r
441                 (S2S_CFG_SIZE + 511) / 512);\r
442 }\r
443 \r
444 \r
445 const S2S_TargetCfg* s2s_getConfigByIndex(int i)\r
446 {\r
447         return (const S2S_TargetCfg*)\r
448                 (s2s_cfg + sizeof(S2S_BoardCfg) + (i * sizeof(S2S_TargetCfg)));\r
449 }\r
450 \r
451 const S2S_TargetCfg* s2s_getConfigById(int scsiId)\r
452 {\r
453         int i;\r
454         for (i = 0; i < S2S_MAX_TARGETS; ++i)\r
455         {\r
456                 const S2S_TargetCfg* tgt = s2s_getConfigByIndex(i);\r
457                 if ((tgt->scsiId & S2S_CFG_TARGET_ID_BITS) == scsiId)\r
458                 {\r
459                         return tgt;\r
460                 }\r
461         }\r
462         return NULL;\r
463 \r
464 }\r
465 \r