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