CAM Transport Layer (XPT).

Submitted by:	The CAM Team
This commit is contained in:
Justin T. Gibbs 1998-09-15 06:33:23 +00:00
parent 28fb27ba21
commit 8b8a9b1d3e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=39212
17 changed files with 9682 additions and 0 deletions

108
sys/cam/cam.c Normal file
View File

@ -0,0 +1,108 @@
/*
* Generic utility routines for the Common Access Method layer.
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#include <sys/param.h>
#include <cam/cam.h>
void
cam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen)
{
/* Trim leading/trailing spaces. */
while (srclen > 0 && src[0] == ' ')
src++, srclen--;
while (srclen > 0 && src[srclen-1] == ' ')
srclen--;
while (srclen > 0 && dstlen > 1) {
u_int8_t *cur_pos = dst;
if (*src < 0x20 || *src >= 0x80) {
/* SCSI-II Specifies that these should never occur. */
/* non-printable character */
if (dstlen > 4) {
*cur_pos++ = '\\';
*cur_pos++ = ((*src & 0300) >> 6) + '0';
*cur_pos++ = ((*src & 0070) >> 3) + '0';
*cur_pos++ = ((*src & 0007) >> 0) + '0';
} else {
*cur_pos++ = '?';
}
} else {
/* normal character */
*cur_pos++ = *src;
}
src++;
srclen--;
dstlen -= cur_pos - dst;
dst = cur_pos;
}
*dst = '\0';
}
/*
* Compare string with pattern, returning 0 on match.
* Short pattern matches trailing blanks in name,
* wildcard '*' in pattern matches rest of name,
* wildcard '?' matches a single non-space character.
*/
int
cam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len)
{
while (*pattern != '\0'&& str_len > 0) {
if (*pattern == '*') {
return (0);
}
if ((*pattern != *str)
&& (*pattern != '?' || *str == ' ')) {
return (1);
}
pattern++;
str++;
str_len--;
}
while (str_len > 0 && *str++ == ' ')
str_len--;
return (str_len);
}
caddr_t
cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries,
int entry_size, cam_quirkmatch_t *comp_func)
{
for (; num_entries > 0; num_entries--, quirk_table += entry_size) {
if ((*comp_func)(target, quirk_table) == 0)
return (quirk_table);
}
return (NULL);
}

165
sys/cam/cam.h Normal file
View File

@ -0,0 +1,165 @@
/*
* Data structures and definitions for the CAM system.
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#ifndef _CAM_CAM_H
#define _CAM_CAM_H 1
#ifdef KERNEL
#include <opt_cam.h>
#endif /* KERNEL */
#include <sys/cdefs.h>
typedef u_int path_id_t;
typedef u_int target_id_t;
typedef u_int lun_id_t;
#define CAM_XPT_PATH_ID ((path_id_t)~0)
#define CAM_BUS_WILDCARD ((path_id_t)~0)
#define CAM_TARGET_WILDCARD ((target_id_t)~0)
#define CAM_LUN_WILDCARD ((lun_id_t)~0)
/*
* Maximum length for a CAM CDB.
*/
#define CAM_MAX_CDBLEN 16
/*
* Definition of a CAM peripheral driver entry. Peripheral drivers instantiate
* one of these for each device they wish to communicate with and pass it into
* the xpt layer when they wish to schedule work on that device via the
* xpt_schecule API.
*/
struct cam_periph;
/*
* Priority information for a CAM structure. The generation number is
* incremented everytime a new entry is entered into the queue giving round
* robin per priority level scheduling.
*/
typedef struct {
u_int32_t priority;
#define CAM_PRIORITY_NONE (u_int32_t)-1
u_int32_t generation;
int index;
#define CAM_UNQUEUED_INDEX -1
#define CAM_ACTIVE_INDEX -2
#define CAM_DONEQ_INDEX -3
} cam_pinfo;
/* CAM flags */
typedef enum {
CAM_FLAG_NONE = 0x00,
CAM_EXPECT_INQ_CHANGE = 0x01
} cam_flags;
/* CAM Status field values */
typedef enum {
CAM_REQ_INPROG, /* CCB request is in progress */
CAM_REQ_CMP, /* CCB request completed without error */
CAM_REQ_ABORTED, /* CCB request aborted by the host */
CAM_UA_ABORT, /* Unable to abort CCB request */
CAM_REQ_CMP_ERR, /* CCB request completed with an error */
CAM_BUSY, /* CAM subsytem is busy */
CAM_REQ_INVALID, /* CCB request was invalid */
CAM_PATH_INVALID, /* Supplied Path ID is invalid */
CAM_DEV_NOT_THERE, /* SCSI Device Not Installed/there */
CAM_UA_TERMIO, /* Unable to terminate I/O CCB request */
CAM_SEL_TIMEOUT, /* Target Selection Timeout */
CAM_CMD_TIMEOUT, /* Command timeout */
CAM_SCSI_STATUS_ERROR, /* SCSI error, look at error code in CCB */
CAM_MSG_REJECT_REC, /* Message Reject Reveived */
CAM_SCSI_BUS_RESET, /* SCSI Bus Reset Sent/Received */
CAM_UNCOR_PARITY, /* Uncorrectable parity error occurred */
CAM_AUTOSENSE_FAIL = 0x10,/* Autosense: request sense cmd fail */
CAM_NO_HBA, /* No HBA Detected error */
CAM_DATA_RUN_ERR, /* Data Overrun error */
CAM_UNEXP_BUSFREE, /* Unexpected Bus Free */
CAM_SEQUENCE_FAIL, /* Target Bus Phase Sequence Failure */
CAM_CCB_LEN_ERR, /* CCB length supplied is inadequate */
CAM_PROVIDE_FAIL, /* Unable to provide requested capability */
CAM_BDR_SENT, /* A SCSI BDR msg was sent to target */
CAM_REQ_TERMIO, /* CCB request terminated by the host */
CAM_UNREC_HBA_ERROR, /* Unrecoverable Host Bus Adapter Error */
CAM_REQ_TOO_BIG, /* The request was too large for this host */
CAM_REQUEUE_REQ, /*
* This request should be requeued to preserve
* transaction ordering. This typically occurs
* when the SIM recognizes an error that should
* freeze the queue and must place additional
* requests for the target at the sim level
* back into the XPT queue.
*/
CAM_IDE = 0x33, /* Initiator Detected Error */
CAM_RESRC_UNAVAIL, /* Resource Unavailable */
CAM_UNACKED_EVENT, /* Unacknowledged Event by Host */
CAM_MESSAGE_RECV, /* Message Received in Host Target Mode */
CAM_INVALID_CDB, /* Invalid CDB received in Host Target Mode */
CAM_LUN_INVALID, /* Lun supplied is invalid */
CAM_TID_INVALID, /* Target ID supplied is invalid */
CAM_FUNC_NOTAVAIL, /* The requested function is not available */
CAM_NO_NEXUS, /* Nexus is not established */
CAM_IID_INVALID, /* The initiator ID is invalid */
CAM_CDB_RECVD, /* The SCSI CDB has been received */
CAM_LUN_ALRDY_ENA, /* The LUN is already eanbeld for target mode */
CAM_SCSI_BUSY, /* SCSI Bus Busy */
CAM_DEV_QFRZN = 0x40, /* The DEV queue is frozen w/this err */
/* Autosense data valid for target */
CAM_AUTOSNS_VALID = 0x80,
CAM_RELEASE_SIMQ = 0x100,/* SIM ready to take more commands */
CAM_SIM_QUEUED = 0x200,/* SIM has this command in it's queue */
CAM_STATUS_MASK = 0x3F, /* Mask bits for just the status # */
} cam_status;
__BEGIN_DECLS
typedef int (cam_quirkmatch_t)(caddr_t, caddr_t);
caddr_t cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries,
int entry_size, cam_quirkmatch_t *comp_func);
void cam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen);
int cam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len);
__END_DECLS
#ifdef KERNEL
static __inline void cam_init_pinfo(cam_pinfo *pinfo);
static __inline void cam_init_pinfo(cam_pinfo *pinfo)
{
pinfo->priority = CAM_PRIORITY_NONE;
pinfo->index = CAM_UNQUEUED_INDEX;
}
#endif /* KERNEL */
#endif /* _CAM_CAM_H */

779
sys/cam/cam_ccb.h Normal file
View File

@ -0,0 +1,779 @@
/*
* Data structures and definitions for CAM Control Blocks (CCBs).
*
* Copyright (c) 1997, 1998 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#ifndef _CAM_CAM_CCB_H
#define _CAM_CAM_CCB_H 1
#include <sys/queue.h>
#include <sys/cdefs.h>
#ifndef KERNEL
#include <sys/callout.h>
#endif
#include <cam/cam_debug.h>
#include <cam/scsi/scsi_all.h>
/* General allocation length definitions for CCB structures */
#define IOCDBLEN CAM_MAX_CDBLEN /* Space for CDB bytes/pointer */
#define VUHBALEN 14 /* Vendor Unique HBA length */
#define SIM_IDLEN 16 /* ASCII string len for SIM ID */
#define HBA_IDLEN 16 /* ASCII string len for HBA ID */
#define DEV_IDLEN 16 /* ASCII string len for device names */
#define CCB_PERIPH_PRIV_SIZE 2 /* size of peripheral private area */
#define CCB_SIM_PRIV_SIZE 2 /* size of sim private area */
/* Struct definitions for CAM control blocks */
/* Common CCB header */
/* CAM CCB flags */
typedef enum {
CAM_CDB_POINTER = 0x00000001,/* The CDB field is a pointer */
CAM_QUEUE_ENABLE = 0x00000002,/* SIM queue actions are enabled */
CAM_CDB_LINKED = 0x00000004,/* CCB contains a linked CDB */
CAM_SCATTER_VALID = 0x00000010,/* Scatter/gather list is valid */
CAM_DIS_AUTOSENSE = 0x00000020,/* Disable autosense feature */
CAM_DIR_RESV = 0x00000000,/* Data direction (00:reserved) */
CAM_DIR_IN = 0x00000040,/* Data direction (01:DATA IN) */
CAM_DIR_OUT = 0x00000080,/* Data direction (10:DATA OUT) */
CAM_DIR_NONE = 0x000000C0,/* Data direction (11:no data) */
CAM_DIR_MASK = 0x000000C0,/* Data direction Mask */
CAM_SOFT_RST_OP = 0x00000100,/* Use Soft reset alternative */
CAM_ENG_SYNC = 0x00000200,/* Flush resid bytes on complete */
CAM_DEV_QFRZDIS = 0x00000400,/* Disable DEV Q freezing */
CAM_DEV_QFREEZE = 0x00000800,/* Freeze DEV Q on execution */
CAM_HIGH_POWER = 0x00001000,/* Command takes a lot of power */
CAM_SENSE_PTR = 0x00002000,/* Sense data is a pointer */
CAM_SENSE_PHYS = 0x00004000,/* Sense pointer is physical addr*/
CAM_TAG_ACTION_VALID = 0x00008000,/* Use the tag action in this ccb*/
CAM_PASS_ERR_RECOVER = 0x00010000,/* Pass driver does err. recovery*/
CAM_DIS_DISCONNECT = 0x00020000,/* Disable disconnect */
CAM_SG_LIST_PHYS = 0x00040000,/* SG list has physical addrs. */
CAM_MSG_BUF_PHYS = 0x00080000,/* Message buffer ptr is physical*/
CAM_SNS_BUF_PHYS = 0x00100000,/* Autosense data ptr is physical*/
CAM_DATA_PHYS = 0x00200000,/* SG/Buffer data ptrs are phys. */
CAM_CDB_PHYS = 0x00400000,/* CDB poiner is physical */
CAM_ENG_SGLIST = 0x00800000,/* SG list is for the HBA engine */
/* Phase cognizant mode flags */
CAM_DIS_AUTOSRP = 0x01000000,/* Diable autosave/restore ptrs */
CAM_DIS_AUTODISC = 0x02000000,/* Disable auto disconnect */
CAM_TGT_CCB_AVAIL = 0x04000000,/* Target CCB available */
CAM_TGT_PHASE_MODE = 0x08000000,/* The SIM runs in phase mode */
CAM_MSGB_VALID = 0x20000000,/* Message buffer valid */
CAM_STATUS_VALID = 0x40000000,/* Status buffer valid */
CAM_DATAB_VALID = 0x80000000,/* Data buffer valid */
/* Host target Mode flags */
CAM_TERM_IO = 0x20000000,/* Terminate I/O Message sup. */
CAM_DISCONNECT = 0x40000000,/* Disconnects are mandatory */
CAM_SEND_STATUS = 0x80000000,/* Send status after data phase */
} ccb_flags;
/* XPT Opcodes for xpt_action */
typedef enum {
/* Common function commands: 0x00->0x0F */
XPT_NOOP, /* Execute Nothing */
XPT_SCSI_IO, /* Execute the requested I/O operation */
XPT_GDEV_TYPE, /* Get type information for specified device */
XPT_GDEVLIST, /* Get a list of peripheral devices */
XPT_PATH_INQ, /* Path routing inquiry */
XPT_REL_SIMQ, /* Release a frozen SIM queue */
XPT_SASYNC_CB, /* Set Asynchronous Callback Parameters */
XPT_SDEV_TYPE, /* Set device type information */
XPT_SCAN_BUS, /* (Re)Scan the SCSI Bus */
XPT_DEV_MATCH, /* Get EDT entries matching the given pattern */
XPT_DEBUG, /* Turn on debugging for a bus, target or lun */
/* SCSI Control Functions: 0x10->0x1F */
XPT_ABORT = 0x10, /* Abort the specified CCB */
XPT_RESET_BUS, /* Reset the specified SCSI bus */
XPT_RESET_DEV, /* Bus Device Reset the specified SCSI device */
XPT_TERM_IO, /* Terminate the I/O process */
XPT_SCAN_LUN, /* Scan Logical Unit */
XPT_GET_TRAN_SETTINGS, /*
* Get default/user transfer settings
* for the target
*/
XPT_SET_TRAN_SETTINGS, /*
* Set transfer rate/width
* negotiation settings
*/
XPT_CALC_GEOMETRY, /*
* Calculate the geometry parameters for
* a device give the sector size and
* volume size.
*/
/* HBA engine commands 0x20->0x2F */
XPT_ENG_INQ = 0x20, /* HBA engine feature inquiry */
XPT_ENG_EXEC, /* HBA execute engine request */
/* Target mode commands: 0x30->0x3F */
XPT_EN_LUN = 0x30, /* Enable LUN as a target */
XPT_TARGET_IO, /* Execute target I/O request */
XPT_ACCEPT_TARGET_IO, /* Accept Host Target Mode CDB */
XPT_CONT_TARGET_IO, /* Continue Host Target I/O Connection */
XPT_IMMED_NOTIFY, /* Notify Host Target driver of event */
XPT_NOTIFY_ACK, /* Acknowledgement of event */
/* Vendor Unique codes: 0x80->0x8F */
XPT_VUNIQUE = 0x80
} xpt_opcode;
typedef union {
LIST_ENTRY(ccb_hdr) le;
SLIST_ENTRY(ccb_hdr) sle;
TAILQ_ENTRY(ccb_hdr) tqe;
STAILQ_ENTRY(ccb_hdr) stqe;
} camq_entry;
typedef union {
void *ptr;
u_long field;
u_int8_t bytes[sizeof(void *) > sizeof(u_long)
? sizeof(void *) : sizeof(u_long)];
} ccb_priv_entry;
typedef union {
ccb_priv_entry entries[CCB_PERIPH_PRIV_SIZE];
u_int8_t bytes[CCB_PERIPH_PRIV_SIZE * sizeof(ccb_priv_entry)];
} ccb_ppriv_area;
typedef union {
ccb_priv_entry entries[CCB_SIM_PRIV_SIZE];
u_int8_t bytes[CCB_SIM_PRIV_SIZE * sizeof(ccb_priv_entry)];
} ccb_spriv_area;
struct ccb_hdr {
cam_pinfo pinfo; /* Info for priority scheduling */
camq_entry xpt_links; /* For chaining in the XPT layer */
camq_entry sim_links; /* For chaining in the SIM layer */
camq_entry periph_links;/* For chaining in the type driver */
u_int32_t retry_count;
/* Callback on completion function */
void (*cbfcnp)(struct cam_periph *, union ccb *);
xpt_opcode func_code; /* XPT function code */
u_int32_t status; /* Status returned by CAM subsystem */
/* Compiled path for this ccb */
struct cam_path *path;
path_id_t path_id; /* Path ID for the request */
target_id_t target_id; /* Target device ID */
lun_id_t target_lun; /* Target LUN number */
u_int32_t flags;
ccb_ppriv_area periph_priv;
ccb_spriv_area sim_priv;
u_int32_t timeout; /* Timeout value */
/* Callout handle used for timeouts */
struct callout_handle timeout_ch;
};
/* Get Device Information CCB */
struct ccb_getdev {
struct ccb_hdr ccb_h;
struct scsi_inquiry_data inq_data;
u_int8_t serial_num[252];
u_int8_t serial_num_len;
u_int8_t pd_type; /* returned peripheral device type */
int dev_openings; /* Space left for more work on device*/
int dev_active; /* Transactions running on the device */
int devq_openings;/* Space left for more queued work */
int devq_queued; /* Transactions queued to be sent */
int held; /*
* CCBs held by peripheral drivers
* for this device
*/
u_int8_t maxtags; /*
* Boundary conditions for number of
* tagged operations
*/
u_int8_t mintags;
};
typedef enum {
CAM_GDEVLIST_LAST_DEVICE,
CAM_GDEVLIST_LIST_CHANGED,
CAM_GDEVLIST_MORE_DEVS,
CAM_GDEVLIST_ERROR
} ccb_getdevlist_status_e;
struct ccb_getdevlist {
struct ccb_hdr ccb_h;
char periph_name[DEV_IDLEN];
u_int32_t unit_number;
unsigned int generation;
u_int32_t index;
ccb_getdevlist_status_e status;
};
typedef enum {
PERIPH_MATCH_NONE = 0x000,
PERIPH_MATCH_PATH = 0x001,
PERIPH_MATCH_TARGET = 0x002,
PERIPH_MATCH_LUN = 0x004,
PERIPH_MATCH_NAME = 0x008,
PERIPH_MATCH_UNIT = 0x010,
PERIPH_MATCH_ANY = 0x01f
} periph_pattern_flags;
struct periph_match_pattern {
char periph_name[DEV_IDLEN];
u_int32_t unit_number;
path_id_t path_id;
target_id_t target_id;
lun_id_t target_lun;
periph_pattern_flags flags;
};
typedef enum {
DEV_MATCH_NONE = 0x000,
DEV_MATCH_PATH = 0x001,
DEV_MATCH_TARGET = 0x002,
DEV_MATCH_LUN = 0x004,
DEV_MATCH_INQUIRY = 0x008,
DEV_MATCH_ANY = 0x00f
} dev_pattern_flags;
struct device_match_pattern {
path_id_t path_id;
target_id_t target_id;
lun_id_t target_lun;
struct scsi_static_inquiry_pattern inq_pat;
dev_pattern_flags flags;
};
typedef enum {
BUS_MATCH_NONE = 0x000,
BUS_MATCH_PATH = 0x001,
BUS_MATCH_NAME = 0x002,
BUS_MATCH_UNIT = 0x004,
BUS_MATCH_BUS_ID = 0x008,
BUS_MATCH_ANY = 0x00f
} bus_pattern_flags;
struct bus_match_pattern {
path_id_t path_id;
char dev_name[DEV_IDLEN];
u_int32_t unit_number;
u_int32_t bus_id;
bus_pattern_flags flags;
};
union match_pattern {
struct periph_match_pattern periph_pattern;
struct device_match_pattern device_pattern;
struct bus_match_pattern bus_pattern;
};
typedef enum {
DEV_MATCH_PERIPH,
DEV_MATCH_DEVICE,
DEV_MATCH_BUS
} dev_match_type;
struct dev_match_pattern {
dev_match_type type;
union match_pattern pattern;
};
struct periph_match_result {
char periph_name[DEV_IDLEN];
u_int32_t unit_number;
path_id_t path_id;
target_id_t target_id;
lun_id_t target_lun;
};
struct device_match_result {
path_id_t path_id;
target_id_t target_id;
lun_id_t target_lun;
struct scsi_inquiry_data inq_data;
};
struct bus_match_result {
path_id_t path_id;
char dev_name[DEV_IDLEN];
u_int32_t unit_number;
u_int32_t bus_id;
};
union match_result {
struct periph_match_result periph_result;
struct device_match_result device_result;
struct bus_match_result bus_result;
};
struct dev_match_result {
dev_match_type type;
union match_result result;
};
typedef enum {
CAM_DEV_MATCH_LAST,
CAM_DEV_MATCH_MORE,
CAM_DEV_MATCH_LIST_CHANGED,
CAM_DEV_MATCH_SIZE_ERROR,
CAM_DEV_MATCH_ERROR
} ccb_dev_match_status;
typedef enum {
CAM_DEV_POS_NONE = 0x000,
CAM_DEV_POS_BUS = 0x001,
CAM_DEV_POS_TARGET = 0x002,
CAM_DEV_POS_DEVICE = 0x004,
CAM_DEV_POS_PERIPH = 0x008,
CAM_DEV_POS_PDPTR = 0x010,
CAM_DEV_POS_TYPEMASK = 0xf00,
CAM_DEV_POS_EDT = 0x100,
CAM_DEV_POS_PDRV = 0x200
} dev_pos_type;
struct ccb_dm_cookie {
void *bus;
void *target;
void *device;
void *periph;
void *pdrv;
};
struct ccb_dev_position {
u_int generations[4];
#define CAM_BUS_GENERATION 0x00
#define CAM_TARGET_GENERATION 0x01
#define CAM_DEV_GENERATION 0x02
#define CAM_PERIPH_GENERATION 0x03
dev_pos_type position_type;
struct ccb_dm_cookie cookie;
};
struct ccb_dev_match {
struct ccb_hdr ccb_h;
ccb_dev_match_status status;
u_int32_t num_patterns;
u_int32_t pattern_buf_len;
struct dev_match_pattern *patterns;
u_int32_t num_matches;
u_int32_t match_buf_len;
struct dev_match_result *matches;
struct ccb_dev_position pos;
};
/*
* Definitions for the path inquiry CCB fields.
*/
#define CAM_VERSION 0x10 /* Hex value for current version */
typedef enum {
PI_MDP_ABLE = 0x80, /* Supports MDP message */
PI_WIDE_32 = 0x40, /* Supports 32 bit wide SCSI */
PI_WIDE_16 = 0x20, /* Supports 16 bit wide SCSI */
PI_SDTR_ABLE = 0x10, /* Supports SDTR message */
PI_LINKED_CDB = 0x08, /* Supports linked CDBs */
PI_TAG_ABLE = 0x02, /* Supports tag queue messages */
PI_SOFT_RST = 0x01, /* Supports soft reset alternative */
} pi_inqflag;
typedef enum {
PIT_PROCESSOR = 0x80, /* Target mode processor mode */
PIT_PHASE = 0x40, /* Target mode phase cog. mode */
PIT_DISCONNECT = 0x20, /* Disconnects supported in target mode */
PIT_TERM_IO = 0x10, /* Terminate I/O message supported in TM */
PIT_GRP_6 = 0x08, /* Group 6 commands supported */
PIT_GRP_7 = 0x04, /* Group 7 commands supported */
} pi_tmflag;
typedef enum {
PIM_SCANHILO = 0x80, /* Bus scans from high ID to low ID */
PIM_NOREMOVE = 0x40, /* Removeable devices not included in scan */
PIM_NOINQUIRY = 0x20, /* Inquiry data not kept by XPT */
} pi_miscflag;
/* Path Inquiry CCB */
struct ccb_pathinq {
struct ccb_hdr ccb_h;
u_int8_t version_num; /* Version number for the SIM/HBA */
u_int8_t hba_inquiry; /* Mimic of INQ byte 7 for the HBA */
u_int8_t target_sprt; /* Flags for target mode support */
u_int8_t hba_misc; /* Misc HBA features */
u_int16_t hba_eng_cnt; /* HBA engine count */
/* Vendor Unique capabilities */
u_int8_t vuhba_flags[VUHBALEN];
u_int32_t max_target; /* Maximum supported Target */
u_int32_t max_lun; /* Maximum supported Lun */
u_int32_t async_flags; /* Installed Async handlers */
path_id_t hpath_id; /* Highest Path ID in the subsystem */
target_id_t initiator_id; /* ID of the HBA on the SCSI bus */
char sim_vid[SIM_IDLEN]; /* Vendor ID of the SIM */
char hba_vid[HBA_IDLEN]; /* Vendor ID of the HBA */
char dev_name[DEV_IDLEN];/* Device name for SIM */
u_int32_t unit_number; /* Unit number for SIM */
u_int32_t bus_id; /* Bus ID for SIM */
};
typedef union {
u_int8_t *sense_ptr; /*
* Pointer to storage
* for sense information
*/
/* Storage Area for sense information */
struct scsi_sense_data sense_buf;
} sense_t;
typedef union {
u_int8_t *cdb_ptr; /* Pointer to the CDB bytes to send */
/* Area for the CDB send */
u_int8_t cdb_bytes[IOCDBLEN];
} cdb_t;
/*
* SCSI I/O Request CCB used for the XPT_SCSI_IO and XPT_CONT_TARGET_IO
* function codes.
*/
struct ccb_scsiio {
struct ccb_hdr ccb_h;
union ccb *next_ccb; /* Ptr for next CCB for action */
u_int8_t *req_map; /* Ptr to mapping info */
u_int8_t *data_ptr; /* Ptr to the data buf/SG list */
u_int32_t dxfer_len; /* Data transfer length */
/* Autosense storage */
struct scsi_sense_data sense_data;
u_int8_t sense_len; /* Number of bytes to autosense */
u_int8_t cdb_len; /* Number of bytes for the CDB */
u_int16_t sglist_cnt; /* Number of SG list entries */
u_int8_t scsi_status; /* Returned SCSI status */
u_int8_t sense_resid; /* Autosense resid length: 2's comp */
u_int32_t resid; /* Transfer residual length: 2's comp */
cdb_t cdb_io; /* Union for CDB bytes/pointer */
u_int8_t *msg_ptr; /* Pointer to the message buffer */
u_int16_t msg_len; /* Number of bytes for the Message */
u_int8_t tag_action; /* What to do for tag queueing */
u_int8_t tag_id; /* tag id from initator (target mode) */
u_int8_t 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 */
u_int8_t cdb_len; /* Number of bytes for the CDB */
u_int8_t tag_action; /* What to do for tag queueing */
u_int8_t tag_id; /* tag id from initator (target mode) */
u_int8_t init_id; /* initiator id of who selected */
};
/* Release SIM Queue */
struct ccb_relsim {
struct ccb_hdr ccb_h;
u_int32_t release_flags;
#define RELSIM_ADJUST_OPENINGS 0x01
#define RELSIM_RELEASE_AFTER_TIMEOUT 0x02
#define RELSIM_RELEASE_AFTER_CMDCMPLT 0x04
#define RELSIM_RELEASE_AFTER_QEMPTY 0x08
u_int32_t openings;
u_int32_t release_timeout;
u_int32_t qfrozen_cnt;
};
/*
* Definitions for the asynchronous callback CCB fields.
*/
typedef enum {
AC_GETDEV_CHANGED = 0x800,/* Getdev info might have changed */
AC_INQ_CHANGED = 0x400,/* Inquiry info might have changed */
AC_TRANSFER_NEG = 0x200,/* New transfer settings in effect */
AC_LOST_DEVICE = 0x100,/* A device went away */
AC_FOUND_DEVICE = 0x080,/* A new device was found */
AC_PATH_DEREGISTERED = 0x040,/* A path has de-registered */
AC_PATH_REGISTERED = 0x020,/* A new path has been registered */
AC_SENT_BDR = 0x010,/* A BDR message was sent to target */
AC_SCSI_AEN = 0x008,/* A SCSI AEN has been received */
AC_UNSOL_RESEL = 0x002,/* Unsolicited reselection occurred */
AC_BUS_RESET = 0x001 /* A SCSI bus reset occurred */
} ac_code;
typedef void ac_callback_t (void *softc, u_int32_t code,
struct cam_path *path, void *args);
/* Set Asynchronous Callback CCB */
struct ccb_setasync {
struct ccb_hdr ccb_h;
u_int32_t event_enable; /* Async Event enables */
ac_callback_t *callback;
void *callback_arg;
};
/* Set Device Type CCB */
struct ccb_setdev {
struct ccb_hdr ccb_h;
u_int8_t dev_type; /* Value for dev type field in EDT */
};
/* SCSI Control Functions */
/* Abort XPT request CCB */
struct ccb_abort {
struct ccb_hdr ccb_h;
union ccb *abort_ccb; /* Pointer to CCB to abort */
};
/* Reset SCSI Bus CCB */
struct ccb_resetbus {
struct ccb_hdr ccb_h;
};
/* Reset SCSI Device CCB */
struct ccb_resetdev {
struct ccb_hdr ccb_h;
};
/* Terminate I/O Process Request CCB */
struct ccb_termio {
struct ccb_hdr ccb_h;
union ccb *termio_ccb; /* Pointer to CCB to terminate */
};
/* Get/Set transfer rate/width/disconnection/tag queueing settings */
struct ccb_trans_settings {
struct ccb_hdr ccb_h;
u_int valid; /* Which fields to honor */
#define CCB_TRANS_SYNC_RATE_VALID 0x01
#define CCB_TRANS_SYNC_OFFSET_VALID 0x02
#define CCB_TRANS_BUS_WIDTH_VALID 0x04
#define CCB_TRANS_DISC_VALID 0x08
#define CCB_TRANS_TQ_VALID 0x10
u_int flags;
#define CCB_TRANS_CURRENT_SETTINGS 0x01
#define CCB_TRANS_USER_SETTINGS 0x02
#define CCB_TRANS_DISC_ENB 0x04
#define CCB_TRANS_TAG_ENB 0x08
u_int sync_period;
u_int sync_offset;
u_int bus_width;
};
/*
* Calculate the geometry parameters for a device
* give the block size and volume size in blocks.
*/
struct ccb_calc_geometry {
struct ccb_hdr ccb_h;
u_int32_t block_size;
u_int32_t volume_size;
u_int16_t cylinders;
u_int8_t heads;
u_int8_t secs_per_track;
};
/*
* Rescan the given bus, or bus/target/lun
*/
struct ccb_rescan {
struct ccb_hdr ccb_h;
cam_flags flags;
};
/*
* Turn on debugging for the given bus, bus/target, or bus/target/lun.
*/
struct ccb_debug {
struct ccb_hdr ccb_h;
cam_debug_flags flags;
};
/* Target mode structures. */
struct ccb_en_lun {
struct ccb_hdr ccb_h;
u_int16_t grp6_len; /* Group 6 VU CDB length */
u_int16_t grp7_len; /* Group 7 VU CDB length */
u_int8_t enable;
};
struct ccb_immed_notify {
struct ccb_hdr ccb_h;
struct scsi_sense_data sense_data;
u_int8_t sense_len; /* Number of bytes in sese buffer */
u_int8_t initiator_id; /* Id of initiator that selected */
u_int16_t seq_id; /* Sequence Identifier */
u_int8_t message_code; /* Message Code */
u_int8_t message_args[7]; /* Message Arguments */
};
struct ccb_notify_ack {
struct ccb_hdr ccb_h;
u_int16_t seq_id; /* Sequence identifier */
u_int8_t event; /* Event flags */
};
/* HBA engine structures. */
typedef enum {
EIT_BUFFER, /* Engine type: buffer memory */
EIT_LOSSLESS, /* Engine type: lossless compression */
EIT_LOSSY, /* Engine type: lossy compression */
EIT_ENCRYPT /* Engine type: encryption */
} ei_type;
typedef enum {
EAD_VUNIQUE, /* Engine algorithm ID: vendor unique */
EAD_LZ1V1, /* Engine algorithm ID: LZ1 var.1 */
EAD_LZ2V1, /* Engine algorithm ID: LZ2 var.1 */
EAD_LZ2V2, /* Engine algorithm ID: LZ2 var.2 */
} ei_algo;
struct ccb_eng_inq {
struct ccb_hdr ccb_h;
u_int16_t eng_num; /* The engine number for this inquiry */
ei_type eng_type; /* Returned engine type */
ei_algo eng_algo; /* Returned engine algorithm type */
u_int32_t eng_memeory; /* Returned engine memory size */
};
struct ccb_eng_exec { /* This structure must match SCSIIO size */
struct ccb_hdr ccb_h;
u_int8_t *pdrv_ptr; /* Ptr used by the peripheral driver */
u_int8_t *req_map; /* Ptr for mapping info on the req. */
u_int8_t *data_ptr; /* Pointer to the data buf/SG list */
u_int32_t dxfer_len; /* Data transfer length */
u_int8_t *engdata_ptr; /* Pointer to the engine buffer data */
u_int16_t sglist_cnt; /* Num of scatter gather list entries */
u_int32_t dmax_len; /* Destination data maximum length */
u_int32_t dest_len; /* Destination data length */
int32_t src_resid; /* Source residual length: 2's comp */
u_int32_t timeout; /* Timeout value */
u_int16_t eng_num; /* Engine number for this request */
u_int16_t vu_flags; /* Vendor Unique flags */
};
/*
* Definitions for the timeout field in the SCSI I/O CCB.
*/
#define CAM_TIME_DEFAULT 0x00000000 /* Use SIM default value */
#define CAM_TIME_INFINITY 0xFFFFFFFF /* Infinite timeout */
#define CAM_SUCCESS 0 /* For signaling general success */
#define CAM_FAILURE 1 /* For signaling general failure */
#define CAM_FALSE 0
#define CAM_TRUE 1
#define XPT_CCB_INVALID -1 /* for signaling a bad CCB to free */
/*
* Union of all CCB types for kernel space allocation. This union should
* never be used for manipulating CCBs - its only use is for the allocation
* and deallocation of raw CCB space and is the return type of xpt_ccb_alloc
* and the argument to xpt_ccb_free.
*/
union ccb {
struct ccb_hdr ccb_h; /* For convenience */
struct ccb_scsiio csio;
struct ccb_getdev cgd;
struct ccb_getdevlist cgdl;
struct ccb_pathinq cpi;
struct ccb_relsim crs;
struct ccb_setasync csa;
struct ccb_setdev csd;
struct ccb_dev_match cdm;
struct ccb_trans_settings cts;
struct ccb_calc_geometry ccg;
struct ccb_abort cab;
struct ccb_resetbus crb;
struct ccb_resetdev crd;
struct ccb_termio tio;
struct ccb_accept_tio atio;
struct ccb_scsiio ctio;
struct ccb_en_lun cel;
struct ccb_immed_notify cin;
struct ccb_notify_ack cna;
struct ccb_eng_inq cei;
struct ccb_eng_exec cee;
struct ccb_rescan crcn;
struct ccb_debug cdbg;
};
__BEGIN_DECLS
static __inline void
cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
u_int32_t flags, u_int8_t tag_action,
u_int8_t *data_ptr, u_int32_t dxfer_len,
u_int8_t sense_len, u_int8_t cdb_len,
u_int32_t timeout);
static __inline void
cam_fill_ctio(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
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_csio(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
u_int32_t flags, u_int8_t tag_action,
u_int8_t *data_ptr, u_int32_t dxfer_len,
u_int8_t sense_len, u_int8_t cdb_len,
u_int32_t timeout)
{
csio->ccb_h.func_code = XPT_SCSI_IO;
csio->ccb_h.flags = flags;
csio->ccb_h.retry_count = retries;
csio->ccb_h.cbfcnp = cbfcnp;
csio->ccb_h.timeout = timeout;
csio->data_ptr = data_ptr;
csio->dxfer_len = dxfer_len;
csio->sense_len = sense_len;
csio->cdb_len = cdb_len;
csio->tag_action = tag_action;
}
static __inline void
cam_fill_ctio(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
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)
{
csio->ccb_h.func_code = XPT_CONT_TARGET_IO;
csio->ccb_h.flags = flags;
csio->ccb_h.retry_count = retries;
csio->ccb_h.cbfcnp = cbfcnp;
csio->ccb_h.timeout = timeout;
csio->data_ptr = data_ptr;
csio->dxfer_len = dxfer_len;
csio->scsi_status = scsi_status;
csio->tag_action = tag_action;
csio->tag_id = tag_id;
csio->init_id = init_id;
}
__END_DECLS
#endif /* _CAM_CAM_CCB_H */

67
sys/cam/cam_conf.h Normal file
View File

@ -0,0 +1,67 @@
/*
* Data structures and definitions for linking CAM into the autoconf system.
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#ifndef _CAM_CAM_CONF_H
#define _CAM_CAM_CONF_H 1
#ifdef KERNEL
#define CAMCONF_UNSPEC 255
#define CAMCONF_ANY 254
/*
* Macro that lets us know something is specified.
*/
#define IS_SPECIFIED(ARG) (ARG != CAMCONF_UNSPEC && ARG != CAMCONF_ANY)
struct cam_sim_config
{
int pathid;
char *sim_name;
int sim_unit;
int sim_bus;
};
struct cam_periph_config
{
char *periph_name;
int periph_unit; /* desired device unit */
int pathid; /* Controller unit */
int target;
int lun;
int flags; /* Flags from config */
};
extern struct cam_sim_config cam_sinit[];
extern struct cam_periph_config cam_pinit[];
#endif /* KERNEL */
#endif /* _CAM_CAM_CONF_H */

77
sys/cam/cam_debug.h Normal file
View File

@ -0,0 +1,77 @@
/*
* Macros for tracing/loging information in the CAM layer
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#ifndef _CAM_CAM_DEBUG_H
#define _CAM_CAM_DEBUG_H 1
#if defined(CAMDEBUG) && defined(KERNEL)
#include <machine/clock.h>
#endif /* CAMDEBUG && KERNEL */
/*
* Debugging flags.
*/
typedef enum {
CAM_DEBUG_NONE = 0x00, /* no debugging */
CAM_DEBUG_INFO = 0x01, /* scsi commands, errors, data */
CAM_DEBUG_TRACE = 0x02, /* routine flow tracking */
CAM_DEBUG_SUBTRACE = 0x04, /* internal to routine flows */
} cam_debug_flags;
#if defined(CAMDEBUG) && defined(KERNEL)
/* Path we want to debug */
extern struct cam_path *cam_dpath;
/* Current debug levels set */
extern u_int32_t cam_dflags;
/* Debugging macros. */
#define CAM_DEBUG(path, flag, printfargs) \
if ((cam_dflags & (flag)) \
&& (cam_dpath != NULL) \
&& (xpt_path_comp(path, cam_dpath) >= 0)) { \
xpt_print_path(path); \
printf printfargs; \
DELAY(100000); \
}
#define CAM_DEBUG_PRINT(flag, printfargs) \
if (cam_dflags & (flag)) { \
printf("cam_debug: "); \
printf printfargs; \
DELAY(100000); \
}
#else /* !CAMDEBUG || !KERNEL */
#define CAM_DEBUG(A, B, C)
#define CAM_DEBUG_PRINT(A, B)
#endif /* CAMDEBUG && KERNEL */
#endif /* _CAM_CAM_DEBUG_H */

115
sys/cam/cam_extend.c Normal file
View File

@ -0,0 +1,115 @@
/*
* Written by Julian Elischer (julian@tfs.com)
* for TRW Financial Systems for use under the MACH(2.5) operating system.
*
* TRW Financial Systems, in accordance with their agreement with Carnegie
* Mellon University, makes this software available to CMU to distribute
* or use in any manner that they see fit as long as this message is kept with
* the software. For this reason TFS also grants any other persons or
* organisations permission to use or modify this software.
*
* TFS supplies this software to be publicly redistributed
* on the understanding that TFS is not responsible for the correct
* functioning of this software in any circumstances.
*
* $Id$
*/
/*
* XXX XXX XXX XXX We should get DEVFS working so that we
* don't have to do this, possibly sparse, array based junk.
*/
/*
* Extensible arrays: Use a realloc like implementation to permit
* the arrays to be extend.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <cam/cam_extend.h>
struct extend_array
{
int nelem;
void **ps;
};
static void *
cam_extend_alloc(size_t s)
{
void *p = malloc(s, M_DEVBUF, M_NOWAIT);
if (!p)
panic("extend_alloc: malloc failed.");
return p;
}
static void
cam_extend_free(void *p)
{
free(p, M_DEVBUF);
}
/* EXTEND_CHUNK: Number of extend slots to allocate whenever we need a new
* one.
*/
#ifndef EXTEND_CHUNK
#define EXTEND_CHUNK 8
#endif
struct extend_array *
cam_extend_new(void)
{
struct extend_array *p = cam_extend_alloc(sizeof(*p));
if (p) {
p->nelem = 0;
p->ps = 0;
}
return p;
}
void *
cam_extend_set(struct extend_array *ea, int index, void *value)
{
if (index >= ea->nelem) {
void **space;
space = cam_extend_alloc(sizeof(void *) * (index + EXTEND_CHUNK));
bzero(space, sizeof(void *) * (index + EXTEND_CHUNK));
/* Make sure we have something to copy before we copy it */
if (ea->nelem) {
bcopy(ea->ps, space, sizeof(void *) * ea->nelem);
cam_extend_free(ea->ps);
}
ea->ps = space;
ea->nelem = index + EXTEND_CHUNK;
}
if (ea->ps[index]) {
printf("extend_set: entry %d already has storage.\n", index);
return 0;
}
else
ea->ps[index] = value;
return value;
}
void *
cam_extend_get(struct extend_array *ea,
int index)
{
if (ea == NULL || index >= ea->nelem || index < 0)
return NULL;
return ea->ps[index];
}
void
cam_extend_release(struct extend_array *ea, int index)
{
void *p = cam_extend_get(ea, index);
if (p) {
ea->ps[index] = 0;
}
}

30
sys/cam/cam_extend.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Written by Julian Elischer (julian@tfs.com)
* for TRW Financial Systems for use under the MACH(2.5) operating system.
*
* TRW Financial Systems, in accordance with their agreement with Carnegie
* Mellon University, makes this software available to CMU to distribute
* or use in any manner that they see fit as long as this message is kept with
* the software. For this reason TFS also grants any other persons or
* organisations permission to use or modify this software.
*
* TFS supplies this software to be publicly redistributed
* on the understanding that TFS is not responsible for the correct
* functioning of this software in any circumstances.
*
* $Id$
*/
#ifndef _CAM_CAM_EXTEND_H
#define _CAM_CAM_EXTEND_H 1
#ifdef KERNEL
struct extend_array;
void *cam_extend_get(struct extend_array *ea, int index);
struct extend_array *cam_extend_new(void);
void *cam_extend_set(struct extend_array *ea, int index, void *value);
void cam_extend_release(struct extend_array *ea, int index);
#endif /* KERNEL */
#endif /* _CAM_CAM_EXTEND_H */

1493
sys/cam/cam_periph.c Normal file

File diff suppressed because it is too large Load Diff

135
sys/cam/cam_periph.h Normal file
View File

@ -0,0 +1,135 @@
/*
* Data structures and definitions for CAM peripheral ("type") drivers.
*
* Copyright (c) 1997, 1998 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#ifndef _CAM_CAM_PERIPH_H
#define _CAM_CAM_PERIPH_H 1
#include <sys/queue.h>
#ifdef KERNEL
extern struct linker_set periphdriver_set;
typedef void (periph_init_t)(void); /*
* Callback informing the peripheral driver
* it can perform it's initialization since
* the XPT is now fully initialized.
*/
typedef periph_init_t *periph_init_func_t;
struct periph_driver {
periph_init_func_t init;
char *driver_name;
TAILQ_HEAD(,cam_periph) units;
u_int generation;
};
typedef enum {
CAM_PERIPH_BIO,
CAM_PERIPH_NET
} cam_periph_type;
/* Generically usefull offsets into the peripheral private area */
#define ppriv_ptr0 periph_priv.entries[0].ptr
#define ppriv_ptr1 periph_priv.entries[1].ptr
#define ppriv_field0 periph_priv.entries[0].field
#define ppriv_field1 periph_priv.entries[1].field
typedef void periph_start_t (struct cam_periph *periph,
union ccb *start_ccb);
typedef cam_status periph_ctor_t (struct cam_periph *periph,
void *arg);
typedef void periph_dtor_t (struct cam_periph *periph);
struct cam_periph {
cam_pinfo pinfo;
periph_start_t *periph_start;
periph_dtor_t *periph_dtor;
char *periph_name;
struct cam_path *path; /* Compiled path to device */
void *softc;
u_int32_t unit_number;
cam_periph_type type;
u_int32_t flags;
#define CAM_PERIPH_RUNNING 0x01
#define CAM_PERIPH_LOCKED 0x02
#define CAM_PERIPH_LOCK_WANTED 0x04
#define CAM_PERIPH_INVALID 0x08
#define CAM_PERIPH_NEW_DEV_FOUND 0x10
u_int32_t immediate_priority;
u_int32_t refcount;
SLIST_HEAD(, ccb_hdr) ccb_list; /* For "immediate" requests */
SLIST_ENTRY(cam_periph) periph_links;
TAILQ_ENTRY(cam_periph) unit_links;
ac_callback_t *deferred_callback;
ac_code deferred_ac;
};
#define CAM_PERIPH_MAXMAPS 2
struct cam_periph_map_info {
int num_bufs_used;
struct buf *bp[CAM_PERIPH_MAXMAPS];
};
cam_status cam_periph_alloc(periph_ctor_t*, periph_dtor_t*, periph_start_t*,
char *name, cam_periph_type type, struct cam_path *, ac_callback_t *, ac_code, void *arg);
struct cam_periph *cam_periph_find(struct cam_path *path, char *name);
int cam_periph_lock(struct cam_periph *periph, int priority);
void cam_periph_unlock(struct cam_periph *periph);
cam_status cam_periph_acquire(struct cam_periph *periph);
void cam_periph_release(struct cam_periph *periph);
void cam_periph_invalidate(struct cam_periph *periph);
int cam_periph_mapmem(union ccb *ccb,
struct cam_periph_map_info *mapinfo);
void cam_periph_unmapmem(union ccb *ccb,
struct cam_periph_map_info *mapinfo);
union ccb *cam_periph_getccb(struct cam_periph *periph,
u_int32_t priority);
void cam_periph_ccbwait(union ccb *ccb);
int cam_periph_runccb(union ccb *ccb,
int (*error_routine)(union ccb *ccb,
cam_flags camflags,
u_int32_t sense_flags),
cam_flags camflags, u_int32_t sense_flags,
struct devstat *ds);
int cam_periph_ioctl(struct cam_periph *periph, int cmd,
caddr_t addr,
int (*error_routine)(union ccb *ccb,
cam_flags camflags,
u_int32_t sense_flags));
u_int32_t cam_release_devq(struct cam_path *path, u_int32_t relsim_flags,
u_int32_t opening_reduction, u_int32_t timeout,
int getcount_only);
int cam_periph_error(union ccb *ccb, cam_flags camflags,
u_int32_t sense_flags, union ccb *save_ccb);
#endif /* KERNEL */
#endif /* _CAM_CAM_PERIPH_H */

441
sys/cam/cam_queue.c Normal file
View File

@ -0,0 +1,441 @@
/*
* CAM request queue management functions.
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/malloc.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_queue.h>
#include <cam/cam_debug.h>
static __inline int
queue_cmp(cam_pinfo **queue_array, int i, int j);
static __inline void
swap(cam_pinfo **queue_array, int i, int j);
static void heap_up(cam_pinfo **queue_array, int new_index);
static void heap_down(cam_pinfo **queue_array, int index,
int last_index);
struct camq *
camq_alloc(int size)
{
struct camq *camq;
camq = (struct camq *)malloc(sizeof(*camq), M_DEVBUF, M_NOWAIT);
if (camq != NULL) {
if (camq_init(camq, size) != 0) {
free(camq, M_DEVBUF);
camq = NULL;
}
}
return (camq);
}
int
camq_init(struct camq *camq, int size)
{
bzero(camq, sizeof(*camq));
camq->array_size = size;
if (camq->array_size != 0) {
camq->queue_array = (cam_pinfo**)malloc(size*sizeof(cam_pinfo*),
M_DEVBUF, M_NOWAIT);
if (camq->queue_array == NULL) {
printf("camq_init: - cannot malloc array!\n");
return (1);
}
}
return (0);
}
/*
* Free a camq structure. This should only be called if a controller
* driver failes somehow during its attach routine or is unloaded and has
* obtained a camq structure. The XPT should ensure that the queue
* is empty before calling this routine.
*/
void
camq_free(struct camq *queue)
{
if (queue != NULL) {
camq_fini(queue);
free(queue, M_DEVBUF);
}
}
void
camq_fini(struct camq *queue)
{
if (queue->queue_array != NULL) {
free(queue->queue_array, M_DEVBUF);
}
}
u_int32_t
camq_resize(struct camq *queue, int new_size)
{
cam_pinfo **new_array;
#ifdef DIAGNOSTIC
if (new_size < queue->entries)
panic("camq_resize: New queue size can't accomodate "
"queued entries.");
#endif
new_array = (cam_pinfo **)malloc(new_size * sizeof(cam_pinfo *),
M_DEVBUF, M_NOWAIT);
if (new_array == NULL) {
/* Couldn't satisfy request */
return (CAM_RESRC_UNAVAIL);
}
if (queue->queue_array != NULL) {
bcopy(queue->queue_array, new_array,
queue->entries * sizeof(cam_pinfo *));
free(queue->queue_array, M_DEVBUF);
}
queue->queue_array = new_array;
queue->array_size = new_size;
return (CAM_REQ_CMP);
}
/*
* camq_regen: Given an array of cam_pinfo* elements with the
* Heap(0, num_elements) property, perform the second half of
* a heap sort, and assign new generation numbers to all entries.
* It is assumed that the starting generation number plus the
* number of entries in the queue is smaller than the wrap point
* of the generation number.
*/
void
camq_regen(struct camq *queue)
{
int index;
for (index = 0; index < queue->entries; index++) {
heap_down(queue->queue_array, index, queue->entries);
queue->queue_array[index]->generation = queue->generation++;
}
/* A sorted array is still a heap, so we are done */
}
/*
* camq_insert: Given an array of cam_pinfo* elememnts with
* the Heap(0, num_elements) property and array_size - num_elements >= 1,
* output Heap(0, num_elements+1) including new_entry in the array.
*/
void
camq_insert(struct camq *queue, cam_pinfo *new_entry)
{
#ifdef DIAGNOSTIC
if (queue->entries >= queue->array_size)
panic("camq_insert: Attempt to insert into a full queue");
#endif
queue->queue_array[queue->entries] = new_entry;
new_entry->index = queue->entries;
if (queue->entries != 0)
heap_up(queue->queue_array, queue->entries);
queue->entries++;
}
/*
* camq_remove: Given an array of cam_pinfo* elevements with the
* Heap(0, num_elements) property and an index such that 0 <= index <=
* num_elements, remove that entry and restore the Heap(0, num_elements-1)
* property.
*/
cam_pinfo *
camq_remove(struct camq *queue, int index)
{
cam_pinfo *removed_entry;
if ((queue->entries - index) <= 0)
return (NULL);
removed_entry = queue->queue_array[index];
queue->entries--;
if (queue->entries != index) {
queue->queue_array[index] = queue->queue_array[queue->entries];
queue->queue_array[index]->index = index;
heap_down(queue->queue_array, index, queue->entries);
}
removed_entry->index = CAM_UNQUEUED_INDEX;
return (removed_entry);
}
/*
* camq_change_priority: Given an array of cam_pinfo* elements with the
* Heap(0, num_entries) property, an index such that 0 <= index <= num_elements,
* and an new priority for the element at index, change the priority of
* element index and restore the Heap(0, num_elements) property.
*/
void
camq_change_priority(struct camq *queue, int index, u_int32_t new_priority)
{
if (new_priority > queue->queue_array[index]->priority) {
queue->queue_array[index]->priority = new_priority;
heap_down(queue->queue_array, index, queue->entries);
} else {
/* new_priority <= old_priority */
queue->queue_array[index]->priority = new_priority;
heap_up(queue->queue_array, index);
}
}
struct cam_devq *
cam_devq_alloc(int devices, int openings)
{
struct cam_devq *devq;
devq = (struct cam_devq *)malloc(sizeof(*devq), M_DEVBUF, M_NOWAIT);
if (devq == NULL) {
printf("cam_devq_alloc: - cannot malloc!\n");
return (NULL);
}
if (cam_devq_init(devq, devices, openings) != 0) {
free(devq, M_DEVBUF);
return (NULL);
}
return (devq);
}
int
cam_devq_init(struct cam_devq *devq, int devices, int openings)
{
bzero(devq, sizeof(*devq));
if (camq_init(&devq->alloc_queue, devices) != 0) {
return (1);
}
if (camq_init(&devq->send_queue, devices) != 0) {
camq_fini(&devq->alloc_queue);
return (1);
}
devq->alloc_openings = openings;
devq->alloc_active = 0;
devq->send_openings = openings;
devq->send_active = 0;
return (0);
}
void
cam_devq_free(struct cam_devq *devq)
{
camq_free(&devq->alloc_queue);
camq_free(&devq->send_queue);
free(devq, M_DEVBUF);
}
u_int32_t
cam_devq_resize(struct cam_devq *camq, int devices)
{
u_int32_t retval;
retval = camq_resize(&camq->alloc_queue, devices);
if (retval == CAM_REQ_CMP)
retval = camq_resize(&camq->send_queue, devices);
return (retval);
}
struct cam_ccbq *
cam_ccbq_alloc(int openings)
{
struct cam_ccbq *ccbq;
ccbq = (struct cam_ccbq *)malloc(sizeof(*ccbq), M_DEVBUF, M_NOWAIT);
if (ccbq == NULL) {
printf("cam_ccbq_alloc: - cannot malloc!\n");
return (NULL);
}
if (cam_ccbq_init(ccbq, openings) != 0) {
free(ccbq, M_DEVBUF);
return (NULL);
}
return (ccbq);
}
void
cam_ccbq_free(struct cam_ccbq *ccbq)
{
if (ccbq) {
camq_fini(&ccbq->queue);
free(ccbq, M_DEVBUF);
}
}
u_int32_t
cam_ccbq_resize(struct cam_ccbq *ccbq, int new_size)
{
int delta;
int space_left;
delta = new_size - (ccbq->dev_active + ccbq->dev_openings);
space_left = new_size
- ccbq->queue.entries
- ccbq->held
- ccbq->dev_active;
/*
* Only attempt to change the underlying queue size if we are
* shrinking it and there is space for all outstanding entries
* in the new array or we have been requested to grow the array.
* We don't fail in the case where we can't reduce the array size,
* but clients that care that the queue be "garbage collected"
* should detect this condition and call us again with the
* same size once the outstanding entries have been processed.
*/
if (space_left < 0
|| camq_resize(&ccbq->queue, new_size) == CAM_REQ_CMP) {
ccbq->devq_openings += delta;
ccbq->dev_openings += delta;
return (CAM_REQ_CMP);
} else {
return (CAM_RESRC_UNAVAIL);
}
}
int
cam_ccbq_init(struct cam_ccbq *ccbq, int openings)
{
bzero(ccbq, sizeof(*ccbq));
if (camq_init(&ccbq->queue, openings) != 0) {
return (1);
}
ccbq->devq_openings = openings;
ccbq->dev_openings = openings;
TAILQ_INIT(&ccbq->active_ccbs);
return (0);
}
void
cam_ccbq_regen(struct cam_ccbq *ccbq)
{
struct ccb_hdr *ccbh;
/* First get all of the guys down at a device */
ccbh = ccbq->active_ccbs.tqh_first;
while (ccbh != NULL) {
ccbh->pinfo.generation = ccbq->queue.generation++;
ccbh = ccbh->xpt_links.tqe.tqe_next;
}
/* Now get everyone in our CAM queue */
camq_regen(&ccbq->queue);
}
/*
* Heap routines for manipulating CAM queues.
*/
/*
* queue_cmp: Given an array of cam_pinfo* elements and indexes i
* and j, return less than 0, 0, or greater than 0 if i is less than,
* equal too, or greater than j respectively.
*/
static __inline int
queue_cmp(cam_pinfo **queue_array, int i, int j)
{
if (queue_array[i]->priority == queue_array[j]->priority)
return ( queue_array[i]->generation
- queue_array[j]->generation );
else
return ( queue_array[i]->priority
- queue_array[j]->priority );
}
/*
* swap: Given an array of cam_pinfo* elements and indexes i and j,
* exchange elements i and j.
*/
static __inline void
swap(cam_pinfo **queue_array, int i, int j)
{
cam_pinfo *temp_qentry;
temp_qentry = queue_array[j];
queue_array[j] = queue_array[i];
queue_array[i] = temp_qentry;
queue_array[j]->index = j;
queue_array[i]->index = i;
}
/*
* heap_up: Given an array of cam_pinfo* elements with the
* Heap(0, new_index-1) property and a new element in location
* new_index, output Heap(0, new_index).
*/
static void
heap_up(cam_pinfo **queue_array, int new_index)
{
int child;
int parent;
child = new_index;
while (child != 0) {
parent = child >> 1;
if (queue_cmp(queue_array, parent, child) <= 0)
break;
swap(queue_array, parent, child);
child = parent;
}
}
/*
* heap_down: Given an array of cam_pinfo* elements with the
* Heap(1, num_entries - 1) property with index 0 containing an unsorted
* entry, output Heap(0, num_entries - 1).
*/
static void
heap_down(cam_pinfo **queue_array, int index, int num_entries)
{
int child;
int parent;
parent = index;
child = parent == 0 ? 1 : parent << 1;
for (; child < num_entries; child = parent << 1) {
if (child + 1 < num_entries) {
/* child+1 is the right child of parent */
if (queue_cmp(queue_array, child + 1, child) < 0)
child++;
}
/* child is now the least child of parent */
if (queue_cmp(queue_array, parent, child) <= 0)
break;
swap(queue_array, child, parent);
parent = child;
}
}

236
sys/cam/cam_queue.h Normal file
View File

@ -0,0 +1,236 @@
/*
* CAM request queue management definitions.
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#ifndef _CAM_CAM_QUEUE_H
#define _CAM_CAM_QUEUE_H 1
#ifdef KERNEL
#include <sys/queue.h>
/*
* This structure implements a heap based priority queue. The queue
* assumes that the objects stored in it begin with a cam_qentry
* structure holding the priority information used to sort the objects.
* This structure is opaque to clients (outside of the XPT layer) to allow
* the implementation to change without affecting them.
*/
struct camq {
cam_pinfo **queue_array;
int array_size;
int entries;
u_int32_t generation;
u_int32_t qfrozen_cnt;
};
TAILQ_HEAD(ccb_hdr_list, ccb_hdr);
struct cam_ccbq {
struct camq queue;
int devq_openings;
int dev_openings;
int dev_active;
int held;
struct ccb_hdr_list active_ccbs;
};
struct cam_ed;
struct cam_devq {
struct camq alloc_queue;
struct camq send_queue;
struct cam_ed *active_dev;
int alloc_openings;
int alloc_active;
int send_openings;
int send_active;
};
struct cam_devq *cam_devq_alloc(int devices, int openings);
int cam_devq_init(struct cam_devq *devq, int devices,
int openings);
void cam_devq_free(struct cam_devq *devq);
u_int32_t cam_devq_resize(struct cam_devq *camq, int openings);
/*
* Allocate a cam_ccb_queue structure and initialize it.
*/
struct cam_ccbq *cam_ccbq_alloc(int openings);
u_int32_t cam_ccbq_resize(struct cam_ccbq *ccbq, int devices);
int cam_ccbq_init(struct cam_ccbq *ccbq, int openings);
void cam_ccbq_free(struct cam_ccbq *ccbq);
void cam_ccbq_fini(struct cam_ccbq *ccbq);
void cam_ccbq_regen(struct cam_ccbq *ccbq);
/*
* Allocate and initialize a cam_queue structure.
*/
struct camq *camq_alloc(int size);
/*
* Resize a cam queue
*/
u_int32_t camq_resize(struct camq *queue, int new_size);
/*
* Initialize a camq structure. Return 0 on success, 1 on failure.
*/
int camq_init(struct camq *camq, int size);
/*
* Free a cam_queue structure. This should only be called if a controller
* driver failes somehow during its attach routine or is unloaded and has
* obtained a cam_queue structure.
*/
void camq_free(struct camq *queue);
/*
* Finialize any internal storage or state of a cam_queue.
*/
void camq_fini(struct camq *queue);
/*
* cam_queue_insert: Given a CAM queue with at least one open spot,
* insert the new entry maintaining order.
*/
void camq_insert(struct camq *queue, cam_pinfo *new_entry);
/*
* camq_remove: Remove and arbitrary entry from the queue maintaining
* queue order.
*/
cam_pinfo *camq_remove(struct camq *queue, int index);
/*
* camq_change_priority: Raise or lower the priority of an entry
* maintaining queue order.
*/
void camq_change_priority(struct camq *queue, int index,
u_int32_t new_priority);
void camq_regen(struct camq *queue);
static __inline int
cam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq);
static __inline void
cam_ccbq_take_opening(struct cam_ccbq *ccbq);
static __inline void
cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb);
static __inline void
cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb);
static __inline union ccb *
cam_ccbq_peek_ccb(struct cam_ccbq *ccbq, int index);
static __inline void
cam_ccbq_send_ccb(struct cam_ccbq *queue, union ccb *send_ccb);
static __inline void
cam_ccbq_ccb_done(struct cam_ccbq *ccbq, union ccb *done_ccb);
static __inline void
cam_ccbq_release_opening(struct cam_ccbq *ccbq);
static __inline int
cam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq)
{
return (ccbq->queue.entries);
}
static __inline void
cam_ccbq_take_opening(struct cam_ccbq *ccbq)
{
ccbq->devq_openings--;
ccbq->held++;
}
static __inline void
cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb)
{
ccbq->held--;
camq_insert(&ccbq->queue, &new_ccb->ccb_h.pinfo);
}
static __inline void
cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb)
{
camq_remove(&ccbq->queue, ccb->ccb_h.pinfo.index);
}
static __inline union ccb *
cam_ccbq_peek_ccb(struct cam_ccbq *ccbq, int index)
{
return((union ccb *)ccbq->queue.queue_array[index]);
}
static __inline void
cam_ccbq_send_ccb(struct cam_ccbq *ccbq, union ccb *send_ccb)
{
TAILQ_INSERT_TAIL(&ccbq->active_ccbs,
&(send_ccb->ccb_h),
xpt_links.tqe);
send_ccb->ccb_h.pinfo.index = CAM_ACTIVE_INDEX;
ccbq->dev_active++;
ccbq->dev_openings--;
}
static __inline void
cam_ccbq_ccb_done(struct cam_ccbq *ccbq, union ccb *done_ccb)
{
TAILQ_REMOVE(&ccbq->active_ccbs, &done_ccb->ccb_h,
xpt_links.tqe);
ccbq->dev_active--;
ccbq->dev_openings++;
ccbq->held++;
}
static __inline void
cam_ccbq_release_opening(struct cam_ccbq *ccbq)
{
ccbq->held--;
ccbq->devq_openings++;
}
#endif /* KERNEL */
#endif /* _CAM_CAM_QUEUE_H */

112
sys/cam/cam_sim.c Normal file
View File

@ -0,0 +1,112 @@
/*
* Common functions for SCSI Interface Modules (SIMs).
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_queue.h>
#define CAM_PATH_ANY (u_int32_t)-1
struct cam_devq *
cam_simq_alloc(u_int32_t max_sim_transactions)
{
return (cam_devq_alloc(/*size*/0, max_sim_transactions));
}
void
cam_simq_free(struct cam_devq *devq)
{
cam_devq_free(devq);
}
struct cam_sim *
cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll,
char *sim_name, void *softc, u_int32_t unit,
u_int32_t max_dev_transactions,
u_int32_t max_tagged_dev_transactions, struct cam_devq *queue)
{
struct cam_sim *sim;
/*
* If this is the xpt layer creating a sim, then it's OK
* to wait for an allocation.
*
* XXX Should we pass in a flag to indicate that wait is OK?
*/
if (strcmp(sim_name, "xpt") == 0)
sim = (struct cam_sim *)malloc(sizeof(struct cam_sim),
M_DEVBUF, M_WAITOK);
else
sim = (struct cam_sim *)malloc(sizeof(struct cam_sim),
M_DEVBUF, M_NOWAIT);
if (sim != NULL) {
sim->sim_action = sim_action;
sim->sim_poll = sim_poll;
sim->sim_name = sim_name;
sim->softc = softc;
sim->path_id = CAM_PATH_ANY;
sim->unit_number = unit;
sim->bus_id = 0; /* set in xpt_bus_register */
sim->base_transfer_speed = 3300; /* asynchronous 3300 kB/sec */
sim->max_tagged_dev_openings = max_tagged_dev_transactions;
sim->max_dev_openings = max_dev_transactions;
sim->flags = 0;
callout_handle_init(&sim->c_handle);
sim->devq = queue;
}
return (sim);
}
void
cam_sim_free(struct cam_sim *sim, int free_devq)
{
if (free_devq)
cam_simq_free(sim->devq);
free(sim, M_DEVBUF);
}
void
cam_sim_set_basexfer_speed(struct cam_sim *sim, u_int32_t base_xfer_speed)
{
sim->base_transfer_speed = base_xfer_speed;
}
void
cam_sim_set_path(struct cam_sim *sim, u_int32_t path_id)
{
sim->path_id = path_id;
}

138
sys/cam/cam_sim.h Normal file
View File

@ -0,0 +1,138 @@
/*
* Data structures and definitions for SCSI Interface Modules (SIMs).
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#ifndef _CAM_CAM_SIM_H
#define _CAM_CAM_SIM_H 1
#ifdef KERNEL
/*
* The sim driver creates a sim for each controller. The sim device
* queue is separately created in order to allow resource sharing between
* sims. For instance, a driver may create one sim for each channel of
* a multi-channel controller and use the same queue for each channel.
* In this way, the queue resources are shared across all the channels
* of the multi-channel controller.
*/
struct cam_sim;
struct cam_devq;
typedef void (*sim_action_func)(struct cam_sim *sim, union ccb *ccb);
typedef void (*sim_poll_func)(struct cam_sim *sim);
struct cam_devq * cam_simq_alloc(u_int32_t max_sim_transactions);
void cam_simq_free(struct cam_devq *devq);
struct cam_sim * cam_sim_alloc(sim_action_func sim_action,
sim_poll_func sim_poll,
char *sim_name,
void *softc,
u_int32_t unit,
u_int32_t max_dev_transactions,
u_int32_t max_tagged_dev_transactions,
struct cam_devq *queue);
void cam_sim_free(struct cam_sim *sim, int free_devq);
/* Optional sim attributes may be set with these. */
void cam_sim_set_basexfer_speed(struct cam_sim *sim,
u_int32_t base_xfer_speed);
void cam_sim_set_path(struct cam_sim *sim, u_int32_t path_id);
/* Convenience routines for accessing sim attributes. */
static __inline u_int32_t cam_sim_path(struct cam_sim *sim);
static __inline char * cam_sim_name(struct cam_sim *sim);
static __inline void * cam_sim_softc(struct cam_sim *sim);
static __inline u_int32_t cam_sim_unit(struct cam_sim *sim);
static __inline u_int32_t cam_sim_bus(struct cam_sim *sim);
/* Generically useful offsets into the sim private area */
#define spriv_ptr0 sim_priv.entries[0].ptr
#define spriv_ptr1 sim_priv.entries[1].ptr
#define spriv_field0 sim_priv.entries[0].field
#define spriv_field1 sim_priv.entries[1].field
/*
* The sim driver should not access anything directly from this
* structure.
*/
struct cam_sim {
sim_action_func sim_action;
sim_poll_func sim_poll;
char *sim_name;
void *softc;
u_int32_t path_id;/* The Boot device may set this to 0? */
u_int32_t unit_number;
u_int32_t bus_id;
u_int32_t base_transfer_speed; /* in kB/s */
u_int32_t max_tagged_dev_openings;
u_int32_t max_dev_openings;
u_int32_t flags;
#define CAM_SIM_REL_TIMEOUT_PENDING 0x01
struct callout_handle c_handle;
struct cam_devq *devq; /* Device Queue to use for this SIM */
};
static __inline u_int32_t
cam_sim_path(struct cam_sim *sim)
{
return (sim->path_id);
}
static __inline char *
cam_sim_name(struct cam_sim *sim)
{
return (sim->sim_name);
}
static __inline void *
cam_sim_softc(struct cam_sim *sim)
{
return (sim->softc);
}
static __inline u_int32_t
cam_sim_unit(struct cam_sim *sim)
{
return (sim->unit_number);
}
static __inline u_int32_t
cam_sim_bus(struct cam_sim *sim)
{
return (sim->bus_id);
}
#endif /* KERNEL */
#endif /* _CAM_CAM_SIM_H */

5610
sys/cam/cam_xpt.c Normal file

File diff suppressed because it is too large Load Diff

75
sys/cam/cam_xpt.h Normal file
View File

@ -0,0 +1,75 @@
/*
* Data structures and definitions for dealing with the
* Common Access Method Transport (xpt) layer.
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#ifndef _CAM_CAM_XPT_H
#define _CAM_CAM_XPT_H 1
/* Forward Declarations */
union ccb;
struct cam_periph;
struct cam_sim;
/*
* Definition of a CAM path. Paths are created from bus, target, and lun ids
* via xpt_create_path and allow for reference to devices without recurring
* lookups in the edt.
*/
struct cam_path;
/* Path functions */
#ifdef KERNEL
void xpt_action(union ccb *new_ccb);
void xpt_setup_ccb(struct ccb_hdr *ccb_h,
struct cam_path *path,
u_int32_t priority);
void xpt_merge_ccb(union ccb *master_ccb,
union ccb *slave_ccb);
cam_status xpt_create_path(struct cam_path **new_path_ptr,
struct cam_periph *perph,
path_id_t path_id,
target_id_t target_id, lun_id_t lun_id);
void xpt_free_path(struct cam_path *path);
int xpt_path_comp(struct cam_path *path1,
struct cam_path *path2);
void xpt_print_path(struct cam_path *path);
path_id_t xpt_path_path_id(struct cam_path *path);
target_id_t xpt_path_target_id(struct cam_path *path);
lun_id_t xpt_path_lun_id(struct cam_path *path);
struct cam_sim *xpt_path_sim(struct cam_path *path);
struct cam_periph *xpt_path_periph(struct cam_path *path);
void xpt_async(u_int32_t async_code, struct cam_path *path,
void *async_arg);
#endif /* KERNEL */
#endif /* _CAM_CAM_XPT_H */

51
sys/cam/cam_xpt_periph.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Data structures and definitions for dealing with the
* Common Access Method Transport (xpt) layer from peripheral
* drivers.
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#ifndef _CAM_CAM_XPT_PERIPH_H
#define _CAM_CAM_XPT_PERIPH_H 1
#include <cam/cam_xpt.h>
/* Functions accessed by the peripheral drivers */
#ifdef KERNEL
void xpt_polled_action(union ccb *ccb);
union ccb *xpt_alloc_ccb(void);
void xpt_free_ccb(union ccb *free_ccb);
void xpt_release_ccb(union ccb *released_ccb);
void xpt_schedule(struct cam_periph *perph, u_int32_t new_priority);
int32_t xpt_add_periph(struct cam_periph *periph);
void xpt_remove_periph(struct cam_periph *periph);
void xpt_announce_periph(struct cam_periph *periph,
char *announce_string);
#endif /* KERNEL */
#endif /* _CAM_CAM_XPT_PERIPH_H */

50
sys/cam/cam_xpt_sim.h Normal file
View File

@ -0,0 +1,50 @@
/*
* Data structures and definitions for dealing with the
* Common Access Method Transport (xpt) layer.
*
* Copyright (c) 1997 Justin T. Gibbs.
* 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.
*
* $Id$
*/
#ifndef _CAM_CAM_XPT_SIM_H
#define _CAM_CAM_XPT_SIM_H 1
#include <cam/cam_xpt.h>
#include <cam/cam_queue.h>
/* Functions accessed by SIM drivers */
#ifdef KERNEL
int32_t xpt_bus_register(struct cam_sim *sim, u_int32_t bus);
int32_t xpt_bus_deregister(u_int8_t path_id);
u_int32_t xpt_freeze_simq(struct cam_sim *sim, u_int count);
void xpt_release_simq(struct cam_sim *sim, int run_queue);
u_int32_t xpt_freeze_devq(struct cam_path *path, u_int count);
void xpt_release_devq(struct cam_ed *dev, int run_queue);
void xpt_done(union ccb *done_ccb);
#endif /* KERNEL */
#endif /* _CAM_CAM_XPT_SIM_H */