1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-02-25 GuEe-GUI the first version
9 */
10
11 #include <rthw.h>
12 #include <rtthread.h>
13 #include <rtdevice.h>
14
15 #define DBG_TAG "scsi.blk"
16 #define DBG_LVL DBG_INFO
17 #include <rtdbg.h>
18
19 #include "../block/blk_dev.h"
20
21 struct scsi_sd
22 {
23 struct rt_blk_disk parent;
24 struct rt_scsi_device *sdev;
25
26 int sd_id;
27 rt_bool_t use16;
28 struct rt_device_blk_geometry geometry;
29 };
30
31 #define raw_to_scsi_sd(raw) rt_container_of(raw, struct scsi_sd, parent)
32
33 static struct rt_dm_ida sd_ida = RT_DM_IDA_INIT(CUSTOM);
34 static struct rt_dm_ida scsi_sd_ida = RT_DM_IDA_INIT(SCSI_SD);
35
scsi_sd_read(struct rt_blk_disk * disk,rt_off_t sector,void * buffer,rt_size_t sector_count)36 static rt_ssize_t scsi_sd_read(struct rt_blk_disk *disk, rt_off_t sector,
37 void *buffer, rt_size_t sector_count)
38 {
39 rt_err_t err;
40 struct scsi_sd *ssd = raw_to_scsi_sd(disk);
41 struct rt_scsi_device *sdev = ssd->sdev;
42
43 sector_count &= RT_UINT32_MAX;
44
45 if (sector >> 32)
46 {
47 err = rt_scsi_read16(sdev, sector, buffer, sector_count);
48 }
49 else
50 {
51 err = rt_scsi_read10(sdev, sector, buffer, sector_count);
52 }
53
54 return !err ? sector_count : (rt_ssize_t)err;
55 }
56
scsi_sd_write(struct rt_blk_disk * disk,rt_off_t sector,const void * buffer,rt_size_t sector_count)57 static rt_ssize_t scsi_sd_write(struct rt_blk_disk *disk, rt_off_t sector,
58 const void *buffer, rt_size_t sector_count)
59 {
60 rt_err_t err;
61 struct scsi_sd *ssd = raw_to_scsi_sd(disk);
62 struct rt_scsi_device *sdev = ssd->sdev;
63
64 sector_count &= RT_UINT32_MAX;
65
66 if (sector >> 32)
67 {
68 err = rt_scsi_write16(sdev, sector, buffer, sector_count);
69 }
70 else
71 {
72 err = rt_scsi_write10(sdev, sector, buffer, sector_count);
73 }
74
75 return !err ? sector_count : (rt_ssize_t)err;
76 }
77
scsi_sd_getgeome(struct rt_blk_disk * disk,struct rt_device_blk_geometry * geometry)78 static rt_err_t scsi_sd_getgeome(struct rt_blk_disk *disk,
79 struct rt_device_blk_geometry *geometry)
80 {
81 struct scsi_sd *ssd = raw_to_scsi_sd(disk);
82
83 rt_memcpy(geometry, &ssd->geometry, sizeof(ssd->geometry));
84
85 return RT_EOK;
86 }
87
scsi_sd_sync(struct rt_blk_disk * disk)88 static rt_err_t scsi_sd_sync(struct rt_blk_disk *disk)
89 {
90 rt_err_t err;
91 rt_size_t lba_count;
92 struct scsi_sd *ssd = raw_to_scsi_sd(disk);
93 struct rt_scsi_device *sdev = ssd->sdev;
94
95 lba_count = ssd->geometry.sector_count;
96
97 if (ssd->use16)
98 {
99 err = rt_scsi_synchronize_cache16(sdev, 0, lba_count);
100 }
101 else
102 {
103 err = rt_scsi_synchronize_cache10(sdev, 0, lba_count);
104 }
105
106 return err;
107 }
108
scsi_sd_erase(struct rt_blk_disk * disk)109 static rt_err_t scsi_sd_erase(struct rt_blk_disk *disk)
110 {
111 rt_err_t err;
112 rt_size_t lba_count;
113 struct scsi_sd *ssd = raw_to_scsi_sd(disk);
114 struct rt_scsi_device *sdev = ssd->sdev;
115
116 lba_count = ssd->geometry.sector_count;
117
118 if (ssd->use16)
119 {
120 err = rt_scsi_write_same16(sdev, 0, lba_count);
121 }
122 else
123 {
124 err = rt_scsi_write_same10(sdev, 0, lba_count);
125 }
126
127 return err;
128 }
129
scsi_sd_autorefresh(struct rt_blk_disk * disk,rt_bool_t is_auto)130 static rt_err_t scsi_sd_autorefresh(struct rt_blk_disk *disk, rt_bool_t is_auto)
131 {
132 rt_err_t err;
133 int sp;
134 rt_size_t size;
135 rt_uint8_t buffer[64];
136 rt_uint8_t *buffer_data;
137 rt_bool_t use6 = RT_TRUE;
138 struct scsi_sd *ssd = raw_to_scsi_sd(disk);
139 struct rt_scsi_device *sdev = ssd->sdev;
140 struct rt_scsi_mode_select_data data;
141
142 err = rt_scsi_mode_sense6(sdev, 0x08, 8, 0, buffer, sizeof(buffer), &data);
143
144 if (err && err != -RT_ENOMEM)
145 {
146 use6 = RT_FALSE;
147 err = rt_scsi_mode_sense10(sdev, 0x08, 8, 0, buffer, sizeof(buffer), &data);
148 }
149 if (err)
150 {
151 return err;
152 }
153
154 size = rt_min_t(rt_size_t, sizeof(buffer),
155 data.length - data.header_length - data.block_descriptor_length);
156 buffer_data = buffer + data.header_length + data.block_descriptor_length;
157 buffer_data[2] &= ~0x05;
158 buffer_data[2] |= (!!is_auto) << 2 | (!!is_auto);
159 sp = buffer_data[0] & 0x80 ? 1 : 0;
160 buffer_data[0] &= ~0x80;
161 data.device_specific = 0;
162
163 if (use6)
164 {
165 err = rt_scsi_mode_select6(sdev, 1, sp, buffer_data, size, &data);
166 }
167 else
168 {
169 err = rt_scsi_mode_select10(sdev, 1, sp, buffer_data, size, &data);
170 }
171
172 return err;
173 }
174
175 static const struct rt_blk_disk_ops scsi_sd_ops =
176 {
177 .read = scsi_sd_read,
178 .write = scsi_sd_write,
179 .getgeome = scsi_sd_getgeome,
180 .sync = scsi_sd_sync,
181 .erase = scsi_sd_erase,
182 .autorefresh = scsi_sd_autorefresh,
183 };
184
scsi_sd_probe(struct rt_scsi_device * sdev)185 rt_err_t scsi_sd_probe(struct rt_scsi_device *sdev)
186 {
187 rt_err_t err;
188 union
189 {
190 struct rt_scsi_read_capacity10_data capacity10;
191 struct rt_scsi_read_capacity16_data capacity16;
192 } data;
193 struct scsi_sd *ssd = rt_calloc(1, sizeof(*ssd));
194
195 if (!ssd)
196 {
197 return -RT_ENOMEM;
198 }
199
200 if ((ssd->sd_id = rt_dm_ida_alloc(&sd_ida)) < 0)
201 {
202 return -RT_EFULL;
203 }
204
205 sdev->priv = ssd;
206 ssd->sdev = sdev;
207 ssd->parent.ida = &scsi_sd_ida;
208 ssd->parent.parallel_io = RT_FALSE;
209 ssd->parent.ops = &scsi_sd_ops;
210 ssd->parent.max_partitions = RT_BLK_PARTITION_MAX;
211
212 if ((err = rt_scsi_read_capacity10(sdev, &data.capacity10)))
213 {
214 goto _fail;
215 }
216 if (data.capacity10.last_block == 0xffffffff)
217 {
218 if ((err = rt_scsi_read_capacity16(sdev, &data.capacity16)))
219 {
220 goto _fail;
221 }
222 ssd->use16 = RT_TRUE;
223 }
224 ssd->geometry.bytes_per_sector = sdev->block_size;
225 ssd->geometry.block_size = sdev->block_size;
226 ssd->geometry.sector_count = sdev->last_block + 1;
227
228 rt_dm_dev_set_name(&ssd->parent.parent, "sd%c%c", letter_name(ssd->sd_id));
229
230 if ((err = rt_hw_blk_disk_register(&ssd->parent)))
231 {
232 goto _fail;
233 }
234
235 return RT_EOK;
236
237 _fail:
238 rt_dm_ida_free(&sd_ida, ssd->sd_id);
239 rt_free(ssd);
240
241 return err;
242 }
243
scsi_sd_remove(struct rt_scsi_device * sdev)244 rt_err_t scsi_sd_remove(struct rt_scsi_device *sdev)
245 {
246 struct scsi_sd *ssd = sdev->priv;
247
248 rt_dm_ida_free(&sd_ida, ssd->sd_id);
249
250 return rt_hw_blk_disk_unregister(&ssd->parent);
251 }
252