Use Docker to build firmware and scsi2sd-util6
[SCSI2SD-V6.git] / src / firmware / sd.c
1 //    Copyright (C) 2013 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 #ifdef STM32F2xx\r
19 #include "stm32f2xx.h"\r
20 #endif\r
21 \r
22 #ifdef STM32F4xx\r
23 #include "stm32f4xx.h"\r
24 #endif\r
25 \r
26 #include "sdio.h"\r
27 #include "bsp_driver_sd.h"\r
28 \r
29 \r
30 #include "scsi.h"\r
31 #include "config.h"\r
32 #include "disk.h"\r
33 #include "sd.h"\r
34 #include "led.h"\r
35 #include "time.h"\r
36 \r
37 #include "scsiPhy.h"\r
38 \r
39 #include <string.h>\r
40 \r
41 // Global\r
42 SdDevice sdDev;\r
43 \r
44 static int sdCmdActive = 0;\r
45 \r
46 int\r
47 sdReadDMAPoll(uint32_t remainingSectors)\r
48 {\r
49     // TODO DMA byte counting disabled for now as it's not\r
50     // working.\r
51     // We can ask the SDIO controller how many bytes have been\r
52     // processed (SDIO_GetDataCounter()) but I'm not sure if that\r
53     // means the data has been transfered via dma to memory yet.\r
54 //    uint32_t dmaBytesRemaining = __HAL_DMA_GET_COUNTER(hsd.hdmarx) * 4;\r
55 \r
56     if (HAL_SD_GetState(&hsd) != HAL_SD_STATE_BUSY)\r
57     {\r
58         // DMA transfer is complete\r
59         sdCmdActive = 0;\r
60         return remainingSectors;\r
61     }\r
62 /*    else\r
63     {\r
64         return remainingSectors - ((dmaBytesRemaining + (SD_SECTOR_SIZE - 1)) / SD_SECTOR_SIZE);\r
65     }*/\r
66     return 0;\r
67 }\r
68 \r
69 void sdReadDMA(uint32_t lba, uint32_t sectors, uint8_t* outputBuffer)\r
70 {\r
71     if (HAL_SD_ReadBlocks_DMA(&hsd, outputBuffer, lba, sectors) != HAL_OK)\r
72     {\r
73         scsiDiskReset();\r
74 \r
75         scsiDev.status = CHECK_CONDITION;\r
76         scsiDev.target->sense.code = HARDWARE_ERROR;\r
77         scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
78         scsiDev.phase = STATUS;\r
79     }\r
80     else\r
81     {\r
82         sdCmdActive = 1;\r
83     }\r
84 }\r
85 \r
86 void sdReadCmd(uint32_t lba, uint32_t sectors)\r
87 {\r
88     uint32_t errorstate;\r
89     hsd.ErrorCode = HAL_SD_ERROR_NONE;\r
90     hsd.State = HAL_SD_STATE_BUSY;\r
91 \r
92     /* Initialize data control register */\r
93     hsd.Instance->DCTRL = 0U;\r
94 \r
95     // The IRQ handler clears flags which we need to read the fifo data\r
96 #if defined(SDIO_STA_STBITERR)\r
97     __HAL_SD_DISABLE_IT(&hsd, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_RXOVERR | SDIO_IT_DATAEND | SDIO_FLAG_RXFIFOHF | SDIO_IT_STBITERR));\r
98 #else\r
99     __HAL_SD_DISABLE_IT(&hsd, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_RXOVERR | SDIO_IT_DATAEND | SDIO_FLAG_RXFIFOHF));\r
100 #endif\r
101 \r
102     if(hsd.SdCard.CardType != CARD_SDHC_SDXC)\r
103     {\r
104         lba *= 512U;\r
105 \r
106         errorstate = SDMMC_CmdBlockLength(hsd.Instance, 512u);\r
107         if(errorstate != HAL_SD_ERROR_NONE)\r
108         {\r
109             __HAL_SD_CLEAR_FLAG(&hsd, SDIO_STATIC_FLAGS);\r
110             scsiDiskReset();\r
111 \r
112             scsiDev.status = CHECK_CONDITION;\r
113             scsiDev.target->sense.code = HARDWARE_ERROR;\r
114             scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
115             scsiDev.phase = STATUS;\r
116             return;\r
117         }\r
118     }\r
119 \r
120     if(sectors > 1U)\r
121     {\r
122         hsd.Context = SD_CONTEXT_READ_MULTIPLE_BLOCK;\r
123         errorstate = SDMMC_CmdReadMultiBlock(hsd.Instance, lba);\r
124     }\r
125     else\r
126     {\r
127         hsd.Context = SD_CONTEXT_READ_SINGLE_BLOCK;\r
128         errorstate = SDMMC_CmdReadSingleBlock(hsd.Instance, lba);\r
129     }\r
130 \r
131     if(errorstate != HAL_SD_ERROR_NONE)\r
132     {\r
133         __HAL_SD_CLEAR_FLAG(&hsd, SDIO_STATIC_FLAGS);\r
134 \r
135         scsiDiskReset();\r
136 \r
137         scsiDev.status = CHECK_CONDITION;\r
138         scsiDev.target->sense.code = HARDWARE_ERROR;\r
139         scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
140         scsiDev.phase = STATUS;\r
141     }\r
142     else\r
143     {\r
144         sdCmdActive = 1;\r
145     }\r
146 }\r
147 \r
148 void sdReadPIOData(uint32_t sectors)\r
149 {\r
150     /* Initialize data control register */\r
151     hsd.Instance->DCTRL = 0U;\r
152 \r
153     SDIO_DataInitTypeDef config;\r
154     config.DataTimeOut   = SDMMC_DATATIMEOUT;\r
155     config.DataLength    = sectors * 512u;\r
156     config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;\r
157     config.TransferDir   = SDIO_TRANSFER_DIR_TO_SDIO;\r
158     config.TransferMode  = SDIO_TRANSFER_MODE_BLOCK;\r
159     config.DPSM          = SDIO_DPSM_ENABLE;\r
160     SDIO_ConfigData(hsd.Instance, &config);\r
161 }\r
162 \r
163 \r
164 void sdCompleteTransfer()\r
165 {\r
166     if (sdCmdActive)\r
167     {\r
168         HAL_SD_Abort(&hsd);\r
169         sdCmdActive = 0;\r
170     }\r
171 }\r
172 \r
173 static void sdClear()\r
174 {\r
175     sdDev.version = 0;\r
176     sdDev.capacity = 0;\r
177     memset(sdDev.csd, 0, sizeof(sdDev.csd));\r
178     memset(sdDev.cid, 0, sizeof(sdDev.cid));\r
179 }\r
180 \r
181 static int sdDoInit()\r
182 {\r
183     int result = 0;\r
184 \r
185     sdClear();\r
186 \r
187     int8_t error = BSP_SD_Init();\r
188     if (error == MSD_OK)\r
189     {\r
190         HAL_SD_CardInfoTypeDef cardInfo;\r
191         HAL_SD_GetCardInfo(&hsd, &cardInfo);\r
192         memcpy(sdDev.csd, hsd.CSD, sizeof(sdDev.csd));\r
193         memcpy(sdDev.cid, hsd.CID, sizeof(sdDev.cid));\r
194         sdDev.capacity = cardInfo.LogBlockNbr;\r
195         blockDev.state |= DISK_PRESENT | DISK_INITIALISED;\r
196         result = 1;\r
197 \r
198         goto out;\r
199     }\r
200 \r
201 //bad:\r
202     blockDev.state &= ~(DISK_PRESENT | DISK_INITIALISED);\r
203 \r
204     sdDev.capacity = 0;\r
205 \r
206 out:\r
207     s2s_ledOff();\r
208     return result;\r
209 }\r
210 \r
211 int sdInit()\r
212 {\r
213     // Check if there's an SD card present.\r
214     int result = 0;\r
215 \r
216     static int firstInit = 1;\r
217 \r
218     if (firstInit)\r
219     {\r
220         blockDev.state &= ~(DISK_PRESENT | DISK_INITIALISED);\r
221         sdClear();\r
222     }\r
223 \r
224     if (firstInit || (scsiDev.phase == BUS_FREE))\r
225     {\r
226         uint8_t cs = HAL_GPIO_ReadPin(nSD_CD_GPIO_Port, nSD_CD_Pin) ? 0 : 1;\r
227 \r
228         if (cs && !(blockDev.state & DISK_PRESENT))\r
229         {\r
230             s2s_ledOn();\r
231 \r
232             // Debounce. Quicker if the card is present at\r
233             // power on\r
234             if (!firstInit)\r
235             {\r
236                 for (int i = 0; cs && (i < 50); ++i)\r
237                 {\r
238                     cs = HAL_GPIO_ReadPin(nSD_CD_GPIO_Port, nSD_CD_Pin) ? 0 : 1;\r
239                     s2s_delay_ms(5);\r
240                 }\r
241             }\r
242 \r
243             if (cs && sdDoInit())\r
244             {\r
245                 blockDev.state |= DISK_PRESENT | DISK_INITIALISED;\r
246 \r
247                 uint8_t wp = HAL_GPIO_ReadPin(nSD_WP_GPIO_Port, nSD_WP_Pin) ? 0 : 1;\r
248                 if (wp)\r
249                 {\r
250                     blockDev.state |= DISK_WP;\r
251                 }\r
252                 else\r
253                 {\r
254                     blockDev.state &= ~DISK_WP;\r
255                 }\r
256 \r
257                 result = 1;\r
258 \r
259                 s2s_ledOff();\r
260             }\r
261             else if (cs)\r
262             {\r
263                 for (int i = 0; i < 10; ++i)\r
264                 {\r
265                     // visual indicator of SD error\r
266                     s2s_ledOff();\r
267                     s2s_delay_ms(50);\r
268                     s2s_ledOn();\r
269                     s2s_delay_ms(50);\r
270                 }\r
271                 s2s_ledOff();\r
272             }\r
273             else\r
274             {\r
275                 s2s_ledOff();\r
276             }\r
277         }\r
278         else if (!cs && (blockDev.state & DISK_PRESENT))\r
279         {\r
280             sdDev.capacity = 0;\r
281             blockDev.state &= ~DISK_PRESENT;\r
282             blockDev.state &= ~DISK_INITIALISED;\r
283             int i;\r
284             for (i = 0; i < S2S_MAX_TARGETS; ++i)\r
285             {\r
286                 scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;\r
287             }\r
288 \r
289             HAL_SD_DeInit(&hsd);\r
290         }\r
291     }\r
292     firstInit = 0;\r
293 \r
294     return result;\r
295 }\r
296 \r
297 // Return 1 if the SD card has no buffer space left for writes and/or is\r
298 // in the programming state.\r
299 int sdIsBusy()\r
300 {\r
301     // Busy while DAT0 is held low.\r
302     return HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_8) == 0;\r
303 }\r
304 \r
305 void sdKeepAlive()\r
306 {\r
307     if (blockDev.state & DISK_PRESENT)\r
308     {\r
309         /*HAL_SD_CardStateTypeDef cardState = */HAL_SD_GetCardState(&hsd);\r
310     }\r
311 }\r