Fix bug in using nor flash storage without SD
[SCSI2SD.git] / software / SCSI2SD / src / 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 "device.h"\r
19 #include "config.h"\r
20 #include "debug.h"\r
21 #include "USBFS.h"\r
22 #include "led.h"\r
23 \r
24 #include "scsi.h"\r
25 #include "scsiPhy.h"\r
26 #include "disk.h"\r
27 #include "trace.h"\r
28 \r
29 #include "../../include/scsi2sd.h"\r
30 #include "../../include/hidpacket.h"\r
31 \r
32 #include <string.h>\r
33 \r
34 static const uint16_t FIRMWARE_VERSION = 0x0485;\r
35 \r
36 // 1 flash row\r
37 static const uint8_t DEFAULT_CONFIG[256] =\r
38 {\r
39         0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00,\r
40         0x00, 0x02, 0x3F, 0x00, 0xFF, 0x00, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x73,\r
41         0x72, 0x63, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,\r
42         0x43, 0x53, 0x49, 0x32, 0x53, 0x44, 0x20, 0x31, 0x2E, 0x30, 0x31, 0x32,\r
43         0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,\r
44         0x37, 0x38, 0x00, 0x00\r
45 };\r
46 \r
47 enum USB_ENDPOINTS\r
48 {\r
49         USB_EP_OUT = 1,\r
50         USB_EP_IN = 2,\r
51         USB_EP_COMMAND = 3,\r
52         USB_EP_DEBUG = 4\r
53 };\r
54 enum USB_STATE\r
55 {\r
56         USB_IDLE,\r
57         USB_DATA_SENT\r
58 };\r
59 \r
60 static uint8_t hidBuffer[USBHID_LEN];\r
61 \r
62 static int usbInEpState;\r
63 static int usbDebugEpState;\r
64 static int usbReady;\r
65 \r
66 static void initBoardConfig(S2S_BoardConfig* config) {\r
67         memcpy(\r
68                 config,\r
69                 (\r
70                         CY_FLASH_BASE +\r
71                         (CY_FLASH_SIZEOF_ARRAY * (size_t) SCSI_CONFIG_ARRAY) +\r
72                         (CY_FLASH_SIZEOF_ROW * SCSI_CONFIG_BOARD_ROW)\r
73                         ),\r
74                 sizeof(S2S_BoardConfig));\r
75 \r
76         if (memcmp(config->magic, "BCFG", 4)) {\r
77                 // Set a default from the deprecated flags, or 0 if\r
78                 // there is no initial config.\r
79                 config->flags = getConfigByIndex(0)->flagsDEPRECATED;\r
80 \r
81                 config->selectionDelay = 255; // auto\r
82                 config->flags6 = S2S_CFG_ENABLE_TERMINATOR;\r
83         }\r
84 }\r
85 \r
86 void configInit(S2S_BoardConfig* config)\r
87 {\r
88         // The USB block will be powered by an internal 3.3V regulator.\r
89         // The PSoC must be operating between 4.6V and 5V for the regulator\r
90         // to work.\r
91         USBFS_Start(0, USBFS_5V_OPERATION);\r
92         usbInEpState = usbDebugEpState = USB_IDLE;\r
93         usbReady = 0; // We don't know if host is connected yet.\r
94 \r
95         int invalid = 1;\r
96         uint8_t* rawConfig = (uint8_t*)getConfigByIndex(0);\r
97         int i;\r
98         for (i = 0; i < 64; ++i)\r
99         {\r
100                 if (rawConfig[i])\r
101                 {\r
102                         invalid = 0;\r
103                         break;\r
104                 }\r
105         }\r
106         if (invalid)\r
107         {\r
108                 // Save a default config.\r
109                 CySetTemp();\r
110                 CyWriteRowData(SCSI_CONFIG_ARRAY, SCSI_CONFIG_0_ROW, DEFAULT_CONFIG);\r
111         }\r
112 \r
113         initBoardConfig(config);\r
114 }\r
115 \r
116 static void\r
117 readFlashCommand(const uint8_t* cmd, size_t cmdSize)\r
118 {\r
119         if (cmdSize < 3)\r
120         {\r
121                 return; // ignore.\r
122         }\r
123         uint8_t flashArray = cmd[1];\r
124         uint8_t flashRow = cmd[2];\r
125 \r
126         uint8_t* flash =\r
127                 CY_FLASH_BASE +\r
128                 (CY_FLASH_SIZEOF_ARRAY * (size_t) flashArray) +\r
129                 (CY_FLASH_SIZEOF_ROW * (size_t) flashRow);\r
130 \r
131         hidPacket_send(flash, SCSI_CONFIG_ROW_SIZE);\r
132 }\r
133 \r
134 static void\r
135 writeFlashCommand(const uint8_t* cmd, size_t cmdSize)\r
136 {\r
137         if (cmdSize < 259)\r
138         {\r
139                 return; // ignore.\r
140         }\r
141         uint8_t flashArray = cmd[257];\r
142         uint8_t flashRow = cmd[258];\r
143 \r
144         // Be very careful not to overwrite the bootloader or other\r\r
145         // code. Bootloader updates no longer supported. Use v5.1 board\r
146         // instead.\r
147         if ((flashArray != SCSI_CONFIG_ARRAY) ||\r
148                 (flashRow < SCSI_CONFIG_4_ROW) ||\r
149                 (flashRow >= SCSI_CONFIG_3_ROW + SCSI_CONFIG_ROWS))\r
150         {\r
151                 uint8_t response[] = { CONFIG_STATUS_ERR };\r
152                 hidPacket_send(response, sizeof(response));\r
153         }\r
154 \r
155         CySetTemp();\r
156         int status = CyWriteRowData(flashArray, flashRow, cmd + 1);\r
157 \r
158         uint8_t response[] =\r
159         {\r
160                 status == CYRET_SUCCESS ? CONFIG_STATUS_GOOD : CONFIG_STATUS_ERR\r
161         };\r
162         hidPacket_send(response, sizeof(response));\r
163 }\r
164 \r
165 static void\r
166 pingCommand()\r
167 {\r
168         uint8_t response[] =\r
169         {\r
170                 CONFIG_STATUS_GOOD\r
171         };\r
172         hidPacket_send(response, sizeof(response));\r
173 }\r
174 \r
175 static void\r
176 sdInfoCommand()\r
177 {\r
178         uint8_t response[sizeof(sdCard.csd) + sizeof(sdCard.cid)];\r
179         memcpy(response, sdCard.csd, sizeof(sdCard.csd));\r
180         memcpy(response + sizeof(sdCard.csd), sdCard.cid, sizeof(sdCard.cid));\r
181 \r
182         hidPacket_send(response, sizeof(response));\r
183 }\r
184 \r
185 \r
186 static void\r
187 scsiTestCommand()\r
188 {\r
189         int resultCode = scsiSelfTest();\r
190         uint8_t response[] =\r
191         {\r
192                 resultCode == 0 ? CONFIG_STATUS_GOOD : CONFIG_STATUS_ERR,\r
193                 resultCode\r
194         };\r
195         hidPacket_send(response, sizeof(response));\r
196 }\r
197 \r
198 static void\r
199 deviceListCommand()\r
200 {\r
201     int deviceCount;\r
202     S2S_Device** devices = s2s_GetDevices(&deviceCount);\r
203     \r
204     uint8_t response[16] = // Make larger if there can be more than 2 devices\r
205     {\r
206         deviceCount\r
207     };\r
208     \r
209     int pos = 1;\r
210     \r
211     for (int i = 0; i < deviceCount; ++i)\r
212     {\r
213         response[pos++] = devices[i]->deviceType;\r
214         \r
215         uint32_t capacity = devices[i]->getCapacity(devices[i]);\r
216         response[pos++] = capacity >> 24;\r
217         response[pos++] = capacity >> 16;\r
218         response[pos++] = capacity >> 8;\r
219         response[pos++] = capacity;\r
220     }\r
221     \r
222     hidPacket_send(response, pos);\r
223 }\r
224 \r
225 static void\r
226 deviceEraseCommand(const uint8_t* cmd)\r
227 {\r
228     int deviceCount;\r
229     S2S_Device** devices = s2s_GetDevices(&deviceCount);\r
230     \r
231     uint32_t sectorNum =\r
232         ((uint32_t)cmd[2]) << 24 |\r
233         ((uint32_t)cmd[3]) << 16 |\r
234         ((uint32_t)cmd[4]) << 8 |\r
235         ((uint32_t)cmd[5]);\r
236 \r
237     uint32_t count =\r
238         ((uint32_t)cmd[6]) << 24 |\r
239         ((uint32_t)cmd[7]) << 16 |\r
240         ((uint32_t)cmd[8]) << 8 |\r
241         ((uint32_t)cmd[9]);\r
242 \r
243     devices[cmd[1]]->erase(devices[cmd[1]], sectorNum, count);\r
244     \r
245         uint8_t response[] =\r
246         {\r
247                 CONFIG_STATUS_GOOD\r
248         };\r
249     hidPacket_send(response, sizeof(response));\r
250 }\r
251 \r
252 static void\r
253 deviceWriteCommand(const uint8_t* cmd)\r
254 {\r
255     int deviceCount;\r
256     S2S_Device** devices = s2s_GetDevices(&deviceCount);\r
257     \r
258     uint32_t sectorNum =\r
259         ((uint32_t)cmd[2]) << 24 |\r
260         ((uint32_t)cmd[3]) << 16 |\r
261         ((uint32_t)cmd[4]) << 8 |\r
262         ((uint32_t)cmd[5]);\r
263 \r
264     devices[cmd[1]]->write(devices[cmd[1]], sectorNum, 1, &cmd[6]);\r
265     \r
266         uint8_t response[] =\r
267         {\r
268                 CONFIG_STATUS_GOOD\r
269         };\r
270     hidPacket_send(response, sizeof(response));\r
271 }\r
272 \r
273 \r
274 static void\r
275 deviceReadCommand(const uint8_t* cmd)\r
276 {\r
277     int deviceCount;\r
278     S2S_Device** devices = s2s_GetDevices(&deviceCount);\r
279     \r
280     uint32_t sectorNum =\r
281         ((uint32_t)cmd[2]) << 24 |\r
282         ((uint32_t)cmd[3]) << 16 |\r
283         ((uint32_t)cmd[4]) << 8 |\r
284         ((uint32_t)cmd[5]);\r
285 \r
286     uint8_t response[512];\r
287     devices[cmd[1]]->read(devices[cmd[1]], sectorNum, 1, &response[0]);\r
288     \r
289     hidPacket_send(&response[0], 512);\r
290 }\r
291 \r
292 static void\r
293 processCommand(const uint8_t* cmd, size_t cmdSize)\r
294 {\r
295         switch (cmd[0])\r
296         {\r
297         case CONFIG_PING:\r
298                 pingCommand();\r
299                 break;\r
300 \r
301         case CONFIG_READFLASH:\r
302                 readFlashCommand(cmd, cmdSize);\r
303                 break;\r
304 \r
305         case CONFIG_WRITEFLASH:\r
306                 writeFlashCommand(cmd, cmdSize);\r
307                 break;\r
308 \r
309         case CONFIG_REBOOT:\r
310                 Bootloadable_1_Load();\r
311                 break;\r
312 \r
313         case CONFIG_SDINFO:\r
314                 sdInfoCommand();\r
315                 break;\r
316 \r
317         case CONFIG_SCSITEST:\r
318                 scsiTestCommand();\r
319                 break;\r
320 \r
321     case S2S_CMD_DEV_LIST:\r
322         deviceListCommand();\r
323         break;\r
324 \r
325     case S2S_CMD_DEV_ERASE:\r
326         deviceEraseCommand(cmd);\r
327         break;\r
328 \r
329     case S2S_CMD_DEV_WRITE:\r
330         deviceWriteCommand(cmd);\r
331         break;\r
332 \r
333     case S2S_CMD_DEV_READ:\r
334         deviceReadCommand(cmd);\r
335         break;\r
336         \r
337         case CONFIG_NONE: // invalid\r
338         default:\r
339                 break;\r
340         }\r
341 }\r
342 \r
343 void configPoll()\r
344 {\r
345         int reset = 0;\r
346         if (!usbReady || USBFS_IsConfigurationChanged())\r
347         {\r
348                 reset = 1;\r
349         }\r
350         usbReady = USBFS_bGetConfiguration();\r
351 \r
352         if (!usbReady)\r
353         {\r
354                 return;\r
355         }\r
356 \r
357         if (reset)\r
358         {\r
359                 USBFS_EnableOutEP(USB_EP_OUT);\r
360                 USBFS_EnableOutEP(USB_EP_COMMAND);\r
361                 usbInEpState = usbDebugEpState = USB_IDLE;\r
362         }\r
363 \r
364         if(USBFS_GetEPState(USB_EP_OUT) == USBFS_OUT_BUFFER_FULL)\r
365         {\r
366                 ledOn();\r
367 \r
368                 // The host sent us some data!\r
369                 int byteCount = USBFS_GetEPCount(USB_EP_OUT);\r
370                 USBFS_ReadOutEP(USB_EP_OUT, hidBuffer, sizeof(hidBuffer));\r
371                 hidPacket_recv(hidBuffer, byteCount);\r
372 \r
373                 size_t cmdSize;\r
374                 const uint8_t* cmd = hidPacket_getPacket(&cmdSize);\r
375                 if (cmd && (cmdSize > 0))\r
376                 {\r
377                         processCommand(cmd, cmdSize);\r
378                 }\r
379 \r
380                 // Allow the host to send us another updated config.\r
381                 USBFS_EnableOutEP(USB_EP_OUT);\r
382 \r
383                 ledOff();\r
384         }\r
385 \r
386         switch (usbInEpState)\r
387         {\r
388         case USB_IDLE:\r
389                 {\r
390                         const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer);\r
391 \r
392                         if (nextChunk)\r
393                         {\r
394                                 USBFS_LoadInEP(USB_EP_IN, nextChunk, sizeof(hidBuffer));\r
395                                 usbInEpState = USB_DATA_SENT;\r
396                         }\r
397                 }\r
398                 break;\r
399 \r
400         case USB_DATA_SENT:\r
401                 if (USBFS_bGetEPAckState(USB_EP_IN))\r
402                 {\r
403                         // Data accepted.\r
404                         usbInEpState = USB_IDLE;\r
405                 }\r
406                 break;\r
407         }\r
408 }\r
409 \r
410 void debugPoll()\r
411 {\r
412         if (!usbReady)\r
413         {\r
414                 return;\r
415         }\r
416 \r
417         if(USBFS_GetEPState(USB_EP_COMMAND) == USBFS_OUT_BUFFER_FULL)\r
418         {\r
419                 // The host sent us some data!\r
420                 int byteCount = USBFS_GetEPCount(USB_EP_COMMAND);\r
421                 USBFS_ReadOutEP(USB_EP_COMMAND, (uint8 *)&hidBuffer, byteCount);\r
422 \r
423                 if (byteCount >= 1 &&\r
424                         hidBuffer[0] == 0x01)\r
425                 {\r
426                         // Reboot command.\r
427                         Bootloadable_1_Load();\r
428                 }\r
429 \r
430                 // Allow the host to send us another command.\r
431                 // (assuming we didn't reboot outselves)\r
432                 USBFS_EnableOutEP(USB_EP_COMMAND);\r
433         }\r
434 \r
435         switch (usbDebugEpState)\r
436         {\r
437         case USB_IDLE:\r
438                 memcpy(&hidBuffer, &scsiDev.cdb, 12);\r
439                 hidBuffer[12] = scsiDev.msgIn;\r
440                 hidBuffer[13] = scsiDev.msgOut;\r
441                 hidBuffer[14] = scsiDev.lastStatus;\r
442                 hidBuffer[15] = scsiDev.lastSense;\r
443                 hidBuffer[16] = scsiDev.phase;\r
444                 hidBuffer[17] = SCSI_ReadFilt(SCSI_Filt_BSY);\r
445                 hidBuffer[18] = SCSI_ReadFilt(SCSI_Filt_SEL);\r
446                 hidBuffer[19] = SCSI_ReadFilt(SCSI_Filt_ATN);\r
447                 hidBuffer[20] = SCSI_ReadFilt(SCSI_Filt_RST);\r
448                 hidBuffer[21] = scsiDev.rstCount;\r
449                 hidBuffer[22] = scsiDev.selCount;\r
450                 hidBuffer[23] = scsiDev.msgCount;\r
451                 hidBuffer[24] = scsiDev.cmdCount;\r
452                 hidBuffer[25] = scsiDev.watchdogTick;\r
453                 hidBuffer[26] = 0; // OBSOLETE. Previously media state\r
454                 hidBuffer[27] = scsiDev.lastSenseASC >> 8;\r
455                 hidBuffer[28] = scsiDev.lastSenseASC;\r
456                 hidBuffer[29] = scsiReadDBxPins();\r
457                 hidBuffer[30] = LastTrace;\r
458 \r
459                 hidBuffer[58] = sdCard.capacity >> 24;\r
460                 hidBuffer[59] = sdCard.capacity >> 16;\r
461                 hidBuffer[60] = sdCard.capacity >> 8;\r
462                 hidBuffer[61] = sdCard.capacity;\r
463 \r
464                 hidBuffer[62] = FIRMWARE_VERSION >> 8;\r
465                 hidBuffer[63] = FIRMWARE_VERSION;\r
466 \r
467                 USBFS_LoadInEP(USB_EP_DEBUG, (uint8 *)&hidBuffer, sizeof(hidBuffer));\r
468                 usbDebugEpState = USB_DATA_SENT;\r
469                 break;\r
470 \r
471         case USB_DATA_SENT:\r
472                 if (USBFS_bGetEPAckState(USB_EP_DEBUG))\r
473                 {\r
474                         // Data accepted.\r
475                         usbDebugEpState = USB_IDLE;\r
476                 }\r
477                 break;\r
478         }\r
479 }\r
480 \r
481 CY_ISR(debugTimerISR)\r
482 {\r
483         Debug_Timer_ReadStatusRegister();\r
484         Debug_Timer_Interrupt_ClearPending();\r
485         uint8 savedIntrStatus = CyEnterCriticalSection();\r
486         debugPoll();\r
487         CyExitCriticalSection(savedIntrStatus);\r
488 }\r
489 \r
490 void debugInit()\r
491 {\r
492         Debug_Timer_Interrupt_StartEx(debugTimerISR);\r
493         Debug_Timer_Start();\r
494 }\r
495 \r
496 void debugPause()\r
497 {\r
498         Debug_Timer_Stop();\r
499 }\r
500 \r
501 void debugResume()\r
502 {\r
503         Debug_Timer_Start();\r
504 }\r
505 \r
506 int isDebugEnabled()\r
507 {\r
508         return usbReady;\r
509 }\r
510 \r
511 // Public method for storing MODE SELECT results.\r
512 void configSave(int scsiId, uint16_t bytesPerSector)\r
513 {\r
514         int cfgIdx;\r
515         for (cfgIdx = 0; cfgIdx < MAX_SCSI_TARGETS; ++cfgIdx)\r
516         {\r
517                 const S2S_TargetCfg* tgt = getConfigByIndex(cfgIdx);\r
518                 if ((tgt->scsiId & CONFIG_TARGET_ID_BITS) == scsiId)\r
519                 {\r
520                         // Save row to flash\r
521                         // We only save the first row of the configuration\r
522                         // this contains the parameters changeable by a MODE SELECT command\r
523                         uint8_t rowData[CYDEV_FLS_ROW_SIZE];\r
524                         S2S_TargetCfg* rowCfgData = (S2S_TargetCfg*)&rowData;\r
525                         memcpy(rowCfgData, tgt, sizeof(rowData));\r
526                         rowCfgData->bytesPerSector = bytesPerSector;\r
527 \r
528                         CySetTemp();\r
529                         CyWriteRowData(\r
530                                 SCSI_CONFIG_ARRAY,\r
531                                 SCSI_CONFIG_0_ROW + (cfgIdx * SCSI_CONFIG_ROWS),\r
532                                 (uint8_t*)rowCfgData);\r
533                         return;\r
534                 }\r
535         }\r
536 }\r
537 \r
538 \r
539 const S2S_TargetCfg* getConfigByIndex(int i)\r
540 {\r
541         if (i <= 3)\r
542         {\r
543                 size_t row = SCSI_CONFIG_0_ROW + (i * SCSI_CONFIG_ROWS);\r
544                 return (const S2S_TargetCfg*)\r
545                         (\r
546                                 CY_FLASH_BASE +\r
547                                 (CY_FLASH_SIZEOF_ARRAY * (size_t) SCSI_CONFIG_ARRAY) +\r
548                                 (CY_FLASH_SIZEOF_ROW * row)\r
549                                 );\r
550         } else {\r
551                 size_t row = SCSI_CONFIG_4_ROW + ((i-4) * SCSI_CONFIG_ROWS);\r
552                 return (const S2S_TargetCfg*)\r
553                         (\r
554                                 CY_FLASH_BASE +\r
555                                 (CY_FLASH_SIZEOF_ARRAY * (size_t) SCSI_CONFIG_ARRAY) +\r
556                                 (CY_FLASH_SIZEOF_ROW * row)\r
557                                 );\r
558         }\r
559 }\r
560 \r
561 const S2S_TargetCfg* getConfigById(int scsiId)\r
562 {\r
563         int i;\r
564         for (i = 0; i < MAX_SCSI_TARGETS; ++i)\r
565         {\r
566                 const S2S_TargetCfg* tgt = getConfigByIndex(i);\r
567                 if ((tgt->scsiId & CONFIG_TARGET_ID_BITS) == scsiId)\r
568                 {\r
569                         return tgt;\r
570                 }\r
571         }\r
572         return NULL;\r
573 \r
574 }\r