2 * Copyright (C) 2012, The AROS Development Team. All rights reserved.
3 * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
5 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
8 #include <aros/debug.h>
9 #include <aros/atomic.h>
11 #include <proto/exec.h>
12 #include <proto/expansion.h>
13 #include <proto/dos.h>
15 #include <dos/filehandler.h>
17 #include <devices/trackdisk.h>
18 #include <devices/scsidisk.h>
20 #include <scsi/commands.h>
21 #include <scsi/values.h>
24 #include "ahci_scsi.h"
27 #include LC_LIBDEFS_FILE
30 * Execute a SCSI TEST UNIT READY every 250ms, to see
31 * if the medium has changed.
33 static void ahci_PortMonitor(struct Task
*parent
, struct Device
*device
, struct cam_sim
*unit
)
36 struct IORequest
*tmr
;
38 D(bug("%s %d: Monitor Start\n", ((struct Node
*)device
)->ln_Name
, unit
->sim_Unit
));
39 AROS_ATOMIC_INC(unit
->sim_UseCount
);
40 Signal(parent
, SIGBREAKF_CTRL_C
);
42 tmr
= ahci_OpenTimer();
46 if ((mp
= CreateMsgPort())) {
48 if ((io
= CreateIORequest(mp
, sizeof(struct IOStdReq
)))) {
49 BOOL media_present
= FALSE
;
51 struct scsi_generic test_unit_ready
= { .opcode
= SCSI_TEST_UNIT_READY
, };
52 struct scsi_sense_data sense
= {};
53 struct SCSICmd scsi
= {};
55 io
->io_Device
= device
;
56 io
->io_Unit
= (struct Unit
*)unit
;
58 D(bug("%s %d: Monitoring\n", ((struct Node
*)device
)->ln_Name
, unit
->sim_Unit
));
60 /* Issue a dummy read and gather sense data as we wish to get the current sense and not the previous */
61 io
->io_Command
= HD_SCSICMD
;
64 IOStdReq(io
)->io_Data
= &scsi
;
65 IOStdReq(io
)->io_Length
= sizeof(scsi
);
66 IOStdReq(io
)->io_Actual
= 0;
67 scsi
.scsi_Data
= NULL
;
69 scsi
.scsi_Command
= (UBYTE
*)&test_unit_ready
;
70 scsi
.scsi_CmdLength
= sizeof(test_unit_ready
);
73 scsi
.scsi_Flags
= SCSIF_READ
|SCSIF_AUTOSENSE
|0x80;
74 scsi
.scsi_SenseData
= (UBYTE
*)&sense
;
75 scsi
.scsi_SenseLength
= sizeof(sense
);
76 scsi
.scsi_SenseActual
= 0;
80 if((io
->io_Error
== 0)) {
81 if((scsi
.scsi_Status
!= SCSI_GOOD
)) {
82 if((sense
.flags
& SSD_KEY
) == SSD_KEY_NOT_READY
) {
83 /* Medium is not present and tray is either closed or open (when additional sense code is 0x3a) */
84 if(sense
.add_sense_code
== 0x3a) {
85 media_present
= FALSE
;
87 if(sense.add_sense_qual == 1) {
88 // medium not present - tray closed
90 if(sense.add_sense_qual == 2) {
91 // medium not present - tray open
98 /* When status returns GOOD, sense key is not applicable -> assume media to be present */
102 /* Presence of media has changed */
103 if((unit
->sim_Flags
|= SIMF_MediaPresent
) != (media_present
)) {
104 ObtainSemaphore(&unit
->sim_Lock
);
106 unit
->sim_Flags
|= SIMF_MediaPresent
;
108 unit
->sim_Flags
&= ~SIMF_MediaPresent
;
110 unit
->sim_ChangeNum
++;
111 ReleaseSemaphore(&unit
->sim_Lock
);
113 struct IORequest
*msg
;
115 D(bug("%s: Media change detected on ahci.device %d (media is %s)\n", __func__
, unit
->sim_Unit
, media_present
? "present" : "not present"));
118 ForeachNode((struct Node
*)&unit
->sim_IOs
, msg
) {
119 D(bug("%s %d: io_Command = 0x%04x\n", ((struct Node
*)device
)->ln_Name
, unit
->sim_Unit
, msg
->io_Command
));
120 if (msg
->io_Command
== TD_ADDCHANGEINT
) {
121 D(bug("%s %d: Interrupt = 0x%p\n", ((struct Node
*)device
)->ln_Name
, unit
->sim_Unit
, IOStdReq(msg
)->io_Data
));
122 Cause((struct Interrupt
*)IOStdReq(msg
)->io_Data
);
130 /* Wait 1s to the next scan */
131 } while ((ahci_WaitTO(tmr
, 1, 0, SIGF_DOS
) & SIGF_DOS
) == 0);
137 AROS_ATOMIC_DEC(unit
->sim_UseCount
);
138 D(bug("%s %d: Monitor End\n", ((struct Node
*)device
)->ln_Name
, unit
->sim_Unit
));
141 static int ahci_RegisterPort(struct ahci_port
*ap
)
143 struct AHCIBase
*AHCIBase
= ap
->ap_sc
->sc_dev
->dev_AHCIBase
;
144 struct cam_sim
*unit
;
147 unit
= AllocPooled(AHCIBase
->ahci_MemPool
, sizeof(*unit
));
153 unit
->sim_Unit
= ap
->ap_sc
->sc_dev
->dev_HostID
* 32 + ap
->ap_num
;
154 InitSemaphore(&unit
->sim_Lock
);
155 NEWLIST(&unit
->sim_IOs
);
157 AddTail((struct List
*)&AHCIBase
->ahci_Units
, (struct Node
*)unit
);
159 /* Now that this device is in the unit list, start the disk change monitor */
160 snprintf(name
, sizeof(name
), "ahci.device %d [media]", unit
->sim_Unit
);
161 unit
->sim_Monitor
= NewCreateTask(TASKTAG_NAME
, name
,
162 TASKTAG_PC
, ahci_PortMonitor
,
163 TASKTAG_ARG1
, FindTask(NULL
),
164 TASKTAG_ARG2
, AHCIBase
,
168 Wait(SIGBREAKF_CTRL_C
);
173 static int ahci_UnregisterPort(struct ahci_port
*ap
)
175 struct ahci_softc
*sc
= ap
->ap_sc
;
176 struct AHCIBase
*AHCIBase
;
177 struct cam_sim
*unit
= ap
->ap_sim
;
179 D(bug("ahci_UnregisterPort: %p\n", ap
));
182 D(bug("No softc?\n"));
186 AHCIBase
= sc
->sc_dev
->dev_AHCIBase
;
188 /* Stop the monitor, and wait for IOs to drain,
189 * and users to CloseDevice() the unit.
191 if (unit
->sim_Monitor
)
192 Signal(unit
->sim_Monitor
, SIGF_DOS
);
193 ObtainSemaphore(&unit
->sim_Lock
);
194 while (unit
->sim_UseCount
) {
195 ReleaseSemaphore(&unit
->sim_Lock
);
197 ObtainSemaphore(&unit
->sim_Lock
);
199 ReleaseSemaphore(&unit
->sim_Lock
);
201 /* Remove from the unit list */
203 Remove((struct Node
*)unit
);
206 FreePooled(AHCIBase
->ahci_MemPool
, unit
, sizeof(*unit
));
211 /* Add a bootnode using expansion.library,
212 * but only when dos.library has not yet been initialized.
213 * This way, we get BootNodes if ahci.device is linked in,
214 * but don't if ahci.device is loaded after booting.
216 static BOOL
ahci_RegisterVolume(struct ahci_port
*ap
, struct ata_port
*at
)
218 struct ExpansionBase
*ExpansionBase
;
220 struct DeviceNode
*devnode
;
221 TEXT dosdevname
[4] = "HA0";
222 const ULONG DOS_ID
= AROS_MAKE_ID('D','O','S','\001');
223 const ULONG CDROM_ID
= AROS_MAKE_ID('C','D','V','D');
224 ULONG unit
= device_get_unit(ap
->ap_sc
->sc_dev
) * 32 + ap
->ap_num
;
226 D(bug("%s: ap = %p, at = %p, unit = %d\n", __func__
, ap
, at
, ap
->ap_sim
? ap
->ap_sim
->sim_Unit
: -1));
228 /* See if dos.library has run */
230 dos_loaded
= (FindName (&SysBase
->LibList
, "dos.library") != NULL
);
234 D(bug("%s: refused to register as boot volume - dos.library already loaded\n", __func__
));
238 if (at
== NULL
|| ap
->ap_type
== ATA_PORT_T_NONE
)
241 /* This should be dealt with using some sort of volume manager or such. */
244 case ATA_PORT_T_DISK
:
246 case ATA_PORT_T_ATAPI
:
250 D(bug("[AHCI>>]:-ahci_RegisterVolume called on unknown devicetype\n"));
254 ExpansionBase
= (struct ExpansionBase
*)OpenLibrary("expansion.library",
259 IPTR pp
[4 + DE_BOOTBLOCKS
+ 1];
262 dosdevname
[2] += ap
->ap_num
;
264 dosdevname
[2] = 'A' + (ap
->ap_num
- 10);
266 pp
[0] = (IPTR
)dosdevname
;
267 pp
[1] = (IPTR
)MOD_NAME_STRING
;
269 pp
[DE_TABLESIZE
+ 4] = DE_BOOTBLOCKS
;
270 pp
[DE_SIZEBLOCK
+ 4] = at
->at_identify
.sector_size
;
271 pp
[DE_NUMHEADS
+ 4] = at
->at_identify
.nheads
;
272 pp
[DE_SECSPERBLOCK
+ 4] = 1;
273 pp
[DE_BLKSPERTRACK
+ 4] = at
->at_identify
.nsectors
;
274 pp
[DE_RESERVEDBLKS
+ 4] = 2;
275 pp
[DE_LOWCYL
+ 4] = 0;
276 pp
[DE_HIGHCYL
+ 4] = (ap
->ap_type
== ATA_PORT_T_DISK
) ? (at
->at_identify
.ncyls
-1) : 0;
277 pp
[DE_NUMBUFFERS
+ 4] = 10;
278 pp
[DE_BUFMEMTYPE
+ 4] = MEMF_PUBLIC
;
279 pp
[DE_MAXTRANSFER
+ 4] = 0x00200000;
280 pp
[DE_MASK
+ 4] = ~3;
281 pp
[DE_BOOTPRI
+ 4] = (ap
->ap_type
== ATA_PORT_T_DISK
) ? 0 : 10;
282 pp
[DE_DOSTYPE
+ 4] = (ap
->ap_type
== ATA_PORT_T_DISK
) ? DOS_ID
: CDROM_ID
;
284 pp
[DE_CONTROL
+ 4] = 0;
285 pp
[DE_BOOTBLOCKS
+ 4] = 2;
287 devnode
= MakeDosNode(pp
);
290 D(bug("[AHCI>>]:-ahci_RegisterVolume: '%s' C/H/S=%d/%d/%d, %s unit %d\n",
291 AROS_BSTR_ADDR(devnode
->dn_Name
), at
->at_identify
.ncyls
, at
->at_identify
.nheads
, at
->at_identify
.nsectors
, MOD_NAME_STRING
, unit
));
292 AddBootNode(pp
[DE_BOOTPRI
+ 4], 0, devnode
, 0);
293 D(bug("[AHCI>>]:-ahci_RegisterVolume: done\n"));
297 CloseLibrary((struct Library
*)ExpansionBase
);
304 int ahci_cam_attach(struct ahci_port
*ap
)
308 D(bug("ahci_cam_attach: port %p\n", ap
));
310 ahci_os_unlock_port(ap
);
311 lockmgr(&ap
->ap_sim_lock
, LK_EXCLUSIVE
);
312 error
= ahci_RegisterPort(ap
);
313 lockmgr(&ap
->ap_sim_lock
, LK_RELEASE
);
314 ahci_os_lock_port(ap
);
319 ap
->ap_flags
|= AP_F_BUS_REGISTERED
;
321 if (ap
->ap_probe
== ATA_PROBE_NEED_IDENT
)
322 error
= ahci_cam_probe(ap
, NULL
);
330 ap
->ap_flags
|= AP_F_CAM_ATTACHED
;
335 void ahci_cam_detach(struct ahci_port
*ap
)
337 D(bug("ahci_cam_detach: port %p\n", ap
));
339 lockmgr(&ap
->ap_sim_lock
, LK_EXCLUSIVE
);
340 if (ap
->ap_flags
& AP_F_BUS_REGISTERED
) {
341 ap
->ap_flags
&= ~AP_F_BUS_REGISTERED
;
344 ahci_UnregisterPort(ap
);
346 lockmgr(&ap
->ap_sim_lock
, LK_RELEASE
);
347 ap
->ap_flags
&= ~AP_F_CAM_ATTACHED
;
351 * The state of the port has changed.
353 * If atx is NULL the physical port has changed state.
354 * If atx is non-NULL a particular target behind a PM has changed state.
356 * If found is -1 the target state must be queued to a non-interrupt context.
357 * (only works with at == NULL).
359 * If found is 0 the target was removed.
360 * If found is 1 the target was inserted.
362 void ahci_cam_changed(struct ahci_port
*ap
, struct ata_port
*atx
, int found
)
364 D(bug("ahci_cam_changed: ap=%p, sim = %p, atx=%p, found=%d\n", ap
, ap
->ap_sim
, atx
, found
));
368 ap
->ap_sim
->sim_Flags
|= SIMF_OffLine
;
370 ap
->ap_sim
->sim_Flags
&= ~SIMF_OffLine
;
374 /* Mark the port scan as completed */
375 ap
->ap_flags
|= AP_F_SCAN_COMPLETED
;
378 static void ahci_strip_string(const char **basep
, int *lenp
)
380 const char *base
= *basep
;
383 while (len
&& (*base
== 0 || *base
== ' ')) {
387 while (len
&& (base
[len
-1] == 0 || base
[len
-1] == ' '))
393 static u_int16_t
bswap16(u_int16_t word
)
395 return ((word
<< 8) & 0xff00) |
396 ((word
>> 8) & 0x00ff);
400 * Fix byte ordering so buffers can be accessed as
404 ata_fix_identify(struct ata_identify
*id
)
409 swap
= (u_int16_t
*)id
->serial
;
410 for (i
= 0; i
< sizeof(id
->serial
) / sizeof(u_int16_t
); i
++)
411 swap
[i
] = bswap16(swap
[i
]);
413 swap
= (u_int16_t
*)id
->firmware
;
414 for (i
= 0; i
< sizeof(id
->firmware
) / sizeof(u_int16_t
); i
++)
415 swap
[i
] = bswap16(swap
[i
]);
417 swap
= (u_int16_t
*)id
->model
;
418 for (i
= 0; i
< sizeof(id
->model
) / sizeof(u_int16_t
); i
++)
419 swap
[i
] = bswap16(swap
[i
]);
423 * Dummy done callback for xa.
425 static void ahci_ata_dummy_done(struct ata_xfer
*xa
)
430 * Setting the transfer mode is irrelevant for the SATA transport
431 * but some (atapi) devices seem to need it anyway. In addition
432 * if we are running through a SATA->PATA converter for some reason
433 * beyond my comprehension we might have to set the mode.
435 * We only support DMA modes for SATA attached devices, so don't bother
439 ahci_set_xfer(struct ahci_port
*ap
, struct ata_port
*atx
)
446 at
= atx
? atx
: ap
->ap_ata
[0];
449 * Figure out the supported UDMA mode. Ignore other legacy modes.
451 mask
= le16toh(at
->at_identify
.ultradma
);
452 if ((mask
& 0xFF) == 0 || mask
== 0xFFFF)
456 while ((mask
& 0x8000) == 0) {
462 * SATA atapi devices often still report a dma mode, even though
463 * it is irrelevant for SATA transport. It is also possible that
464 * we are running through a SATA->PATA converter and seeing the
467 * In this case the device may require a (dummy) SETXFER to be
468 * sent before it will work properly.
470 xa
= ahci_ata_get_xfer(ap
, atx
);
471 xa
->complete
= ahci_ata_dummy_done
;
472 xa
->fis
->command
= ATA_C_SET_FEATURES
;
473 xa
->fis
->features
= ATA_SF_SETXFER
;
474 xa
->fis
->flags
= ATA_H2D_FLAGS_CMD
| at
->at_target
;
475 xa
->fis
->sector_count
= mode
;
476 xa
->flags
= ATA_F_PIO
| ATA_F_POLL
;
479 if (ahci_ata_cmd(xa
) != ATA_S_COMPLETE
) {
480 kprintf("%s: Unable to set dummy xfer mode \n",
482 } else if (bootverbose
) {
483 kprintf("%s: Set dummy xfer mode to %02x\n",
484 ATANAME(ap
, atx
), mode
);
486 ahci_ata_put_xfer(xa
);
492 * DISK-specific probe after initial ident
495 ahci_cam_probe_disk(struct ahci_port
*ap
, struct ata_port
*atx
)
500 at
= atx
? atx
: ap
->ap_ata
[0];
503 * Set dummy xfer mode
505 ahci_set_xfer(ap
, atx
);
508 * Enable write cache if supported
510 * NOTE: "WD My Book" external disk devices have a very poor
511 * daughter board between the the ESATA and the HD. Sending
512 * any ATA_C_SET_FEATURES commands will break the hardware port
513 * with a fatal protocol error. However, this device also
514 * indicates that WRITECACHE is already on and READAHEAD is
515 * not supported so we avoid the issue.
517 if ((at
->at_identify
.cmdset82
& ATA_IDENTIFY_WRITECACHE
) &&
518 (at
->at_identify
.features85
& ATA_IDENTIFY_WRITECACHE
) == 0) {
519 xa
= ahci_ata_get_xfer(ap
, atx
);
520 xa
->complete
= ahci_ata_dummy_done
;
521 xa
->fis
->command
= ATA_C_SET_FEATURES
;
522 xa
->fis
->features
= ATA_SF_WRITECACHE_EN
;
523 /* xa->fis->features = ATA_SF_LOOKAHEAD_EN; */
524 xa
->fis
->flags
= ATA_H2D_FLAGS_CMD
| at
->at_target
;
526 xa
->flags
= ATA_F_PIO
| ATA_F_POLL
;
529 if (ahci_ata_cmd(xa
) == ATA_S_COMPLETE
)
530 at
->at_features
|= ATA_PORT_F_WCACHE
;
532 kprintf("%s: Unable to enable write-caching\n",
534 ahci_ata_put_xfer(xa
);
538 * Enable readahead if supported
540 if ((at
->at_identify
.cmdset82
& ATA_IDENTIFY_LOOKAHEAD
) &&
541 (at
->at_identify
.features85
& ATA_IDENTIFY_LOOKAHEAD
) == 0) {
542 xa
= ahci_ata_get_xfer(ap
, atx
);
543 xa
->complete
= ahci_ata_dummy_done
;
544 xa
->fis
->command
= ATA_C_SET_FEATURES
;
545 xa
->fis
->features
= ATA_SF_LOOKAHEAD_EN
;
546 xa
->fis
->flags
= ATA_H2D_FLAGS_CMD
| at
->at_target
;
548 xa
->flags
= ATA_F_PIO
| ATA_F_POLL
;
551 if (ahci_ata_cmd(xa
) == ATA_S_COMPLETE
)
552 at
->at_features
|= ATA_PORT_F_RAHEAD
;
554 kprintf("%s: Unable to enable read-ahead\n",
556 ahci_ata_put_xfer(xa
);
560 * FREEZE LOCK the device so malicious users can't lock it on us.
561 * As there is no harm in issuing this to devices that don't
562 * support the security feature set we just send it, and don't bother
563 * checking if the device sends a command abort to tell us it doesn't
566 if ((at
->at_identify
.cmdset82
& ATA_IDENTIFY_SECURITY
) &&
567 (at
->at_identify
.securestatus
& ATA_SECURE_FROZEN
) == 0 &&
568 (AhciNoFeatures
& (1 << ap
->ap_num
)) == 0) {
569 xa
= ahci_ata_get_xfer(ap
, atx
);
570 xa
->complete
= ahci_ata_dummy_done
;
571 xa
->fis
->command
= ATA_C_SEC_FREEZE_LOCK
;
572 xa
->fis
->flags
= ATA_H2D_FLAGS_CMD
| at
->at_target
;
573 xa
->flags
= ATA_F_PIO
| ATA_F_POLL
;
576 if (ahci_ata_cmd(xa
) == ATA_S_COMPLETE
)
577 at
->at_features
|= ATA_PORT_F_FRZLCK
;
579 kprintf("%s: Unable to set security freeze\n",
581 ahci_ata_put_xfer(xa
);
584 /* Fix up sector size, if the Word 106 is valid */
585 if ((at
->at_identify
.phys_sect_sz
& 0xc000) == 0x4000) {
586 /* Physical sector size is longer than 256 16-bit words? */
587 if (at
->at_identify
.phys_sect_sz
& (1 << 12)) {
590 logsize
= at
->at_identify
.words_lsec
[0];
592 logsize
+= at
->at_identify
.words_lsec
[1];
593 D(physize
= logsize
>> (at
->at_identify
.phys_sect_sz
& 3));
594 D(kprintf("%s: Logical sector size: %d bytes\n",
595 ATANAME(ap
, atx
), logsize
* 2));
596 D(kprintf("%s: Physical sector size: %d bytes\n",
597 ATANAME(ap
, atx
), physize
* 2));
598 at
->at_identify
.sector_size
= logsize
* 2;
600 D(kprintf("%s: Physical sector size == Logical sector size\n", ATANAME(ap
, atx
)));
601 at
->at_identify
.sector_size
= 256 * 2;
604 kprintf("%s: ATA IDENTIFY: Invalid Word 106: 0x%04x\n", ATANAME(ap
, atx
), at
->at_identify
.phys_sect_sz
);
605 at
->at_identify
.sector_size
= 256 * 2;
607 D(kprintf("%s: Sector size: %d bytes\n", ATANAME(ap
, atx
), at
->at_identify
.sector_size
));
609 #if 1 /* Temporary debugging... */
611 kprintf("%s: ATA IDENTIFY\n", ATANAME(ap
, atx
));
612 for (i
= 0; i
< 128; i
++) {
613 if ((i
%8) == 0) kprintf("%s %3d:", ATANAME(ap
, atx
), i
);
614 kprintf(" %04x", ((uint16_t *)(&at
->at_identify
))[i
]);
615 if ((i
%8) == 7) kprintf("\n");
623 * ATAPI-specific probe after initial ident
626 ahci_cam_probe_atapi(struct ahci_port
*ap
, struct ata_port
*atx
)
628 ahci_set_xfer(ap
, atx
);
634 * Once the AHCI port has been attached we need to probe for a device or
635 * devices on the port and setup various options.
637 * If at is NULL we are probing the direct-attached device on the port,
638 * which may or may not be a port multiplier.
641 ahci_cam_probe(struct ahci_port
*ap
, struct ata_port
*atx
)
646 u_int64_t capacity_bytes
;
653 const char *model_id
;
654 const char *firmware_id
;
655 const char *serial_id
;
664 * A NULL atx indicates a probe of the directly connected device.
665 * A non-NULL atx indicates a device connected via a port multiplier.
666 * We need to preserve atx for calls to ahci_ata_get_xfer().
668 * at is always non-NULL. For directly connected devices we supply
669 * an (at) pointing to target 0.
672 at
= ap
->ap_ata
[0]; /* direct attached - device 0 */
673 if (ap
->ap_type
== ATA_PORT_T_PM
) {
674 kprintf("%s: Found Port Multiplier\n",
678 at
->at_type
= ap
->ap_type
;
681 if (atx
->at_type
== ATA_PORT_T_PM
) {
682 kprintf("%s: Bogus device, reducing port count to %d\n",
683 ATANAME(ap
, atx
), atx
->at_target
);
684 if (ap
->ap_pmcount
> atx
->at_target
)
685 ap
->ap_pmcount
= atx
->at_target
;
689 if (ap
->ap_type
== ATA_PORT_T_NONE
)
691 if (at
->at_type
== ATA_PORT_T_NONE
)
695 * Issue identify, saving the result
697 xa
= ahci_ata_get_xfer(ap
, atx
);
698 xa
->complete
= ahci_ata_dummy_done
;
699 xa
->data
= &at
->at_identify
;
700 xa
->datalen
= sizeof(at
->at_identify
);
701 xa
->flags
= ATA_F_READ
| ATA_F_PIO
| ATA_F_POLL
;
702 xa
->fis
->flags
= ATA_H2D_FLAGS_CMD
| at
->at_target
;
704 switch(at
->at_type
) {
705 case ATA_PORT_T_DISK
:
706 xa
->fis
->command
= ATA_C_IDENTIFY
;
709 case ATA_PORT_T_ATAPI
:
710 xa
->fis
->command
= ATA_C_ATAPI_IDENTIFY
;
711 xa
->flags
|= ATA_F_AUTOSENSE
;
715 xa
->fis
->command
= ATA_C_ATAPI_IDENTIFY
;
716 type
= "UNKNOWN(ATAPI?)";
719 xa
->fis
->features
= 0;
723 if (ahci_ata_cmd(xa
) != ATA_S_COMPLETE
) {
724 kprintf("%s: Detected %s device but unable to IDENTIFY\n",
725 ATANAME(ap
, atx
), type
);
726 ahci_ata_put_xfer(xa
);
729 ahci_ata_put_xfer(xa
);
731 ata_fix_identify(&at
->at_identify
);
734 * Read capacity using SATA probe info.
736 if (le16toh(at
->at_identify
.cmdset83
) & 0x0400) {
737 /* LBA48 feature set supported */
739 for (i
= 3; i
>= 0; --i
) {
742 le16toh(at
->at_identify
.addrsecxt
[i
]);
745 capacity
= le16toh(at
->at_identify
.addrsec
[1]);
747 capacity
+= le16toh(at
->at_identify
.addrsec
[0]);
750 capacity
= 1024 * 1024 / 512;
751 at
->at_capacity
= capacity
;
753 ap
->ap_probe
= ATA_PROBE_GOOD
;
755 capacity_bytes
= capacity
* 512;
758 * Negotiate NCQ, throw away any ata_xfer's beyond the negotiated
759 * number of slots and limit the number of CAM ccb's to one less
760 * so we always have a slot available for recovery.
762 * NCQ is not used if ap_ncqdepth is 1 or the host controller does
763 * not support it, and in that case the driver can handle extra
766 * NCQ is currently used only with direct-attached disks. It is
767 * not used with port multipliers or direct-attached ATAPI devices.
769 * Remember at least one extra CCB needs to be reserved for the
772 if ((ap
->ap_sc
->sc_cap
& AHCI_REG_CAP_SNCQ
) &&
773 ap
->ap_type
== ATA_PORT_T_DISK
&&
774 (le16toh(at
->at_identify
.satacap
) & (1 << 8))) {
775 at
->at_ncqdepth
= (le16toh(at
->at_identify
.qdepth
) & 0x1F) + 1;
776 devncqdepth
= at
->at_ncqdepth
;
777 if (at
->at_ncqdepth
> ap
->ap_sc
->sc_ncmds
)
778 at
->at_ncqdepth
= ap
->ap_sc
->sc_ncmds
;
779 if (at
->at_ncqdepth
> 1) {
780 for (i
= 0; i
< ap
->ap_sc
->sc_ncmds
; ++i
) {
781 xa
= ahci_ata_get_xfer(ap
, atx
);
782 if (xa
->tag
< at
->at_ncqdepth
) {
783 xa
->state
= ATA_S_COMPLETE
;
784 ahci_ata_put_xfer(xa
);
788 if (at
->at_ncqdepth
>= ap
->ap_sc
->sc_ncmds
) {
789 cam_sim_set_max_tags(ap
->ap_sim
,
790 at
->at_ncqdepth
- 1);
798 model_len
= sizeof(at
->at_identify
.model
);
799 model_id
= at
->at_identify
.model
;
800 ahci_strip_string(&model_id
, &model_len
);
802 firmware_len
= sizeof(at
->at_identify
.firmware
);
803 firmware_id
= at
->at_identify
.firmware
;
804 ahci_strip_string(&firmware_id
, &firmware_len
);
806 serial_len
= sizeof(at
->at_identify
.serial
);
807 serial_id
= at
->at_identify
.serial
;
808 ahci_strip_string(&serial_id
, &serial_len
);
811 * Generate informatiive strings.
813 * NOTE: We do not automatically set write caching, lookahead,
814 * or the security state for ATAPI devices.
816 if (at
->at_identify
.cmdset82
& ATA_IDENTIFY_WRITECACHE
) {
817 if (at
->at_identify
.features85
& ATA_IDENTIFY_WRITECACHE
)
819 else if (at
->at_type
== ATA_PORT_T_ATAPI
)
827 if (at
->at_identify
.cmdset82
& ATA_IDENTIFY_LOOKAHEAD
) {
828 if (at
->at_identify
.features85
& ATA_IDENTIFY_LOOKAHEAD
)
830 else if (at
->at_type
== ATA_PORT_T_ATAPI
)
838 if (at
->at_identify
.cmdset82
& ATA_IDENTIFY_SECURITY
) {
839 if (at
->at_identify
.securestatus
& ATA_SECURE_FROZEN
)
841 else if (at
->at_type
== ATA_PORT_T_ATAPI
)
843 else if (AhciNoFeatures
& (1 << ap
->ap_num
))
844 scstr
= "<disabled>";
851 kprintf("%s: Found %s \"%*.*s %*.*s\" serial=\"%*.*s\"\n"
852 "%s: tags=%d/%d satacap=%04x satafea=%04x NCQ=%s "
853 "capacity=%lld.%02dMB\n",
857 model_len
, model_len
, model_id
,
858 firmware_len
, firmware_len
, firmware_id
,
859 serial_len
, serial_len
, serial_id
,
862 devncqdepth
, ap
->ap_sc
->sc_ncmds
,
863 at
->at_identify
.satacap
,
864 at
->at_identify
.satafsup
,
865 (at
->at_ncqdepth
> 1 ? "YES" : "NO"),
866 (long long)capacity_bytes
/ (1024 * 1024),
867 (int)(capacity_bytes
% (1024 * 1024)) * 100 / (1024 * 1024)
869 kprintf("%s: f85=%04x f86=%04x f87=%04x WC=%s RA=%s SEC=%s\n",
871 at
->at_identify
.features85
,
872 at
->at_identify
.features86
,
873 at
->at_identify
.features87
,
880 * Additional type-specific probing
882 switch(at
->at_type
) {
883 case ATA_PORT_T_DISK
:
884 error
= ahci_cam_probe_disk(ap
, atx
);
886 case ATA_PORT_T_ATAPI
:
887 error
= ahci_cam_probe_atapi(ap
, atx
);
895 at
->at_probe
= ATA_PROBE_FAILED
;
897 ap
->ap_probe
= at
->at_probe
;
899 at
->at_probe
= ATA_PROBE_GOOD
;
901 ap
->ap_probe
= at
->at_probe
;
902 ahci_RegisterVolume(ap
, at
);