summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2011-04-13 16:20:54 +0000
committermav <mav@FreeBSD.org>2011-04-13 16:20:54 +0000
commit193a7ed98c36af02e5fa376afc2934e3b6f02aaa (patch)
tree50152a120489fd01d6729de29dac3161f46fd826 /sys/cam
parent165d024cbce00d510ea8791849003b57f417aa39 (diff)
downloadFreeBSD-src-193a7ed98c36af02e5fa376afc2934e3b6f02aaa.zip
FreeBSD-src-193a7ed98c36af02e5fa376afc2934e3b6f02aaa.tar.gz
Improve SATA Asynchronous Notification feature support in CAM:
- make SATA SIMs announce capabilities to handle SDB with Notification bit; - make PMP driver honor this SIMs capability; - make SATA XPT to negotiate and enable this feature for ATAPI devices. This feature allows supporting SATA ATAPI devices to inform system about some events happened, that may require attention. In my case this allows LG GH22LS50 SATA DVR-RW drive to report tray open/close events. Events reported to CAM in form of AC_SCSI_AEN async. Further they could be used as a hints for checking device status and reporting media change to upper layers, for example, via spoiling mechanism of GEOM.
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/ata/ata_pmp.c7
-rw-r--r--sys/cam/ata/ata_xpt.c25
-rw-r--r--sys/cam/cam_ccb.h1
3 files changed, 31 insertions, 2 deletions
diff --git a/sys/cam/ata/ata_pmp.c b/sys/cam/ata/ata_pmp.c
index 3520376..e6eb4a2 100644
--- a/sys/cam/ata/ata_pmp.c
+++ b/sys/cam/ata/ata_pmp.c
@@ -533,7 +533,8 @@ pmpstart(struct cam_periph *periph, union ccb *start_ccb)
/*data_ptr*/NULL,
/*dxfer_len*/0,
pmp_default_timeout * 1000);
- ata_pm_write_cmd(ataio, 0x60, 15, 0xf);
+ ata_pm_write_cmd(ataio, 0x60, 15, 0x07 |
+ ((softc->caps & CTS_SATA_CAPS_H_AN) ? 0x08 : 0));
break;
default:
break;
@@ -672,7 +673,9 @@ pmpdone(struct cam_periph *periph, union ccb *done_ccb)
cts.xport_specific.sata.revision = (res & 0x0f0) >> 4;
cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION;
cts.xport_specific.sata.caps = softc->caps &
- (CTS_SATA_CAPS_H_PMREQ | CTS_SATA_CAPS_H_DMAAA);
+ (CTS_SATA_CAPS_H_PMREQ |
+ CTS_SATA_CAPS_H_DMAAA |
+ CTS_SATA_CAPS_H_AN);
cts.xport_specific.sata.valid |= CTS_SATA_VALID_CAPS;
xpt_action((union ccb *)&cts);
xpt_free_path(dpath);
diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c
index db45f8f..b836485 100644
--- a/sys/cam/ata/ata_xpt.c
+++ b/sys/cam/ata/ata_xpt.c
@@ -87,6 +87,7 @@ typedef enum {
PROBE_SETPM,
PROBE_SETAPST,
PROBE_SETDMAAA,
+ PROBE_SETAN,
PROBE_SET_MULTI,
PROBE_INQUIRY,
PROBE_FULL_INQUIRY,
@@ -103,6 +104,7 @@ static char *probe_action_text[] = {
"PROBE_SETPM",
"PROBE_SETAPST",
"PROBE_SETDMAAA",
+ "PROBE_SETAN",
"PROBE_SET_MULTI",
"PROBE_INQUIRY",
"PROBE_FULL_INQUIRY",
@@ -436,6 +438,19 @@ negotiate:
(softc->caps & CTS_SATA_CAPS_H_DMAAA) ? 0x10 : 0x90,
0, 0x02);
break;
+ case PROBE_SETAN:
+ cam_fill_ataio(ataio,
+ 1,
+ probedone,
+ CAM_DIR_NONE,
+ 0,
+ NULL,
+ 0,
+ 30*1000);
+ ata_28bit_cmd(ataio, ATA_SETFEATURES,
+ (softc->caps & CTS_SATA_CAPS_H_AN) ? 0x10 : 0x90,
+ 0, 0x05);
+ break;
case PROBE_SET_MULTI:
{
u_int sectors, bytecount;
@@ -1027,6 +1042,16 @@ noerror:
}
/* FALLTHROUGH */
case PROBE_SETDMAAA:
+ if ((ident_buf->satasupport & ATA_SUPPORT_ASYNCNOTIF) &&
+ (!(softc->caps & CTS_SATA_CAPS_H_AN)) !=
+ (!(ident_buf->sataenabled & ATA_SUPPORT_ASYNCNOTIF))) {
+ PROBE_SET_ACTION(softc, PROBE_SETAN);
+ xpt_release_ccb(done_ccb);
+ xpt_schedule(periph, priority);
+ return;
+ }
+ /* FALLTHROUGH */
+ case PROBE_SETAN:
notsata:
if (path->device->protocol == PROTO_ATA) {
PROBE_SET_ACTION(softc, PROBE_SET_MULTI);
diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
index 9c1e3ab..bee07e8 100644
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -889,6 +889,7 @@ struct ccb_trans_settings_sata {
#define CTS_SATA_CAPS_H_PMREQ 0x00000001
#define CTS_SATA_CAPS_H_APST 0x00000002
#define CTS_SATA_CAPS_H_DMAAA 0x00000010 /* Auto-activation */
+#define CTS_SATA_CAPS_H_AN 0x00000020 /* Async. notification */
#define CTS_SATA_CAPS_D 0xffff0000
#define CTS_SATA_CAPS_D_PMREQ 0x00010000
#define CTS_SATA_CAPS_D_APST 0x00020000
OpenPOWER on IntegriCloud