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 "rtdm.scsi"
16 #define DBG_LVL DBG_INFO
17 #include <rtdbg.h>
18 
19 /*
20  * Since SCSI is used for storage (almost),
21  * we do not want to implement SCSI as a system DM bus.
22  */
23 struct scsi_driver
24 {
25     rt_err_t (*probe)(struct rt_scsi_device *sdev);
26     rt_err_t (*remove)(struct rt_scsi_device *sdev);
27 };
28 
29 extern rt_err_t scsi_sd_probe(struct rt_scsi_device *sdev);
30 extern rt_err_t scsi_sd_remove(struct rt_scsi_device *sdev);
31 
32 extern rt_err_t scsi_cdrom_probe(struct rt_scsi_device *sdev);
33 extern rt_err_t scsi_cdrom_remove(struct rt_scsi_device *sdev);
34 
35 static struct scsi_driver driver_table[SCSI_DEVICE_TYPE_MAX] =
36 {
37 #ifdef RT_SCSI_SD
38     [SCSI_DEVICE_TYPE_DIRECT] =
39     {
40         .probe = scsi_sd_probe,
41         .remove = scsi_sd_remove,
42     },
43 #endif /* RT_SCSI_SD */
44 #ifdef RT_SCSI_CDROM
45     [SCSI_DEVICE_TYPE_CDROM] =
46     {
47         .probe = scsi_cdrom_probe,
48         .remove = scsi_cdrom_remove,
49     },
50 #endif /* RT_SCSI_CDROM */
51 };
52 
scsi_device_setup(struct rt_scsi_device * sdev)53 static rt_err_t scsi_device_setup(struct rt_scsi_device *sdev)
54 {
55     rt_err_t err;
56     rt_tick_t timeout;
57 
58     if (sdev->host->ops->reset)
59     {
60         if ((err = sdev->host->ops->reset(sdev)))
61         {
62             return err;
63         }
64     }
65 
66     if (!driver_table[sdev->devtype].probe)
67     {
68         LOG_E("Device type %x is not supported", sdev->devtype);
69 
70         return -RT_ENOSYS;
71     }
72 
73     timeout = rt_tick_from_millisecond(5000);
74     timeout += rt_tick_get();
75 
76     while ((err = rt_scsi_test_unit_ready(sdev)))
77     {
78         if (rt_tick_get() >= timeout)
79         {
80             return -RT_ETIMEOUT;
81         }
82     }
83 
84     return driver_table[sdev->devtype].probe(sdev);
85 }
86 
rt_scsi_host_register(struct rt_scsi_host * scsi)87 rt_err_t rt_scsi_host_register(struct rt_scsi_host *scsi)
88 {
89     struct rt_scsi_device tmp_sdev, *sdev;
90 
91     if (!scsi || !scsi->dev || !scsi->ops)
92     {
93         return -RT_EINVAL;
94     }
95 
96     if (!scsi->max_id || !scsi->max_lun)
97     {
98         return -RT_EINVAL;
99     }
100 
101     rt_list_init(&scsi->lun_nodes);
102 
103     rt_memset(&tmp_sdev, 0, sizeof(tmp_sdev));
104     tmp_sdev.host = scsi;
105 
106     for (rt_size_t id = 0; id < scsi->max_id; ++id)
107     {
108         for (rt_size_t lun = 0; lun < scsi->max_lun; ++lun)
109         {
110             tmp_sdev.id = id;
111             tmp_sdev.lun = lun;
112 
113             if (rt_scsi_inquiry(&tmp_sdev, RT_NULL))
114             {
115                 continue;
116             }
117 
118             if (tmp_sdev.devtype >= SCSI_DEVICE_TYPE_MAX)
119             {
120                 /*
121                  * This might seem odd, but we're only aiming to
122                  * support simple SCSI.
123                  * If devices appear on the bus out of order,
124                  * we won't perform additional scans.
125                  */
126                 scsi->max_id = id;
127                 scsi->max_lun = lun;
128 
129                 LOG_D("Scan is end of ID: %u LUN: %u", id, lun);
130                 break;
131             }
132 
133             if (!(sdev = rt_malloc(sizeof(*sdev))))
134             {
135                 if (!rt_list_isempty(&scsi->lun_nodes))
136                 {
137                     LOG_E("No memory to create device ID: %u, LUN: %u", id, lun);
138 
139                     return RT_EOK;
140                 }
141 
142                 return -RT_ENOMEM;
143             }
144 
145             rt_memcpy(sdev, &tmp_sdev, sizeof(*sdev));
146             rt_list_init(&sdev->list);
147 
148             if (scsi_device_setup(sdev))
149             {
150                 rt_free(sdev);
151                 continue;
152             }
153 
154             rt_list_insert_before(&scsi->lun_nodes, &sdev->list);
155         }
156     }
157 
158     return rt_list_isempty(&scsi->lun_nodes) ? -RT_EEMPTY : RT_EOK;
159 }
160 
rt_scsi_host_unregister(struct rt_scsi_host * scsi)161 rt_err_t rt_scsi_host_unregister(struct rt_scsi_host *scsi)
162 {
163     struct rt_scsi_device *sdev, *next_sdev;
164 
165     if (!scsi)
166     {
167         return -RT_EINVAL;
168     }
169 
170     rt_list_for_each_entry_safe(sdev, next_sdev, &scsi->lun_nodes, list)
171     {
172         rt_list_remove(&sdev->list);
173 
174         if (sdev->host->ops->reset)
175         {
176             sdev->host->ops->reset(sdev);
177         }
178 
179         if (!driver_table[sdev->devtype].remove)
180         {
181             driver_table[sdev->devtype].remove(sdev);
182         }
183 
184         rt_free(sdev);
185     }
186 
187     return RT_EOK;
188 }
189 
scsi_transfer(struct rt_scsi_device * sdev,struct rt_scsi_cmd * cmd)190 rt_inline rt_err_t scsi_transfer(struct rt_scsi_device *sdev, struct rt_scsi_cmd *cmd)
191 {
192     return sdev->host->ops->transfer(sdev, cmd);
193 }
194 
rt_scsi_request_sense(struct rt_scsi_device * sdev,struct rt_scsi_request_sense_data * out_data)195 rt_err_t rt_scsi_request_sense(struct rt_scsi_device *sdev,
196         struct rt_scsi_request_sense_data *out_data)
197 {
198     rt_err_t err;
199     struct rt_scsi_cmd cmd;
200 
201     rt_memset(&cmd, 0, sizeof(cmd));
202     cmd.op.request_sense.opcode = RT_SCSI_CMD_REQUEST_SENSE;
203     cmd.op.request_sense.config = 0;
204     cmd.op.request_sense.alloc_length = 0x12;
205     cmd.op.request_sense.control = 0;
206     cmd.op_size = sizeof(cmd.op.request_sense);
207     cmd.data.ptr = &cmd.data.request_sense;
208     cmd.data.size = sizeof(cmd.data.request_sense);
209 
210     err = scsi_transfer(sdev, &cmd);
211 
212     if (!err && out_data)
213     {
214         rt_memcpy(out_data, &cmd.data.request_sense, sizeof(*out_data));
215     }
216 
217     return err;
218 }
219 
rt_scsi_test_unit_ready(struct rt_scsi_device * sdev)220 rt_err_t rt_scsi_test_unit_ready(struct rt_scsi_device *sdev)
221 {
222     struct rt_scsi_cmd cmd;
223 
224     rt_memset(&cmd, 0, sizeof(cmd));
225     cmd.op.test_unit_ready.opcode = RT_SCSI_CMD_TEST_UNIT_READY;
226     cmd.op.test_unit_ready.control = 0;
227     cmd.op_size = sizeof(cmd.op.test_unit_ready);
228 
229     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
230 }
231 
rt_scsi_inquiry(struct rt_scsi_device * sdev,struct rt_scsi_inquiry_data * out_data)232 rt_err_t rt_scsi_inquiry(struct rt_scsi_device *sdev,
233         struct rt_scsi_inquiry_data *out_data)
234 {
235     rt_err_t err;
236     struct rt_scsi_cmd cmd;
237 
238     rt_memset(&cmd, 0, sizeof(cmd));
239     cmd.op.inquiry.opcode = RT_SCSI_CMD_INQUIRY;
240     cmd.op.inquiry.config = 0;
241     cmd.op.inquiry.page = 0;
242     cmd.op.inquiry.alloc_length = 0x24;
243     cmd.op.inquiry.control = 0;
244     cmd.op_size = sizeof(cmd.op.inquiry);
245     cmd.data.ptr = &cmd.data.inquiry;
246     cmd.data.size = sizeof(cmd.data.inquiry);
247 
248     err = scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
249 
250     if (!err)
251     {
252         sdev->devtype = cmd.data.inquiry.devtype & RT_SCSI_DEVTYPE_MASK;
253         sdev->removable = cmd.data.inquiry.rmb >> RT_SCSI_REMOVABLE_BIT;
254 
255         if (out_data)
256         {
257             rt_memcpy(out_data, &cmd.data.inquiry, sizeof(*out_data));
258         }
259     }
260 
261     return err;
262 }
263 
rt_scsi_read_capacity10(struct rt_scsi_device * sdev,struct rt_scsi_read_capacity10_data * out_data)264 rt_err_t rt_scsi_read_capacity10(struct rt_scsi_device *sdev,
265         struct rt_scsi_read_capacity10_data *out_data)
266 {
267     rt_err_t err;
268     struct rt_scsi_cmd cmd;
269 
270     rt_memset(&cmd, 0, sizeof(cmd));
271     cmd.op.read_capacity10.opcode = RT_SCSI_CMD_READ_CAPACITY10;
272     cmd.op.read_capacity10.config = 0;
273     cmd.op.read_capacity10.logical_block_addr = 0;
274     cmd.op.read_capacity10.pmi = 0;
275     cmd.op.read_capacity10.control = 0;
276     cmd.op_size = sizeof(cmd.op.read_capacity10);
277     cmd.data.ptr = &cmd.data.read_capacity10;
278     cmd.data.size = sizeof(cmd.data.read_capacity10);
279 
280     err = scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
281 
282     if (!err)
283     {
284         sdev->last_block = rt_be32_to_cpu(cmd.data.read_capacity10.last_block);
285         sdev->block_size = rt_be32_to_cpu(cmd.data.read_capacity10.block_size);
286 
287         if (out_data)
288         {
289             rt_memcpy(out_data, &cmd.data.read_capacity10, sizeof(*out_data));
290         }
291     }
292 
293     return err;
294 }
295 
rt_scsi_read_capacity16(struct rt_scsi_device * sdev,struct rt_scsi_read_capacity16_data * out_data)296 rt_err_t rt_scsi_read_capacity16(struct rt_scsi_device *sdev,
297         struct rt_scsi_read_capacity16_data *out_data)
298 {
299     rt_err_t err;
300     struct rt_scsi_cmd cmd;
301 
302     rt_memset(&cmd, 0, sizeof(cmd));
303     cmd.op.read_capacity16.opcode = RT_SCSI_CMD_READ_CAPACITY16;
304     cmd.op.read_capacity16.config = 0x10;
305     cmd.op.read_capacity16.logical_block_addr = 0;
306     cmd.op.read_capacity16.alloc_len = rt_cpu_to_be32(sizeof(cmd.data.read_capacity16));
307     cmd.op.read_capacity16.pmi = 0;
308     cmd.op.read_capacity16.control = 0;
309     cmd.op_size = sizeof(cmd.op.read_capacity16);
310     cmd.data.ptr = &cmd.data.read_capacity16;
311     cmd.data.size = sizeof(cmd.data.read_capacity16);
312 
313     err = scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
314 
315     if (!err)
316     {
317         sdev->last_block = rt_be64_to_cpu(cmd.data.read_capacity16.last_block);
318         sdev->block_size = rt_be32_to_cpu(cmd.data.read_capacity16.block_size);
319 
320         if (out_data)
321         {
322             rt_memcpy(out_data, &cmd.data.read_capacity16, sizeof(*out_data));
323         }
324     }
325 
326     return err;
327 }
328 
rt_scsi_read10(struct rt_scsi_device * sdev,rt_off_t lba,void * buffer,rt_size_t size)329 rt_err_t rt_scsi_read10(struct rt_scsi_device *sdev,
330         rt_off_t lba, void *buffer, rt_size_t size)
331 {
332     struct rt_scsi_cmd cmd;
333 
334     rt_memset(&cmd, 0, sizeof(cmd));
335     cmd.op.read10.opcode = RT_SCSI_CMD_READ10;
336     cmd.op.read10.config = 0;
337     cmd.op.read10.lba = rt_cpu_to_be32(lba);
338     cmd.op.read10.size = rt_cpu_to_be16(size);
339     cmd.op_size = sizeof(cmd.op.read10);
340     cmd.data.ptr = buffer;
341     cmd.data.size = size * sdev->block_size;
342 
343     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
344 }
345 
rt_scsi_read12(struct rt_scsi_device * sdev,rt_off_t lba,void * buffer,rt_size_t size)346 rt_err_t rt_scsi_read12(struct rt_scsi_device *sdev,
347         rt_off_t lba, void *buffer, rt_size_t size)
348 {
349     struct rt_scsi_cmd cmd;
350 
351     rt_memset(&cmd, 0, sizeof(cmd));
352     cmd.op.read12.opcode = RT_SCSI_CMD_READ12;
353     cmd.op.read12.config = 0;
354     cmd.op.read12.lba = rt_cpu_to_be32(lba);
355     cmd.op.read12.size = rt_cpu_to_be32(size);
356     cmd.op.read12.control = 0;
357     cmd.op_size = sizeof(cmd.op.read12);
358     cmd.data.ptr = buffer;
359     cmd.data.size = size * sdev->block_size;
360 
361     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
362 }
363 
rt_scsi_read16(struct rt_scsi_device * sdev,rt_off_t lba,void * buffer,rt_size_t size)364 rt_err_t rt_scsi_read16(struct rt_scsi_device *sdev,
365         rt_off_t lba, void *buffer, rt_size_t size)
366 {
367     struct rt_scsi_cmd cmd;
368 
369     rt_memset(&cmd, 0, sizeof(cmd));
370     cmd.op.read16.opcode = RT_SCSI_CMD_READ16;
371     cmd.op.read16.config = 0;
372     cmd.op.read16.lba = rt_cpu_to_be64(lba);
373     cmd.op.read16.size = rt_cpu_to_be32(size);
374     cmd.op.read16.control = 0;
375     cmd.op_size = sizeof(cmd.op.read16);
376     cmd.data.ptr = buffer;
377     cmd.data.size = size * sdev->block_size;
378 
379     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
380 }
381 
rt_scsi_write10(struct rt_scsi_device * sdev,rt_off_t lba,const void * buffer,rt_size_t size)382 rt_err_t rt_scsi_write10(struct rt_scsi_device *sdev,
383         rt_off_t lba, const void *buffer, rt_size_t size)
384 {
385     struct rt_scsi_cmd cmd;
386 
387     rt_memset(&cmd, 0, sizeof(cmd));
388     cmd.op.write10.opcode = RT_SCSI_CMD_WRITE10;
389     cmd.op.write10.config = 0;
390     cmd.op.write10.lba = rt_cpu_to_be32(lba);
391     cmd.op.write10.size = rt_cpu_to_be16(size);
392     cmd.op_size = sizeof(cmd.op.write10);
393     cmd.data.ptr = (void *)buffer;
394     cmd.data.size = size * sdev->block_size;
395 
396     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
397 }
398 
rt_scsi_write12(struct rt_scsi_device * sdev,rt_off_t lba,const void * buffer,rt_size_t size)399 rt_err_t rt_scsi_write12(struct rt_scsi_device *sdev,
400         rt_off_t lba, const void *buffer, rt_size_t size)
401 {
402     struct rt_scsi_cmd cmd;
403 
404     rt_memset(&cmd, 0, sizeof(cmd));
405     cmd.op.write12.opcode = RT_SCSI_CMD_WRITE12;
406     cmd.op.write12.config = 0;
407     cmd.op.write12.lba = rt_cpu_to_be32(lba);
408     cmd.op.write12.size = rt_cpu_to_be32(size);
409     cmd.op.write12.control = 0;
410     cmd.op_size = sizeof(cmd.op.write12);
411     cmd.data.ptr = (void *)buffer;
412     cmd.data.size = size * sdev->block_size;
413 
414     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
415 }
416 
rt_scsi_write16(struct rt_scsi_device * sdev,rt_off_t lba,const void * buffer,rt_size_t size)417 rt_err_t rt_scsi_write16(struct rt_scsi_device *sdev,
418         rt_off_t lba, const void *buffer, rt_size_t size)
419 {
420     struct rt_scsi_cmd cmd;
421 
422     rt_memset(&cmd, 0, sizeof(cmd));
423     cmd.op.write16.opcode = RT_SCSI_CMD_WRITE16;
424     cmd.op.write16.config = 0;
425     cmd.op.write16.lba = rt_cpu_to_be64(lba);
426     cmd.op.write16.size = rt_cpu_to_be32(size);
427     cmd.op.write16.control = 0;
428     cmd.op_size = sizeof(cmd.op.write16);
429     cmd.data.ptr = (void *)buffer;
430     cmd.data.size = size * sdev->block_size;
431 
432     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
433 }
434 
rt_scsi_synchronize_cache10(struct rt_scsi_device * sdev,rt_off_t lba,rt_size_t size)435 rt_err_t rt_scsi_synchronize_cache10(struct rt_scsi_device *sdev,
436         rt_off_t lba, rt_size_t size)
437 {
438     struct rt_scsi_cmd cmd;
439 
440     rt_memset(&cmd, 0, sizeof(cmd));
441     cmd.op.synchronize_cache10.opcode = RT_SCSI_CMD_SYNCHRONIZE_CACHE10;
442     cmd.op.synchronize_cache10.config = 0;
443     cmd.op.synchronize_cache10.lba = rt_cpu_to_be32(lba);
444     cmd.op.synchronize_cache10.size = rt_cpu_to_be16(size);
445     cmd.op.synchronize_cache10.control = 0;
446     cmd.op_size = sizeof(cmd.op.synchronize_cache10);
447 
448     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
449 }
450 
rt_scsi_synchronize_cache16(struct rt_scsi_device * sdev,rt_off_t lba,rt_size_t size)451 rt_err_t rt_scsi_synchronize_cache16(struct rt_scsi_device *sdev,
452         rt_off_t lba, rt_size_t size)
453 {
454     struct rt_scsi_cmd cmd;
455 
456     rt_memset(&cmd, 0, sizeof(cmd));
457     cmd.op.synchronize_cache16.opcode = RT_SCSI_CMD_SYNCHRONIZE_CACHE16;
458     cmd.op.synchronize_cache16.config = 0;
459     cmd.op.synchronize_cache16.lba = rt_cpu_to_be64(lba);
460     cmd.op.synchronize_cache16.size = rt_cpu_to_be32(size);
461     cmd.op.synchronize_cache16.control = 0;
462     cmd.op_size = sizeof(cmd.op.synchronize_cache16);
463 
464     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
465 }
466 
rt_scsi_write_same10(struct rt_scsi_device * sdev,rt_off_t lba,rt_size_t size)467 rt_err_t rt_scsi_write_same10(struct rt_scsi_device *sdev,
468         rt_off_t lba, rt_size_t size)
469 {
470     struct rt_scsi_cmd cmd;
471 
472     rt_memset(&cmd, 0, sizeof(cmd));
473     cmd.op.write_same10.opcode = RT_SCSI_CMD_WRITE_SAME10;
474     cmd.op.write_same10.config = RT_BIT(RT_SCSI_UNMAP_SHIFT);
475     cmd.op.write_same10.lba = rt_cpu_to_be32(lba);
476     cmd.op.write_same10.size = rt_cpu_to_be16(size);
477     cmd.op.write_same10.control = 0;
478     cmd.op_size = sizeof(cmd.op.write_same10);
479 
480     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
481 }
482 
rt_scsi_write_same16(struct rt_scsi_device * sdev,rt_off_t lba,rt_size_t size)483 rt_err_t rt_scsi_write_same16(struct rt_scsi_device *sdev,
484         rt_off_t lba, rt_size_t size)
485 {
486     struct rt_scsi_cmd cmd;
487 
488     rt_memset(&cmd, 0, sizeof(cmd));
489     cmd.op.write_same16.opcode = RT_SCSI_CMD_WRITE_SAME16;
490     cmd.op.write_same16.config = RT_BIT(RT_SCSI_UNMAP_SHIFT);
491     cmd.op.write_same16.lba = rt_cpu_to_be64(lba);
492     cmd.op.write_same16.size = rt_cpu_to_be32(size);
493     cmd.op.write_same16.control = 0;
494     cmd.op_size = sizeof(cmd.op.write_same16);
495 
496     return scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
497 }
498 
rt_scsi_mode_select6(struct rt_scsi_device * sdev,rt_uint8_t pf,rt_uint8_t sp,void * buffer,rt_size_t size,struct rt_scsi_mode_select_data * data)499 rt_err_t rt_scsi_mode_select6(struct rt_scsi_device *sdev,
500         rt_uint8_t pf, rt_uint8_t sp, void *buffer, rt_size_t size,
501         struct rt_scsi_mode_select_data *data)
502 {
503     rt_err_t err;
504     rt_uint8_t *real_buffer;
505     struct rt_scsi_cmd cmd;
506 
507     real_buffer = rt_malloc(4 + size);
508 
509     if (!real_buffer)
510     {
511         return -RT_ENOMEM;
512     }
513 
514     rt_memcpy(real_buffer + 4, buffer, size);
515     size += 4;
516     real_buffer[0] = 0;
517     real_buffer[1] = data->medium_type;
518     real_buffer[2] = data->device_specific;
519     real_buffer[3] = data->block_descriptor_length;
520 
521     rt_memset(&cmd, 0, sizeof(cmd));
522     cmd.op.mode_select6.opcode = RT_SCSI_CMD_MODE_SELECT;
523     cmd.op.mode_select6.config = pf ? RT_BIT(RT_SCSI_PF_SHIFT) : 0;
524     cmd.op.mode_select6.config |= sp ? RT_BIT(RT_SCSI_SP_SHIFT) : 0;
525     cmd.op.mode_select6.param_list_len = (rt_uint8_t)size;
526     cmd.op.mode_select6.control = 0;
527     cmd.op_size = sizeof(cmd.op.mode_select6);
528     cmd.data.ptr = real_buffer;
529     cmd.data.size = size;
530 
531     err = scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
532 
533     rt_free(real_buffer);
534 
535     return err;
536 }
537 
rt_scsi_mode_select10(struct rt_scsi_device * sdev,rt_uint8_t pf,rt_uint8_t sp,void * buffer,rt_size_t size,struct rt_scsi_mode_select_data * data)538 rt_err_t rt_scsi_mode_select10(struct rt_scsi_device *sdev,
539         rt_uint8_t pf, rt_uint8_t sp, void *buffer, rt_size_t size,
540         struct rt_scsi_mode_select_data *data)
541 {
542     rt_err_t err;
543     rt_uint8_t *real_buffer;
544     struct rt_scsi_cmd cmd;
545 
546     real_buffer = rt_malloc(8 + size);
547 
548     if (!real_buffer)
549     {
550         return -RT_ENOMEM;
551     }
552 
553     rt_memcpy(real_buffer + 8, buffer, size);
554     size += 8;
555     real_buffer[0] = 0;
556     real_buffer[1] = 0;
557     real_buffer[2] = data->medium_type;
558     real_buffer[3] = data->device_specific;
559     real_buffer[4] = data->longlba ? 0x01 : 0;
560     real_buffer[5] = 0;
561     real_buffer[6] = rt_cpu_to_be16(data->block_descriptor_length);
562 
563     rt_memset(&cmd, 0, sizeof(cmd));
564     cmd.op.mode_select10.opcode = RT_SCSI_CMD_MODE_SELECT10;
565     cmd.op.mode_select10.config = pf ? RT_BIT(RT_SCSI_PF_SHIFT) : 0;
566     cmd.op.mode_select10.config |= sp ? RT_BIT(RT_SCSI_SP_SHIFT) : 0;
567     cmd.op.mode_select10.param_list_len = rt_cpu_to_be16(size);
568     cmd.op.mode_select10.control = 0;
569     cmd.op_size = sizeof(cmd.op.mode_select10);
570     cmd.data.ptr = real_buffer;
571     cmd.data.size = size;
572 
573     err = scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
574 
575     rt_free(real_buffer);
576 
577     return err;
578 }
579 
scsi_mode_sense_fill(struct rt_scsi_mode_select_data * data,rt_uint8_t modepage,rt_uint8_t * buffer,rt_bool_t use10)580 static void scsi_mode_sense_fill(struct rt_scsi_mode_select_data *data,
581         rt_uint8_t modepage, rt_uint8_t *buffer, rt_bool_t use10)
582 {
583     if (buffer[0] == 0x86 && buffer[1] == 0x0b && (modepage == 6 || modepage == 8))
584     {
585         data->header_length = 0;
586         data->length = 13;
587         data->medium_type = 0;
588         data->device_specific = 0;
589         data->longlba = 0;
590         data->block_descriptor_length = 0;
591     }
592     else if (use10)
593     {
594         data->length = rt_be16_to_cpu(buffer[0]) + 2;
595         data->medium_type = buffer[2];
596         data->device_specific = buffer[3];
597         data->longlba = buffer[4] & 0x01;
598         data->block_descriptor_length = rt_be16_to_cpu(buffer[6]);
599     }
600     else
601     {
602         data->length = buffer[0] + 1;
603         data->medium_type = buffer[1];
604         data->device_specific = buffer[2];
605         data->block_descriptor_length = buffer[3];
606     }
607 }
608 
rt_scsi_mode_sense6(struct rt_scsi_device * sdev,rt_uint8_t dbd,rt_uint8_t modepage,rt_uint8_t subpage,void * buffer,rt_size_t size,struct rt_scsi_mode_select_data * data)609 rt_err_t rt_scsi_mode_sense6(struct rt_scsi_device *sdev,
610         rt_uint8_t dbd, rt_uint8_t modepage, rt_uint8_t subpage, void *buffer, rt_size_t size,
611         struct rt_scsi_mode_select_data *data)
612 {
613     rt_err_t err;
614     struct rt_scsi_cmd cmd;
615 
616     rt_memset(buffer, 0, size);
617 
618     rt_memset(&cmd, 0, sizeof(cmd));
619     cmd.op.mode_sense6.opcode = RT_SCSI_CMD_MODE_SENSE;
620     cmd.op.mode_sense6.config = dbd & 0x18;
621     cmd.op.mode_sense6.page_control_code = modepage;
622     cmd.op.mode_sense6.subpage_code = subpage;
623     cmd.op.mode_sense6.allocation_len = (rt_uint8_t)size;
624     cmd.op.mode_sense6.control = 0;
625     cmd.op_size = sizeof(cmd.op.mode_sense6);
626     cmd.data.ptr = buffer;
627     cmd.data.size = size;
628 
629     err = scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
630 
631     if (!err)
632     {
633         data->header_length = 4;
634         scsi_mode_sense_fill(data, modepage, buffer, RT_FALSE);
635     }
636 
637     return err;
638 }
639 
rt_scsi_mode_sense10(struct rt_scsi_device * sdev,rt_uint8_t dbd,rt_uint8_t modepage,rt_uint8_t subpage,void * buffer,rt_size_t size,struct rt_scsi_mode_select_data * data)640 rt_err_t rt_scsi_mode_sense10(struct rt_scsi_device *sdev,
641         rt_uint8_t dbd, rt_uint8_t modepage, rt_uint8_t subpage, void *buffer, rt_size_t size,
642         struct rt_scsi_mode_select_data *data)
643 {
644     rt_err_t err;
645     struct rt_scsi_cmd cmd;
646 
647     rt_memset(buffer, 0, size);
648 
649     rt_memset(&cmd, 0, sizeof(cmd));
650     cmd.op.mode_sense6.opcode = RT_SCSI_CMD_MODE_SENSE10;
651     cmd.op.mode_sense6.config = dbd & 0x18;
652     cmd.op.mode_sense6.page_control_code = modepage;
653     cmd.op.mode_sense6.subpage_code = subpage;
654     cmd.op.mode_sense6.allocation_len = rt_cpu_to_be16(size);
655     cmd.op.mode_sense6.control = 0;
656     cmd.op_size = sizeof(cmd.op.mode_sense6);
657     cmd.data.ptr = buffer;
658     cmd.data.size = size;
659 
660     err = scsi_transfer(sdev, &cmd) ? : rt_scsi_request_sense(sdev, RT_NULL);
661 
662     if (!err)
663     {
664         data->header_length = 8;
665         scsi_mode_sense_fill(data, modepage, buffer, RT_FALSE);
666     }
667 
668     return err;
669 }
670