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 struct scsi_cdrom
20 {
21     struct rt_blk_disk parent;
22     struct rt_scsi_device *sdev;
23 
24     int cdrom_id;
25     struct rt_device_blk_geometry geometry;
26 };
27 
28 #define raw_to_scsi_cdrom(raw) rt_container_of(raw, struct scsi_cdrom, parent)
29 
30 static struct rt_dm_ida cdrom_ida = RT_DM_IDA_INIT(CUSTOM);
31 static struct rt_dm_ida scsi_cdrom_ida = RT_DM_IDA_INIT(SCSI_CDROM);
32 
scsi_cdrom_read(struct rt_blk_disk * disk,rt_off_t sector,void * buffer,rt_size_t sector_count)33 static rt_ssize_t scsi_cdrom_read(struct rt_blk_disk *disk, rt_off_t sector,
34         void *buffer, rt_size_t sector_count)
35 {
36     rt_err_t err;
37     struct scsi_cdrom *scdrom = raw_to_scsi_cdrom(disk);
38     struct rt_scsi_device *sdev = scdrom->sdev;
39 
40     sector_count &= RT_UINT32_MAX;
41 
42     if (sector >> 32)
43     {
44         err = rt_scsi_read16(sdev, sector, buffer, sector_count);
45     }
46     else
47     {
48         err = rt_scsi_read12(sdev, sector, buffer, sector_count);
49     }
50 
51     return !err ? sector_count : (rt_ssize_t)err;
52 }
53 
scsi_cdrom_getgeome(struct rt_blk_disk * disk,struct rt_device_blk_geometry * geometry)54 static rt_err_t scsi_cdrom_getgeome(struct rt_blk_disk *disk,
55         struct rt_device_blk_geometry *geometry)
56 {
57     struct scsi_cdrom *scdrom = raw_to_scsi_cdrom(disk);
58 
59     rt_memcpy(geometry, &scdrom->geometry, sizeof(scdrom->geometry));
60 
61     return RT_EOK;
62 }
63 
64 static const struct rt_blk_disk_ops scsi_cdrom_ops =
65 {
66     .read = scsi_cdrom_read,
67     .getgeome = scsi_cdrom_getgeome,
68 };
69 
scsi_cdrom_probe(struct rt_scsi_device * sdev)70 rt_err_t scsi_cdrom_probe(struct rt_scsi_device *sdev)
71 {
72     rt_err_t err;
73     union
74     {
75         struct rt_scsi_read_capacity10_data capacity10;
76         struct rt_scsi_read_capacity16_data capacity16;
77     } data;
78     struct scsi_cdrom *scdrom = rt_calloc(1, sizeof(*scdrom));
79 
80     if (!scdrom)
81     {
82         return -RT_ENOMEM;
83     }
84 
85     if ((scdrom->cdrom_id = rt_dm_ida_alloc(&cdrom_ida)) < 0)
86     {
87         return -RT_EFULL;
88     }
89 
90     sdev->priv = scdrom;
91     scdrom->sdev = sdev;
92     scdrom->parent.ida = &scsi_cdrom_ida;
93     scdrom->parent.read_only = RT_TRUE;
94     scdrom->parent.parallel_io = RT_FALSE;
95     scdrom->parent.ops = &scsi_cdrom_ops;
96     scdrom->parent.max_partitions = RT_BLK_PARTITION_NONE;
97 
98     if ((err = rt_scsi_read_capacity10(sdev, &data.capacity10)))
99     {
100         goto _fail;
101     }
102     if (data.capacity10.last_block == 0xffffffff)
103     {
104         if ((err = rt_scsi_read_capacity16(sdev, &data.capacity16)))
105         {
106             goto _fail;
107         }
108     }
109     scdrom->geometry.bytes_per_sector = sdev->block_size;
110     scdrom->geometry.block_size = sdev->block_size;
111     scdrom->geometry.sector_count = sdev->last_block + 1;
112 
113     rt_dm_dev_set_name(&scdrom->parent.parent, "cdrom%u", scdrom->cdrom_id);
114 
115     if ((err = rt_hw_blk_disk_register(&scdrom->parent)))
116     {
117         goto _fail;
118     }
119 
120     return RT_EOK;
121 
122 _fail:
123     rt_dm_ida_free(&cdrom_ida, scdrom->cdrom_id);
124     rt_free(scdrom);
125 
126     return err;
127 }
128 
scsi_cdrom_remove(struct rt_scsi_device * sdev)129 rt_err_t scsi_cdrom_remove(struct rt_scsi_device *sdev)
130 {
131     struct scsi_cdrom *scdrom = sdev->priv;
132 
133     rt_dm_ida_free(&cdrom_ida, scdrom->cdrom_id);
134 
135     return rt_hw_blk_disk_unregister(&scdrom->parent);
136 }
137