Rev 4507 | Rev 4530 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 4507 | Rev 4529 | ||
|---|---|---|---|
| Line 48... | Line 48... | ||
| 48 | #include <as.h> |
48 | #include <as.h> |
| 49 | #include <futex.h> |
49 | #include <futex.h> |
| 50 | #include <devmap.h> |
50 | #include <devmap.h> |
| 51 | #include <sys/types.h> |
51 | #include <sys/types.h> |
| 52 | #include <errno.h> |
52 | #include <errno.h> |
| - | 53 | #include <bool.h> |
|
| 53 | 54 | ||
| 54 | #define NAME "ata_bd" |
55 | #define NAME "ata_bd" |
| 55 | 56 | ||
| 56 | enum { |
57 | enum { |
| 57 | CTL_READ_START = 0, |
58 | CTL_READ_START = 0, |
| Line 131... | Line 132... | ||
| 131 | ER_ABRT = 0x04, /**< Aborted Command */ |
132 | ER_ABRT = 0x04, /**< Aborted Command */ |
| 132 | ER_TK0NF = 0x02, /**< Track 0 Not Found */ |
133 | ER_TK0NF = 0x02, /**< Track 0 Not Found */ |
| 133 | ER_AMNF = 0x01 /**< Address Mark Not Found */ |
134 | ER_AMNF = 0x01 /**< Address Mark Not Found */ |
| 134 | }; |
135 | }; |
| 135 | 136 | ||
| - | 137 | typedef struct { |
|
| - | 138 | bool present; |
|
| - | 139 | unsigned heads; |
|
| - | 140 | unsigned cylinders; |
|
| - | 141 | unsigned sectors; |
|
| - | 142 | uint64_t blocks; |
|
| - | 143 | } disk_t; |
|
| - | 144 | ||
| 136 | static const size_t block_size = 512; |
145 | static const size_t block_size = 512; |
| 137 | static size_t comm_size; |
146 | static size_t comm_size; |
| 138 | 147 | ||
| 139 | static uintptr_t cmd_physical = 0x1f0; |
148 | static uintptr_t cmd_physical = 0x1f0; |
| 140 | static uintptr_t ctl_physical = 0x170; |
149 | static uintptr_t ctl_physical = 0x170; |
| Line 143... | Line 152... | ||
| 143 | 152 | ||
| 144 | static dev_handle_t dev_handle[MAX_DISKS]; |
153 | static dev_handle_t dev_handle[MAX_DISKS]; |
| 145 | 154 | ||
| 146 | static atomic_t dev_futex = FUTEX_INITIALIZER; |
155 | static atomic_t dev_futex = FUTEX_INITIALIZER; |
| 147 | 156 | ||
| 148 | static unsigned heads, cylinders, sectors; |
- | |
| 149 | static uint64_t disk_blocks; |
157 | static disk_t disk[2]; |
| 150 | 158 | ||
| 151 | static int ata_bd_init(void); |
159 | static int ata_bd_init(void); |
| 152 | static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall); |
160 | static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall); |
| 153 | static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, off_t size, |
161 | static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, off_t size, |
| 154 | void *buf); |
162 | void *buf); |
| 155 | static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, |
163 | static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, |
| 156 | void *buf); |
164 | void *buf); |
| - | 165 | static int drive_identify(int drive_id, disk_t *d); |
|
| 157 | 166 | ||
| 158 | int main(int argc, char **argv) |
167 | int main(int argc, char **argv) |
| 159 | { |
168 | { |
| 160 | uint8_t status; |
169 | uint8_t status; |
| - | 170 | char name[16]; |
|
| 161 | uint16_t data; |
171 | int i, rc; |
| 162 | int i; |
172 | int n_disks; |
| 163 | 173 | ||
| 164 | printf(NAME ": ATA disk driver\n"); |
174 | printf(NAME ": ATA disk driver\n"); |
| 165 | 175 | ||
| 166 | printf("cmd_physical = 0x%x\n", cmd_physical); |
176 | printf("cmd_physical = 0x%x\n", cmd_physical); |
| 167 | printf("ctl_physical = 0x%x\n", ctl_physical); |
177 | printf("ctl_physical = 0x%x\n", ctl_physical); |
| Line 185... | Line 195... | ||
| 185 | } while ((status & SR_BSY) != 0); |
195 | } while ((status & SR_BSY) != 0); |
| 186 | printf("Done\n"); |
196 | printf("Done\n"); |
| 187 | 197 | ||
| 188 | printf("Status = 0x%x\n", pio_read_8(&cmd->status)); |
198 | printf("Status = 0x%x\n", pio_read_8(&cmd->status)); |
| 189 | 199 | ||
| - | 200 | (void) drive_identify(0, &disk[0]); |
|
| - | 201 | (void) drive_identify(1, &disk[1]); |
|
| - | 202 | ||
| - | 203 | n_disks = 0; |
|
| - | 204 | ||
| - | 205 | for (i = 0; i < MAX_DISKS; i++) { |
|
| - | 206 | /* Skip unattached drives. */ |
|
| - | 207 | if (disk[i].present == false) |
|
| - | 208 | continue; |
|
| - | 209 | ||
| - | 210 | snprintf(name, 16, "disk%d", i); |
|
| - | 211 | rc = devmap_device_register(name, &dev_handle[i]); |
|
| - | 212 | if (rc != EOK) { |
|
| - | 213 | devmap_hangup_phone(DEVMAP_DRIVER); |
|
| - | 214 | printf(NAME ": Unable to register device %s.\n", |
|
| - | 215 | name); |
|
| - | 216 | return rc; |
|
| - | 217 | } |
|
| - | 218 | ++n_disks; |
|
| - | 219 | } |
|
| - | 220 | ||
| - | 221 | if (n_disks == 0) { |
|
| - | 222 | printf("No disks detected.\n"); |
|
| - | 223 | return -1; |
|
| - | 224 | } |
|
| - | 225 | ||
| - | 226 | printf(NAME ": Accepting connections\n"); |
|
| - | 227 | async_manager(); |
|
| - | 228 | ||
| - | 229 | /* Not reached */ |
|
| - | 230 | return 0; |
|
| - | 231 | } |
|
| - | 232 | ||
| - | 233 | static int drive_identify(int disk_id, disk_t *d) |
|
| - | 234 | { |
|
| - | 235 | uint16_t data; |
|
| - | 236 | uint8_t status; |
|
| - | 237 | int i; |
|
| - | 238 | ||
| 190 | printf("Issue drive_identify command\n"); |
239 | printf("Identify drive %d\n", disk_id); |
| 191 | pio_write_8(&cmd->drive_head, 0x00); |
240 | pio_write_8(&cmd->drive_head, ((disk_id != 0) ? DHR_DRV : 0)); |
| 192 | async_usleep(100); |
241 | async_usleep(100); |
| 193 | pio_write_8(&cmd->command, 0xEC); |
242 | pio_write_8(&cmd->command, 0xEC); |
| 194 | 243 | ||
| - | 244 | status = pio_read_8(&cmd->status); |
|
| 195 | printf("Status = 0x%x\n", pio_read_8(&cmd->status)); |
245 | printf("Status = 0x%x\n", status); |
| - | 246 | ||
| - | 247 | d->present = false; |
|
| - | 248 | ||
| - | 249 | /* |
|
| - | 250 | * Detect if drive is present. This is Qemu only! Need to |
|
| - | 251 | * do the right thing to work with real drives. |
|
| - | 252 | */ |
|
| - | 253 | if ((status & SR_DRDY) == 0) { |
|
| - | 254 | printf("None attached.\n"); |
|
| - | 255 | return ENOENT; |
|
| - | 256 | } |
|
| 196 | 257 | ||
| 197 | for (i = 0; i < 256; i++) { |
258 | for (i = 0; i < 256; i++) { |
| 198 | do { |
259 | do { |
| 199 | status = pio_read_8(&cmd->status); |
260 | status = pio_read_8(&cmd->status); |
| 200 | } while ((status & SR_DRDY) == 0); |
261 | } while ((status & SR_DRDY) == 0); |
| 201 | 262 | ||
| 202 | data = pio_read_16(&cmd->data_port); |
263 | data = pio_read_16(&cmd->data_port); |
| 203 | 264 | ||
| 204 | switch (i) { |
265 | switch (i) { |
| 205 | case 1: cylinders = data; break; |
266 | case 1: d->cylinders = data; break; |
| 206 | case 3: heads = data; break; |
267 | case 3: d->heads = data; break; |
| 207 | case 6: sectors = data; break; |
268 | case 6: d->sectors = data; break; |
| 208 | } |
269 | } |
| 209 | } |
270 | } |
| 210 | 271 | ||
| 211 | printf("\n\nStatus = 0x%x\n", pio_read_8(&cmd->status)); |
272 | printf("\n\nStatus = 0x%x\n", pio_read_8(&cmd->status)); |
| 212 | 273 | ||
| - | 274 | d->blocks = d->cylinders * d->heads * d->sectors; |
|
| - | 275 | ||
| 213 | printf("Geometry: %u cylinders, %u heads, %u sectors\n", |
276 | printf("Geometry: %u cylinders, %u heads, %u sectors\n", |
| 214 | cylinders, heads, sectors); |
277 | d->cylinders, d->heads, d->sectors); |
| 215 | disk_blocks = cylinders * heads * sectors; |
- | |
| 216 | 278 | ||
| 217 | printf(NAME ": Accepting connections\n"); |
- | |
| 218 | async_manager(); |
279 | d->present = true; |
| 219 | 280 | ||
| 220 | /* Not reached */ |
- | |
| 221 | return 0; |
281 | return EOK; |
| 222 | } |
282 | } |
| 223 | 283 | ||
| 224 | static int ata_bd_init(void) |
284 | static int ata_bd_init(void) |
| 225 | { |
285 | { |
| 226 | void *vaddr; |
286 | void *vaddr; |
| 227 | int rc, i; |
287 | int rc; |
| 228 | char name[16]; |
- | |
| 229 | 288 | ||
| 230 | rc = devmap_driver_register(NAME, ata_bd_connection); |
289 | rc = devmap_driver_register(NAME, ata_bd_connection); |
| 231 | if (rc < 0) { |
290 | if (rc < 0) { |
| 232 | printf(NAME ": Unable to register driver.\n"); |
291 | printf(NAME ": Unable to register driver.\n"); |
| 233 | return rc; |
292 | return rc; |
| Line 247... | Line 306... | ||
| 247 | return rc; |
306 | return rc; |
| 248 | } |
307 | } |
| 249 | 308 | ||
| 250 | ctl = vaddr; |
309 | ctl = vaddr; |
| 251 | 310 | ||
| 252 | for (i = 0; i < MAX_DISKS; i++) { |
- | |
| 253 | snprintf(name, 16, "disk%d", i); |
- | |
| 254 | rc = devmap_device_register(name, &dev_handle[i]); |
- | |
| 255 | if (rc != EOK) { |
- | |
| 256 | devmap_hangup_phone(DEVMAP_DRIVER); |
- | |
| 257 | printf(NAME ": Unable to register device %s.\n", |
- | |
| 258 | name); |
- | |
| 259 | return rc; |
- | |
| 260 | } |
- | |
| 261 | } |
- | |
| 262 | 311 | ||
| 263 | return EOK; |
312 | return EOK; |
| 264 | } |
313 | } |
| 265 | 314 | ||
| 266 | static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall) |
315 | static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall) |
| Line 283... | Line 332... | ||
| 283 | disk_id = -1; |
332 | disk_id = -1; |
| 284 | for (i = 0; i < MAX_DISKS; i++) |
333 | for (i = 0; i < MAX_DISKS; i++) |
| 285 | if (dev_handle[i] == dh) |
334 | if (dev_handle[i] == dh) |
| 286 | disk_id = i; |
335 | disk_id = i; |
| 287 | 336 | ||
| 288 | if (disk_id < 0) { |
337 | if (disk_id < 0 || disk[disk_id].present == false) { |
| 289 | ipc_answer_0(iid, EINVAL); |
338 | ipc_answer_0(iid, EINVAL); |
| 290 | return; |
339 | return; |
| 291 | } |
340 | } |
| 292 | 341 | ||
| 293 | /* Answer the IPC_M_CONNECT_ME_TO call. */ |
342 | /* Answer the IPC_M_CONNECT_ME_TO call. */ |
| Line 372... | Line 421... | ||
| 372 | uint16_t data; |
421 | uint16_t data; |
| 373 | uint8_t status; |
422 | uint8_t status; |
| 374 | uint64_t c, h, s; |
423 | uint64_t c, h, s; |
| 375 | uint64_t idx; |
424 | uint64_t idx; |
| 376 | uint8_t drv_head; |
425 | uint8_t drv_head; |
| - | 426 | disk_t *d; |
|
| - | 427 | ||
| - | 428 | d = &disk[disk_id]; |
|
| 377 | 429 | ||
| 378 | /* Check device bounds. */ |
430 | /* Check device bounds. */ |
| 379 | if (blk_idx >= disk_blocks) |
431 | if (blk_idx >= d->blocks) |
| 380 | return EINVAL; |
432 | return EINVAL; |
| 381 | 433 | ||
| 382 | /* Compute CHS. */ |
434 | /* Compute CHS. */ |
| 383 | c = blk_idx / (heads * sectors); |
435 | c = blk_idx / (d->heads * d->sectors); |
| 384 | idx = blk_idx % (heads * sectors); |
436 | idx = blk_idx % (d->heads * d->sectors); |
| 385 | 437 | ||
| 386 | h = idx / sectors; |
438 | h = idx / d->sectors; |
| 387 | s = 1 + (idx % sectors); |
439 | s = 1 + (idx % d->sectors); |
| 388 | 440 | ||
| 389 | /* New value for Drive/Head register */ |
441 | /* New value for Drive/Head register */ |
| 390 | drv_head = |
442 | drv_head = |
| 391 | ((disk_id != 0) ? DHR_DRV : 0) | |
443 | ((disk_id != 0) ? DHR_DRV : 0) | |
| 392 | (h & 0x0f); |
444 | (h & 0x0f); |