52c9ce25d8
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
206 lines
6.2 KiB
C
206 lines
6.2 KiB
C
/*-
|
|
* 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
|