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