SD hotswap, SD fixes, SCSI interface fixes, performance improvements.
[SCSI2SD-V6.git] / src / firmware / usb_device / usbd_msc_storage_sd.c
1 //      Copyright (C) 2016 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
19 #include "usbd_msc_storage_sd.h"
20 #include "stm32f2xx.h"
21 #include "bsp_driver_sd.h"
22 #include "../bsp.h"
23 #include "../disk.h"
24 #include "../led.h"
25 #include "../sd.h"
26 #include "../config.h"
27 #include "../geometry.h"
28 #include "../inquiry.h"
29 #include "usb_device.h"
30
31
32
33 static int8_t s2s_usbd_storage_Init(uint8_t lun);
34
35 static int8_t s2s_usbd_storage_GetCapacity(
36         uint8_t lun,
37         uint32_t *block_num,
38         uint16_t *block_size);
39
40 static int8_t s2s_usbd_storage_IsReady(uint8_t lun);
41
42 static int8_t s2s_usbd_storage_IsWriteProtected(uint8_t lun);
43
44 int8_t s2s_usbd_storage_Read(
45         uint8_t lun,
46         uint8_t *buf,
47         uint32_t blk_addr,
48         uint16_t blk_len);
49
50 int8_t s2s_usbd_storage_Write(
51         uint8_t lun,
52         uint8_t *buf,
53         uint32_t blk_addr,
54         uint16_t blk_len);
55
56 int8_t s2s_usbd_storage_GetMaxLun (void);
57 uint32_t s2s_usbd_storage_Inquiry (uint8_t lun, uint8_t* buf, uint8_t maxlen);
58
59
60 USBD_StorageTypeDef USBD_MSC_SD_fops =
61 {
62         s2s_usbd_storage_Init,
63         s2s_usbd_storage_GetCapacity,
64         s2s_usbd_storage_IsReady,
65         s2s_usbd_storage_IsWriteProtected,
66         s2s_usbd_storage_Read,
67         s2s_usbd_storage_Write,
68         s2s_usbd_storage_GetMaxLun,
69         s2s_usbd_storage_Inquiry
70 };
71
72 static const S2S_TargetCfg* getUsbConfig(uint8_t lun) {
73         int count = 0;
74         for (int i = 0; i < S2S_MAX_TARGETS; ++i)
75         {
76                 const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
77                 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
78                 {
79                         if (count == lun)
80                         {
81                                 return cfg;
82                         }
83                         else
84                         {
85                                 count++;
86                         }
87                 }
88         }
89         return s2s_getConfigByIndex(0); // Fallback, try not to crash
90 }
91
92 int8_t s2s_usbd_storage_Init(uint8_t lun)
93 {
94         return (0);
95 }
96
97 int8_t s2s_usbd_storage_GetCapacity (uint8_t lun, uint32_t *block_num, uint16_t *block_size)
98 {
99         const S2S_TargetCfg* cfg = getUsbConfig(lun);
100
101         uint32_t capacity = getScsiCapacity(
102                 cfg->sdSectorStart,
103                 cfg->bytesPerSector,
104                 cfg->scsiSectors);
105
106         *block_num  = capacity;
107         *block_size = cfg->bytesPerSector;
108         return (0);
109 }
110
111 uint32_t s2s_usbd_storage_Inquiry (uint8_t lun, uint8_t* buf, uint8_t maxlen)
112 {
113         const S2S_TargetCfg* cfg = getUsbConfig(lun);
114
115         return s2s_getStandardInquiry(cfg, buf, maxlen);
116 }
117
118 int8_t s2s_usbd_storage_IsReady (uint8_t lun)
119 {
120         const S2S_TargetCfg* cfg = getUsbConfig(lun);
121         return (
122                         cfg &&
123                         (blockDev.state & DISK_PRESENT) &&
124                         (blockDev.state & DISK_INITIALISED)
125                         ) ? 0 : 1; // inverse logic
126 }
127
128
129 int8_t s2s_usbd_storage_IsWriteProtected (uint8_t lun)
130 {
131         return blockDev.state & DISK_WP;
132 }
133
134 int8_t s2s_usbd_storage_Read (uint8_t lun,
135                 uint8_t *buf,
136                 uint32_t blk_addr,
137                 uint16_t blk_len)
138 {
139         s2s_ledOn();
140         const S2S_TargetCfg* cfg = getUsbConfig(lun);
141
142         if (cfg->bytesPerSector == 512)
143         {
144                 BSP_SD_ReadBlocks_DMA(
145                         (uint32_t*) buf,
146                         (cfg->sdSectorStart + blk_addr) * 512ll,
147                         512,
148                         blk_len);
149         }
150         else
151         {
152                 int sdPerScsi = SDSectorsPerSCSISector(cfg->bytesPerSector);
153                 int sdSectorNum =  cfg->sdSectorStart + (blk_addr * sdPerScsi);
154
155                 for (int blk = 0; blk < blk_len; ++blk)
156                 {
157                         for (int i = 0; i < SDSectorsPerSCSISector(cfg->bytesPerSector); ++i)
158                         {
159                                 uint8_t partial[512] S2S_DMA_ALIGN;
160                                 BSP_SD_ReadBlocks_DMA(
161                                         (uint32_t*) partial,
162                                         sdSectorNum * 512LL,
163                                         512,
164                                         1);
165                                 sdSectorNum++;
166
167                                 int validBytes = cfg->bytesPerSector % SD_SECTOR_SIZE;
168                                 if (validBytes == 0) validBytes = SD_SECTOR_SIZE;
169
170                                 memcpy(buf, partial, validBytes);
171
172                                 buf += validBytes;
173                         }
174
175                 }
176
177         }
178         s2s_ledOff();
179         return 0;
180 }
181
182 int8_t s2s_usbd_storage_Write (uint8_t lun,
183                 uint8_t *buf,
184                 uint32_t blk_addr,
185                 uint16_t blk_len)
186 {
187         s2s_ledOn();
188         const S2S_TargetCfg* cfg = getUsbConfig(lun);
189
190         if (cfg->bytesPerSector == 512)
191         {
192                 BSP_SD_WriteBlocks_DMA(
193                         (uint32_t*) buf,
194                         (cfg->sdSectorStart + blk_addr) * 512ll,
195                         512,
196                         blk_len);
197         }
198         else
199         {
200                 int sdPerScsi = SDSectorsPerSCSISector(cfg->bytesPerSector);
201                 int sdSectorNum =  cfg->sdSectorStart + (blk_addr * sdPerScsi);
202
203                 for (int blk = 0; blk < blk_len; ++blk)
204                 {
205                         for (int i = 0; i < SDSectorsPerSCSISector(cfg->bytesPerSector); ++i)
206                         {
207                                 uint8_t partial[512] S2S_DMA_ALIGN;
208                                 BSP_SD_WriteBlocks_DMA(
209                                         (uint32_t*) partial,
210                                         sdSectorNum * 512LL,
211                                         512,
212                                         1);
213                                 sdSectorNum++;
214
215                                 int validBytes = cfg->bytesPerSector % SD_SECTOR_SIZE;
216                                 if (validBytes == 0) validBytes = SD_SECTOR_SIZE;
217
218                                 memcpy(buf, partial, validBytes);
219
220                                 buf += validBytes;
221                         }
222
223                 }
224
225         }
226
227         s2s_ledOff();
228         return 0;
229 }
230
231 int8_t s2s_usbd_storage_GetMaxLun (void)
232 {
233         int count = 0;
234         for (int i = 0; i < S2S_MAX_TARGETS; ++i)
235         {
236                 const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
237                 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
238                 {
239                         count++;
240                 }
241         }
242         return count - 1 < 0 ? 0 : count - 1;
243 }
244
245 void s2s_initUsbDeviceStorage(void)
246 {
247         USBD_MSC_RegisterStorage(&hUsbDeviceFS, &USBD_MSC_SD_fops);
248 }
249