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