Add a CAM interface to the aac driver. This is useful in case you should

ever connect a SCSI Cdrom/Tape/Jukebox/Scanner/Printer/kitty-litter-scooper
to your high-end RAID controller.  The interface to the arrays is still
via the block interface; this merely provides a way to circumvent the
RAID functionality and access the SCSI buses directly.  Note that for
somewhat obvious reasons, hard drives are not exposed to the da driver
through this interface, though you can still talk to them via the pass
driver.  Be the first on your block to low-level format unsuspecting
drives that are part of an array!

To enable this, add the 'aacp' device to your kernel config.

MFC after:	3 days
This commit is contained in:
Scott Long 2002-04-27 01:31:17 +00:00
parent 3465a702f3
commit fe3cb0e1ec
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=95536
12 changed files with 989 additions and 48 deletions

View File

@ -115,6 +115,7 @@ device ses # SCSI Environmental Services (and SAF-TE)
# RAID controllers
device aac # Adaptec FSA RAID
device aacp # SCSI passthrough for aac (requires CAM)
device amr # AMI MegaRAID
device ida # Compaq Smart RAID
device mlx # Mylex DAC960 family

View File

@ -1288,6 +1288,7 @@ device mly
# support).
#
device aac
device aacp # SCSI Passthrough interface (optional)
#
# Compaq Smart RAID, Mylex DAC960 and AMI MegaRAID controllers. Only

View File

@ -196,6 +196,7 @@ dev/aac/aac.c optional aac
dev/aac/aac_debug.c optional aac
dev/aac/aac_disk.c optional aac
dev/aac/aac_pci.c optional aac pci
dev/aac/aac_cam.c optional aacp aac
dev/acpica/acpi.c optional acpica
dev/acpica/acpica_support.c optional acpica
dev/acpica/acpi_acad.c optional acpica nowerror

View File

@ -70,13 +70,14 @@
#include <dev/aac/aac_ioctl.h>
#include <dev/aac/aacvar.h>
#include <dev/aac/aac_tables.h>
#include <dev/aac/aac_cam.h>
static void aac_startup(void *arg);
static void aac_add_container(struct aac_softc *sc,
struct aac_mntinforesp *mir, int f);
static void aac_get_bus_info(struct aac_softc *sc);
/* Command Processing */
static void aac_startio(struct aac_softc *sc);
static void aac_timeout(struct aac_softc *sc);
static int aac_start(struct aac_command *cm);
static void aac_complete(void *context, int pending);
@ -87,9 +88,6 @@ static void aac_host_command(struct aac_softc *sc);
static void aac_host_response(struct aac_softc *sc);
/* Command Buffer Management */
static int aac_alloc_command(struct aac_softc *sc,
struct aac_command **cmp);
static void aac_release_command(struct aac_command *cm);
static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
int nseg, int error);
static int aac_alloc_commands(struct aac_softc *sc);
@ -327,6 +325,10 @@ aac_attach(struct aac_softc *sc)
SHUTDOWN_PRI_DEFAULT)) == NULL)
device_printf(sc->aac_dev, "shutdown event registration failed\n");
/* Register with CAM for the non-DASD devices */
if (!(sc->quirks & AAC_QUIRK_NOCAM))
aac_get_bus_info(sc);
return(0);
}
@ -349,7 +351,7 @@ aac_startup(void *arg)
/* disconnect ourselves from the intrhook chain */
config_intrhook_disestablish(&sc->aac_ich);
aac_get_sync_fib(sc, &fib, 0);
aac_alloc_sync_fib(sc, &fib, 0);
mi = (struct aac_mntinfo *)&fib->data[0];
/* loop over possible containers */
@ -409,7 +411,7 @@ aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
mir->MntTable[0].FileSystemName,
mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
if ((child = device_add_child(sc->aac_dev, NULL, -1)) == NULL)
if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
device_printf(sc->aac_dev, "device_add_child failed\n");
else
device_set_ivars(child, co);
@ -545,7 +547,7 @@ aac_shutdown(device_t dev)
*/
device_printf(sc->aac_dev, "shutting down controller...");
aac_get_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
cc = (struct aac_close_command *)&fib->data[0];
cc->Command = VM_CloseAll;
@ -669,7 +671,7 @@ aac_intr(void *arg)
/*
* Start as much queued I/O as possible on the controller
*/
static void
void
aac_startio(struct aac_softc *sc)
{
struct aac_command *cm;
@ -781,7 +783,7 @@ aac_host_command(struct aac_softc *sc)
/* XXX Compute the Size field? */
size = fib->Header.Size;
if (size > sizeof(struct aac_fib)) {
size = sizeof(struct aac_fib);
size = sizeof(struct aac_fib);
fib->Header.Size = size;
}
/*
@ -1041,7 +1043,7 @@ aac_wait_command(struct aac_command *cm, int timeout)
/*
* Allocate a command.
*/
static int
int
aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
{
struct aac_command *cm;
@ -1058,7 +1060,7 @@ aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
/*
* Release a command back to the freelist.
*/
static void
void
aac_release_command(struct aac_command *cm)
{
debug_called(3);
@ -1330,8 +1332,8 @@ aac_init(struct aac_softc *sc)
* Create DMA tag for the common structure and allocate it.
*/
if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */
1, 0, /* algnmnt, boundary */
BUS_SPACE_MAXADDR, /* lowaddr */
1, 0, /* algnmnt, boundary */
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
sizeof(struct aac_common), /* maxsize */
@ -1350,7 +1352,7 @@ aac_init(struct aac_softc *sc)
}
bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
sc->aac_common, sizeof(*sc->aac_common), aac_common_map,
sc, 0);
sc, 0);
bzero(sc->aac_common, sizeof(*sc->aac_common));
/*
@ -1515,7 +1517,7 @@ aac_sync_command(struct aac_softc *sc, u_int32_t command,
* Grab the sync fib area.
*/
int
aac_get_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags)
aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags)
{
/*
@ -2070,11 +2072,12 @@ aac_describe_controller(struct aac_softc *sc)
debug_called(2);
aac_get_sync_fib(sc, &fib, 0);
aac_alloc_sync_fib(sc, &fib, 0);
fib->data[0] = 0;
if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
aac_release_sync_fib(sc);
return;
}
info = (struct aac_adapter_info *)&fib->data[0];
@ -2093,6 +2096,8 @@ aac_describe_controller(struct aac_softc *sc)
info->KernelRevision.external.comp.dash,
info->KernelRevision.buildNumber,
(u_int32_t)(info->SerialNumber & 0xffffff));
aac_release_sync_fib(sc);
}
/*
@ -2366,7 +2371,7 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
* doesn't tell us anything else! Re-enumerate the
* containers and sort things out.
*/
aac_get_sync_fib(sc, &fib, 0);
aac_alloc_sync_fib(sc, &fib, 0);
mi = (struct aac_mntinfo *)&fib->data[0];
mi->Command = VM_NameServe;
mi->MntType = FT_FILESYS;
@ -2697,3 +2702,101 @@ aac_query_disk(struct aac_softc *sc, caddr_t uptr)
return (error);
}
static void
aac_get_bus_info(struct aac_softc *sc)
{
struct aac_fib *fib;
struct aac_ctcfg *c_cmd;
struct aac_ctcfg_resp *c_resp;
struct aac_vmioctl *vmi;
struct aac_vmi_businf_resp *vmi_resp;
struct aac_getbusinf businfo;
struct aac_cam_inf *caminf;
device_t child;
int i, found, error;
aac_alloc_sync_fib(sc, &fib, 0);
c_cmd = (struct aac_ctcfg *)&fib->data[0];
c_cmd->Command = VM_ContainerConfig;
c_cmd->cmd = CT_GET_SCSI_METHOD;
c_cmd->param = 0;
error = aac_sync_fib(sc, ContainerCommand, 0, fib,
sizeof(struct aac_ctcfg));
if (error) {
device_printf(sc->aac_dev, "Error %d sending "
"VM_ContainerConfig command\n", error);
aac_release_sync_fib(sc);
return;
}
c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
if (c_resp->Status != ST_OK) {
device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
c_resp->Status);
aac_release_sync_fib(sc);
return;
}
sc->scsi_method_id = c_resp->param;
vmi = (struct aac_vmioctl *)&fib->data[0];
vmi->Command = VM_Ioctl;
vmi->ObjType = FT_DRIVE;
vmi->MethId = sc->scsi_method_id;
vmi->ObjId = 0;
vmi->IoctlCmd = GetBusInfo;
error = aac_sync_fib(sc, ContainerCommand, 0, fib,
sizeof(struct aac_vmioctl));
if (error) {
device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
error);
aac_release_sync_fib(sc);
return;
}
vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
if (vmi_resp->Status != ST_OK) {
device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
vmi_resp->Status);
aac_release_sync_fib(sc);
return;
}
bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
aac_release_sync_fib(sc);
found = 0;
for (i = 0; i < businfo.BusCount; i++) {
if (businfo.BusValid[i] != AAC_BUS_VALID)
continue;
MALLOC(caminf, struct aac_cam_inf *,
sizeof(struct aac_cam_inf), M_AACBUF, M_NOWAIT | M_ZERO);
if (caminf == NULL)
continue;
child = device_add_child(sc->aac_dev, "aacp", -1);
if (child == NULL) {
device_printf(sc->aac_dev, "device_add_child failed\n");
continue;
}
caminf->TargetsPerBus = businfo.TargetsPerBus;
caminf->BusNumber = i;
caminf->InitiatorBusId = businfo.InitiatorBusId[i];
caminf->aac_sc = sc;
device_set_ivars(child, caminf);
device_set_desc(child, "SCSI Passthrough Bus");
found = 1;
}
if (found)
bus_generic_attach(sc->aac_dev);
return;
}

591
sys/dev/aac/aac_cam.c Normal file
View File

@ -0,0 +1,591 @@
/*
* Copyright (c) 2002 Adaptec, Inc.
* 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.
*
* 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$
*/
/*
* CAM front-end for communicating with non-DASD devices
*/
#include "opt_aac.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_debug.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
#include <cam/scsi/scsi_all.h>
#include <cam/scsi/scsi_message.h>
#include <dev/aac/aac_compat.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/devicestat.h>
#include <sys/disk.h>
#include <machine/md_var.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <dev/aac/aacreg.h>
#include <dev/aac/aac_ioctl.h>
#include <dev/aac/aacvar.h>
#include <dev/aac/aac_cam.h>
struct aac_cam {
device_t dev;
struct aac_cam_inf *inf;
u_int32_t scsi_method_id;
int bus;
struct cam_sim *sim;
struct cam_path *path;
};
static int aac_cam_probe(device_t dev);
static int aac_cam_attach(device_t dev);
static int aac_cam_detach(device_t dev);
static void aac_cam_action(struct cam_sim *, union ccb *);
static void aac_cam_poll(struct cam_sim *);
static void aac_cam_complete(struct aac_command *);
static u_int32_t aac_cam_reset_bus(struct cam_sim *, union ccb *);
static u_int32_t aac_cam_abort_ccb(struct cam_sim *, union ccb *);
static u_int32_t aac_cam_term_io(struct cam_sim *, union ccb *);
static int aac_cam_get_tran_settings(struct aac_softc *, struct ccb_trans_settings *, u_int32_t);
static devclass_t aac_pass_devclass;
static device_method_t aac_pass_methods[] = {
DEVMETHOD(device_probe, aac_cam_probe),
DEVMETHOD(device_attach, aac_cam_attach),
DEVMETHOD(device_detach, aac_cam_detach),
{ 0, 0 }
};
static driver_t aac_pass_driver = {
"aacp",
aac_pass_methods,
sizeof(struct aac_cam)
};
DRIVER_MODULE(aacp, aac, aac_pass_driver, aac_pass_devclass, 0, 0);
MODULE_DEPEND(aacp, cam, 1, 1, 1);
MALLOC_DEFINE(M_AACCAM, "aaccam", "AAC CAM info");
static int
aac_cam_probe(device_t dev)
{
debug_called(2);
return (0);
}
static int
aac_cam_detach(device_t dev)
{
return (0);
}
/*
* Register the driver as a CAM SIM
*/
static int
aac_cam_attach(device_t dev)
{
struct cam_devq *devq;
struct cam_sim *sim;
struct cam_path *path;
struct aac_cam *camsc;
struct aac_cam_inf *inf;
debug_called(1);
camsc = (struct aac_cam *)device_get_softc(dev);
inf = (struct aac_cam_inf *)device_get_ivars(dev);
camsc->inf = inf;
devq = cam_simq_alloc(inf->TargetsPerBus);
if (devq == NULL)
return (EIO);
sim = cam_sim_alloc(aac_cam_action, aac_cam_poll, "aacp", camsc,
device_get_unit(dev), 1, 1, devq);
if (sim == NULL) {
cam_simq_free(devq);
return (EIO);
}
if (xpt_bus_register(sim, 0) != CAM_SUCCESS) {
cam_sim_free(sim, TRUE);
return (EIO);
}
if (xpt_create_path(&path, NULL, cam_sim_path(sim),
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
xpt_bus_deregister(cam_sim_path(sim));
cam_sim_free(sim, TRUE);
return (EIO);
}
camsc->sim = sim;
camsc->path = path;
camsc->bus = cam_sim_bus(sim);
return (0);
}
static void
aac_cam_action(struct cam_sim *sim, union ccb *ccb)
{
struct aac_cam *camsc;
struct aac_softc *sc;
struct aac_srb32 *srb;
struct aac_fib *fib;
struct aac_command *cm;
debug_called(2);
camsc = (struct aac_cam *)cam_sim_softc(sim);
sc = camsc->inf->aac_sc;
/* Synchronous ops, and ops that don't require communication with the
* controller */
switch(ccb->ccb_h.func_code) {
case XPT_SCSI_IO:
case XPT_RESET_DEV:
/* These are handled down below */
break;
case XPT_CALC_GEOMETRY:
{
struct ccb_calc_geometry *ccg;
u_int32_t size_mb;
u_int32_t secs_per_cylinder;
ccg = &ccb->ccg;
size_mb = ccg->volume_size /
((1024L * 1024L) / ccg->block_size);
if (size_mb >= (2 * 1024)) { /* 2GB */
ccg->heads = 255;
ccg->secs_per_track = 63;
} else if (size_mb >= (1 * 1024)) { /* 1GB */
ccg->heads = 128;
ccg->secs_per_track = 32;
} else {
ccg->heads = 64;
ccg->secs_per_track = 32;
}
secs_per_cylinder = ccg->heads * ccg->secs_per_track;
ccg->cylinders = ccg->volume_size / secs_per_cylinder;
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
return;
}
case XPT_PATH_INQ:
{
struct ccb_pathinq *cpi = &ccb->cpi;
cpi->version_num = 1;
cpi->hba_inquiry = PI_WIDE_16;
cpi->target_sprt = 0;
cpi->hba_misc = 0;
cpi->hba_eng_cnt = 0;
cpi->max_target = camsc->inf->TargetsPerBus;
cpi->max_lun = 8; /* Per the controller spec */
cpi->initiator_id = camsc->inf->InitiatorBusId;
cpi->bus_id = cam_sim_bus(sim);
cpi->base_transfer_speed = 3300;
strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
cpi->unit_number = cam_sim_unit(sim);
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
return;
}
case XPT_GET_TRAN_SETTINGS:
{
u_int32_t handle;
handle = AAC_BTL_TO_HANDLE(cam_sim_bus(sim),
ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
ccb->ccb_h.status = aac_cam_get_tran_settings(sc, &ccb->cts,
handle);
xpt_done(ccb);
return;
}
case XPT_SET_TRAN_SETTINGS:
ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
xpt_done(ccb);
return;
case XPT_RESET_BUS:
if (!(sc->quirks & AAC_QUIRK_CAM_NORESET)) {
ccb->ccb_h.status = aac_cam_reset_bus(sim, ccb);
} else {
ccb->ccb_h.status = CAM_REQ_CMP;
}
xpt_done(ccb);
return;
case XPT_ABORT:
ccb->ccb_h.status = aac_cam_abort_ccb(sim, ccb);
xpt_done(ccb);
return;
case XPT_TERM_IO:
ccb->ccb_h.status = aac_cam_term_io(sim, ccb);
xpt_done(ccb);
return;
default:
device_printf(sc->aac_dev, "Unsupported command 0x%x\n",
ccb->ccb_h.func_code);
ccb->ccb_h.status = CAM_PROVIDE_FAIL;
xpt_done(ccb);
return;
}
/* Async ops that require communcation with the controller */
if (aac_alloc_command(sc, &cm)) {
xpt_freeze_simq(sim, 1);
ccb->ccb_h.status = CAM_REQUEUE_REQ;
xpt_done(ccb);
return;
}
fib = cm->cm_fib;
srb = (struct aac_srb32 *)&fib->data[0];
cm->cm_datalen = 0;
switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
case CAM_DIR_IN:
srb->flags = AAC_SRB_FLAGS_DATA_IN;
cm->cm_flags |= AAC_CMD_DATAIN;
break;
case CAM_DIR_OUT:
srb->flags = AAC_SRB_FLAGS_DATA_OUT;
cm->cm_flags |= AAC_CMD_DATAOUT;
break;
case CAM_DIR_NONE:
srb->flags = AAC_SRB_FLAGS_NO_DATA_XFER;
break;
default:
srb->flags = AAC_SRB_FLAGS_UNSPECIFIED_DIRECTION;
cm->cm_flags |= AAC_CMD_DATAIN | AAC_CMD_DATAOUT;
break;
}
switch(ccb->ccb_h.func_code) {
case XPT_SCSI_IO:
{
struct ccb_scsiio *csio = &ccb->csio;
srb->function = AAC_SRB_FUNC_EXECUTE_SCSI;
/*
* Copy the CDB into the SRB. It's only 6-16 bytes,
* so a copy is not too expensive.
*/
srb->cdb_len = csio->cdb_len;
if (ccb->ccb_h.flags & CAM_CDB_POINTER)
bcopy(csio->cdb_io.cdb_ptr, (u_int8_t *)&srb->cdb[0],
srb->cdb_len);
else
bcopy(csio->cdb_io.cdb_bytes, (u_int8_t *)&srb->cdb[0],
srb->cdb_len);
/* Map the s/g list. XXX 32bit addresses only! */
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
srb->data_len = csio->dxfer_len;
if (ccb->ccb_h.flags & CAM_DATA_PHYS) {
srb->sg_map32.SgCount = 1;
srb->sg_map32.SgEntry[0].SgAddress =
(u_int32_t)csio->data_ptr;
srb->sg_map32.SgEntry[0].SgByteCount =
csio->dxfer_len;
} else {
/*
* Arrange things so that the S/G
* map will get set up automagically
*/
cm->cm_data = (void *)csio->data_ptr;
cm->cm_datalen = csio->dxfer_len;
cm->cm_sgtable = &srb->sg_map32;
}
} else {
/* XXX Need to handle multiple s/g elements */
panic("aac_cam: multiple s/g elements");
}
} else {
srb->sg_map32.SgCount = 0;
srb->sg_map32.SgEntry[0].SgByteCount = 0;
srb->data_len = 0;
}
break;
}
case XPT_RESET_DEV:
if (!(sc->quirks & AAC_QUIRK_CAM_NORESET)) {
srb->function = AAC_SRB_FUNC_RESET_DEVICE;
break;
} else {
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
return;
}
default:
break;
}
srb->bus = cam_sim_bus(sim); /* Bus number relative to the card */
srb->target = ccb->ccb_h.target_id;
srb->lun = ccb->ccb_h.target_lun;
srb->timeout = ccb->ccb_h.timeout; /* XXX */
srb->retry_limit = 0;
cm->cm_complete = aac_cam_complete;
cm->cm_private = ccb;
cm->cm_timestamp = time_second;
cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
fib->Header.XferState =
AAC_FIBSTATE_HOSTOWNED |
AAC_FIBSTATE_INITIALISED |
AAC_FIBSTATE_FROMHOST |
AAC_FIBSTATE_REXPECTED |
AAC_FIBSTATE_NORM;
fib->Header.Command = ScsiPortCommand;
fib->Header.Size = sizeof(struct aac_fib_header) +
sizeof(struct aac_srb32);
aac_enqueue_ready(cm);
aac_startio(cm->cm_sc);
return;
}
static void
aac_cam_poll(struct cam_sim *sim)
{
/*
* Pinging the interrupt routine isn't very safe, nor is it
* really necessary. Do nothing.
*/
}
static void
aac_cam_complete(struct aac_command *cm)
{
union ccb *ccb;
struct aac_srb_response *srbr;
struct aac_softc *sc;
debug_called(2);
sc = cm->cm_sc;
ccb = cm->cm_private;
srbr = (struct aac_srb_response *)&cm->cm_fib->data[0];
if (srbr->fib_status != 0) {
device_printf(sc->aac_dev, "Passthru FIB failed!\n");
ccb->ccb_h.status = CAM_REQ_ABORTED;
} else {
/*
* The SRB error codes just happen to match the CAM error
* codes. How convienient!
*/
ccb->ccb_h.status = srbr->srb_status;
/* Take care of SCSI_IO ops. */
if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
u_int8_t command, device;
ccb->csio.scsi_status = srbr->scsi_status;
/* Take care of autosense */
if (srbr->sense_len) {
int sense_len, scsi_sense_len;
scsi_sense_len = sizeof(struct scsi_sense_data);
bzero(&ccb->csio.sense_data, scsi_sense_len);
sense_len = (srbr->sense_len >
scsi_sense_len) ? scsi_sense_len :
srbr->sense_len;
bcopy(&srbr->sense[0], &ccb->csio.sense_data,
srbr->sense_len);
ccb->csio.sense_len = sense_len;
ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
scsi_sense_print(&ccb->csio);
}
/* If this is an inquiry command, fake things out */
if (ccb->ccb_h.flags & CAM_CDB_POINTER)
command = ccb->csio.cdb_io.cdb_ptr[0];
else
command = ccb->csio.cdb_io.cdb_bytes[0];
if ((command == INQUIRY) &&
(ccb->ccb_h.status == CAM_REQ_CMP)) {
device = ccb->csio.data_ptr[0] & 0x1f;
/*
* We want DASD and PROC devices to only be
* visible through the pass device.
*/
if ((device == T_DIRECT) ||
(device == T_PROCESSOR) ||
(sc->quirks & AAC_QUIRK_CAM_PASSONLY))
ccb->csio.data_ptr[0] =
((device & 0xe0) | T_NODEVICE);
}
}
}
aac_release_command(cm);
xpt_done(ccb);
return;
}
static u_int32_t
aac_cam_reset_bus(struct cam_sim *sim, union ccb *ccb)
{
struct aac_fib *fib;
struct aac_softc *sc;
struct aac_cam *camsc;
struct aac_vmioctl *vmi;
struct aac_resetbus *rbc;
int e;
camsc = (struct aac_cam *)cam_sim_softc(sim);
sc = camsc->inf->aac_sc;
if (sc == NULL) {
printf("Null sc?\n");
return (CAM_REQ_ABORTED);
}
aac_alloc_sync_fib(sc, &fib, 0);
vmi = (struct aac_vmioctl *)&fib->data[0];
vmi->Command = VM_Ioctl;
vmi->ObjType = FT_DRIVE;
vmi->MethId = sc->scsi_method_id;
vmi->ObjId = 0;
vmi->IoctlCmd = ResetBus;
rbc = (struct aac_resetbus *)&vmi->IoctlBuf[0];
rbc->BusNumber = cam_sim_bus(sim);
e = aac_sync_fib(sc, ContainerCommand, 0, fib,
sizeof(struct aac_vmioctl));
if (e) {
device_printf(sc->aac_dev, "Error 0x%x sending passthrough\n",
e);
aac_release_sync_fib(sc);
return (CAM_REQ_ABORTED);
}
aac_release_sync_fib(sc);
return (CAM_REQ_CMP);
}
static u_int32_t
aac_cam_abort_ccb(struct cam_sim *sim, union ccb *ccb)
{
return (CAM_UA_ABORT);
}
static u_int32_t
aac_cam_term_io(struct cam_sim *sim, union ccb *ccb)
{
return (CAM_UA_TERMIO);
}
static int
aac_cam_get_tran_settings(struct aac_softc *sc, struct ccb_trans_settings *cts, u_int32_t handle)
{
struct aac_fib *fib;
struct aac_vmioctl *vmi;
struct aac_vmi_devinfo_resp *vmi_resp;
int error;
aac_alloc_sync_fib(sc, &fib, 0);
vmi = (struct aac_vmioctl *)&fib->data[0];
vmi->Command = VM_Ioctl;
vmi->ObjType = FT_DRIVE;
vmi->MethId = sc->scsi_method_id;
vmi->ObjId = handle;
vmi->IoctlCmd = GetDeviceProbeInfo;
error = aac_sync_fib(sc, ContainerCommand, 0, fib,
sizeof(struct aac_vmioctl));
if (error) {
device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
error);
aac_release_sync_fib(sc);
return (CAM_REQ_INVALID);
}
vmi_resp = (struct aac_vmi_devinfo_resp *)&fib->data[0];
if (vmi_resp->Status != ST_OK) {
device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
vmi_resp->Status);
aac_release_sync_fib(sc);
return (CAM_REQ_CMP_ERR);
}
cts->bus_width = ((vmi_resp->Inquiry7 & 0x60) >> 5);
if (vmi_resp->ScsiRate) {
cts->sync_period =
scsi_calc_syncparam((10000 / vmi_resp->ScsiRate));
cts->sync_offset = vmi_resp->ScsiOffset;
} else {
cts->sync_period = 0;
cts->sync_offset = 0;
}
cts->flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
cts->valid = CCB_TRANS_DISC_VALID |
CCB_TRANS_SYNC_RATE_VALID |
CCB_TRANS_SYNC_OFFSET_VALID |
CCB_TRANS_BUS_WIDTH_VALID |
CCB_TRANS_TQ_VALID;
aac_release_sync_fib(sc);
return (CAM_REQ_CMP);
}

34
sys/dev/aac/aac_cam.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2002 Adaptec, Inc.
* 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.
*
* 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$
*/
struct aac_cam_inf {
int TargetsPerBus;
int BusNumber;
int InitiatorBusId;
struct aac_softc *aac_sc;
};

View File

@ -269,7 +269,7 @@ aac_disk_dump(dev_t dev, void *virtual, vm_offset_t physical, off_t offset, size
}
}
aac_get_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
bw = (struct aac_blockwrite *)&fib->data[0];
while (length > 0) {

View File

@ -90,30 +90,44 @@ struct aac_ident
u_int16_t subvendor;
u_int16_t subdevice;
int hwif;
int quirks;
char *desc;
} aac_identifiers[] = {
{0x1028, 0x0001, 0x1028, 0x0001, AAC_HWIF_I960RX, "Dell PERC 2/Si"},
{0x1028, 0x0002, 0x1028, 0x0002, AAC_HWIF_I960RX, "Dell PERC 3/Di"},
{0x1028, 0x0003, 0x1028, 0x0003, AAC_HWIF_I960RX, "Dell PERC 3/Si"},
{0x1028, 0x0004, 0x1028, 0x00d0, AAC_HWIF_I960RX, "Dell PERC 3/Si"},
{0x1028, 0x0002, 0x1028, 0x00d1, AAC_HWIF_I960RX, "Dell PERC 3/Di"},
{0x1028, 0x0002, 0x1028, 0x00d9, AAC_HWIF_I960RX, "Dell PERC 3/Di"},
{0x1028, 0x0008, 0x1028, 0x00cf, AAC_HWIF_I960RX, "Dell PERC 3/Di"},
{0x1028, 0x000a, 0x1028, 0x0106, AAC_HWIF_I960RX, "Dell PERC 3/Di"},
{0x1028, 0x000a, 0x1028, 0x011b, AAC_HWIF_I960RX, "Dell PERC 3/Di"},
{0x1028, 0x000a, 0x1028, 0x0121, AAC_HWIF_I960RX, "Dell PERC 3/Di"},
{0x1011, 0x0046, 0x9005, 0x0364, AAC_HWIF_STRONGARM, "Adaptec AAC-364"},
{0x1011, 0x0046, 0x9005, 0x0365, AAC_HWIF_STRONGARM,
"Adaptec SCSI RAID 5400S"},
{0x1011, 0x0046, 0x9005, 0x1364, AAC_HWIF_STRONGARM, "Dell PERC 2/QC"},
{0x1011, 0x0046, 0x103c, 0x10c2, AAC_HWIF_STRONGARM, "HP NetRaid-4M"},
{0x9005, 0x0285, 0x9005, 0x0285, AAC_HWIF_I960RX,
{0x1028, 0x0001, 0x1028, 0x0001, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
"Dell PERC 2/Si"},
{0x1028, 0x0002, 0x1028, 0x0002, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
"Dell PERC 3/Di"},
{0x1028, 0x0003, 0x1028, 0x0003, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
"Dell PERC 3/Si"},
{0x1028, 0x0004, 0x1028, 0x00d0, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
"Dell PERC 3/Si"},
{0x1028, 0x0002, 0x1028, 0x00d1, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
"Dell PERC 3/Di"},
{0x1028, 0x0002, 0x1028, 0x00d9, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
"Dell PERC 3/Di"},
{0x1028, 0x0008, 0x1028, 0x00cf, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
"Dell PERC 3/Di"},
{0x1028, 0x000a, 0x1028, 0x0106, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
"Dell PERC 3/Di"},
{0x1028, 0x000a, 0x1028, 0x011b, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
"Dell PERC 3/Di"},
{0x1028, 0x000a, 0x1028, 0x0121, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
"Dell PERC 3/Di"},
{0x1011, 0x0046, 0x9005, 0x0364, AAC_HWIF_STRONGARM, AAC_QUIRK_NOCAM,
"Adaptec AAC-364"},
{0x1011, 0x0046, 0x9005, 0x0365, AAC_HWIF_STRONGARM, 0,
"Adaptec SCSI RAID 5400S"},
{0x1011, 0x0046, 0x9005, 0x1364, AAC_HWIF_STRONGARM, AAC_QUIRK_NOCAM |
AAC_QUIRK_PERC2QC, "Dell PERC 2/QC"},
{0x1011, 0x0046, 0x103c, 0x10c2, AAC_HWIF_STRONGARM,
AAC_QUIRK_CAM_NORESET, "HP NetRaid-4M"},
{0x9005, 0x0285, 0x9005, 0x0285, AAC_HWIF_I960RX, 0,
"Adaptec SCSI RAID 2200S"},
{0x9005, 0x0285, 0x9005, 0x0287, AAC_HWIF_I960RX,
{0x9005, 0x0285, 0x9005, 0x0287, AAC_HWIF_I960RX, 0,
"Adaptec SCSI RAID 2200S"},
{0x9005, 0x0285, 0x9005, 0x0286, AAC_HWIF_I960RX,
{0x9005, 0x0285, 0x9005, 0x0286, AAC_HWIF_I960RX, 0,
"Adaptec SCSI RAID 2120S"},
{0, 0, 0, 0, 0, 0}
{0, 0, 0, 0, 0, 0, 0}
};
/*
@ -266,7 +280,7 @@ aac_pci_attach(device_t dev)
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
0, /* flags */
&sc->aac_fib_dmat)) {
device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");
device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
goto out;
}
@ -277,7 +291,9 @@ aac_pci_attach(device_t dev)
sc->aac_hwif = AAC_HWIF_UNKNOWN;
for (i = 0; aac_identifiers[i].vendor != 0; i++) {
if ((aac_identifiers[i].vendor == pci_get_vendor(dev)) &&
(aac_identifiers[i].device == pci_get_device(dev))) {
(aac_identifiers[i].device == pci_get_device(dev)) &&
(aac_identifiers[i].subvendor == pci_get_subvendor(dev)) &&
(aac_identifiers[i].subdevice == pci_get_subdevice(dev))) {
sc->aac_hwif = aac_identifiers[i].hwif;
switch(sc->aac_hwif) {
case AAC_HWIF_I960RX:
@ -294,6 +310,10 @@ aac_pci_attach(device_t dev)
sc->aac_if = aac_fa_interface;
break;
}
/* Set up quirks */
sc->quirks = aac_identifiers[i].quirks;
break;
}
}
@ -304,13 +324,6 @@ aac_pci_attach(device_t dev)
}
/*
* Check for quirky hardware
*/
if (pci_get_subdevice(dev) == 0x1364 &&
pci_get_subvendor(dev) == 0x9005)
sc->quirks |= AAC_QUIRK_PERC2QC;
/*
* Do bus-independent initialisation.
*/

View File

@ -1001,6 +1001,105 @@ struct aac_closecommand {
u_int32_t ContainerId;
} __attribute__ ((packed));
/*
* Container Config Command
*/
#define CT_GET_SCSI_METHOD 64
struct aac_ctcfg {
AAC_VMCommand Command;
u_int32_t cmd;
u_int32_t param;
} __attribute__ ((packed));
struct aac_ctcfg_resp {
AAC_FSAStatus Status;
u_int32_t resp;
u_int32_t param;
} __attribute__ ((packed));
/*
* 'Ioctl' commads
*/
#define AAC_SCSI_MAX_PORTS 10
#define AAC_BUS_NO_EXIST 0
#define AAC_BUS_VALID 1
#define AAC_BUS_FAULTED 2
#define AAC_BUS_DISABLED 3
#define GetBusInfo 0x9
struct aac_getbusinf {
u_int32_t ProbeComplete;
u_int32_t BusCount;
u_int32_t TargetsPerBus;
u_int8_t InitiatorBusId[AAC_SCSI_MAX_PORTS];
u_int8_t BusValid[AAC_SCSI_MAX_PORTS];
} __attribute__ ((packed));
struct aac_vmioctl {
AAC_VMCommand Command;
AAC_FType ObjType;
u_int32_t MethId;
u_int32_t ObjId;
u_int32_t IoctlCmd;
u_int32_t IoctlBuf[1]; /* Placeholder? */
} __attribute__ ((packed));
struct aac_vmi_businf_resp {
AAC_FSAStatus Status;
AAC_FType ObjType;
u_int32_t MethId;
u_int32_t ObjId;
u_int32_t IoctlCmd;
struct aac_getbusinf BusInf;
} __attribute__ ((packed));
#define AAC_BTL_TO_HANDLE(b, t, l) \
(((b & 0x3f) << 7) | ((l & 0x7) << 4) | (t & 0xf))
#define GetDeviceProbeInfo 0x5
struct aac_vmi_devinfo_resp {
AAC_FSAStatus Status;
AAC_FType ObjType;
u_int32_t MethId;
u_int32_t ObjId;
u_int32_t IoctlCmd;
u_int8_t VendorId[8];
u_int8_t ProductId[16];
u_int8_t ProductRev[4];
u_int32_t Inquiry7;
u_int32_t align1;
u_int32_t Inquiry0;
u_int32_t align2;
u_int32_t Inquiry1;
u_int32_t align3;
u_int32_t reserved[2];
u_int8_t VendorSpecific[20];
u_int32_t Smart:1;
u_int32_t AAC_Managed:1;
u_int32_t align4;
u_int32_t reserved2:6;
u_int32_t Bus;
u_int32_t Target;
u_int32_t Lun;
u_int32_t ultraEnable:1,
disconnectEnable:1,
fast20EnabledW:1,
scamDevice:1,
scamTolerant:1,
setForSync:1,
setForWide:1,
syncDevice:1,
wideDevice:1,
reserved1:7,
ScsiRate:8,
ScsiOffset:8;
}; /* Do not pack */
#define ResetBus 0x16
struct aac_resetbus {
u_int32_t BusNumber;
};
/*
* Write 'stability' options.
*/
@ -1061,6 +1160,93 @@ struct aac_close_command {
u_int32_t ContainerId;
};
/*
* SCSI Passthrough structures
*/
struct aac_srb32 {
u_int32_t function;
u_int32_t bus;
u_int32_t target;
u_int32_t lun;
u_int32_t timeout;
u_int32_t flags;
u_int32_t data_len;
u_int32_t retry_limit;
u_int32_t cdb_len;
u_int8_t cdb[16];
struct aac_sg_table sg_map32;
};
enum {
AAC_SRB_FUNC_EXECUTE_SCSI = 0x00,
AAC_SRB_FUNC_CLAIM_DEVICE,
AAC_SRB_FUNC_IO_CONTROL,
AAC_SRB_FUNC_RECEIVE_EVENT,
AAC_SRB_FUNC_RELEASE_QUEUE,
AAC_SRB_FUNC_ATTACH_DEVICE,
AAC_SRB_FUNC_RELEASE_DEVICE,
AAC_SRB_FUNC_SHUTDOWN,
AAC_SRB_FUNC_FLUSH,
AAC_SRB_FUNC_ABORT_COMMAND = 0x10,
AAC_SRB_FUNC_RELEASE_RECOVERY,
AAC_SRB_FUNC_RESET_BUS,
AAC_SRB_FUNC_RESET_DEVICE,
AAC_SRB_FUNC_TERMINATE_IO,
AAC_SRB_FUNC_FLUSH_QUEUE,
AAC_SRB_FUNC_REMOVE_DEVICE,
AAC_SRB_FUNC_DOMAIN_VALIDATION
};
#define AAC_SRB_FLAGS_NO_DATA_XFER 0x0000
#define AAC_SRB_FLAGS_DISABLE_DISCONNECT 0x0004
#define AAC_SRB_FLAGS_DISABLE_SYNC_TRANSFER 0x0008
#define AAC_SRB_FLAGS_BYPASS_FROZEN_QUEUE 0x0010
#define AAC_SRB_FLAGS_DISABLE_AUTOSENSE 0x0020
#define AAC_SRB_FLAGS_DATA_IN 0x0040
#define AAC_SRB_FLAGS_DATA_OUT 0x0080
#define AAC_SRB_FLAGS_UNSPECIFIED_DIRECTION \
(AAC_SRB_FLAGS_DATA_IN | AAC_SRB_FLAGS_DATA_OUT)
#define AAC_HOST_SENSE_DATA_MAX 30
struct aac_srb_response {
u_int32_t fib_status;
u_int32_t srb_status;
u_int32_t scsi_status;
u_int32_t data_len;
u_int32_t sense_len;
u_int8_t sense[AAC_HOST_SENSE_DATA_MAX];
};
enum {
AAC_SRB_STS_PENDING = 0x00,
AAC_SRB_STS_SUCCESS,
AAC_SRB_STS_ABORTED,
AAC_SRB_STS_ABORT_FAILED,
AAC_SRB_STS_ERROR,
AAC_SRB_STS_BUSY,
AAC_SRB_STS_INVALID_REQUEST,
AAC_SRB_STS_INVALID_PATH_ID,
AAC_SRB_STS_NO_DEVICE,
AAC_SRB_STS_TIMEOUT,
AAC_SRB_STS_SELECTION_TIMEOUT,
AAC_SRB_STS_COMMAND_TIMEOUT,
AAC_SRB_STS_MESSAGE_REJECTED = 0x0D,
AAC_SRB_STS_BUS_RESET,
AAC_SRB_STS_PARITY_ERROR,
AAC_SRB_STS_REQUEST_SENSE_FAILED,
AAC_SRB_STS_NO_HBA,
AAC_SRB_STS_DATA_OVERRUN,
AAC_SRB_STS_UNEXPECTED_BUS_FREE,
AAC_SRB_STS_PHASE_SEQUENCE_FAILURE,
AAC_SRB_STS_BAD_SRB_BLOCK_LENGTH,
AAC_SRB_STS_REQUEST_FLUSHED,
AAC_SRB_STS_INVALID_LUN = 0x20,
AAC_SRB_STS_INVALID_TARGET_ID,
AAC_SRB_STS_BAD_FUNCTION,
AAC_SRB_STS_ERROR_RECOVERY
};
/*
* Register set for adapters based on the Falcon bridge and PPC core
*/

View File

@ -362,6 +362,11 @@ struct aac_softc
#define AAC_AIFFLAGS_EXITED (1 << 3)
u_int32_t quirks;
#define AAC_QUIRK_PERC2QC (1 << 0)
#define AAC_QUIRK_NOCAM (1 << 1) /* No SCSI passthrough */
#define AAC_QUIRK_CAM_NORESET (1 << 2) /* Fake SCSI resets */
#define AAC_QUIRK_CAM_PASSONLY (1 << 3) /* Only create pass devices */
u_int32_t scsi_method_id;
};
@ -377,7 +382,11 @@ extern int aac_resume(device_t dev);
extern void aac_intr(void *arg);
extern void aac_submit_bio(struct bio *bp);
extern void aac_biodone(struct bio *bp);
extern int aac_get_sync_fib(struct aac_softc *sc,
extern void aac_startio(struct aac_softc *sc);
extern int aac_alloc_command(struct aac_softc *sc,
struct aac_command **cmp);
extern void aac_release_command(struct aac_command *cm);
extern int aac_alloc_sync_fib(struct aac_softc *sc,
struct aac_fib **fib, int flags);
extern void aac_release_sync_fib(struct aac_softc *sc);
extern int aac_sync_fib(struct aac_softc *sc, u_int32_t command,

View File

@ -115,6 +115,7 @@ device ses # SCSI Environmental Services (and SAF-TE)
# RAID controllers
device aac # Adaptec FSA RAID
device aacp # SCSI passthrough for aac (requires CAM)
device amr # AMI MegaRAID
device ida # Compaq Smart RAID
device mlx # Mylex DAC960 family

View File

@ -3,7 +3,8 @@
.PATH: ${.CURDIR}/../../dev/aac
KMOD= aac
SRCS= aac.c aac_pci.c aac_disk.c opt_aac.h
SRCS= aac.c aac_pci.c aac_disk.c aac_cam.c
SRCS+= opt_scsi.h opt_cam.h opt_aac.h
SRCS+= device_if.h bus_if.h pci_if.h
CFLAGS+= -DAAC_COMPAT_LINUX