Fix bug in scsi self-test function
[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 = 0x0614;\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                 1 // useSdConfig, always true for V6.\r
198         };\r
199         hidPacket_send(response, sizeof(response));\r
200 }\r
201 \r
202 static void\r
203 debugCommand()\r
204 {\r
205         uint8_t response[32];\r
206         memcpy(&response, &scsiDev.cdb, 12);\r
207         response[12] = scsiDev.msgIn;\r
208         response[13] = scsiDev.msgOut;\r
209         response[14] = scsiDev.lastStatus;\r
210         response[15] = scsiDev.lastSense;\r
211         response[16] = scsiDev.phase;\r
212         response[17] = *SCSI_STS_SCSI;\r
213         response[18] = scsiDev.target != NULL ? scsiDev.target->syncOffset : 0;\r
214         response[19] = scsiDev.target != NULL ? scsiDev.target->syncPeriod : 0;\r
215         response[20] = scsiDev.minSyncPeriod;\r
216         response[21] = scsiDev.rstCount;\r
217         response[22] = scsiDev.selCount;\r
218         response[23] = scsiDev.msgCount;\r
219         response[24] = scsiDev.cmdCount;\r
220         response[25] = scsiDev.watchdogTick;\r
221         response[26] = blockDev.state;\r
222         response[27] = scsiDev.lastSenseASC >> 8;\r
223         response[28] = scsiDev.lastSenseASC;\r
224         response[29] = *SCSI_STS_DBX & 0xff; // What we've read\r
225         response[30] = LastTrace;\r
226         response[31] = *SCSI_STS_DBX >> 8; // What we're writing\r
227         hidPacket_send(response, sizeof(response));\r
228 }\r
229 \r
230 static void\r
231 sdWriteCommand(const uint8_t* cmd, size_t cmdSize)\r
232 {\r
233         if (cmdSize < 517)\r
234         {\r
235                 return; // ignore.\r
236         }\r
237         uint32_t lba =\r
238                 (((uint32_t)cmd[1]) << 24) |\r
239                 (((uint32_t)cmd[2]) << 16) |\r
240                 (((uint32_t)cmd[3]) << 8) |\r
241                 ((uint32_t)cmd[4]);\r
242 \r
243         memcpy(configDmaBuf, &cmd[5], 512);\r
244         BSP_SD_WriteBlocks_DMA((uint32_t*) configDmaBuf, lba * 512ll, 512, 1);\r
245 \r
246         uint8_t response[] =\r
247         {\r
248                 S2S_CFG_STATUS_GOOD\r
249         };\r
250         hidPacket_send(response, sizeof(response));\r
251 }\r
252 \r
253 static void\r
254 sdReadCommand(const uint8_t* cmd, size_t cmdSize)\r
255 {\r
256         if (cmdSize < 5)\r
257         {\r
258                 return; // ignore.\r
259         }\r
260         uint32_t lba =\r
261                 (((uint32_t)cmd[1]) << 24) |\r
262                 (((uint32_t)cmd[2]) << 16) |\r
263                 (((uint32_t)cmd[3]) << 8) |\r
264                 ((uint32_t)cmd[4]);\r
265 \r
266         BSP_SD_ReadBlocks_DMA((uint32_t*) configDmaBuf, lba * 512ll, 512, 1);\r
267         hidPacket_send(configDmaBuf, 512);\r
268 }\r
269 \r
270 static void\r
271 processCommand(const uint8_t* cmd, size_t cmdSize)\r
272 {\r
273         switch (cmd[0])\r
274         {\r
275         case S2S_CMD_PING:\r
276                 pingCommand();\r
277                 break;\r
278 \r
279         case S2S_CMD_REBOOT:\r
280                 s2s_enterBootloader();\r
281                 break;\r
282 \r
283         case S2S_CMD_SDINFO:\r
284                 sdInfoCommand();\r
285                 break;\r
286 \r
287         case S2S_CMD_SCSITEST:\r
288                 scsiTestCommand();\r
289                 break;\r
290 \r
291         case S2S_CMD_DEVINFO:\r
292                 scsiDevInfoCommand();\r
293                 break;\r
294 \r
295         case S2S_CMD_SD_WRITE:\r
296                 sdWriteCommand(cmd, cmdSize);\r
297                 break;\r
298 \r
299         case S2S_CMD_SD_READ:\r
300                 sdReadCommand(cmd, cmdSize);\r
301                 break;\r
302 \r
303         case S2S_CMD_DEBUG:\r
304                 if (debugTimerStarted == 0) {\r
305                         debugInit();\r
306                 }\r
307                 debugCommand();\r
308                 break;\r
309 \r
310         case S2S_CMD_NONE: // invalid\r
311         default:\r
312                 break;\r
313         }\r
314 }\r
315 \r
316 void s2s_configPoll()\r
317 {\r
318         s2s_spin_lock(&usbDevLock);\r
319 \r
320         if (!USBD_Composite_IsConfigured(&hUsbDeviceFS))\r
321         {\r
322                 usbInEpState = USB_IDLE;\r
323                 goto out;\r
324         }\r
325 \r
326         if (USBD_HID_IsReportReady(&hUsbDeviceFS))\r
327         {\r
328                 s2s_ledOn();\r
329 \r
330                 // The host sent us some data!\r
331                 uint8_t hidBuffer[USBHID_LEN];\r
332                 int byteCount = USBD_HID_GetReport(&hUsbDeviceFS, hidBuffer, sizeof(hidBuffer));\r
333                 hidPacket_recv(hidBuffer, byteCount);\r
334 \r
335                 size_t cmdSize;\r
336                 const uint8_t* cmd = hidPacket_getPacket(&cmdSize);\r
337                 if (cmd && (cmdSize > 0))\r
338                 {\r
339                         processCommand(cmd, cmdSize);\r
340                 }\r
341 \r
342                 s2s_ledOff();\r
343         }\r
344 \r
345         switch (usbInEpState)\r
346         {\r
347         case USB_IDLE:\r
348                 {\r
349                         uint8_t hidBuffer[USBHID_LEN];\r
350                         const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);\r
351 \r
352                         if (nextChunk)\r
353                         {\r
354                                 USBD_HID_SendReport (&hUsbDeviceFS, nextChunk, sizeof(hidBuffer));\r
355                                 usbInEpState = USB_DATA_SENT;\r
356                         }\r
357                 }\r
358                 break;\r
359 \r
360         case USB_DATA_SENT:\r
361                 if (!USBD_HID_IsBusy(&hUsbDeviceFS))\r
362                 {\r
363                         // Data accepted.\r
364                         usbInEpState = USB_IDLE;\r
365                 }\r
366                 break;\r
367         }\r
368 \r
369 out:\r
370         s2s_spin_unlock(&usbDevLock);\r
371 }\r
372 \r
373 void s2s_debugTimer()\r
374 {\r
375         if (!USBD_Composite_IsConfigured(&hUsbDeviceFS))\r
376         {\r
377                 usbInEpState = USB_IDLE;\r
378                 return;\r
379         }\r
380 \r
381         if (USBD_HID_IsReportReady(&hUsbDeviceFS))\r
382         {\r
383                 uint8_t hidBuffer[USBHID_LEN];\r
384                 int byteCount = USBD_HID_GetReport(&hUsbDeviceFS, hidBuffer, sizeof(hidBuffer));\r
385                 hidPacket_recv(hidBuffer, byteCount);\r
386 \r
387                 size_t cmdSize;\r
388                 const uint8_t* cmd = hidPacket_peekPacket(&cmdSize);\r
389                 // This is called from an ISR, only process simple commands.\r
390                 if (cmd && (cmdSize > 0))\r
391                 {\r
392                         if (cmd[0] == S2S_CMD_DEBUG)\r
393                         {\r
394                                 hidPacket_getPacket(&cmdSize);\r
395                                 debugCommand();\r
396                         }\r
397                         else if (cmd[0] == S2S_CMD_PING)\r
398                         {\r
399                                 hidPacket_getPacket(&cmdSize);\r
400                                 pingCommand();\r
401                         }\r
402                 }\r
403         }\r
404 \r
405         switch (usbInEpState)\r
406         {\r
407                 case USB_IDLE:\r
408                 {\r
409                         uint8_t hidBuffer[USBHID_LEN];\r
410                         const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);\r
411 \r
412                         if (nextChunk)\r
413                         {\r
414                                 USBD_HID_SendReport (&hUsbDeviceFS, nextChunk, sizeof(hidBuffer));\r
415                                 usbInEpState = USB_DATA_SENT;\r
416                         }\r
417                 }\r
418                 break;\r
419 \r
420                 case USB_DATA_SENT:\r
421                         if (!USBD_HID_IsBusy(&hUsbDeviceFS))\r
422                         {\r
423                                 // Data accepted.\r
424                                 usbInEpState = USB_IDLE;\r
425                         }\r
426                         break;\r
427         }\r
428 }\r
429 \r
430 \r
431 \r
432 // Public method for storing MODE SELECT results.\r
433 void s2s_configSave(int scsiId, uint16_t bytesPerSector)\r
434 {\r
435         S2S_TargetCfg* cfg = (S2S_TargetCfg*) s2s_getConfigById(scsiId);\r
436         cfg->bytesPerSector = bytesPerSector;\r
437 \r
438         BSP_SD_WriteBlocks_DMA(\r
439                 (uint32_t*) &s2s_cfg[0],\r
440                 (sdDev.capacity - S2S_CFG_SIZE) * 512ll,\r
441                 512,\r
442                 (S2S_CFG_SIZE + 511) / 512);\r
443 }\r
444 \r
445 \r
446 const S2S_TargetCfg* s2s_getConfigByIndex(int i)\r
447 {\r
448         return (const S2S_TargetCfg*)\r
449                 (s2s_cfg + sizeof(S2S_BoardCfg) + (i * sizeof(S2S_TargetCfg)));\r
450 }\r
451 \r
452 const S2S_TargetCfg* s2s_getConfigById(int scsiId)\r
453 {\r
454         int i;\r
455         for (i = 0; i < S2S_MAX_TARGETS; ++i)\r
456         {\r
457                 const S2S_TargetCfg* tgt = s2s_getConfigByIndex(i);\r
458                 if ((tgt->scsiId & S2S_CFG_TARGET_ID_BITS) == scsiId)\r
459                 {\r
460                         return tgt;\r
461                 }\r
462         }\r
463         return NULL;\r
464 \r
465 }\r
466 \r