refactor: striped more arch-related code from the kernel code base
[lunaix-os.git] / lunaix-os / hal / ahci / ahci.c
1 /**
2  * @file ahci.c
3  * @author Lunaixsky (zelong56@gmail.com)
4  * @brief A software implementation of Serial ATA AHCI 1.3.1 Specification
5  * @version 0.1
6  * @date 2022-06-28
7  *
8  * @copyright Copyright (c) 2022
9  *
10  */
11 #include <hal/ahci/ahci.h>
12 #include <hal/ahci/hba.h>
13 #include <hal/ahci/sata.h>
14 #include <hal/ahci/scsi.h>
15
16 #include <hal/pci.h>
17 #include <klibc/string.h>
18 #include <lunaix/block.h>
19 #include <lunaix/isrm.h>
20 #include <lunaix/mm/mmio.h>
21 #include <lunaix/mm/pmm.h>
22 #include <lunaix/mm/valloc.h>
23 #include <lunaix/mm/vmm.h>
24 #include <lunaix/spike.h>
25 #include <lunaix/syslog.h>
26
27 #define HBA_FIS_SIZE 256
28 #define HBA_CLB_SIZE 1024
29
30 #define HBA_MY_IE (HBA_PxINTR_DHR | HBA_PxINTR_TFE | HBA_PxINTR_OF)
31
32 // #define DO_HBA_FULL_RESET
33
34 LOG_MODULE("AHCI")
35
36 struct llist_header ahcis;
37
38 static char sata_ifs[][20] = { "Not detected",
39                                "SATA I (1.5Gbps)",
40                                "SATA II (3.0Gbps)",
41                                "SATA III (6.0Gbps)" };
42
43 extern void
44 ahci_fsexport(struct block_dev* bdev, void* fs_node);
45
46 extern void
47 __ahci_hba_isr(const isr_param* param);
48
49 extern void
50 __ahci_blkio_handler(struct blkio_req* req);
51
52 int
53 ahci_init_device(struct hba_port* port);
54
55 void
56 achi_register_ops(struct hba_port* port);
57
58 void
59 ahci_register_device(struct hba_device* hbadev);
60
61 void*
62 ahci_driver_init(struct pci_device* ahci_dev);
63
64 void
65 __hba_reset_port(hba_reg_t* port_reg)
66 {
67     // 根据:SATA-AHCI spec section 10.4.2 描述的端口重置流程
68     port_reg[HBA_RPxCMD] &= ~HBA_PxCMD_ST;
69     port_reg[HBA_RPxCMD] &= ~HBA_PxCMD_FRE;
70     int cnt = wait_until_expire(!(port_reg[HBA_RPxCMD] & HBA_PxCMD_CR), 500000);
71     if (cnt) {
72         return;
73     }
74     // 如果port未响应,则继续执行重置
75     port_reg[HBA_RPxSCTL] = (port_reg[HBA_RPxSCTL] & ~0xf) | 1;
76     io_delay(100000); // 等待至少一毫秒,差不多就行了
77     port_reg[HBA_RPxSCTL] &= ~0xf;
78 }
79
80 void
81 ahci_init()
82 {
83     llist_init_head(&ahcis);
84     pci_add_driver("Serial ATA AHCI", AHCI_HBA_CLASS, 0, 0, ahci_driver_init);
85 }
86
87 void*
88 ahci_driver_init(struct pci_device* ahci_dev)
89 {
90     struct pci_base_addr* bar6 = &ahci_dev->bar[5];
91     assert_msg(bar6->type & BAR_TYPE_MMIO, "AHCI: BAR#6 is not MMIO.");
92
93     pci_reg_t cmd = pci_read_cspace(ahci_dev->cspace_base, PCI_REG_STATUS_CMD);
94
95     // 禁用传统中断(因为我们使用MSI),启用MMIO访问,允许PCI设备间访问
96     cmd |= (PCI_RCMD_MM_ACCESS | PCI_RCMD_DISABLE_INTR | PCI_RCMD_BUS_MASTER);
97
98     pci_write_cspace(ahci_dev->cspace_base, PCI_REG_STATUS_CMD, cmd);
99
100     int iv = isrm_ivexalloc(__ahci_hba_isr);
101     pci_setup_msi(ahci_dev, iv);
102
103     struct ahci_driver* ahci_drv = vzalloc(sizeof(*ahci_drv));
104     struct ahci_hba* hba = &ahci_drv->hba;
105     ahci_drv->id = iv;
106
107     llist_append(&ahcis, &ahci_drv->ahci_drvs);
108
109     hba->base = (hba_reg_t*)ioremap(bar6->start, bar6->size);
110
111 #ifdef DO_HBA_FULL_RESET
112     // 重置HBA
113     hba->base[HBA_RGHC] |= HBA_RGHC_RESET;
114     wait_until(!(hba->base[HBA_RGHC] & HBA_RGHC_RESET));
115 #endif
116
117     // 启用AHCI工作模式,启用中断
118     hba->base[HBA_RGHC] |= HBA_RGHC_ACHI_ENABLE;
119     hba->base[HBA_RGHC] |= HBA_RGHC_INTR_ENABLE;
120
121     // As per section 3.1.1, this is 0 based value.
122     hba_reg_t cap = hba->base[HBA_RCAP];
123     hba_reg_t pmap = hba->base[HBA_RPI];
124
125     hba->ports_num = (cap & 0x1f) + 1;  // CAP.PI
126     hba->cmd_slots = (cap >> 8) & 0x1f; // CAP.NCS
127     hba->version = hba->base[HBA_RVER];
128     hba->ports_bmp = pmap;
129
130     /* ------ HBA端口配置 ------ */
131     ptr_t clb_pg_addr = 0, fis_pg_addr = 0;
132     ptr_t clb_pa = 0, fis_pa = 0;
133
134     for (size_t i = 0, fisp = 0, clbp = 0; i < 32;
135          i++, pmap >>= 1, fisp = (fisp + 1) % 16, clbp = (clbp + 1) % 4) {
136         if (!(pmap & 0x1)) {
137             continue;
138         }
139
140         struct hba_port* port =
141           (struct hba_port*)valloc(sizeof(struct hba_port));
142         hba_reg_t* port_regs =
143           (hba_reg_t*)(&hba->base[HBA_RPBASE + i * HBA_RPSIZE]);
144
145 #ifndef DO_HBA_FULL_RESET
146         __hba_reset_port(port_regs);
147 #endif
148
149         if (!clbp) {
150             // 每页最多4个命令队列
151             clb_pa = pmm_alloc_page(KERNEL_PID, PP_FGLOCKED);
152             clb_pg_addr = (ptr_t)ioremap(clb_pa, 0x1000);
153             memset((void*)clb_pg_addr, 0, 0x1000);
154         }
155         if (!fisp) {
156             // 每页最多16个FIS
157             fis_pa = pmm_alloc_page(KERNEL_PID, PP_FGLOCKED);
158             fis_pg_addr = (ptr_t)ioremap(fis_pa, 0x1000);
159             memset((void*)fis_pg_addr, 0, 0x1000);
160         }
161
162         /* 重定向CLB与FIS */
163         port_regs[HBA_RPxCLB] = clb_pa + clbp * HBA_CLB_SIZE;
164         port_regs[HBA_RPxFB] = fis_pa + fisp * HBA_FIS_SIZE;
165
166         *port = (struct hba_port){
167             .regs = port_regs,
168             .ssts = port_regs[HBA_RPxSSTS],
169             .cmdlst = (struct hba_cmdh*)(clb_pg_addr + clbp * HBA_CLB_SIZE),
170             .fis = (void*)(fis_pg_addr + fisp * HBA_FIS_SIZE),
171             .hba = hba
172         };
173
174         /* 初始化端口,并置于就绪状态 */
175         port_regs[HBA_RPxCI] = 0;
176
177         hba_clear_reg(port_regs[HBA_RPxSERR]);
178
179         hba->ports[i] = port;
180
181         if (!HBA_RPxSSTS_IF(port->ssts)) {
182             continue;
183         }
184
185         wait_until(!(port_regs[HBA_RPxCMD] & HBA_PxCMD_CR));
186         port_regs[HBA_RPxCMD] |= HBA_PxCMD_FRE;
187         port_regs[HBA_RPxCMD] |= HBA_PxCMD_ST;
188
189         if (!ahci_init_device(port)) {
190             kprintf(KERROR "init fail: 0x%x@p%d\n", port->regs[HBA_RPxSIG], i);
191             continue;
192         }
193
194         struct hba_device* hbadev = port->device;
195         kprintf(KINFO "sata%d: %s, blk_size=%d, blk=0..%d\n",
196                 i,
197                 hbadev->model,
198                 hbadev->block_size,
199                 (u32_t)hbadev->max_lba);
200
201         ahci_register_device(hbadev);
202     }
203
204     return ahci_drv;
205 }
206
207 void
208 ahci_register_device(struct hba_device* hbadev)
209 {
210     struct block_dev* bdev =
211       block_alloc_dev(hbadev->model, hbadev, __ahci_blkio_handler);
212
213     bdev->end_lba = hbadev->max_lba;
214     bdev->blk_size = hbadev->block_size;
215
216     block_mount(bdev, ahci_fsexport);
217 }
218
219 int
220 __get_free_slot(struct hba_port* port)
221 {
222     hba_reg_t pxsact = port->regs[HBA_RPxSACT];
223     hba_reg_t pxci = port->regs[HBA_RPxCI];
224     hba_reg_t free_bmp = pxsact | pxci;
225     u32_t i = 0;
226     for (; i <= port->hba->cmd_slots && (free_bmp & 0x1); i++, free_bmp >>= 1)
227         ;
228     return i | -(i > port->hba->cmd_slots);
229 }
230
231 void
232 sata_create_fis(struct sata_reg_fis* cmd_fis,
233                 u8_t command,
234                 lba_t lba,
235                 u16_t sector_count)
236 {
237     cmd_fis->head.type = SATA_REG_FIS_H2D;
238     cmd_fis->head.options = SATA_REG_FIS_COMMAND;
239     cmd_fis->head.status_cmd = command;
240     cmd_fis->dev = 0;
241
242     cmd_fis->lba0 = SATA_LBA_COMPONENT(lba, 0);
243     cmd_fis->lba8 = SATA_LBA_COMPONENT(lba, 8);
244     cmd_fis->lba16 = SATA_LBA_COMPONENT(lba, 16);
245     cmd_fis->lba24 = SATA_LBA_COMPONENT(lba, 24);
246
247     cmd_fis->lba32 = SATA_LBA_COMPONENT(lba, 32);
248     cmd_fis->lba40 = SATA_LBA_COMPONENT(lba, 40);
249
250     cmd_fis->count = sector_count;
251 }
252
253 int
254 hba_bind_sbuf(struct hba_cmdh* cmdh, struct hba_cmdt* cmdt, struct membuf mbuf)
255 {
256     assert_msg(mbuf.size <= 0x400000U, "HBA: Buffer too big");
257     cmdh->prdt_len = 1;
258     cmdt->entries[0] =
259       (struct hba_prdte){ .data_base = vmm_v2p((ptr_t)mbuf.buffer),
260                           .byte_count = mbuf.size - 1 };
261
262     return 0;
263 }
264
265 int
266 hba_bind_vbuf(struct hba_cmdh* cmdh, struct hba_cmdt* cmdt, struct vecbuf* vbuf)
267 {
268     size_t i = 0;
269     struct vecbuf* pos = vbuf;
270
271     do {
272         assert_msg(i < HBA_MAX_PRDTE, "HBA: Too many PRDTEs");
273         assert_msg(pos->buf.size <= 0x400000U, "HBA: Buffer too big");
274
275         cmdt->entries[i++] =
276           (struct hba_prdte){ .data_base = vmm_v2p((ptr_t)pos->buf.buffer),
277                               .byte_count = pos->buf.size - 1 };
278         pos = list_entry(pos->components.next, struct vecbuf, components);
279     } while (pos != vbuf);
280
281     cmdh->prdt_len = i + 1;
282
283     return 0;
284 }
285
286 int
287 hba_prepare_cmd(struct hba_port* port,
288                 struct hba_cmdt** cmdt,
289                 struct hba_cmdh** cmdh)
290 {
291     int slot = __get_free_slot(port);
292     assert_msg(slot >= 0, "HBA: No free slot");
293
294     // 构建命令头(Command Header)和命令表(Command Table)
295     struct hba_cmdh* cmd_header = &port->cmdlst[slot];
296     struct hba_cmdt* cmd_table = vzalloc_dma(sizeof(struct hba_cmdt));
297
298     memset(cmd_header, 0, sizeof(*cmd_header));
299
300     // 将命令表挂到命令头上
301     cmd_header->cmd_table_base = vmm_v2p((ptr_t)cmd_table);
302     cmd_header->options =
303       HBA_CMDH_FIS_LEN(sizeof(struct sata_reg_fis)) | HBA_CMDH_CLR_BUSY;
304
305     *cmdh = cmd_header;
306     *cmdt = cmd_table;
307
308     return slot;
309 }
310
311 int
312 ahci_init_device(struct hba_port* port)
313 {
314     /* 发送ATA命令,参考:SATA AHCI Spec Rev.1.3.1, section 5.5 */
315     struct hba_cmdt* cmd_table;
316     struct hba_cmdh* cmd_header;
317
318     // mask DHR interrupt
319     port->regs[HBA_RPxIE] &= ~HBA_MY_IE;
320
321     // 预备DMA接收缓存,用于存放HBA传回的数据
322     u16_t* data_in = (u16_t*)valloc_dma(512);
323
324     int slot = hba_prepare_cmd(port, &cmd_table, &cmd_header);
325     hba_bind_sbuf(
326       cmd_header, cmd_table, (struct membuf){ .buffer = data_in, .size = 512 });
327
328     port->device = vzalloc(sizeof(struct hba_device));
329     port->device->port = port;
330     port->device->hba = port->hba;
331
332     // 在命令表中构建命令FIS
333     struct sata_reg_fis* cmd_fis = (struct sata_reg_fis*)cmd_table->command_fis;
334
335     // 根据设备类型使用合适的命令
336     if (port->regs[HBA_RPxSIG] == HBA_DEV_SIG_ATA) {
337         // ATA 一般为硬盘
338         sata_create_fis(cmd_fis, ATA_IDENTIFY_DEVICE, 0, 0);
339     } else {
340         // ATAPI 一般为光驱,软驱,或者磁带机
341         port->device->flags |= HBA_DEV_FATAPI;
342         sata_create_fis(cmd_fis, ATA_IDENTIFY_PAKCET_DEVICE, 0, 0);
343     }
344
345     if (!ahci_try_send(port, slot)) {
346         goto fail;
347     }
348
349     /*
350         等待数据到达内存
351         解析IDENTIFY DEVICE传回来的数据。
352           参考:
353             * ATA/ATAPI Command Set - 3 (ACS-3), Section 7.12.7
354     */
355     ahci_parse_dev_info(port->device, data_in);
356
357     if (!(port->device->flags & HBA_DEV_FATAPI)) {
358         goto done;
359     }
360
361     /*
362         注意:ATAPI设备是无法通过IDENTIFY PACKET DEVICE 获取容量信息的。
363         我们需要使用SCSI命令的READ_CAPACITY(16)进行获取。
364         步骤如下:
365             1. 因为ATAPI走的是SCSI,而AHCI对此专门进行了SATA的封装,
366                也就是通过SATA的PACKET命令对SCSI命令进行封装。所以我们
367                首先需要构建一个PACKET命令的FIS
368             2. 接着,在ACMD中构建命令READ_CAPACITY的CDB - 一种SCSI命令的封装
369             3. 然后把cmd_header->options的A位置位,表示这是一个送往ATAPI的命令。
370                 一点细节:
371                     1. HBA往底层SATA控制器发送PACKET FIS
372                     2. SATA控制器回复PIO Setup FIS
373                     3. HBA读入ACMD中的CDB,打包成Data FIS进行答复
374                     4. SATA控制器解包,拿到CDB,通过SCSI协议转发往ATAPI设备。
375                     5. ATAPI设备回复Return Parameter,SATA通过DMA Setup FIS
376                        发起DMA请求,HBA介入,将Return Parameter写入我们在PRDT
377                        里设置的data_in位置。
378             4. 最后照常等待HBA把结果写入data_in,然后直接解析就好了。
379           参考:
380             * ATA/ATAPI Command Set - 3 (ACS-3), Section 7.18
381             * SATA AHCI HBA Spec, Section 5.3.7
382             * SCSI Command Reference Manual, Section 3.26
383     */
384
385     sata_create_fis(cmd_fis, ATA_PACKET, 512 << 8, 0);
386
387     // for dev use 12 bytes cdb, READ_CAPACITY must use the 10 bytes variation.
388     if (port->device->cbd_size == SCSI_CDB12) {
389         struct scsi_cdb12* cdb12 = (struct scsi_cdb12*)cmd_table->atapi_cmd;
390         // ugly tricks to construct 10 byte cdb from 12 byte cdb
391         scsi_create_packet12(cdb12, SCSI_READ_CAPACITY_10, 0, 512 << 8);
392     } else {
393         struct scsi_cdb16* cdb16 = (struct scsi_cdb16*)cmd_table->atapi_cmd;
394         scsi_create_packet16(cdb16, SCSI_READ_CAPACITY_16, 0, 512);
395         cdb16->misc1 = 0x10; // service action
396     }
397
398     cmd_header->transferred_size = 0;
399     cmd_header->options |= HBA_CMDH_ATAPI;
400
401     if (!ahci_try_send(port, slot)) {
402         goto fail;
403     }
404
405     scsi_parse_capacity(port->device, (u32_t*)data_in);
406
407 done:
408     // reset interrupt status and unmask D2HR interrupt
409     port->regs[HBA_RPxIE] |= HBA_MY_IE;
410     achi_register_ops(port);
411
412     vfree_dma(data_in);
413     vfree_dma(cmd_table);
414
415     return 1;
416
417 fail:
418     port->regs[HBA_RPxIE] |= HBA_MY_IE;
419     vfree_dma(data_in);
420     vfree_dma(cmd_table);
421
422     return 0;
423 }
424
425 int
426 ahci_identify_device(struct hba_device* device)
427 {
428     // 用于重新识别设备(比如在热插拔的情况下)
429     vfree(device);
430     return ahci_init_device(device->port);
431 }
432
433 void
434 achi_register_ops(struct hba_port* port)
435 {
436     port->device->ops.identify = ahci_identify_device;
437     if (!(port->device->flags & HBA_DEV_FATAPI)) {
438         port->device->ops.submit = sata_submit;
439     } else {
440         port->device->ops.submit = scsi_submit;
441     }
442 }