summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2009-11-24 12:47:58 +0000
committermav <mav@FreeBSD.org>2009-11-24 12:47:58 +0000
commitb24d810911ca1e67681fbadffbba2d75d47fb1cf (patch)
tree31e803922647a1513999571920a38125262f4b93
parentcdd3b43ca83628c61d1cbcb1a11c9ade61daf720 (diff)
downloadFreeBSD-src-b24d810911ca1e67681fbadffbba2d75d47fb1cf.zip
FreeBSD-src-b24d810911ca1e67681fbadffbba2d75d47fb1cf.tar.gz
MFp4:
- Extend XPT-SIM transfer settings control API. Now it allows to report to SATA SIM number of tags supported by each device, implement ATA mode and SATA revision negotiation for both SATA and PATA SIMs. - Make ahci(4) and siis(4) to use submitted maximum tag number, when scheduling requests. It allows to support NCQ on devices with lower tags count then controller supports. - Make PMP driver to report attached devices connection speeds. - Implement ATA mode negotiation between user settings, device and controller capabilities.
-rw-r--r--sbin/camcontrol/camcontrol.c83
-rw-r--r--sys/cam/ata/ata_all.c109
-rw-r--r--sys/cam/ata/ata_all.h7
-rw-r--r--sys/cam/ata/ata_pmp.c14
-rw-r--r--sys/cam/ata/ata_xpt.c73
-rw-r--r--sys/cam/cam_ccb.h18
-rw-r--r--sys/cam/cam_xpt.c25
-rw-r--r--sys/dev/ahci/ahci.c90
-rw-r--r--sys/dev/ahci/ahci.h11
-rw-r--r--sys/dev/siis/siis.c82
-rw-r--r--sys/dev/siis/siis.h12
11 files changed, 428 insertions, 96 deletions
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 7d88998..73bcd8f 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -226,6 +226,12 @@ static int scsireadcapacity(struct cam_device *device, int argc, char **argv,
static int atapm(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
#endif /* MINIMALISTIC */
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
camcontrol_optret
getoption(char *arg, cam_cmdmask *cmdnum, cam_argmask *argnum,
@@ -950,21 +956,27 @@ camxferrate(struct cam_device *device)
if (sas->valid & CTS_SAS_VALID_SPEED)
speed = sas->bitrate;
+ } else if (ccb->cts.transport == XPORT_ATA) {
+ struct ccb_trans_settings_ata *ata =
+ &ccb->cts.xport_specific.ata;
+
+ if (ata->valid & CTS_ATA_VALID_MODE)
+ speed = ata_mode2speed(ata->mode);
} else if (ccb->cts.transport == XPORT_SATA) {
- struct ccb_trans_settings_sata *sata =
+ struct ccb_trans_settings_sata *sata =
&ccb->cts.xport_specific.sata;
- if (sata->valid & CTS_SATA_VALID_SPEED)
- speed = sata->bitrate;
+ if (sata->valid & CTS_SATA_VALID_REVISION)
+ speed = ata_revision2speed(sata->revision);
}
mb = speed / 1000;
if (mb > 0) {
- fprintf(stdout, "%s%d: %d.%03dMB/s transfers ",
+ fprintf(stdout, "%s%d: %d.%03dMB/s transfers",
device->device_name, device->dev_unit_num,
mb, speed % 1000);
} else {
- fprintf(stdout, "%s%d: %dKB/s transfers ",
+ fprintf(stdout, "%s%d: %dKB/s transfers",
device->device_name, device->dev_unit_num,
speed);
}
@@ -975,7 +987,7 @@ camxferrate(struct cam_device *device)
if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
&& (spi->sync_offset != 0))
- fprintf(stdout, "(%d.%03dMHz, offset %d", freq / 1000,
+ fprintf(stdout, " (%d.%03dMHz, offset %d", freq / 1000,
freq % 1000, spi->sync_offset);
if (((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0)
@@ -995,18 +1007,24 @@ camxferrate(struct cam_device *device)
struct ccb_trans_settings_ata *ata =
&ccb->cts.xport_specific.ata;
- if (ata->valid & CTS_ATA_VALID_BYTECOUNT) {
- fprintf(stdout, "(PIO size %dbytes)",
- ata->bytecount);
- }
+ printf(" (");
+ if (ata->valid & CTS_ATA_VALID_MODE)
+ printf("%s, ", ata_mode2string(ata->mode));
+ if (ata->valid & CTS_ATA_VALID_BYTECOUNT)
+ printf("PIO size %dbytes", ata->bytecount);
+ printf(")");
} else if (ccb->cts.transport == XPORT_SATA) {
struct ccb_trans_settings_sata *sata =
&ccb->cts.xport_specific.sata;
- if (sata->valid & CTS_SATA_VALID_BYTECOUNT) {
- fprintf(stdout, "(PIO size %dbytes)",
- sata->bytecount);
- }
+ printf(" (");
+ if (sata->valid & CTS_SATA_VALID_REVISION)
+ printf("SATA %d.x, ", sata->revision);
+ if (sata->valid & CTS_SATA_VALID_MODE)
+ printf("%s, ", ata_mode2string(sata->mode));
+ if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
+ printf("PIO size %dbytes", sata->bytecount);
+ printf(")");
}
if (ccb->cts.protocol == PROTO_SCSI) {
@@ -2757,7 +2775,44 @@ cts_print(struct cam_device *device, struct ccb_trans_settings *cts)
"enabled" : "disabled");
}
}
+ if (cts->transport == XPORT_ATA) {
+ struct ccb_trans_settings_ata *ata =
+ &cts->xport_specific.ata;
+ if ((ata->valid & CTS_ATA_VALID_MODE) != 0) {
+ fprintf(stdout, "%sATA mode: %s\n", pathstr,
+ ata_mode2string(ata->mode));
+ }
+ if ((ata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) {
+ fprintf(stdout, "%sPIO transaction length: %d\n",
+ pathstr, ata->bytecount);
+ }
+ }
+ if (cts->transport == XPORT_SATA) {
+ struct ccb_trans_settings_sata *sata =
+ &cts->xport_specific.sata;
+
+ if ((sata->valid & CTS_SATA_VALID_REVISION) != 0) {
+ fprintf(stdout, "%sSATA revision: %d.x\n", pathstr,
+ sata->revision);
+ }
+ if ((sata->valid & CTS_SATA_VALID_MODE) != 0) {
+ fprintf(stdout, "%sATA mode: %s\n", pathstr,
+ ata_mode2string(sata->mode));
+ }
+ if ((sata->valid & CTS_SATA_VALID_BYTECOUNT) != 0) {
+ fprintf(stdout, "%sPIO transaction length: %d\n",
+ pathstr, sata->bytecount);
+ }
+ if ((sata->valid & CTS_SATA_VALID_PM) != 0) {
+ fprintf(stdout, "%sPMP presence: %d\n", pathstr,
+ sata->pm_present);
+ }
+ if ((sata->valid & CTS_SATA_VALID_TAGS) != 0) {
+ fprintf(stdout, "%sNumber of tags: %d\n", pathstr,
+ sata->tags);
+ }
+ }
if (cts->protocol == PROTO_SCSI) {
struct ccb_trans_settings_scsi *scsi=
&cts->proto_specific.scsi;
diff --git a/sys/cam/ata/ata_all.c b/sys/cam/ata/ata_all.c
index 5863ea8..fb834bf 100644
--- a/sys/cam/ata/ata_all.c
+++ b/sys/cam/ata/ata_all.c
@@ -491,22 +491,111 @@ ata_max_umode(struct ata_params *ap)
}
int
-ata_max_mode(struct ata_params *ap, int mode, int maxmode)
+ata_max_mode(struct ata_params *ap, int maxmode)
{
- if (maxmode && mode > maxmode)
- mode = maxmode;
+ if (maxmode == 0)
+ maxmode = ATA_DMA_MAX;
+ if (maxmode >= ATA_UDMA0 && ata_max_umode(ap) > 0)
+ return (min(maxmode, ata_max_umode(ap)));
+ if (maxmode >= ATA_WDMA0 && ata_max_wmode(ap) > 0)
+ return (min(maxmode, ata_max_wmode(ap)));
+ return (min(maxmode, ata_max_pmode(ap)));
+}
- if (mode >= ATA_UDMA0 && ata_max_umode(ap) > 0)
- return (min(mode, ata_max_umode(ap)));
+char *
+ata_mode2string(int mode)
+{
+ switch (mode) {
+ case -1: return "UNSUPPORTED";
+ case 0: return "NONE";
+ case ATA_PIO0: return "PIO0";
+ case ATA_PIO1: return "PIO1";
+ case ATA_PIO2: return "PIO2";
+ case ATA_PIO3: return "PIO3";
+ case ATA_PIO4: return "PIO4";
+ case ATA_WDMA0: return "WDMA0";
+ case ATA_WDMA1: return "WDMA1";
+ case ATA_WDMA2: return "WDMA2";
+ case ATA_UDMA0: return "UDMA0";
+ case ATA_UDMA1: return "UDMA1";
+ case ATA_UDMA2: return "UDMA2";
+ case ATA_UDMA3: return "UDMA3";
+ case ATA_UDMA4: return "UDMA4";
+ case ATA_UDMA5: return "UDMA5";
+ case ATA_UDMA6: return "UDMA6";
+ default:
+ if (mode & ATA_DMA_MASK)
+ return "BIOSDMA";
+ else
+ return "BIOSPIO";
+ }
+}
- if (mode >= ATA_WDMA0 && ata_max_wmode(ap) > 0)
- return (min(mode, ata_max_wmode(ap)));
+u_int
+ata_mode2speed(int mode)
+{
+ switch (mode) {
+ case ATA_PIO0:
+ default:
+ return (3300);
+ case ATA_PIO1:
+ return (5200);
+ case ATA_PIO2:
+ return (8300);
+ case ATA_PIO3:
+ return (11100);
+ case ATA_PIO4:
+ return (16700);
+ case ATA_WDMA0:
+ return (4200);
+ case ATA_WDMA1:
+ return (13300);
+ case ATA_WDMA2:
+ return (16700);
+ case ATA_UDMA0:
+ return (16700);
+ case ATA_UDMA1:
+ return (25000);
+ case ATA_UDMA2:
+ return (33300);
+ case ATA_UDMA3:
+ return (44400);
+ case ATA_UDMA4:
+ return (66700);
+ case ATA_UDMA5:
+ return (100000);
+ case ATA_UDMA6:
+ return (133000);
+ }
+}
- if (mode > ata_max_pmode(ap))
- return (min(mode, ata_max_pmode(ap)));
+u_int
+ata_revision2speed(int revision)
+{
+ switch (revision) {
+ case 1:
+ default:
+ return (150000);
+ case 2:
+ return (300000);
+ case 3:
+ return (600000);
+ }
+}
- return (mode);
+int
+ata_speed2revision(u_int speed)
+{
+ switch (speed) {
+ case 150000:
+ default:
+ return (1);
+ case 300000:
+ return (2);
+ case 600000:
+ return (3);
+ }
}
int
diff --git a/sys/cam/ata/ata_all.h b/sys/cam/ata/ata_all.h
index 13de02d..d286220 100644
--- a/sys/cam/ata/ata_all.h
+++ b/sys/cam/ata/ata_all.h
@@ -112,7 +112,12 @@ void ata_bpack(int8_t *src, int8_t *dst, int len);
int ata_max_pmode(struct ata_params *ap);
int ata_max_wmode(struct ata_params *ap);
int ata_max_umode(struct ata_params *ap);
-int ata_max_mode(struct ata_params *ap, int mode, int maxmode);
+int ata_max_mode(struct ata_params *ap, int maxmode);
+
+char * ata_mode2string(int mode);
+u_int ata_mode2speed(int mode);
+u_int ata_revision2speed(int revision);
+int ata_speed2revision(u_int speed);
int ata_identify_match(caddr_t identbuffer, caddr_t table_entry);
int ata_static_identify_match(caddr_t identbuffer, caddr_t table_entry);
diff --git a/sys/cam/ata/ata_pmp.c b/sys/cam/ata/ata_pmp.c
index 1aa6839..e34992b 100644
--- a/sys/cam/ata/ata_pmp.c
+++ b/sys/cam/ata/ata_pmp.c
@@ -516,6 +516,7 @@ printf("PM RESET %d%s\n", softc->pm_step,
static void
pmpdone(struct cam_periph *periph, union ccb *done_ccb)
{
+ struct ccb_trans_settings cts;
struct pmp_softc *softc;
struct ccb_ataio *ataio;
union ccb *work_ccb;
@@ -635,6 +636,19 @@ pmpdone(struct cam_periph *periph, union ccb *done_ccb)
done_ccb->ataio.res.sector_count;
if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) {
printf("PM status: %d - %08x\n", softc->pm_step, res);
+ /* Report device speed. */
+ if (xpt_create_path(&dpath, periph,
+ xpt_path_path_id(periph->path),
+ softc->pm_step, 0) == CAM_REQ_CMP) {
+ bzero(&cts, sizeof(cts));
+ xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NORMAL);
+ cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+ cts.type = CTS_TYPE_CURRENT_SETTINGS;
+ cts.xport_specific.sata.revision = (res & 0x0f0) >> 4;
+ cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION;
+ xpt_action((union ccb *)&cts);
+ xpt_free_path(dpath);
+ }
softc->found |= (1 << softc->pm_step);
softc->pm_step++;
} else {
diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c
index 24a64fe..0018ed1 100644
--- a/sys/cam/ata/ata_xpt.c
+++ b/sys/cam/ata/ata_xpt.c
@@ -275,7 +275,7 @@ probeschedule(struct cam_periph *periph)
static void
probestart(struct cam_periph *periph, union ccb *start_ccb)
{
- /* Probe the device that our peripheral driver points to */
+ struct ccb_trans_settings cts;
struct ccb_ataio *ataio;
struct ccb_scsiio *csio;
probe_softc *softc;
@@ -333,6 +333,55 @@ probestart(struct cam_periph *periph, union ccb *start_ccb)
ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
break;
case PROBE_SETMODE:
+ {
+ int mode, wantmode;
+
+ mode = 0;
+ /* Fetch user modes from SIM. */
+ bzero(&cts, sizeof(cts));
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+ cts.type = CTS_TYPE_USER_SETTINGS;
+ xpt_action((union ccb *)&cts);
+ if (path->device->transport == XPORT_ATA) {
+ if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
+ mode = cts.xport_specific.ata.mode;
+ } else {
+ if (cts.xport_specific.ata.valid & CTS_SATA_VALID_MODE)
+ mode = cts.xport_specific.sata.mode;
+ }
+negotiate:
+ /* Honor device capabilities. */
+ wantmode = mode = ata_max_mode(ident_buf, mode);
+ /* Report modes to SIM. */
+ bzero(&cts, sizeof(cts));
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+ cts.type = CTS_TYPE_CURRENT_SETTINGS;
+ if (path->device->transport == XPORT_ATA) {
+ cts.xport_specific.ata.mode = mode;
+ cts.xport_specific.ata.valid = CTS_ATA_VALID_MODE;
+ } else {
+ cts.xport_specific.sata.mode = mode;
+ cts.xport_specific.sata.valid = CTS_SATA_VALID_MODE;
+ }
+ xpt_action((union ccb *)&cts);
+ /* Fetch user modes from SIM. */
+ bzero(&cts, sizeof(cts));
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+ cts.type = CTS_TYPE_CURRENT_SETTINGS;
+ xpt_action((union ccb *)&cts);
+ if (path->device->transport == XPORT_ATA) {
+ if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
+ mode = cts.xport_specific.ata.mode;
+ } else {
+ if (cts.xport_specific.ata.valid & CTS_SATA_VALID_MODE)
+ mode = cts.xport_specific.sata.mode;
+ }
+ /* If SIM disagree - renegotiate. */
+ if (mode != wantmode)
+ goto negotiate;
cam_fill_ataio(ataio,
1,
probedone,
@@ -341,12 +390,11 @@ probestart(struct cam_periph *periph, union ccb *start_ccb)
/*data_ptr*/NULL,
/*dxfer_len*/0,
30 * 1000);
- ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
- ata_max_mode(ident_buf, ATA_UDMA6, ATA_UDMA6));
+ ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
break;
+ }
case PROBE_SET_MULTI:
{
- struct ccb_trans_settings cts;
u_int sectors;
sectors = max(1, min(ident_buf->sectors_intr & 0xff, 16));
@@ -564,6 +612,7 @@ proberequestbackoff(struct cam_periph *periph, struct cam_ed *device)
static void
probedone(struct cam_periph *periph, union ccb *done_ccb)
{
+ struct ccb_trans_settings cts;
struct ata_params *ident_buf;
probe_softc *softc;
struct cam_path *path;
@@ -619,9 +668,7 @@ noerror:
PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
} else if (sign == 0x9669 &&
done_ccb->ccb_h.target_id == 15) {
- struct ccb_trans_settings cts;
-
- /* Report SIM that PM is present. */
+ /* Report SIM that PM is present. */
bzero(&cts, sizeof(cts));
xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
@@ -716,11 +763,17 @@ noerror:
ATA_QUEUE_LEN(ident_buf->queue) + 1;
}
ata_find_quirk(path->device);
- /* XXX: If not all tags allowed, we must to tell SIM which are. */
- if (path->device->mintags < path->bus->sim->max_tagged_dev_openings)
- path->device->mintags = path->device->maxtags = 0;
if (path->device->mintags != 0 &&
path->bus->sim->max_tagged_dev_openings != 0) {
+ /* Report SIM which tags are allowed. */
+ bzero(&cts, sizeof(cts));
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+ cts.type = CTS_TYPE_CURRENT_SETTINGS;
+ cts.xport_specific.sata.tags = path->device->maxtags;
+ cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS;
+ xpt_action((union ccb *)&cts);
+ /* Reconfigure queues for tagged queueing. */
xpt_start_tags(path);
}
ata_device_transport(path);
diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
index 815da9d..5cae7d3 100644
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -819,19 +819,23 @@ struct ccb_trans_settings_sas {
struct ccb_trans_settings_ata {
u_int valid; /* Which fields to honor */
#define CTS_ATA_VALID_MODE 0x01
-#define CTS_ATA_VALID_BYTECOUNT 0x04
- u_int32_t mode;
+#define CTS_ATA_VALID_BYTECOUNT 0x02
+ int mode; /* Mode */
u_int bytecount; /* Length of PIO transaction */
};
struct ccb_trans_settings_sata {
u_int valid; /* Which fields to honor */
-#define CTS_SATA_VALID_SPEED 0x01
-#define CTS_SATA_VALID_PM 0x02
-#define CTS_SATA_VALID_BYTECOUNT 0x04
- u_int32_t bitrate; /* Mbps */
- u_int pm_present; /* PM is present (XPT->SIM) */
+#define CTS_SATA_VALID_MODE 0x01
+#define CTS_SATA_VALID_BYTECOUNT 0x02
+#define CTS_SATA_VALID_REVISION 0x04
+#define CTS_SATA_VALID_PM 0x08
+#define CTS_SATA_VALID_TAGS 0x10
+ int mode; /* Legacy PATA mode */
u_int bytecount; /* Length of PIO transaction */
+ u_int revision; /* SATA revision */
+ u_int pm_present; /* PM is present (XPT->SIM) */
+ u_int tags; /* Number of allowed tags */
};
/* Get/Set transfer rate/width/disconnection/tag queueing settings */
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 02d8d20..88ee309 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -1140,12 +1140,19 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string)
if (sas->valid & CTS_SAS_VALID_SPEED)
speed = sas->bitrate;
}
+ if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
+ struct ccb_trans_settings_ata *ata =
+ &cts.xport_specific.ata;
+
+ if (ata->valid & CTS_ATA_VALID_MODE)
+ speed = ata_mode2speed(ata->mode);
+ }
if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
struct ccb_trans_settings_sata *sata =
&cts.xport_specific.sata;
- if (sata->valid & CTS_SATA_VALID_SPEED)
- speed = sata->bitrate;
+ if (sata->valid & CTS_SATA_VALID_REVISION)
+ speed = ata_revision2speed(sata->revision);
}
mb = speed / 1000;
@@ -1195,15 +1202,25 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string)
struct ccb_trans_settings_ata *ata =
&cts.xport_specific.ata;
+ printf(" (");
+ if (ata->valid & CTS_ATA_VALID_MODE)
+ printf("%s, ", ata_mode2string(ata->mode));
if (ata->valid & CTS_ATA_VALID_BYTECOUNT)
- printf(" (PIO size %dbytes)", ata->bytecount);
+ printf("PIO size %dbytes", ata->bytecount);
+ printf(")");
}
if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
struct ccb_trans_settings_sata *sata =
&cts.xport_specific.sata;
+ printf(" (");
+ if (sata->valid & CTS_SATA_VALID_REVISION)
+ printf("SATA %d.x, ", sata->revision);
+ if (sata->valid & CTS_SATA_VALID_MODE)
+ printf("%s, ", ata_mode2string(sata->mode));
if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
- printf(" (PIO size %dbytes)", sata->bytecount);
+ printf("PIO size %dbytes", sata->bytecount);
+ printf(")");
}
if (path->device->inq_flags & SID_CmdQue
|| path->device->flags & CAM_DEV_TAG_AFTER_COUNT) {
diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c
index 459aa64..0cb67f4 100644
--- a/sys/dev/ahci/ahci.c
+++ b/sys/dev/ahci/ahci.c
@@ -776,7 +776,7 @@ ahci_ch_attach(device_t dev)
struct ahci_controller *ctlr = device_get_softc(device_get_parent(dev));
struct ahci_channel *ch = device_get_softc(dev);
struct cam_devq *devq;
- int rid, error;
+ int rid, error, i;
ch->dev = dev;
ch->unit = (intptr_t)device_get_ivars(dev);
@@ -789,6 +789,13 @@ ahci_ch_attach(device_t dev)
device_get_unit(dev), "pm_level", &ch->pm_level);
if (ch->pm_level > 3)
callout_init_mtx(&ch->pm_timer, &ch->mtx, 0);
+ for (i = 0; i < 16; i++) {
+ ch->user[i].revision = 0;
+ ch->user[i].mode = 0;
+ ch->user[i].bytecount = 8192;
+ ch->user[i].tags = ch->numslots;
+ ch->curr[i] = ch->user[i];
+ }
/* Limit speed for my onboard JMicron external port.
* It is not eSATA really. */
if (pci_get_devid(ctlr->dev) == 0x2363197b &&
@@ -1275,6 +1282,10 @@ ahci_check_collision(device_t dev, union ccb *ccb)
if (ch->numtslots != 0 &&
ch->taggedtarget != ccb->ccb_h.target_id)
return (1);
+ /* Tagged command while we have no supported tag free. */
+ if (((~ch->oslots) & (0xffffffff >> (32 -
+ ch->curr[ccb->ccb_h.target_id].tags))) == 0)
+ return (1);
} else {
/* Untagged command while tagged are active. */
if (ch->numrslots != 0 && ch->numtslots != 0)
@@ -1298,15 +1309,21 @@ ahci_begin_transaction(device_t dev, union ccb *ccb)
{
struct ahci_channel *ch = device_get_softc(dev);
struct ahci_slot *slot;
- int tag;
+ int tag, tags;
/* Choose empty slot. */
+ tags = ch->numslots;
+ if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
+ (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA))
+ tags = ch->curr[ccb->ccb_h.target_id].tags;
tag = ch->lastslot;
- while (ch->slot[tag].state != AHCI_SLOT_EMPTY) {
- if (++tag >= ch->numslots)
+ while (1) {
+ if (tag >= tags)
tag = 0;
- KASSERT(tag != ch->lastslot, ("ahci: ALL SLOTS BUSY!"));
- }
+ if (ch->slot[tag].state == AHCI_SLOT_EMPTY)
+ break;
+ tag++;
+ };
ch->lastslot = tag;
/* Occupy chosen slot. */
slot = &ch->slot[tag];
@@ -1315,6 +1332,7 @@ ahci_begin_transaction(device_t dev, union ccb *ccb)
if (ch->numrslots == 0 && ch->pm_level > 3)
callout_stop(&ch->pm_timer);
/* Update channel stats. */
+ ch->oslots |= (1 << slot->slot);
ch->numrslots++;
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
(ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) {
@@ -1635,6 +1653,7 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et)
ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
}
/* Free slot. */
+ ch->oslots &= ~(1 << slot->slot);
ch->rslots &= ~(1 << slot->slot);
ch->aslots &= ~(1 << slot->slot);
slot->state = AHCI_SLOT_EMPTY;
@@ -1664,7 +1683,7 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et)
} else
xpt_done(ccb);
/* Unfreeze frozen command. */
- if (ch->frozen && ch->numrslots == 0) {
+ if (ch->frozen && !ahci_check_collision(dev, ch->frozen)) {
union ccb *fccb = ch->frozen;
ch->frozen = NULL;
ahci_begin_transaction(dev, fccb);
@@ -2125,10 +2144,22 @@ ahciaction(struct cam_sim *sim, union ccb *ccb)
case XPT_SET_TRAN_SETTINGS:
{
struct ccb_trans_settings *cts = &ccb->cts;
+ struct ahci_device *d;
- if (cts->xport_specific.sata.valid & CTS_SATA_VALID_PM) {
+ if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
+ d = &ch->curr[ccb->ccb_h.target_id];
+ else
+ d = &ch->user[ccb->ccb_h.target_id];
+ if (cts->xport_specific.sata.valid & CTS_SATA_VALID_REVISION)
+ d->revision = cts->xport_specific.sata.revision;
+ if (cts->xport_specific.sata.valid & CTS_SATA_VALID_MODE)
+ d->mode = cts->xport_specific.sata.mode;
+ if (cts->xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
+ d->bytecount = min(8192, cts->xport_specific.sata.bytecount);
+ if (cts->xport_specific.sata.valid & CTS_SATA_VALID_TAGS)
+ d->tags = min(ch->numslots, cts->xport_specific.sata.tags);
+ if (cts->xport_specific.sata.valid & CTS_SATA_VALID_PM)
ch->pm_present = cts->xport_specific.sata.pm_present;
- }
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
break;
@@ -2137,36 +2168,41 @@ ahciaction(struct cam_sim *sim, union ccb *ccb)
/* Get default/user set transfer settings for the target */
{
struct ccb_trans_settings *cts = &ccb->cts;
+ struct ahci_device *d;
uint32_t status;
+ if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
+ d = &ch->curr[ccb->ccb_h.target_id];
+ else
+ d = &ch->user[ccb->ccb_h.target_id];
cts->protocol = PROTO_ATA;
cts->protocol_version = PROTO_VERSION_UNSPECIFIED;
cts->transport = XPORT_SATA;
cts->transport_version = XPORT_VERSION_UNSPECIFIED;
cts->proto_specific.valid = 0;
cts->xport_specific.sata.valid = 0;
- if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
+ if (cts->type == CTS_TYPE_CURRENT_SETTINGS &&
+ (ccb->ccb_h.target_id == 15 ||
+ (ccb->ccb_h.target_id == 0 && !ch->pm_present))) {
status = ATA_INL(ch->r_mem, AHCI_P_SSTS) & ATA_SS_SPD_MASK;
- else
- status = ATA_INL(ch->r_mem, AHCI_P_SCTL) & ATA_SC_SPD_MASK;
- if (status & ATA_SS_SPD_GEN3) {
- cts->xport_specific.sata.bitrate = 600000;
- cts->xport_specific.sata.valid |= CTS_SATA_VALID_SPEED;
- } else if (status & ATA_SS_SPD_GEN2) {
- cts->xport_specific.sata.bitrate = 300000;
- cts->xport_specific.sata.valid |= CTS_SATA_VALID_SPEED;
- } else if (status & ATA_SS_SPD_GEN1) {
- cts->xport_specific.sata.bitrate = 150000;
- cts->xport_specific.sata.valid |= CTS_SATA_VALID_SPEED;
- }
- if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
- cts->xport_specific.sata.pm_present =
- (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_PMA) ?
- 1 : 0;
+ if (status & 0x0f0) {
+ cts->xport_specific.sata.revision =
+ (status & 0x0f0) >> 4;
+ cts->xport_specific.sata.valid |=
+ CTS_SATA_VALID_REVISION;
+ }
} else {
- cts->xport_specific.sata.pm_present = ch->pm_present;
+ cts->xport_specific.sata.revision = d->revision;
+ cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION;
}
+ cts->xport_specific.sata.mode = d->mode;
+ cts->xport_specific.sata.valid |= CTS_SATA_VALID_MODE;
+ cts->xport_specific.sata.bytecount = d->bytecount;
+ cts->xport_specific.sata.valid |= CTS_SATA_VALID_BYTECOUNT;
+ cts->xport_specific.sata.pm_present = ch->pm_present;
cts->xport_specific.sata.valid |= CTS_SATA_VALID_PM;
+ cts->xport_specific.sata.tags = d->tags;
+ cts->xport_specific.sata.valid |= CTS_SATA_VALID_TAGS;
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
break;
diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h
index cda9078..e4ae23c 100644
--- a/sys/dev/ahci/ahci.h
+++ b/sys/dev/ahci/ahci.h
@@ -340,6 +340,13 @@ struct ahci_slot {
struct callout timeout; /* Execution timeout */
};
+struct ahci_device {
+ u_int revision;
+ int mode;
+ u_int bytecount;
+ u_int tags;
+};
+
/* structure describing an ATA channel */
struct ahci_channel {
device_t dev; /* Device handle */
@@ -362,6 +369,7 @@ struct ahci_channel {
struct mtx mtx; /* state lock */
int devices; /* What is present */
int pm_present; /* PM presence reported */
+ uint32_t oslots; /* Occupied slots */
uint32_t rslots; /* Running slots */
uint32_t aslots; /* Slots with atomic commands */
int numrslots; /* Number of running slots */
@@ -372,6 +380,9 @@ struct ahci_channel {
int taggedtarget; /* Last tagged target */
union ccb *frozen; /* Frozen command */
struct callout pm_timer; /* Power management events */
+
+ struct ahci_device user[16]; /* User-specified settings */
+ struct ahci_device curr[16]; /* Current settings */
};
/* structure describing a AHCI controller */
diff --git a/sys/dev/siis/siis.c b/sys/dev/siis/siis.c
index 1693883..0ce8e01 100644
--- a/sys/dev/siis/siis.c
+++ b/sys/dev/siis/siis.c
@@ -415,12 +415,19 @@ siis_ch_attach(device_t dev)
{
struct siis_channel *ch = device_get_softc(dev);
struct cam_devq *devq;
- int rid, error;
+ int rid, error, i;
ch->dev = dev;
ch->unit = (intptr_t)device_get_ivars(dev);
resource_int_value(device_get_name(dev),
device_get_unit(dev), "pm_level", &ch->pm_level);
+ for (i = 0; i < 16; i++) {
+ ch->user[i].revision = 0;
+ ch->user[i].mode = 0;
+ ch->user[i].bytecount = 8192;
+ ch->user[i].tags = SIIS_MAX_SLOTS;
+ ch->curr[i] = ch->user[i];
+ }
resource_int_value(device_get_name(dev),
device_get_unit(dev), "sata_rev", &ch->sata_rev);
mtx_init(&ch->mtx, "SIIS channel lock", NULL, MTX_DEF);
@@ -833,6 +840,13 @@ siis_check_collision(device_t dev, union ccb *ccb)
mtx_assert(&ch->mtx, MA_OWNED);
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
+ (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) {
+ /* Tagged command while we have no supported tag free. */
+ if (((~ch->oslots) & (0x7fffffff >> (31 -
+ ch->curr[ccb->ccb_h.target_id].tags))) == 0)
+ return (1);
+ }
+ if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
(ccb->ataio.cmd.flags & (CAM_ATAIO_CONTROL | CAM_ATAIO_NEEDRESULT))) {
/* Atomic command while anything active. */
if (ch->numrslots != 0)
@@ -850,21 +864,20 @@ siis_begin_transaction(device_t dev, union ccb *ccb)
{
struct siis_channel *ch = device_get_softc(dev);
struct siis_slot *slot;
- int tag;
+ int tag, tags;
mtx_assert(&ch->mtx, MA_OWNED);
/* Choose empty slot. */
- tag = ch->lastslot;
- while (ch->slot[tag].state != SIIS_SLOT_EMPTY) {
- if (++tag >= SIIS_MAX_SLOTS)
- tag = 0;
- KASSERT(tag != ch->lastslot, ("siis: ALL SLOTS BUSY!"));
- }
- ch->lastslot = tag;
+ tags = SIIS_MAX_SLOTS;
+ if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
+ (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA))
+ tags = ch->curr[ccb->ccb_h.target_id].tags;
+ tag = fls((~ch->oslots) & (0x7fffffff >> (31 - tags))) - 1;
/* Occupy chosen slot. */
slot = &ch->slot[tag];
slot->ccb = ccb;
/* Update channel stats. */
+ ch->oslots |= (1 << slot->slot);
ch->numrslots++;
if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
(ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) {
@@ -1118,6 +1131,7 @@ siis_end_transaction(struct siis_slot *slot, enum siis_err_type et)
ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
}
/* Free slot. */
+ ch->oslots &= ~(1 << slot->slot);
ch->rslots &= ~(1 << slot->slot);
ch->aslots &= ~(1 << slot->slot);
if (et != SIIS_ERR_TIMEOUT) {
@@ -1143,7 +1157,7 @@ siis_end_transaction(struct siis_slot *slot, enum siis_err_type et)
} else
xpt_done(ccb);
/* Unfreeze frozen command. */
- if (ch->frozen && ch->numrslots == 0) {
+ if (ch->frozen && !siis_check_collision(dev, ch->frozen)) {
union ccb *fccb = ch->frozen;
ch->frozen = NULL;
siis_begin_transaction(dev, fccb);
@@ -1554,7 +1568,20 @@ siisaction(struct cam_sim *sim, union ccb *ccb)
case XPT_SET_TRAN_SETTINGS:
{
struct ccb_trans_settings *cts = &ccb->cts;
+ struct siis_device *d;
+ if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
+ d = &ch->curr[ccb->ccb_h.target_id];
+ else
+ d = &ch->user[ccb->ccb_h.target_id];
+ if (cts->xport_specific.sata.valid & CTS_SATA_VALID_REVISION)
+ d->revision = cts->xport_specific.sata.revision;
+ if (cts->xport_specific.sata.valid & CTS_SATA_VALID_MODE)
+ d->mode = cts->xport_specific.sata.mode;
+ if (cts->xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
+ d->bytecount = min(8192, cts->xport_specific.sata.bytecount);
+ if (cts->xport_specific.sata.valid & CTS_SATA_VALID_TAGS)
+ d->tags = min(SIIS_MAX_SLOTS, cts->xport_specific.sata.tags);
if (cts->xport_specific.sata.valid & CTS_SATA_VALID_PM) {
ch->pm_present = cts->xport_specific.sata.pm_present;
if (ch->pm_present)
@@ -1570,30 +1597,41 @@ siisaction(struct cam_sim *sim, union ccb *ccb)
/* Get default/user set transfer settings for the target */
{
struct ccb_trans_settings *cts = &ccb->cts;
+ struct siis_device *d;
uint32_t status;
+ if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
+ d = &ch->curr[ccb->ccb_h.target_id];
+ else
+ d = &ch->user[ccb->ccb_h.target_id];
cts->protocol = PROTO_ATA;
cts->protocol_version = PROTO_VERSION_UNSPECIFIED;
cts->transport = XPORT_SATA;
cts->transport_version = XPORT_VERSION_UNSPECIFIED;
cts->proto_specific.valid = 0;
cts->xport_specific.sata.valid = 0;
- if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
+ if (cts->type == CTS_TYPE_CURRENT_SETTINGS &&
+ (ccb->ccb_h.target_id == 15 ||
+ (ccb->ccb_h.target_id == 0 && !ch->pm_present))) {
status = ATA_INL(ch->r_mem, SIIS_P_SSTS) & ATA_SS_SPD_MASK;
- else
- status = ATA_INL(ch->r_mem, SIIS_P_SCTL) & ATA_SC_SPD_MASK;
- if (status & ATA_SS_SPD_GEN3) {
- cts->xport_specific.sata.bitrate = 600000;
- cts->xport_specific.sata.valid |= CTS_SATA_VALID_SPEED;
- } else if (status & ATA_SS_SPD_GEN2) {
- cts->xport_specific.sata.bitrate = 300000;
- cts->xport_specific.sata.valid |= CTS_SATA_VALID_SPEED;
- } else if (status & ATA_SS_SPD_GEN1) {
- cts->xport_specific.sata.bitrate = 150000;
- cts->xport_specific.sata.valid |= CTS_SATA_VALID_SPEED;
+ if (status & 0x0f0) {
+ cts->xport_specific.sata.revision =
+ (status & 0x0f0) >> 4;
+ cts->xport_specific.sata.valid |=
+ CTS_SATA_VALID_REVISION;
+ }
+ } else {
+ cts->xport_specific.sata.revision = d->revision;
+ cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION;
}
+ cts->xport_specific.sata.mode = d->mode;
+ cts->xport_specific.sata.valid |= CTS_SATA_VALID_MODE;
+ cts->xport_specific.sata.bytecount = d->bytecount;
+ cts->xport_specific.sata.valid |= CTS_SATA_VALID_BYTECOUNT;
cts->xport_specific.sata.pm_present = ch->pm_present;
cts->xport_specific.sata.valid |= CTS_SATA_VALID_PM;
+ cts->xport_specific.sata.tags = d->tags;
+ cts->xport_specific.sata.valid |= CTS_SATA_VALID_TAGS;
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
break;
diff --git a/sys/dev/siis/siis.h b/sys/dev/siis/siis.h
index 20de88f..6bb28d9 100644
--- a/sys/dev/siis/siis.h
+++ b/sys/dev/siis/siis.h
@@ -346,6 +346,13 @@ struct siis_slot {
struct callout timeout; /* Execution timeout */
};
+struct siis_device {
+ u_int revision;
+ int mode;
+ u_int bytecount;
+ u_int tags;
+};
+
/* structure describing an ATA channel */
struct siis_channel {
device_t dev; /* Device handle */
@@ -364,6 +371,7 @@ struct siis_channel {
struct mtx mtx; /* state lock */
int devices; /* What is present */
int pm_present; /* PM presence reported */
+ uint32_t oslots; /* Occupied slots */
uint32_t rslots; /* Running slots */
uint32_t aslots; /* Slots with atomic commands */
uint32_t eslots; /* Slots in error */
@@ -374,8 +382,10 @@ struct siis_channel {
int readlog; /* Our READ LOG active */
int fatalerr; /* Fatal error happend */
int recovery; /* Some slots are in error */
- int lastslot; /* Last used slot */
union ccb *frozen; /* Frozen command */
+
+ struct siis_device user[16]; /* User-specified settings */
+ struct siis_device curr[16]; /* Current settings */
};
/* structure describing a SIIS controller */
OpenPOWER on IntegriCloud