Separate the parallel scsi knowledge out of the core of the XPT, and

modularize it so that new transports can be created.

Add a transport for SATA

Add a periph+protocol layer for ATA

Add a driver for AHCI-compliant hardware.

Add a maxio field to CAM so that drivers can advertise their max
I/O capability.  Modify various drivers so that they are insulated
from the value of MAXPHYS.

The new ATA/SATA code supports AHCI-compliant hardware, and will override
the classic ATA driver if it is loaded as a module at boot time or compiled
into the kernel.  The stack now support NCQ (tagged queueing) for increased
performance on modern SATA drives.  It also supports port multipliers.

ATA drives are accessed via 'ada' device nodes.  ATAPI drives are
accessed via 'cd' device nodes.  They can all be enumerated and manipulated
via camcontrol, just like SCSI drives.  SCSI commands are not translated to
their ATA equivalents; ATA native commands are used throughout the entire
stack, including camcontrol.  See the camcontrol manpage for further
details.  Testing this code may require that you update your fstab, and
possibly modify your BIOS to enable AHCI functionality, if available.

This code is very experimental at the moment.  The userland ABI/API has
changed, so applications will need to be recompiled.  It may change
further in the near future.  The 'ada' device name may also change as
more infrastructure is completed in this project.  The goal is to
eventually put all CAM busses and devices until newbus, allowing for
interesting topology and management options.

Few functional changes will be seen with existing SCSI/SAS/FC drivers,
though the userland ABI has still changed.  In the future, transports
specific modules for SAS and FC may appear in order to better support
the topologies and capabilities of these technologies.

The modularization of CAM and the addition of the ATA/SATA modules is
meant to break CAM out of the mold of being specific to SCSI, letting it
grow to be a framework for arbitrary transports and protocols.  It also
allows drivers to be written to support discrete hardware without
jeopardizing the stability of non-related hardware.  While only an AHCI
driver is provided now, a Silicon Image driver is also in the works.
Drivers for ICH1-4, ICH5-6, PIIX, classic IDE, and any other hardware
is possible and encouraged.  Help with new transports is also encouraged.

Submitted by:	scottl, mav
Approved by:	re
This commit is contained in:
Scott Long 2009-07-10 08:18:08 +00:00
parent f6c09dd6a8
commit 52c9ce25d8
51 changed files with 9094 additions and 2506 deletions

View File

@ -78,6 +78,8 @@
..
..
cam
ata
..
scsi
..
..

View File

@ -38,7 +38,7 @@ LDIRS= bsm cam geom net net80211 netatalk netgraph netinet netinet6 \
nfs nfsclient nfsserver \
sys vm
LSUBDIRS= cam/scsi \
LSUBDIRS= cam/ata cam/scsi \
dev/acpica dev/an dev/bktr dev/firewire dev/hwpmc \
dev/ic dev/iicbus ${_dev_ieee488} dev/lmc dev/ofw \
dev/pbio ${_dev_powermac_nvram} dev/ppbus dev/smbus \

View File

@ -2,7 +2,8 @@
LIB= cam
SHLIBDIR?= /lib
SRCS= camlib.c scsi_cmdparse.c scsi_all.c scsi_da.c scsi_sa.c cam.c
SRCS= camlib.c scsi_cmdparse.c scsi_all.c scsi_da.c scsi_sa.c cam.c \
ata_all.c
INCS= camlib.h
DPADD= ${LIBSBUF}
@ -34,7 +35,8 @@ MLINKS+= cam.3 cam_open_device.3 \
cam_cdbparse.3 csio_encode_visit.3 \
cam_cdbparse.3 buff_encode_visit.3
.PATH: ${.CURDIR}/../../sys/cam/scsi ${.CURDIR}/../../sys/cam
.PATH: ${.CURDIR}/../../sys/cam/scsi ${.CURDIR}/../../sys/cam/ata \
${.CURDIR}/../../sys/cam
SDIR= ${.CURDIR}/../../sys
CFLAGS+= -I${.CURDIR} -I${SDIR}

View File

@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd August 21, 2006
.Dd June 29, 2009
.Dt CAMCONTROL 8
.Os
.Sh NAME
@ -59,6 +59,10 @@
.Op Fl S
.Op Fl R
.Nm
.Ic identify
.Op device id
.Op generic args
.Nm
.Ic reportluns
.Op device id
.Op generic args
@ -283,6 +287,8 @@ This is to aid in script writing.
.It Fl R
Print out transfer rate information.
.El
.It Ic identify
Send a ATA identify command (0xec) to a device.
.It Ic reportluns
Send the SCSI REPORT LUNS (0xA0) command to the given device.
By default,

View File

@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ioctl.h>
#include <sys/stdint.h>
#include <sys/types.h>
#include <sys/endian.h>
#include <stdio.h>
#include <stdlib.h>
@ -49,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <cam/scsi/scsi_da.h>
#include <cam/scsi/scsi_pass.h>
#include <cam/scsi/scsi_message.h>
#include <cam/ata/ata_all.h>
#include <camlib.h>
#include "camcontrol.h"
@ -71,7 +73,8 @@ typedef enum {
CAM_CMD_RATE = 0x0000000f,
CAM_CMD_DETACH = 0x00000010,
CAM_CMD_REPORTLUNS = 0x00000011,
CAM_CMD_READCAP = 0x00000012
CAM_CMD_READCAP = 0x00000012,
CAM_CMD_IDENTIFY = 0x00000013
} cam_cmdmask;
typedef enum {
@ -126,6 +129,7 @@ struct camcontrol_opts option_table[] = {
#ifndef MINIMALISTIC
{"tur", CAM_CMD_TUR, CAM_ARG_NONE, NULL},
{"inquiry", CAM_CMD_INQUIRY, CAM_ARG_NONE, "DSR"},
{"identify", CAM_CMD_IDENTIFY, CAM_ARG_NONE, NULL},
{"start", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT, NULL},
{"stop", CAM_CMD_STARTSTOP, CAM_ARG_NONE, NULL},
{"load", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT | CAM_ARG_EJECT, NULL},
@ -401,19 +405,35 @@ getdevtree(void)
} else
skip_device = 0;
cam_strvis(vendor, dev_result->inq_data.vendor,
if (dev_result->protocol == PROTO_SCSI) {
cam_strvis(vendor, dev_result->inq_data.vendor,
sizeof(dev_result->inq_data.vendor),
sizeof(vendor));
cam_strvis(product,
cam_strvis(product,
dev_result->inq_data.product,
sizeof(dev_result->inq_data.product),
sizeof(product));
cam_strvis(revision,
cam_strvis(revision,
dev_result->inq_data.revision,
sizeof(dev_result->inq_data.revision),
sizeof(revision));
sprintf(tmpstr, "<%s %s %s>", vendor, product,
sprintf(tmpstr, "<%s %s %s>", vendor, product,
revision);
} else if (dev_result->protocol == PROTO_ATA ||
dev_result->protocol == PROTO_SATAPM) {
cam_strvis(product,
dev_result->ident_data.model,
sizeof(dev_result->ident_data.model),
sizeof(product));
cam_strvis(revision,
dev_result->ident_data.revision,
sizeof(dev_result->ident_data.revision),
sizeof(revision));
sprintf(tmpstr, "<%s %s>", product,
revision);
} else {
sprintf(tmpstr, "<>");
}
if (need_close) {
fprintf(stdout, ")\n");
need_close = 0;
@ -899,6 +919,14 @@ scsixferrate(struct cam_device *device)
if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
freq = scsi_calc_syncsrate(spi->sync_period);
speed = freq;
} else {
struct ccb_pathinq cpi;
retval = get_cpi(device, &cpi);
if (retval == 0) {
speed = cpi.base_transfer_speed;
freq = 0;
}
}
fprintf(stdout, "%s%d: ", device->device_name,
@ -974,6 +1002,224 @@ scsixferrate(struct cam_device *device)
return(retval);
}
static void
atacapprint(struct ata_params *parm)
{
u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
((u_int32_t)parm->lba_size_2 << 16);
u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
((u_int64_t)parm->lba_size48_2 << 16) |
((u_int64_t)parm->lba_size48_3 << 32) |
((u_int64_t)parm->lba_size48_4 << 48);
printf("\n");
printf("Protocol ");
if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
if (parm->satacapabilities & ATA_SATA_GEN2)
printf("SATA revision 2.x\n");
else if (parm->satacapabilities & ATA_SATA_GEN1)
printf("SATA revision 1.x\n");
else
printf("Unknown SATA revision\n");
}
else
printf("ATA/ATAPI revision %d\n", ata_version(parm->version_major));
printf("device model %.40s\n", parm->model);
printf("serial number %.20s\n", parm->serial);
printf("firmware revision %.8s\n", parm->revision);
printf("cylinders %d\n", parm->cylinders);
printf("heads %d\n", parm->heads);
printf("sectors/track %d\n", parm->sectors);
if (parm->config == ATA_PROTO_CFA ||
(parm->support.command2 & ATA_SUPPORT_CFA))
printf("CFA supported\n");
printf("lba%ssupported ",
parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
if (lbasize)
printf("%d sectors\n", lbasize);
else
printf("\n");
printf("lba48%ssupported ",
parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
if (lbasize48)
printf("%ju sectors\n", (uintmax_t)lbasize48);
else
printf("\n");
printf("dma%ssupported\n",
parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
printf("overlap%ssupported\n",
parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
printf("\nFeature "
"Support Enable Value Vendor\n");
printf("write cache %s %s\n",
parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
printf("read ahead %s %s\n",
parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
printf("Native Command Queuing (NCQ) %s %s"
" %d/0x%02X\n",
parm->satacapabilities & ATA_SUPPORT_NCQ ?
"yes" : "no", " -",
(parm->satacapabilities & ATA_SUPPORT_NCQ) ?
ATA_QUEUE_LEN(parm->queue) : 0,
(parm->satacapabilities & ATA_SUPPORT_NCQ) ?
ATA_QUEUE_LEN(parm->queue) : 0);
}
printf("Tagged Command Queuing (TCQ) %s %s %d/0x%02X\n",
parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue));
printf("SMART %s %s\n",
parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
printf("microcode download %s %s\n",
parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
printf("security %s %s\n",
parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
printf("power management %s %s\n",
parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
printf("advanced power management %s %s %d/0x%02X\n",
parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no",
parm->apm_value, parm->apm_value);
printf("automatic acoustic management %s %s "
"%d/0x%02X %d/0x%02X\n",
parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
ATA_ACOUSTIC_CURRENT(parm->acoustic),
ATA_ACOUSTIC_CURRENT(parm->acoustic),
ATA_ACOUSTIC_VENDOR(parm->acoustic),
ATA_ACOUSTIC_VENDOR(parm->acoustic));
}
static int
ataidentify(struct cam_device *device, int retry_count, int timeout)
{
union ccb *ccb;
struct ata_params *ident_buf;
int error = 0;
int16_t *ptr;
ccb = cam_getccb(device);
if (ccb == NULL) {
warnx("couldn't allocate CCB");
return(1);
}
/* cam_getccb cleans up the header, caller has to zero the payload */
bzero(&(&ccb->ccb_h)[1],
sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr));
ident_buf = (struct ata_params *)malloc(
sizeof(struct ata_params));
if (ident_buf == NULL) {
cam_freeccb(ccb);
warnx("can't malloc memory for identify\n");
return(1);
}
bzero(ident_buf, sizeof(*ident_buf));
cam_fill_ataio(&ccb->ataio,
retry_count,
NULL,
/*flags*/CAM_DIR_IN,
MSG_SIMPLE_Q_TAG,
/*data_ptr*/(u_int8_t *)ident_buf,
/*dxfer_len*/sizeof(struct ata_params),
timeout ? timeout : 30 * 1000);
// if (periph->path->device->protocol == PROTO_ATA)
ata_36bit_cmd(&ccb->ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
// else
// ata_36bit_cmd(&ccb->ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
/* Disable freezing the device queue */
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
if (arglist & CAM_ARG_ERR_RECOVER)
ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
if (cam_send_ccb(device, ccb) < 0) {
perror("error sending ATA identify");
if (arglist & CAM_ARG_VERBOSE) {
cam_error_print(device, ccb, CAM_ESF_ALL,
CAM_EPF_ALL, stderr);
}
cam_freeccb(ccb);
return(1);
}
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
error = 1;
if (arglist & CAM_ARG_VERBOSE) {
cam_error_print(device, ccb, CAM_ESF_ALL,
CAM_EPF_ALL, stderr);
}
}
cam_freeccb(ccb);
if (error != 0) {
free(ident_buf);
return(error);
}
for (ptr = (int16_t *)ident_buf;
ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) {
*ptr = le16toh(*ptr);
}
if (strncmp(ident_buf->model, "FX", 2) &&
strncmp(ident_buf->model, "NEC", 3) &&
strncmp(ident_buf->model, "Pioneer", 7) &&
strncmp(ident_buf->model, "SHARP", 5)) {
ata_bswap(ident_buf->model, sizeof(ident_buf->model));
ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
}
ata_btrim(ident_buf->model, sizeof(ident_buf->model));
ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
fprintf(stdout, "%s%d: ", device->device_name,
device->dev_unit_num);
ata_print_ident(ident_buf);
atacapprint(ident_buf);
free(ident_buf);
return(0);
}
#endif /* MINIMALISTIC */
/*
@ -3675,6 +3921,7 @@ usage(int verbose)
" camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n"
" camcontrol tur [dev_id][generic args]\n"
" camcontrol inquiry [dev_id][generic args] [-D] [-S] [-R]\n"
" camcontrol identify [dev_id][generic args]\n"
" camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n"
" camcontrol readcap [dev_id][generic args] [-b] [-h] [-H] [-N]\n"
" [-q] [-s]\n"
@ -3710,6 +3957,7 @@ usage(int verbose)
"periphlist list all CAM peripheral drivers attached to a device\n"
"tur send a test unit ready to the named device\n"
"inquiry send a SCSI inquiry command to the named device\n"
"identify send a ATA identify command to the named device\n"
"reportluns send a SCSI report luns command to the device\n"
"readcap send a SCSI read capacity command to the device\n"
"start send a Start Unit command to the device\n"
@ -4035,6 +4283,9 @@ main(int argc, char **argv)
error = scsidoinquiry(cam_dev, argc, argv, combinedopt,
retry_count, timeout);
break;
case CAM_CMD_IDENTIFY:
error = ataidentify(cam_dev, retry_count, timeout);
break;
case CAM_CMD_STARTSTOP:
error = scsistart(cam_dev, arglist & CAM_ARG_START_UNIT,
arglist & CAM_ARG_EJECT, retry_count,

View File

@ -23,6 +23,7 @@ MAN= aac.4 \
aha.4 \
ahb.4 \
ahc.4 \
ahci.4 \
ahd.4 \
aio.4 \
alc.4 \

132
share/man/man4/ahci.4 Normal file
View File

@ -0,0 +1,132 @@
.\" Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd June 26, 2009
.Dt AHCI 4
.Os
.Sh NAME
.Nm ahci
.Nd Serial ATA Advanced Host Controller Interface driver
.Sh SYNOPSIS
To compile this driver into the kernel,
place the following lines in your
kernel configuration file:
.Bd -ragged -offset indent
.Cd "device pci"
.Cd "device scbus"
.Cd "device ahci"
.Ed
.Pp
Alternatively, to load the driver as a
module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
ahci_load="YES"
.Ed
.Pp
The following tunables are settable from the loader:
.Bl -ohang
.It Va hint.ahci.X.msi
controls Message Signaled Interrupts (MSI) usage by the specified controller
.Bl -tag -compact
.It 0
MSI disabled;
.It 1
single MSI vector used, if supported (default);
.It 2
multiple MSI vectors used, if supported;
.El
.It Va hint.ahcich.X.pm_level
controls SATA interface Power Management for specified channel,
allowing some power to be saved at the cost of additional command
latency.
Possible values:
.Bl -tag -compact
.It 0
interface Power Management is disabled (default);
.It 1
device is allowed to initiate PM state change, host is passive;
.It 2
host initiates PARTIAL PM state transition every time port becomes idle;
.It 3
host initiates SLUMBER PM state transition every time port becomes idle.
.El
Note that interface Power Management is not compatible with
device presence detection.
You will have to reset bus manually on device hot-plug.
.It Va hint.ahcich.X.sata_rev
setting to nonzero value limits maximum SATA revision (speed).
Values 1, 2 and 3 are respectively 1.5, 3 and 6Gbps.
.El
.Sh DESCRIPTION
This driver provides the CAM subsystem with native access to the
.Tn SATA
ports of AHCI-compatible controllers.
Each SATA port found is represented to CAM as a separate bus with one
target, or, if HBA supports Port Multipliers, 15 targets.
Most of the bus-management details are handled by the SATA-specific
transport of CAM.
Connected ATA disks are handled by the ATA protocol disk peripheral driver
.Xr ada 4 .
ATAPI devices are handled by the SCSI protocol peripheral drivers
.Xr cd 4 ,
.Xr da 4 ,
.Xr sa 4 ,
etc.
.Pp
Driver features include support for Serial ATA and ATAPI devices,
Port Multipliers, hardware command queues (up to 32 commands per port),
Native Command Queuing, SATA interface Power Management, device hot-plug
and Message Signaled Interrupts.
.Pp
The Port Multiplier FIS Based Switching feature added in the AHCI 1.2
specification, which is required for effective parallel operation of devices
behind Port Multipliers, is not yet supported.
.Pp
AHCI hardware is also supported by ataahci driver from
.Xr ata 4
subsystem. If both drivers are loaded at the same time, this one will be
given precedence as the more functional of the two.
.Sh HARDWARE
The
.Nm
driver supports AHCI compatible controllers having PCI class 1 (mass storage),
subclass 6 (SATA) and programming interface 1 (AHCI).
.Sh SEE ALSO
.Xr ada 4 ,
.Xr cd 4 ,
.Xr da 4 ,
.Xr sa 4 ,
.Xr scsi 4 ,
.Xr ata 4
.Sh HISTORY
The
.Nm
driver first appeared in
.Fx 8.0 .
.Sh AUTHORS
.An Alexander Motin Aq mav@FreeBSD.org .

304
sys/cam/ata/ata_all.c Normal file
View File

@ -0,0 +1,304 @@
/*-
* Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#ifdef _KERNEL
#include <opt_scsi.h>
#include <sys/systm.h>
#include <sys/libkern.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#else
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
#endif
#endif
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_queue.h>
#include <cam/cam_xpt.h>
#include <sys/ata.h>
#include <cam/ata/ata_all.h>
#include <sys/sbuf.h>
#include <sys/endian.h>
int
ata_version(int ver)
{
int bit;
if (ver == 0xffff)
return 0;
for (bit = 15; bit >= 0; bit--)
if (ver & (1<<bit))
return bit;
return 0;
}
void
ata_print_ident(struct ata_params *ident_data)
{
char product[48], revision[16];
cam_strvis(product, ident_data->model, sizeof(ident_data->model),
sizeof(product));
cam_strvis(revision, ident_data->revision, sizeof(ident_data->revision),
sizeof(revision));
printf("<%s %s> ATA/ATAPI-%d",
product, revision, ata_version(ident_data->version_major));
if (ident_data->satacapabilities && ident_data->satacapabilities != 0xffff) {
if (ident_data->satacapabilities & ATA_SATA_GEN2)
printf(" SATA 2.x");
else if (ident_data->satacapabilities & ATA_SATA_GEN1)
printf(" SATA 1.x");
else
printf(" SATA");
}
printf(" device\n");
}
void
ata_36bit_cmd(struct ccb_ataio *ataio, uint8_t cmd, uint8_t features,
uint32_t lba, uint8_t sector_count)
{
bzero(&ataio->cmd, sizeof(ataio->cmd));
ataio->cmd.flags = 0;
ataio->cmd.command = cmd;
ataio->cmd.features = features;
ataio->cmd.lba_low = lba;
ataio->cmd.lba_mid = lba >> 8;
ataio->cmd.lba_high = lba >> 16;
ataio->cmd.device = 0x40 | ((lba >> 24) & 0x0f);
ataio->cmd.sector_count = sector_count;
}
void
ata_48bit_cmd(struct ccb_ataio *ataio, uint8_t cmd, uint16_t features,
uint64_t lba, uint16_t sector_count)
{
bzero(&ataio->cmd, sizeof(ataio->cmd));
ataio->cmd.flags = CAM_ATAIO_48BIT;
ataio->cmd.command = cmd;
ataio->cmd.features = features;
ataio->cmd.lba_low = lba;
ataio->cmd.lba_mid = lba >> 8;
ataio->cmd.lba_high = lba >> 16;
ataio->cmd.device = 0x40;
ataio->cmd.lba_low_exp = lba >> 24;
ataio->cmd.lba_mid_exp = lba >> 32;
ataio->cmd.lba_high_exp = lba >> 40;
ataio->cmd.features_exp = features >> 8;
ataio->cmd.sector_count = sector_count;
ataio->cmd.sector_count_exp = sector_count >> 8;
}
void
ata_ncq_cmd(struct ccb_ataio *ataio, uint8_t cmd,
uint64_t lba, uint16_t sector_count)
{
bzero(&ataio->cmd, sizeof(ataio->cmd));
ataio->cmd.flags = CAM_ATAIO_48BIT | CAM_ATAIO_FPDMA;
ataio->cmd.command = cmd;
ataio->cmd.features = sector_count;
ataio->cmd.lba_low = lba;
ataio->cmd.lba_mid = lba >> 8;
ataio->cmd.lba_high = lba >> 16;
ataio->cmd.device = 0x40;
ataio->cmd.lba_low_exp = lba >> 24;
ataio->cmd.lba_mid_exp = lba >> 32;
ataio->cmd.lba_high_exp = lba >> 40;
ataio->cmd.features_exp = sector_count >> 8;
}
void
ata_reset_cmd(struct ccb_ataio *ataio)
{
bzero(&ataio->cmd, sizeof(ataio->cmd));
ataio->cmd.flags = CAM_ATAIO_CONTROL | CAM_ATAIO_NEEDRESULT;
ataio->cmd.control = 0x04;
}
void
ata_pm_read_cmd(struct ccb_ataio *ataio, int reg, int port)
{
bzero(&ataio->cmd, sizeof(ataio->cmd));
ataio->cmd.flags = CAM_ATAIO_48BIT | CAM_ATAIO_NEEDRESULT;
ataio->cmd.command = ATA_READ_PM;
ataio->cmd.features = reg;
ataio->cmd.features_exp = reg >> 8;
ataio->cmd.device = port & 0x0f;
}
void
ata_pm_write_cmd(struct ccb_ataio *ataio, int reg, int port, uint64_t val)
{
bzero(&ataio->cmd, sizeof(ataio->cmd));
ataio->cmd.flags = CAM_ATAIO_48BIT | CAM_ATAIO_NEEDRESULT;
ataio->cmd.command = ATA_WRITE_PM;
ataio->cmd.features = reg;
ataio->cmd.lba_low = val >> 8;
ataio->cmd.lba_mid = val >> 16;
ataio->cmd.lba_high = val >> 24;
ataio->cmd.device = port & 0x0f;
ataio->cmd.lba_low_exp = val >> 40;
ataio->cmd.lba_mid_exp = val >> 48;
ataio->cmd.lba_high_exp = val >> 56;
ataio->cmd.features_exp = reg >> 8;
ataio->cmd.sector_count = val;
ataio->cmd.sector_count_exp = val >> 32;
}
void
ata_bswap(int8_t *buf, int len)
{
u_int16_t *ptr = (u_int16_t*)(buf + len);
while (--ptr >= (u_int16_t*)buf)
*ptr = be16toh(*ptr);
}
void
ata_btrim(int8_t *buf, int len)
{
int8_t *ptr;
for (ptr = buf; ptr < buf+len; ++ptr)
if (!*ptr || *ptr == '_')
*ptr = ' ';
for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr)
*ptr = 0;
}
void
ata_bpack(int8_t *src, int8_t *dst, int len)
{
int i, j, blank;
for (i = j = blank = 0 ; i < len; i++) {
if (blank && src[i] == ' ') continue;
if (blank && src[i] != ' ') {
dst[j++] = src[i];
blank = 0;
continue;
}
if (src[i] == ' ') {
blank = 1;
if (i == 0)
continue;
}
dst[j++] = src[i];
}
while (j < len)
dst[j++] = 0x00;
}
int
ata_max_pmode(struct ata_params *ap)
{
if (ap->atavalid & ATA_FLAG_64_70) {
if (ap->apiomodes & 0x02)
return ATA_PIO4;
if (ap->apiomodes & 0x01)
return ATA_PIO3;
}
if (ap->mwdmamodes & 0x04)
return ATA_PIO4;
if (ap->mwdmamodes & 0x02)
return ATA_PIO3;
if (ap->mwdmamodes & 0x01)
return ATA_PIO2;
if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x200)
return ATA_PIO2;
if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x100)
return ATA_PIO1;
if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x000)
return ATA_PIO0;
return ATA_PIO0;
}
int
ata_max_wmode(struct ata_params *ap)
{
if (ap->mwdmamodes & 0x04)
return ATA_WDMA2;
if (ap->mwdmamodes & 0x02)
return ATA_WDMA1;
if (ap->mwdmamodes & 0x01)
return ATA_WDMA0;
return -1;
}
int
ata_max_umode(struct ata_params *ap)
{
if (ap->atavalid & ATA_FLAG_88) {
if (ap->udmamodes & 0x40)
return ATA_UDMA6;
if (ap->udmamodes & 0x20)
return ATA_UDMA5;
if (ap->udmamodes & 0x10)
return ATA_UDMA4;
if (ap->udmamodes & 0x08)
return ATA_UDMA3;
if (ap->udmamodes & 0x04)
return ATA_UDMA2;
if (ap->udmamodes & 0x02)
return ATA_UDMA1;
if (ap->udmamodes & 0x01)
return ATA_UDMA0;
}
return -1;
}
int
ata_max_mode(struct ata_params *ap, int mode, int maxmode)
{
if (maxmode && mode > maxmode)
mode = maxmode;
if (mode >= ATA_UDMA0 && ata_max_umode(ap) > 0)
return (min(mode, ata_max_umode(ap)));
if (mode >= ATA_WDMA0 && ata_max_wmode(ap) > 0)
return (min(mode, ata_max_wmode(ap)));
if (mode > ata_max_pmode(ap))
return (min(mode, ata_max_pmode(ap)));
return (mode);
}

105
sys/cam/ata/ata_all.h Normal file
View File

@ -0,0 +1,105 @@
/*-
* Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef CAM_ATA_ALL_H
#define CAM_ATA_ALL_H 1
#include <sys/ata.h>
struct ccb_ataio;
struct cam_periph;
union ccb;
struct ata_cmd {
u_int8_t flags; /* ATA command flags */
#define CAM_ATAIO_48BIT 0x01 /* Command has 48-bit format */
#define CAM_ATAIO_FPDMA 0x02 /* FPDMA command */
#define CAM_ATAIO_CONTROL 0x04 /* Control, not a command */
#define CAM_ATAIO_NEEDRESULT 0x08 /* Request requires result. */
u_int8_t command;
u_int8_t features;
u_int8_t lba_low;
u_int8_t lba_mid;
u_int8_t lba_high;
u_int8_t device;
u_int8_t lba_low_exp;
u_int8_t lba_mid_exp;
u_int8_t lba_high_exp;
u_int8_t features_exp;
u_int8_t sector_count;
u_int8_t sector_count_exp;
u_int8_t control;
};
struct ata_res {
u_int8_t flags; /* ATA command flags */
#define CAM_ATAIO_48BIT 0x01 /* Command has 48-bit format */
u_int8_t status;
u_int8_t error;
u_int8_t lba_low;
u_int8_t lba_mid;
u_int8_t lba_high;
u_int8_t device;
u_int8_t lba_low_exp;
u_int8_t lba_mid_exp;
u_int8_t lba_high_exp;
u_int8_t sector_count;
u_int8_t sector_count_exp;
};
int ata_version(int ver);
void ata_print_ident(struct ata_params *ident_data);
void ata_36bit_cmd(struct ccb_ataio *ataio, uint8_t cmd, uint8_t features,
uint32_t lba, uint8_t sector_count);
void ata_48bit_cmd(struct ccb_ataio *ataio, uint8_t cmd, uint16_t features,
uint64_t lba, uint16_t sector_count);
void ata_ncq_cmd(struct ccb_ataio *ataio, uint8_t cmd,
uint64_t lba, uint16_t sector_count);
void ata_reset_cmd(struct ccb_ataio *ataio);
void ata_pm_read_cmd(struct ccb_ataio *ataio, int reg, int port);
void ata_pm_write_cmd(struct ccb_ataio *ataio, int reg, int port, uint64_t val);
void ata_bswap(int8_t *buf, int len);
void ata_btrim(int8_t *buf, int len);
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);
#endif

1144
sys/cam/ata/ata_da.c Normal file

File diff suppressed because it is too large Load Diff

1895
sys/cam/ata/ata_xpt.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#ifdef _KERNEL
#include <sys/libkern.h>
#include <cam/cam_queue.h>
#include <cam/cam_xpt.h>
#endif
@ -81,6 +82,7 @@ const struct cam_status_entry cam_status_table[] = {
{ CAM_UNREC_HBA_ERROR, "Unrecoverable Host Bus Adapter Error" },
{ CAM_REQ_TOO_BIG, "The request was too large for this host" },
{ CAM_REQUEUE_REQ, "Unconditionally Re-queue Request", },
{ CAM_ATA_STATUS_ERROR, "ATA Status Error" },
{ CAM_IDE, "Initiator Detected Error Message Received" },
{ CAM_RESRC_UNAVAIL, "Resource Unavailable" },
{ CAM_UNACKED_EVENT, "Unacknowledged Event by Host" },

View File

@ -129,6 +129,7 @@ typedef enum {
* requests for the target at the sim level
* back into the XPT queue.
*/
CAM_ATA_STATUS_ERROR, /* ATA error, look at error code in CCB */
CAM_SCSI_IT_NEXUS_LOST, /* Initiator/Target Nexus lost. */
CAM_IDE = 0x33, /* Initiator Detected Error */
CAM_RESRC_UNAVAIL, /* Resource Unavailable */

View File

@ -40,6 +40,7 @@
#endif
#include <cam/cam_debug.h>
#include <cam/scsi/scsi_all.h>
#include <cam/ata/ata_all.h>
/* General allocation length definitions for CCB structures */
@ -169,6 +170,8 @@ typedef enum {
* a device give the sector size and
* volume size.
*/
XPT_ATA_IO = 0x18 | XPT_FC_DEV_QUEUED,
/* Execute the requested ATA I/O operation */
/* HBA engine commands 0x20->0x2F */
XPT_ENG_INQ = 0x20 | XPT_FC_XPT_ONLY,
@ -213,6 +216,7 @@ typedef enum {
PROTO_SCSI, /* Small Computer System Interface */
PROTO_ATA, /* AT Attachment */
PROTO_ATAPI, /* AT Attachment Packetized Interface */
PROTO_SATAPM, /* SATA Port Multiplier */
} cam_proto;
typedef enum {
@ -225,6 +229,7 @@ typedef enum {
XPORT_PPB, /* Parallel Port Bus */
XPORT_ATA, /* AT Attachment */
XPORT_SAS, /* Serial Attached SCSI */
XPORT_SATA, /* Serial AT Attachment */
} cam_xport;
#define PROTO_VERSION_UNKNOWN (UINT_MAX - 1)
@ -284,7 +289,9 @@ struct ccb_hdr {
/* Get Device Information CCB */
struct ccb_getdev {
struct ccb_hdr ccb_h;
cam_proto protocol;
struct scsi_inquiry_data inq_data;
struct ata_params ident_data;
u_int8_t serial_num[252];
u_int8_t reserved;
u_int8_t serial_num_len;
@ -412,7 +419,9 @@ struct device_match_result {
path_id_t path_id;
target_id_t target_id;
lun_id_t target_lun;
cam_proto protocol;
struct scsi_inquiry_data inq_data;
struct ata_params ident_data;
dev_result_flags flags;
};
@ -495,6 +504,7 @@ typedef enum {
PI_WIDE_16 = 0x20, /* Supports 16 bit wide SCSI */
PI_SDTR_ABLE = 0x10, /* Supports SDTR message */
PI_LINKED_CDB = 0x08, /* Supports linked CDBs */
PI_SATAPM = 0x04, /* Supports SATA PM */
PI_TAG_ABLE = 0x02, /* Supports tag queue messages */
PI_SOFT_RST = 0x01 /* Supports soft reset alternative */
} pi_inqflag;
@ -562,6 +572,7 @@ struct ccb_pathinq {
struct ccb_pathinq_settings_sas sas;
char ccb_pathinq_settings_opaque[PATHINQ_SETTINGS_SIZE];
} xport_specific;
u_int maxio; /* Max supported I/O size, in bytes. */
};
/* Path Statistics CCB */
@ -617,6 +628,28 @@ struct ccb_scsiio {
u_int init_id; /* initiator id of who selected */
};
/*
* ATA I/O Request CCB used for the XPT_ATA_IO function code.
*/
struct ccb_ataio {
struct ccb_hdr ccb_h;
union ccb *next_ccb; /* Ptr for next CCB for action */
struct ata_cmd cmd; /* ATA command register set */
struct ata_res res; /* ATA result register set */
u_int8_t *data_ptr; /* Ptr to the data buf/SG list */
u_int32_t dxfer_len; /* Data transfer length */
u_int32_t resid; /* Transfer residual length: 2's comp */
u_int8_t tag_action; /* What to do for tag queueing */
/*
* The tag action should be either the define below (to send a
* non-tagged transaction) or one of the defined scsi tag messages
* from scsi_message.h.
*/
#define CAM_TAG_ACTION_NONE 0x00
u_int tag_id; /* tag id from initator (target mode) */
u_int init_id; /* initiator id of who selected */
};
struct ccb_accept_tio {
struct ccb_hdr ccb_h;
cdb_t cdb_io; /* Union for CDB bytes/pointer */
@ -746,6 +779,13 @@ struct ccb_trans_settings_sas {
u_int32_t bitrate; /* Mbps */
};
struct ccb_trans_settings_sata {
u_int valid; /* Which fields to honor */
#define CTS_SATA_VALID_SPEED 0x01
#define CTS_SATA_VALID_PM 0x02
u_int32_t bitrate; /* Mbps */
u_int pm_present; /* PM is present (XPT->SIM) */
};
/* Get/Set transfer rate/width/disconnection/tag queueing settings */
struct ccb_trans_settings {
@ -764,6 +804,7 @@ struct ccb_trans_settings {
struct ccb_trans_settings_spi spi;
struct ccb_trans_settings_fc fc;
struct ccb_trans_settings_sas sas;
struct ccb_trans_settings_sata sata;
} xport_specific;
};
@ -907,6 +948,7 @@ union ccb {
struct ccb_eng_exec cee;
struct ccb_rescan crcn;
struct ccb_debug cdbg;
struct ccb_ataio ataio;
};
__BEGIN_DECLS
@ -924,7 +966,14 @@ cam_fill_ctio(struct ccb_scsiio *csio, u_int32_t retries,
u_int32_t flags, u_int tag_action, u_int tag_id,
u_int init_id, u_int scsi_status, u_int8_t *data_ptr,
u_int32_t dxfer_len, u_int32_t timeout);
static __inline void
cam_fill_ataio(struct ccb_ataio *ataio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
u_int32_t flags, u_int tag_action,
u_int8_t *data_ptr, u_int32_t dxfer_len,
u_int32_t timeout);
static __inline void
cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
@ -965,6 +1014,23 @@ cam_fill_ctio(struct ccb_scsiio *csio, u_int32_t retries,
csio->init_id = init_id;
}
static __inline void
cam_fill_ataio(struct ccb_ataio *ataio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
u_int32_t flags, u_int tag_action,
u_int8_t *data_ptr, u_int32_t dxfer_len,
u_int32_t timeout)
{
ataio->ccb_h.func_code = XPT_ATA_IO;
ataio->ccb_h.flags = flags;
ataio->ccb_h.retry_count = retries;
ataio->ccb_h.cbfcnp = cbfcnp;
ataio->ccb_h.timeout = timeout;
ataio->data_ptr = data_ptr;
ataio->dxfer_len = dxfer_len;
ataio->tag_action = tag_action;
}
void cam_calc_geometry(struct ccb_calc_geometry *ccg, int extended);
__END_DECLS

View File

@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_queue.h>
#include <cam/cam_xpt_periph.h>
#include <cam/cam_periph.h>
#include <cam/cam_debug.h>
@ -570,6 +571,8 @@ cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
u_int8_t **data_ptrs[CAM_PERIPH_MAXMAPS];
u_int32_t lengths[CAM_PERIPH_MAXMAPS];
u_int32_t dirs[CAM_PERIPH_MAXMAPS];
/* Some controllers may not be able to handle more data. */
size_t maxmap = DFLTPHYS;
switch(ccb->ccb_h.func_code) {
case XPT_DEV_MATCH:
@ -592,6 +595,11 @@ cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
dirs[0] = CAM_DIR_IN;
numbufs = 1;
}
/*
* This request will not go to the hardware, no reason
* to be so strict. vmapbuf() is able to map up to MAXPHYS.
*/
maxmap = MAXPHYS;
break;
case XPT_SCSI_IO:
case XPT_CONT_TARGET_IO:
@ -603,6 +611,15 @@ cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK;
numbufs = 1;
break;
case XPT_ATA_IO:
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE)
return(0);
data_ptrs[0] = &ccb->ataio.data_ptr;
lengths[0] = ccb->ataio.dxfer_len;
dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK;
numbufs = 1;
break;
default:
return(EINVAL);
break; /* NOTREACHED */
@ -625,12 +642,12 @@ cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
* boundary.
*/
if ((lengths[i] +
(((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK)) > DFLTPHYS){
(((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK)) > maxmap){
printf("cam_periph_mapmem: attempt to map %lu bytes, "
"which is greater than DFLTPHYS(%d)\n",
"which is greater than %lu\n",
(long)(lengths[i] +
(((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK)),
DFLTPHYS);
(u_long)maxmap);
return(E2BIG);
}
@ -662,7 +679,7 @@ cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
/* put our pointer in the data slot */
mapinfo->bp[i]->b_data = *data_ptrs[i];
/* set the transfer length, we know it's < DFLTPHYS */
/* set the transfer length, we know it's < MAXPHYS */
mapinfo->bp[i]->b_bufsize = lengths[i];
/* set the direction */
@ -738,6 +755,10 @@ cam_periph_unmapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
data_ptrs[0] = &ccb->csio.data_ptr;
numbufs = min(mapinfo->num_bufs_used, 1);
break;
case XPT_ATA_IO:
data_ptrs[0] = &ccb->ataio.data_ptr;
numbufs = min(mapinfo->num_bufs_used, 1);
break;
default:
/* allow ourselves to be swapped once again */
PRELE(curproc);
@ -1583,6 +1604,13 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
xpt_print(ccb->ccb_h.path, "AutoSense Failed\n");
error = EIO; /* we have to kill the command */
break;
case CAM_ATA_STATUS_ERROR:
if (bootverbose && printed == 0) {
xpt_print(ccb->ccb_h.path,
"Request completed with CAM_ATA_STATUS_ERROR\n");
printed++;
}
/* FALLTHROUGH */
case CAM_REQ_CMP_ERR:
if (bootverbose && printed == 0) {
xpt_print(ccb->ccb_h.path,

File diff suppressed because it is too large Load Diff

View File

@ -48,7 +48,45 @@ struct cam_path;
#ifdef _KERNEL
/*
* Definition of an async handler callback block. These are used to add
* SIMs and peripherals to the async callback lists.
*/
struct async_node {
SLIST_ENTRY(async_node) links;
u_int32_t event_enable; /* Async Event enables */
void (*callback)(void *arg, u_int32_t code,
struct cam_path *path, void *args);
void *callback_arg;
};
SLIST_HEAD(async_list, async_node);
SLIST_HEAD(periph_list, cam_periph);
#if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG)
#error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS"
#endif
/*
* In order to enable the CAM_DEBUG_* options, the user must have CAMDEBUG
* enabled. Also, the user must have either none, or all of CAM_DEBUG_BUS,
* CAM_DEBUG_TARGET, and CAM_DEBUG_LUN specified.
*/
#if defined(CAM_DEBUG_BUS) || defined(CAM_DEBUG_TARGET) \
|| defined(CAM_DEBUG_LUN)
#ifdef CAMDEBUG
#if !defined(CAM_DEBUG_BUS) || !defined(CAM_DEBUG_TARGET) \
|| !defined(CAM_DEBUG_LUN)
#error "You must define all or none of CAM_DEBUG_BUS, CAM_DEBUG_TARGET \
and CAM_DEBUG_LUN"
#endif /* !CAM_DEBUG_BUS || !CAM_DEBUG_TARGET || !CAM_DEBUG_LUN */
#else /* !CAMDEBUG */
#error "You must use options CAMDEBUG if you use the CAM_DEBUG_* options"
#endif /* CAMDEBUG */
#endif /* CAM_DEBUG_BUS || CAM_DEBUG_TARGET || CAM_DEBUG_LUN */
void xpt_action(union ccb *new_ccb);
void xpt_action_default(union ccb *new_ccb);
void xpt_setup_ccb(struct ccb_hdr *ccb_h,
struct cam_path *path,
u_int32_t priority);
@ -81,6 +119,14 @@ void xpt_lock_buses(void);
void xpt_unlock_buses(void);
cam_status xpt_register_async(int event, ac_callback_t *cbfunc,
void *cbarg, struct cam_path *path);
cam_status xpt_compile_path(struct cam_path *new_path,
struct cam_periph *perph,
path_id_t path_id,
target_id_t target_id,
lun_id_t lun_id);
void xpt_release_path(struct cam_path *path);
#endif /* _KERNEL */
#endif /* _CAM_CAM_XPT_H */

205
sys/cam/cam_xpt_internal.h Normal file
View File

@ -0,0 +1,205 @@
/*-
* Copyright 2009 Scott Long
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _CAM_CAM_XPT_INTERNAL_H
#define _CAM_CAM_XPT_INTERNAL_H 1
/* Forward Declarations */
struct cam_eb;
struct cam_et;
struct cam_ed;
typedef struct cam_ed * (*xpt_alloc_device_func)(struct cam_eb *bus,
struct cam_et *target,
lun_id_t lun_id);
typedef void (*xpt_release_device_func)(struct cam_eb *bus,
struct cam_et *target,
struct cam_ed *device);
typedef void (*xpt_action_func)(union ccb *start_ccb);
typedef void (*xpt_dev_async_func)(u_int32_t async_code,
struct cam_eb *bus,
struct cam_et *target,
struct cam_ed *device,
void *async_arg);
typedef void (*xpt_announce_periph_func)(struct cam_periph *periph,
char *announce_string);
struct xpt_xport {
xpt_alloc_device_func alloc_device;
xpt_release_device_func reldev;
xpt_action_func action;
xpt_dev_async_func async;
xpt_announce_periph_func announce;
};
/*
* Structure for queueing a device in a run queue.
* There is one run queue for allocating new ccbs,
* and another for sending ccbs to the controller.
*/
struct cam_ed_qinfo {
cam_pinfo pinfo;
struct cam_ed *device;
};
/*
* The CAM EDT (Existing Device Table) contains the device information for
* all devices for all busses in the system. The table contains a
* cam_ed structure for each device on the bus.
*/
struct cam_ed {
TAILQ_ENTRY(cam_ed) links;
struct cam_ed_qinfo alloc_ccb_entry;
struct cam_ed_qinfo send_ccb_entry;
struct cam_et *target;
struct cam_sim *sim;
lun_id_t lun_id;
struct camq drvq; /*
* Queue of type drivers wanting to do
* work on this device.
*/
struct cam_ccbq ccbq; /* Queue of pending ccbs */
struct async_list asyncs; /* Async callback info for this B/T/L */
struct periph_list periphs; /* All attached devices */
u_int generation; /* Generation number */
struct cam_periph *owner; /* Peripheral driver's ownership tag */
void *quirk; /* Oddities about this device */
u_int maxtags;
u_int mintags;
cam_proto protocol;
u_int protocol_version;
cam_xport transport;
u_int transport_version;
struct scsi_inquiry_data inq_data;
struct ata_params ident_data;
u_int8_t inq_flags; /*
* Current settings for inquiry flags.
* This allows us to override settings
* like disconnection and tagged
* queuing for a device.
*/
u_int8_t queue_flags; /* Queue flags from the control page */
u_int8_t serial_num_len;
u_int8_t *serial_num;
u_int32_t qfrozen_cnt;
u_int32_t flags;
#define CAM_DEV_UNCONFIGURED 0x01
#define CAM_DEV_REL_TIMEOUT_PENDING 0x02
#define CAM_DEV_REL_ON_COMPLETE 0x04
#define CAM_DEV_REL_ON_QUEUE_EMPTY 0x08
#define CAM_DEV_RESIZE_QUEUE_NEEDED 0x10
#define CAM_DEV_TAG_AFTER_COUNT 0x20
#define CAM_DEV_INQUIRY_DATA_VALID 0x40
#define CAM_DEV_IN_DV 0x80
#define CAM_DEV_DV_HIT_BOTTOM 0x100
u_int32_t tag_delay_count;
#define CAM_TAG_DELAY_COUNT 5
u_int32_t tag_saved_openings;
u_int32_t refcount;
struct callout callout;
};
/*
* Each target is represented by an ET (Existing Target). These
* entries are created when a target is successfully probed with an
* identify, and removed when a device fails to respond after a number
* of retries, or a bus rescan finds the device missing.
*/
struct cam_et {
TAILQ_HEAD(, cam_ed) ed_entries;
TAILQ_ENTRY(cam_et) links;
struct cam_eb *bus;
target_id_t target_id;
u_int32_t refcount;
u_int generation;
struct timeval last_reset;
};
/*
* Each bus is represented by an EB (Existing Bus). These entries
* are created by calls to xpt_bus_register and deleted by calls to
* xpt_bus_deregister.
*/
struct cam_eb {
TAILQ_HEAD(, cam_et) et_entries;
TAILQ_ENTRY(cam_eb) links;
path_id_t path_id;
struct cam_sim *sim;
struct timeval last_reset;
u_int32_t flags;
#define CAM_EB_RUNQ_SCHEDULED 0x01
u_int32_t refcount;
u_int generation;
device_t parent_dev;
struct xpt_xport *xport;
};
struct cam_path {
struct cam_periph *periph;
struct cam_eb *bus;
struct cam_et *target;
struct cam_ed *device;
};
struct xpt_xport * scsi_get_xport(void);
struct xpt_xport * ata_get_xport(void);
struct cam_ed * xpt_alloc_device(struct cam_eb *bus,
struct cam_et *target,
lun_id_t lun_id);
void xpt_run_dev_sendq(struct cam_eb *bus);
int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo,
u_int32_t new_priority);
u_int32_t xpt_dev_ccbq_resize(struct cam_path *path, int newopenings);
static __inline int
xpt_schedule_dev_sendq(struct cam_eb *bus, struct cam_ed *dev)
{
int retval;
if (dev->ccbq.dev_openings > 0) {
/*
* The priority of a device waiting for controller
* resources is that of the the highest priority CCB
* enqueued.
*/
retval =
xpt_schedule_dev(&bus->sim->devq->send_queue,
&dev->send_ccb_entry.pinfo,
CAMQ_GET_HEAD(&dev->ccbq.queue)->priority);
} else {
retval = 0;
}
return (retval);
}
MALLOC_DECLARE(M_CAMXPT);
#endif

View File

@ -33,6 +33,7 @@
#ifndef _CAM_CAM_XPT_PERIPH_H
#define _CAM_CAM_XPT_PERIPH_H 1
#include <cam/cam_queue.h>
#include <cam/cam_xpt.h>
/* Functions accessed by the peripheral drivers */

View File

@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_queue.h>
#include <cam/cam_xpt.h>
#include <cam/scsi/scsi_all.h>
#include <sys/sbuf.h>

View File

@ -496,6 +496,9 @@ cdasync(void *callback_arg, u_int32_t code,
if (cgd == NULL)
break;
if (cgd->protocol != PROTO_SCSI)
break;
if (SID_TYPE(&cgd->inq_data) != T_CDROM
&& SID_TYPE(&cgd->inq_data) != T_WORM)
break;

View File

@ -287,6 +287,9 @@ chasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
if (cgd == NULL)
break;
if (cgd->protocol != PROTO_SCSI)
break;
if (SID_TYPE(&cgd->inq_data)!= T_CHANGER)
break;

View File

@ -1028,6 +1028,9 @@ daasync(void *callback_arg, u_int32_t code,
if (cgd == NULL)
break;
if (cgd->protocol != PROTO_SCSI)
break;
if (SID_TYPE(&cgd->inq_data) != T_DIRECT
&& SID_TYPE(&cgd->inq_data) != T_RBC
&& SID_TYPE(&cgd->inq_data) != T_OPTICAL)
@ -1195,6 +1198,7 @@ daregister(struct cam_periph *periph, void *arg)
softc->quirks = DA_Q_NONE;
/* Check if the SIM does not want 6 byte commands */
bzero(&cpi, sizeof(cpi));
xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
@ -1244,7 +1248,12 @@ daregister(struct cam_periph *periph, void *arg)
softc->disk->d_dump = dadump;
softc->disk->d_name = "da";
softc->disk->d_drv1 = periph;
softc->disk->d_maxsize = DFLTPHYS; /* XXX: probably not arbitrary */
if (cpi.maxio == 0)
softc->disk->d_maxsize = DFLTPHYS; /* traditional default */
else if (cpi.maxio > MAXPHYS)
softc->disk->d_maxsize = MAXPHYS; /* for safety */
else
softc->disk->d_maxsize = cpi.maxio;
softc->disk->d_unit = periph->unit_number;
softc->disk->d_flags = 0;
if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0)

View File

@ -528,7 +528,8 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
* ready), it will save a few cycles if we check for it here.
*/
if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0)
&& (((ccb->ccb_h.func_code == XPT_SCSI_IO)
&& (((ccb->ccb_h.func_code == XPT_SCSI_IO ||
ccb->ccb_h.func_code == XPT_ATA_IO)
&& ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE))
|| (ccb->ccb_h.func_code == XPT_DEV_MATCH))) {

View File

@ -366,6 +366,9 @@ ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
if (cgd == NULL)
break;
if (cgd->protocol != PROTO_SCSI)
break;
if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
break;

View File

@ -1398,6 +1398,9 @@ saasync(void *callback_arg, u_int32_t code,
if (cgd == NULL)
break;
if (cgd->protocol != PROTO_SCSI)
break;
if (SID_TYPE(&cgd->inq_data) != T_SEQUENTIAL)
break;

View File

@ -251,6 +251,9 @@ sesasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
break;
}
if (cgd->protocol != PROTO_SCSI)
break;
inq_len = cgd->inq_data.additional_length + 4;
/*

View File

@ -226,6 +226,9 @@ sgasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
if (cgd == NULL)
break;
if (cgd->protocol != PROTO_SCSI)
break;
/*
* Allocate a peripheral instance for this device and
* start the probe process.

2382
sys/cam/scsi/scsi_xpt.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -110,9 +110,13 @@ cam/cam_periph.c optional scbus
cam/cam_queue.c optional scbus
cam/cam_sim.c optional scbus
cam/cam_xpt.c optional scbus
cam/ata/ata_all.c optional scbus
cam/ata/ata_xpt.c optional scbus
cam/scsi/scsi_xpt.c optional scbus
cam/scsi/scsi_all.c optional scbus
cam/scsi/scsi_cd.c optional cd
cam/scsi/scsi_ch.c optional ch
cam/ata/ata_da.c optional da
cam/scsi/scsi_da.c optional da
cam/scsi/scsi_low.c optional ct | ncv | nsp | stg
cam/scsi/scsi_low_pisa.c optional ct | ncv | nsp | stg
@ -459,6 +463,7 @@ dev/aha/aha.c optional aha
dev/aha/aha_isa.c optional aha isa
dev/aha/aha_mca.c optional aha mca
dev/ahb/ahb.c optional ahb eisa
dev/ahci/ahci.c optional ahci pci
dev/aic/aic.c optional aic
dev/aic/aic_pccard.c optional aic pccard
dev/aic7xxx/ahc_eisa.c optional ahc eisa

View File

@ -1345,7 +1345,7 @@ adv_attach(adv)
/* highaddr */ BUS_SPACE_MAXADDR,
/* filter */ NULL,
/* filterarg */ NULL,
/* maxsize */ MAXPHYS,
/* maxsize */ ADV_MAXPHYS,
/* nsegments */ max_sg,
/* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT,
/* flags */ BUS_DMA_ALLOCNOW,

View File

@ -58,6 +58,8 @@ typedef u_int8_t target_bit_vector;
#define ADV_MAX_TID 7
#define ADV_MAX_LUN 7
#define ADV_MAXPHYS (128 * 1024)
/* Enumeration of board types */
typedef enum {
ADV_NONE = 0x000,

1858
sys/dev/ahci/ahci.c Normal file

File diff suppressed because it is too large Load Diff

422
sys/dev/ahci/ahci.h Normal file
View File

@ -0,0 +1,422 @@
/*-
* Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/* ATA register defines */
#define ATA_DATA 0 /* (RW) data */
#define ATA_FEATURE 1 /* (W) feature */
#define ATA_F_DMA 0x01 /* enable DMA */
#define ATA_F_OVL 0x02 /* enable overlap */
#define ATA_COUNT 2 /* (W) sector count */
#define ATA_SECTOR 3 /* (RW) sector # */
#define ATA_CYL_LSB 4 /* (RW) cylinder# LSB */
#define ATA_CYL_MSB 5 /* (RW) cylinder# MSB */
#define ATA_DRIVE 6 /* (W) Sector/Drive/Head */
#define ATA_D_LBA 0x40 /* use LBA addressing */
#define ATA_D_IBM 0xa0 /* 512 byte sectors, ECC */
#define ATA_COMMAND 7 /* (W) command */
#define ATA_ERROR 8 /* (R) error */
#define ATA_E_ILI 0x01 /* illegal length */
#define ATA_E_NM 0x02 /* no media */
#define ATA_E_ABORT 0x04 /* command aborted */
#define ATA_E_MCR 0x08 /* media change request */
#define ATA_E_IDNF 0x10 /* ID not found */
#define ATA_E_MC 0x20 /* media changed */
#define ATA_E_UNC 0x40 /* uncorrectable data */
#define ATA_E_ICRC 0x80 /* UDMA crc error */
#define ATA_E_ATAPI_SENSE_MASK 0xf0 /* ATAPI sense key mask */
#define ATA_IREASON 9 /* (R) interrupt reason */
#define ATA_I_CMD 0x01 /* cmd (1) | data (0) */
#define ATA_I_IN 0x02 /* read (1) | write (0) */
#define ATA_I_RELEASE 0x04 /* released bus (1) */
#define ATA_I_TAGMASK 0xf8 /* tag mask */
#define ATA_STATUS 10 /* (R) status */
#define ATA_ALTSTAT 11 /* (R) alternate status */
#define ATA_S_ERROR 0x01 /* error */
#define ATA_S_INDEX 0x02 /* index */
#define ATA_S_CORR 0x04 /* data corrected */
#define ATA_S_DRQ 0x08 /* data request */
#define ATA_S_DSC 0x10 /* drive seek completed */
#define ATA_S_SERVICE 0x10 /* drive needs service */
#define ATA_S_DWF 0x20 /* drive write fault */
#define ATA_S_DMA 0x20 /* DMA ready */
#define ATA_S_READY 0x40 /* drive ready */
#define ATA_S_BUSY 0x80 /* busy */
#define ATA_CONTROL 12 /* (W) control */
#define ATA_A_IDS 0x02 /* disable interrupts */
#define ATA_A_RESET 0x04 /* RESET controller */
#define ATA_A_4BIT 0x08 /* 4 head bits */
#define ATA_A_HOB 0x80 /* High Order Byte enable */
/* SATA register defines */
#define ATA_SSTATUS 13
#define ATA_SS_DET_MASK 0x0000000f
#define ATA_SS_DET_NO_DEVICE 0x00000000
#define ATA_SS_DET_DEV_PRESENT 0x00000001
#define ATA_SS_DET_PHY_ONLINE 0x00000003
#define ATA_SS_DET_PHY_OFFLINE 0x00000004
#define ATA_SS_SPD_MASK 0x000000f0
#define ATA_SS_SPD_NO_SPEED 0x00000000
#define ATA_SS_SPD_GEN1 0x00000010
#define ATA_SS_SPD_GEN2 0x00000020
#define ATA_SS_SPD_GEN3 0x00000040
#define ATA_SS_IPM_MASK 0x00000f00
#define ATA_SS_IPM_NO_DEVICE 0x00000000
#define ATA_SS_IPM_ACTIVE 0x00000100
#define ATA_SS_IPM_PARTIAL 0x00000200
#define ATA_SS_IPM_SLUMBER 0x00000600
#define ATA_SERROR 14
#define ATA_SE_DATA_CORRECTED 0x00000001
#define ATA_SE_COMM_CORRECTED 0x00000002
#define ATA_SE_DATA_ERR 0x00000100
#define ATA_SE_COMM_ERR 0x00000200
#define ATA_SE_PROT_ERR 0x00000400
#define ATA_SE_HOST_ERR 0x00000800
#define ATA_SE_PHY_CHANGED 0x00010000
#define ATA_SE_PHY_IERROR 0x00020000
#define ATA_SE_COMM_WAKE 0x00040000
#define ATA_SE_DECODE_ERR 0x00080000
#define ATA_SE_PARITY_ERR 0x00100000
#define ATA_SE_CRC_ERR 0x00200000
#define ATA_SE_HANDSHAKE_ERR 0x00400000
#define ATA_SE_LINKSEQ_ERR 0x00800000
#define ATA_SE_TRANSPORT_ERR 0x01000000
#define ATA_SE_UNKNOWN_FIS 0x02000000
#define ATA_SCONTROL 15
#define ATA_SC_DET_MASK 0x0000000f
#define ATA_SC_DET_IDLE 0x00000000
#define ATA_SC_DET_RESET 0x00000001
#define ATA_SC_DET_DISABLE 0x00000004
#define ATA_SC_SPD_MASK 0x000000f0
#define ATA_SC_SPD_NO_SPEED 0x00000000
#define ATA_SC_SPD_SPEED_GEN1 0x00000010
#define ATA_SC_SPD_SPEED_GEN2 0x00000020
#define ATA_SC_SPD_SPEED_GEN3 0x00000040
#define ATA_SC_IPM_MASK 0x00000f00
#define ATA_SC_IPM_NONE 0x00000000
#define ATA_SC_IPM_DIS_PARTIAL 0x00000100
#define ATA_SC_IPM_DIS_SLUMBER 0x00000200
#define ATA_SACTIVE 16
#define AHCI_MAX_PORTS 32
#define AHCI_MAX_SLOTS 32
/* SATA AHCI v1.0 register defines */
#define AHCI_CAP 0x00
#define AHCI_CAP_NPMASK 0x0000001f
#define AHCI_CAP_SXS 0x00000020
#define AHCI_CAP_EMS 0x00000040
#define AHCI_CAP_CCCS 0x00000080
#define AHCI_CAP_NCS 0x00001F00
#define AHCI_CAP_NCS_SHIFT 8
#define AHCI_CAP_PSC 0x00002000
#define AHCI_CAP_SSC 0x00004000
#define AHCI_CAP_PMD 0x00008000
#define AHCI_CAP_FBSS 0x00010000
#define AHCI_CAP_SPM 0x00020000
#define AHCI_CAP_SAM 0x00080000
#define AHCI_CAP_ISS 0x00F00000
#define AHCI_CAP_ISS_SHIFT 20
#define AHCI_CAP_SCLO 0x01000000
#define AHCI_CAP_SAL 0x02000000
#define AHCI_CAP_SALP 0x04000000
#define AHCI_CAP_SSS 0x08000000
#define AHCI_CAP_SMPS 0x10000000
#define AHCI_CAP_SSNTF 0x20000000
#define AHCI_CAP_SNCQ 0x40000000
#define AHCI_CAP_64BIT 0x80000000
#define AHCI_GHC 0x04
#define AHCI_GHC_AE 0x80000000
#define AHCI_GHC_MRSM 0x00000004
#define AHCI_GHC_IE 0x00000002
#define AHCI_GHC_HR 0x00000001
#define AHCI_IS 0x08
#define AHCI_PI 0x0c
#define AHCI_VS 0x10
#define AHCI_OFFSET 0x100
#define AHCI_STEP 0x80
#define AHCI_P_CLB 0x00
#define AHCI_P_CLBU 0x04
#define AHCI_P_FB 0x08
#define AHCI_P_FBU 0x0c
#define AHCI_P_IS 0x10
#define AHCI_P_IE 0x14
#define AHCI_P_IX_DHR 0x00000001
#define AHCI_P_IX_PS 0x00000002
#define AHCI_P_IX_DS 0x00000004
#define AHCI_P_IX_SDB 0x00000008
#define AHCI_P_IX_UF 0x00000010
#define AHCI_P_IX_DP 0x00000020
#define AHCI_P_IX_PC 0x00000040
#define AHCI_P_IX_DI 0x00000080
#define AHCI_P_IX_PRC 0x00400000
#define AHCI_P_IX_IPM 0x00800000
#define AHCI_P_IX_OF 0x01000000
#define AHCI_P_IX_INF 0x04000000
#define AHCI_P_IX_IF 0x08000000
#define AHCI_P_IX_HBD 0x10000000
#define AHCI_P_IX_HBF 0x20000000
#define AHCI_P_IX_TFE 0x40000000
#define AHCI_P_IX_CPD 0x80000000
#define AHCI_P_CMD 0x18
#define AHCI_P_CMD_ST 0x00000001
#define AHCI_P_CMD_SUD 0x00000002
#define AHCI_P_CMD_POD 0x00000004
#define AHCI_P_CMD_CLO 0x00000008
#define AHCI_P_CMD_FRE 0x00000010
#define AHCI_P_CMD_CCS_MASK 0x00001f00
#define AHCI_P_CMD_CCS_SHIFT 8
#define AHCI_P_CMD_ISS 0x00002000
#define AHCI_P_CMD_FR 0x00004000
#define AHCI_P_CMD_CR 0x00008000
#define AHCI_P_CMD_CPS 0x00010000
#define AHCI_P_CMD_PMA 0x00020000
#define AHCI_P_CMD_HPCP 0x00040000
#define AHCI_P_CMD_ISP 0x00080000
#define AHCI_P_CMD_CPD 0x00100000
#define AHCI_P_CMD_ATAPI 0x01000000
#define AHCI_P_CMD_DLAE 0x02000000
#define AHCI_P_CMD_ALPE 0x04000000
#define AHCI_P_CMD_ASP 0x08000000
#define AHCI_P_CMD_ICC_MASK 0xf0000000
#define AHCI_P_CMD_NOOP 0x00000000
#define AHCI_P_CMD_ACTIVE 0x10000000
#define AHCI_P_CMD_PARTIAL 0x20000000
#define AHCI_P_CMD_SLUMBER 0x60000000
#define AHCI_P_TFD 0x20
#define AHCI_P_SIG 0x24
#define AHCI_P_SSTS 0x28
#define AHCI_P_SCTL 0x2c
#define AHCI_P_SERR 0x30
#define AHCI_P_SACT 0x34
#define AHCI_P_CI 0x38
#define AHCI_P_SNTF 0x3C
#define AHCI_P_FBS 0x40
/* Just to be sure, if building as module. */
#if MAXPHYS < 512 * 1024
#undef MAXPHYS
#define MAXPHYS 512 * 1024
#endif
/* Pessimistic prognosis on number of required S/G entries */
#define AHCI_SG_ENTRIES (roundup(btoc(MAXPHYS) + 1, 8))
/* Command list. 32 commands. First, 1Kbyte aligned. */
#define AHCI_CL_OFFSET 0
#define AHCI_CL_SIZE 32
/* Command tables. Up to 32 commands, Each, 128byte aligned. */
#define AHCI_CT_OFFSET (AHCI_CL_OFFSET + AHCI_CL_SIZE * AHCI_MAX_SLOTS)
#define AHCI_CT_SIZE (128 + AHCI_SG_ENTRIES * 16)
/* Total main work area. */
#define AHCI_WORK_SIZE (AHCI_CT_OFFSET + AHCI_CT_SIZE * ch->numslots)
struct ahci_dma_prd {
u_int64_t dba;
u_int32_t reserved;
u_int32_t dbc; /* 0 based */
#define AHCI_PRD_MASK 0x003fffff /* max 4MB */
#define AHCI_PRD_MAX (AHCI_PRD_MASK + 1)
#define AHCI_PRD_IPC (1 << 31)
} __packed;
struct ahci_cmd_tab {
u_int8_t cfis[64];
u_int8_t acmd[32];
u_int8_t reserved[32];
struct ahci_dma_prd prd_tab[AHCI_SG_ENTRIES];
} __packed;
struct ahci_cmd_list {
u_int16_t cmd_flags;
#define AHCI_CMD_ATAPI 0x0020
#define AHCI_CMD_WRITE 0x0040
#define AHCI_CMD_PREFETCH 0x0080
#define AHCI_CMD_RESET 0x0100
#define AHCI_CMD_BIST 0x0200
#define AHCI_CMD_CLR_BUSY 0x0400
u_int16_t prd_length; /* PRD entries */
u_int32_t bytecount;
u_int64_t cmd_table_phys; /* 128byte aligned */
} __packed;
/* misc defines */
#define ATA_IRQ_RID 0
#define ATA_INTR_FLAGS (INTR_MPSAFE|INTR_TYPE_BIO|INTR_ENTROPY)
struct ata_dmaslot {
bus_dmamap_t data_map; /* data DMA map */
int nsegs; /* Number of segs loaded */
};
/* structure holding DMA related information */
struct ata_dma {
bus_dma_tag_t work_tag; /* workspace DMA tag */
bus_dmamap_t work_map; /* workspace DMA map */
uint8_t *work; /* workspace */
bus_addr_t work_bus; /* bus address of work */
bus_dma_tag_t rfis_tag; /* RFIS list DMA tag */
bus_dmamap_t rfis_map; /* RFIS list DMA map */
uint8_t *rfis; /* FIS receive area */
bus_addr_t rfis_bus; /* bus address of rfis */
bus_dma_tag_t data_tag; /* data DMA tag */
u_int64_t max_address; /* highest DMA'able address */
};
enum ahci_slot_states {
AHCI_SLOT_EMPTY,
AHCI_SLOT_LOADING,
AHCI_SLOT_RUNNING,
AHCI_SLOT_WAITING
};
struct ahci_slot {
device_t dev; /* Device handle */
u_int8_t slot; /* Number of this slot */
enum ahci_slot_states state; /* Slot state */
union ccb *ccb; /* CCB occupying slot */
struct ata_dmaslot dma; /* DMA data of this slot */
struct callout timeout; /* Execution timeout */
};
/* structure describing an ATA channel */
struct ahci_channel {
device_t dev; /* Device handle */
int unit; /* Physical channel */
struct resource *r_mem; /* Memory of this channel */
struct resource *r_irq; /* Interrupt of this channel */
void *ih; /* Interrupt handle */
struct ata_dma dma; /* DMA data */
struct cam_sim *sim;
struct cam_path *path;
uint32_t caps; /* Controller capabilities */
int numslots; /* Number of present slots */
int pm_level; /* power management level */
int sata_rev; /* Maximum allowed SATA generation */
struct ahci_slot slot[AHCI_MAX_SLOTS];
union ccb *hold[AHCI_MAX_SLOTS];
struct mtx mtx; /* state lock */
int devices; /* What is present */
int pm_present; /* PM presence reported */
uint32_t rslots; /* Running slots */
uint32_t aslots; /* Slots with atomic commands */
int numrslots; /* Number of running slots */
int numtslots; /* Number of tagged slots */
int readlog; /* Our READ LOG active */
int lastslot; /* Last used slot */
int taggedtarget; /* Last tagged target */
union ccb *frozen; /* Frozen command */
};
/* structure describing a AHCI controller */
struct ahci_controller {
device_t dev;
int r_rid;
struct resource *r_mem;
struct rman sc_iomem;
struct ahci_controller_irq {
struct ahci_controller *ctlr;
struct resource *r_irq;
void *handle;
int r_irq_rid;
int mode;
#define AHCI_IRQ_MODE_ALL 0
#define AHCI_IRQ_MODE_AFTER 1
#define AHCI_IRQ_MODE_ONE 2
} irqs[16];
int numirqs;
int channels;
int ichannels;
struct {
void (*function)(void *);
void *argument;
} interrupt[AHCI_MAX_PORTS];
};
enum ahci_err_type {
AHCI_ERR_NONE, /* No error */
AHCI_ERR_INVALID, /* Error detected by us before submitting. */
AHCI_ERR_INNOCENT, /* Innocent victim. */
AHCI_ERR_TFE, /* Task File Error. */
AHCI_ERR_SATA, /* SATA error. */
AHCI_ERR_TIMEOUT, /* Command execution timeout. */
AHCI_ERR_NCQ, /* NCQ command error. CCB should be put on hold
* until READ LOG executed to reveal error. */
};
/* macros to hide busspace uglyness */
#define ATA_INB(res, offset) \
bus_read_1((res), (offset))
#define ATA_INW(res, offset) \
bus_read_2((res), (offset))
#define ATA_INL(res, offset) \
bus_read_4((res), (offset))
#define ATA_INSW(res, offset, addr, count) \
bus_read_multi_2((res), (offset), (addr), (count))
#define ATA_INSW_STRM(res, offset, addr, count) \
bus_read_multi_stream_2((res), (offset), (addr), (count))
#define ATA_INSL(res, offset, addr, count) \
bus_read_multi_4((res), (offset), (addr), (count))
#define ATA_INSL_STRM(res, offset, addr, count) \
bus_read_multi_stream_4((res), (offset), (addr), (count))
#define ATA_OUTB(res, offset, value) \
bus_write_1((res), (offset), (value))
#define ATA_OUTW(res, offset, value) \
bus_write_2((res), (offset), (value))
#define ATA_OUTL(res, offset, value) \
bus_write_4((res), (offset), (value))
#define ATA_OUTSW(res, offset, addr, count) \
bus_write_multi_2((res), (offset), (addr), (count))
#define ATA_OUTSW_STRM(res, offset, addr, count) \
bus_write_multi_stream_2((res), (offset), (addr), (count))
#define ATA_OUTSL(res, offset, addr, count) \
bus_write_multi_4((res), (offset), (addr), (count))
#define ATA_OUTSL_STRM(res, offset, addr, count) \
bus_write_multi_stream_4((res), (offset), (addr), (count))

View File

@ -102,7 +102,8 @@
* The number of dma segments supported. The sequencer can handle any number
* of physically contiguous S/G entrys. To reduce the driver's memory
* consumption, we limit the number supported to be sufficient to handle
* the largest mapping supported by the kernel, MAXPHYS. Assuming the
* the largest mapping supported by the the legacy kernel MAXPHYS setting of
* 128K. This can be increased once some testing is done. Assuming the
* transfer is as fragmented as possible and unaligned, this turns out to
* be the number of paged sized transfers in MAXPHYS plus an extra element
* to handle any unaligned residual. The sequencer fetches SG elements
@ -110,7 +111,8 @@
* multiple of 16 which should align us on even the largest of cacheline
* boundaries.
*/
#define AHD_NSEG (roundup(btoc(MAXPHYS) + 1, 16))
#define AHD_MAXPHYS (128 * 1024)
#define AHD_NSEG (roundup(btoc(AHD_MAXPHYS) + 1, 16))
/* This driver supports target mode */
#ifdef NOT_YET

View File

@ -115,15 +115,16 @@ extern devclass_t ahc_devclass;
* The number of dma segments supported. The sequencer can handle any number
* of physically contiguous S/G entrys. To reduce the driver's memory
* consumption, we limit the number supported to be sufficient to handle
* the largest mapping supported by the kernel, MAXPHYS. Assuming the
* transfer is as fragmented as possible and unaligned, this turns out to
* the largest mapping supported by the the legacy kernel MAXPHYS setting of
* 128K. This can be increased once some testing is done. Assuming the
* be the number of paged sized transfers in MAXPHYS plus an extra element
* to handle any unaligned residual. The sequencer fetches SG elements
* in cacheline sized chucks, so make the number per-transaction an even
* multiple of 16 which should align us on even the largest of cacheline
* boundaries.
*/
#define AHC_NSEG (roundup(btoc(MAXPHYS) + 1, 16))
#define AHC_MAXPHYS (128 * 1024)
#define AHC_NSEG (roundup(btoc(AHC_MAXPHYS) + 1, 16))
/* This driver supports target mode */
#define AHC_TARGET_MODE 1

View File

@ -95,7 +95,8 @@ struct amd_sg {
#define AMD_MAX_SYNC_OFFSET 15
#define AMD_TARGET_MAX 7
#define AMD_LUN_MAX 7
#define AMD_NSEG (btoc(MAXPHYS) + 1)
#define AMD_MAXPHYS (128 * 1024) /* legacy MAXPHYS */
#define AMD_NSEG (btoc(AMD_MAXPHYS) + 1)
#define AMD_MAXTRANSFER_SIZE 0xFFFFFF /* restricted by 24 bit counter */
#define MAX_DEVICES 10
#define MAX_TAGS_CMD_QUEUE 256

View File

@ -376,7 +376,7 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
cpi->unit_number = cam_sim_unit(sim);
cpi->bus_id = cam_sim_bus(sim);
cpi->base_transfer_speed = 3300;
cpi->transport = XPORT_ATA;
cpi->transport = XPORT_SPI;
cpi->transport_version = 2;
cpi->protocol = PROTO_SCSI;
cpi->protocol_version = SCSI_REV_2;
@ -418,6 +418,8 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
break;
}
}
cpi->maxio = softc->ata_ch->dma.max_iosize ?
softc->ata_ch->dma.max_iosize : DFLTPHYS;
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
return;
@ -456,7 +458,7 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
struct ccb_trans_settings *cts = &ccb->cts;
cts->protocol = PROTO_SCSI;
cts->protocol_version = SCSI_REV_2;
cts->transport = XPORT_ATA;
cts->transport = XPORT_SPI;
cts->transport_version = XPORT_VERSION_UNSPECIFIED;
cts->proto_specific.valid = 0;
cts->xport_specific.valid = 0;
@ -666,13 +668,11 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
xpt_freeze_simq(sim, /*count*/ 1);
ccb_h->status = CAM_REQUEUE_REQ;
xpt_done(ccb);
mtx_unlock(&softc->state_lock);
return;
action_invalid:
ccb_h->status = CAM_REQ_INVALID;
xpt_done(ccb);
mtx_unlock(&softc->state_lock);
return;
}

View File

@ -2976,6 +2976,7 @@ ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
cpi->transport_version = 2;
cpi->protocol = PROTO_SCSI;
cpi->protocol_version = SCSI_REV_2;
cpi->maxio = (CISS_MAX_SG_ELEMENTS - 1) * PAGE_SIZE;
ccb->ccb_h.status = CAM_REQ_CMP;
break;
}

View File

@ -141,6 +141,9 @@ struct ciss_request
#define CISS_COMMAND_SG_LENGTH ((CISS_COMMAND_ALLOC_SIZE - sizeof(struct ciss_command)) \
/ sizeof(struct ciss_sg_entry))
/* XXX Prep for increasing max i/o */
#define CISS_MAX_SG_ELEMENTS 33
/*
* Per-logical-drive data.
*/

View File

@ -561,7 +561,8 @@ void isp_common_dmateardown(ispsoftc_t *, struct ccb_scsiio *, uint32_t);
#endif
/* Should be BUS_SPACE_MAXSIZE, but MAXPHYS is larger than BUS_SPACE_MAXSIZE */
#define ISP_NSEGS ((MAXPHYS / PAGE_SIZE) + 1)
#define ISP_MAXPHYS (128 * 1024)
#define ISP_NSEGS ((ISP_MAXPHYS / PAGE_SIZE) + 1)
/*
* Platform specific inline functions

View File

@ -341,7 +341,7 @@ mfi_attach(struct mfi_softc *sc)
status = sc->mfi_read_fw_status(sc);
sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
sc->mfi_max_sge = min(max_fw_sge, ((MAXPHYS / PAGE_SIZE) + 1));
sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1));
/*
* Create the dma tag for data buffers. Used both for block I/O

View File

@ -379,6 +379,7 @@ mfi_print_sense(struct mfi_softc *sc, void *sense)
MALLOC_DECLARE(M_MFIBUF);
#define MFI_CMD_TIMEOUT 30
#define MFI_MAXPHYS (128 * 1024)
#ifdef MFI_DEBUG
extern void mfi_print_cmd(struct mfi_command *cm);

View File

@ -1979,7 +1979,7 @@ mlx_user_command(struct mlx_softc *sc, struct mlx_usercommand *mu)
* initial contents
*/
if (mu->mu_datasize > 0) {
if (mu->mu_datasize > MAXPHYS) {
if (mu->mu_datasize > MLX_MAXPHYS) {
error = EINVAL;
goto out;
}

View File

@ -47,6 +47,7 @@
* making that fit cleanly without crossing page boundaries requires rounding up
* to the next power of two.
*/
#define MLX_MAXPHYS (128 * 124)
#define MLX_NSEG 64
#define MLX_NSLOTS 256 /* max number of command slots */

View File

@ -986,6 +986,9 @@ mpt_pio_read(struct mpt_softc *mpt, int offset)
/* Max MPT Reply we are willing to accept (must be power of 2) */
#define MPT_REPLY_SIZE 256
/* Max i/o size, based on legacy MAXPHYS. Can be increased. */
#define MPT_MAXPHYS (128 * 1024)
/*
* Must be less than 16384 in order for target mode to work
*/

View File

@ -795,9 +795,9 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt)
/*
* XXX: we should say that nsegs is 'unrestricted, but that
* XXX: tickles a horrible bug in the busdma code. Instead,
* XXX: we'll derive a reasonable segment limit from MAXPHYS
* XXX: we'll derive a reasonable segment limit from MPT_MAXPHYS
*/
nsegs = (MAXPHYS / PAGE_SIZE) + 1;
nsegs = (MPT_MAXPHYS / PAGE_SIZE) + 1;
if (mpt_dma_tag_create(mpt, mpt->parent_dmat, 1,
0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
NULL, NULL, MAXBSIZE, nsegs, BUS_SPACE_MAXSIZE_32BIT, 0,

View File

@ -94,7 +94,8 @@ typedef struct _SGentry {
#define TRM_MAX_CMD_PER_LUN 32
#define TRM_MAX_SRB_CNT 256
#define TRM_MAX_START_JOB 256
#define TRM_NSEG (btoc(MAXPHYS) + 1)
#define TRM_MAXPHYS (128 * 1024)
#define TRM_NSEG (btoc(TRM_MAXPHYS) + 1)
#define TRM_MAXTRANSFER_SIZE 0xFFFFFF /* restricted by 24 bit counter */
#define PAGELEN 4096

View File

@ -14,6 +14,7 @@ SUBDIR= ${_3dfx} \
${_agp} \
aha \
${_ahb} \
ahci \
${_aic} \
aic7xxx \
aio \

View File

@ -0,0 +1,8 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../dev/ahci
KMOD= ahci
SRCS= ahci.c ahci.h device_if.h bus_if.h pci_if.h opt_cam.h
.include <bsd.kmod.mk>

View File

@ -2,7 +2,7 @@
S= ${.CURDIR}/../..
.PATH: $S/cam $S/cam/scsi
.PATH: $S/cam $S/cam/scsi $S/cam/ata
KMOD= cam
@ -24,6 +24,10 @@ SRCS+= scsi_sa.c
SRCS+= scsi_ses.c
SRCS+= scsi_sg.c
SRCS+= scsi_targ_bh.c scsi_target.c
SRCS+= scsi_xpt.c
SRCS+= ata_all.c
SRCS+= ata_xpt.c
SRCS+= ata_da.c
EXPORT_SYMS= YES # XXX evaluate