#ifndef _DEV_SCSIPI_SCSIPICONF_H_
#define _DEV_SCSIPI_SCSIPICONF_H_
typedef int boolean;
#include <sys/callout.h>
#include <sys/queue.h>
#include <sys/condvar.h>
#include <dev/scsipi/scsi_spc.h>
#include <dev/scsipi/scsipi_debug.h>
struct buf;
struct proc;
struct device;
struct scsipi_channel;
struct scsipi_periph;
struct scsipi_xfer;
TAILQ_HEAD(scsipi_xfer_queue, scsipi_xfer);
struct scsipi_generic {
u_int8_t opcode;
u_int8_t bytes[15];
};
typedef enum {
ASYNC_EVENT_MAX_OPENINGS,
ASYNC_EVENT_XFER_MODE,
ASYNC_EVENT_RESET
} scsipi_async_event_t;
struct scsipi_max_openings {
int mo_target;
int mo_lun;
int mo_openings;
};
struct scsipi_xfer_mode {
int xm_target;
int xm_mode;
int xm_period;
int xm_offset;
};
typedef enum {
ADAPTER_REQ_RUN_XFER,
ADAPTER_REQ_GROW_RESOURCES,
ADAPTER_REQ_SET_XFER_MODE
} scsipi_adapter_req_t;
#ifdef _KERNEL
struct scsipi_periphsw {
int (*psw_error)(struct scsipi_xfer *);
void (*psw_start)(struct scsipi_periph *);
int (*psw_async)(struct scsipi_periph *,
scsipi_async_event_t, void *);
void (*psw_done)(struct scsipi_xfer *, int);
};
struct disk_parms;
struct scsipi_inquiry_pattern;
struct scsipi_adapter {
device_t adapt_dev;
int adapt_nchannels;
volatile int adapt_refcnt;
int adapt_openings;
int adapt_max_periph;
int adapt_flags;
void (*adapt_request)(struct scsipi_channel *,
scsipi_adapter_req_t, void *);
void (*adapt_minphys)(struct buf *);
int (*adapt_ioctl)(struct scsipi_channel *, u_long,
void *, int, struct proc *);
int (*adapt_enable)(device_t, int);
int (*adapt_getgeom)(struct scsipi_periph *,
struct disk_parms *, u_long);
int (*adapt_accesschk)(struct scsipi_periph *,
struct scsipi_inquiry_pattern *);
kmutex_t adapt_mtx;
volatile int adapt_running;
};
#define SCSIPI_ADAPT_POLL_ONLY 0x01
#define SCSIPI_ADAPT_MPSAFE 0x02
void scsipi_adapter_minphys(struct scsipi_channel *, struct buf *);
void scsipi_adapter_request(struct scsipi_channel *,
scsipi_adapter_req_t, void *);
int scsipi_adapter_ioctl(struct scsipi_channel *, u_long,
void *, int, struct proc *);
int scsipi_adapter_enable(struct scsipi_adapter *, int);
#endif
struct scsipi_bustype {
int bustype_type;
void (*bustype_cmd)(struct scsipi_xfer *);
int (*bustype_interpret_sense)(struct scsipi_xfer *);
void (*bustype_printaddr)(struct scsipi_periph *);
void (*bustype_kill_pending)(struct scsipi_periph *);
void (*bustype_async_event_xfer_mode)(struct scsipi_channel *,
void *);
};
#define SCSIPI_BUSTYPE_TYPE_SHIFT 0
#define SCSIPI_BUSTYPE_TYPE(x) (((x) >> SCSIPI_BUSTYPE_TYPE_SHIFT) & 0xff)
#define SCSIPI_BUSTYPE_SCSI 0
#define SCSIPI_BUSTYPE_ATAPI 1
#define SCSIPI_BUSTYPE_SUBTYPE_SHIFT 8
#define SCSIPI_BUSTYPE_SUBTYPE(x) (((x) >> SCSIPI_BUSTYPE_SUBTYPE_SHIFT) & 0xff)
#define SCSIPI_BUSTYPE_BUSTYPE(t, s) \
((t) << SCSIPI_BUSTYPE_TYPE_SHIFT | (s) << SCSIPI_BUSTYPE_SUBTYPE_SHIFT)
#define SCSIPI_CHAN_PERIPH_BUCKETS 16
#define SCSIPI_CHAN_PERIPH_HASHMASK (SCSIPI_CHAN_PERIPH_BUCKETS - 1)
#ifdef _KERNEL
struct scsipi_channel {
const struct scsipi_bustype *chan_bustype;
const char *chan_name;
struct scsipi_adapter *chan_adapter;
LIST_HEAD(, scsipi_periph) chan_periphtab[SCSIPI_CHAN_PERIPH_BUCKETS];
int chan_channel;
int chan_flags;
int chan_openings;
int chan_max_periph;
int chan_ntargets;
int chan_nluns;
int chan_id;
int chan_defquirks;
struct lwp *chan_dthread;
struct lwp *chan_thread;
int chan_tflags;
int chan_qfreeze;
struct scsipi_xfer_queue chan_queue;
struct scsipi_xfer_queue chan_complete;
void (*chan_callback)(struct scsipi_channel *, void *);
void *chan_callback_arg;
void (*chan_init_cb)(struct scsipi_channel *, void *);
void *chan_init_cb_arg;
kcondvar_t chan_cv_comp;
kcondvar_t chan_cv_thr;
kcondvar_t chan_cv_xs;
#define chan_cv_complete(ch) (&(ch)->chan_cv_comp)
#define chan_cv_thread(ch) (&(ch)->chan_cv_thr)
};
#define chan_running(ch) ((ch)->chan_adapter->adapt_running)
#define chan_mtx(ch) (&(ch)->chan_adapter->adapt_mtx)
#endif
#define SCSIPI_CHAN_OPENINGS 0x01
#define SCSIPI_CHAN_CANGROW 0x02
#define SCSIPI_CHAN_NOSETTLE 0x04
#define SCSIPI_CHAN_TACTIVE 0x08
#define SCSIPI_CHANT_SHUTDOWN 0x01
#define SCSIPI_CHANT_CALLBACK 0x02
#define SCSIPI_CHANT_KICK 0x04
#define SCSIPI_CHANT_GROWRES 0x08
#define SCSIPI_CHAN_MAX_PERIPH(chan) \
(((chan)->chan_flags & SCSIPI_CHAN_OPENINGS) ? \
(chan)->chan_max_periph : (chan)->chan_adapter->adapt_max_periph)
#define scsipi_printaddr(periph) \
(*(periph)->periph_channel->chan_bustype->bustype_printaddr)((periph))
#define scsipi_periph_bustype(periph) \
(periph)->periph_channel->chan_bustype->bustype_type
#define PERIPH_NTAGWORDS ((256 / 8) / sizeof(u_int32_t))
#ifdef _KERNEL
struct scsipi_opcodes
{
struct scsipi_opinfo
{
long ti_timeout;
unsigned long ti_flags;
#define SCSIPI_TI_VALID 0x0001
#define SCSIPI_TI_LOGGED 0x8000
} opcode_info[0x100];
};
struct scsipi_periph {
device_t periph_dev;
struct scsipi_channel *periph_channel;
LIST_ENTRY(scsipi_periph) periph_hash;
const struct scsipi_periphsw *periph_switch;
int periph_openings;
int periph_active;
int periph_sent;
int periph_mode;
int periph_period;
int periph_offset;
u_int8_t periph_type;
int periph_cap;
int periph_quirks;
int periph_flags;
int periph_dbflags;
int periph_target;
int periph_lun;
int periph_version;
int periph_qfreeze;
struct scsipi_opcodes *periph_opcs;
u_int32_t periph_freetags[PERIPH_NTAGWORDS];
struct scsipi_xfer_queue periph_xferq;
callout_t periph_callout;
struct scsipi_xfer *periph_xscheck;
kcondvar_t periph_cv;
#define periph_cv_periph(p) (&(p)->periph_cv)
#define periph_cv_active(p) (&(p)->periph_cv)
};
#endif
#define PERIPH_XFER_MODE(periph) \
(((periph)->periph_flags & PERIPH_MODE_VALID) ? \
(periph)->periph_mode : 0)
#define PERIPH_CAP_ANEC 0x0001
#define PERIPH_CAP_TERMIOP 0x0002
#define PERIPH_CAP_RELADR 0x0004
#define PERIPH_CAP_WIDE32 0x0008
#define PERIPH_CAP_WIDE16 0x0010
#define PERIPH_CAP_SYNC 0x0080
#define PERIPH_CAP_LINKCMDS 0x0100
#define PERIPH_CAP_TQING 0x0200
#define PERIPH_CAP_SFTRESET 0x0400
#define PERIPH_CAP_CMD16 0x0800
#define PERIPH_CAP_DT 0x1000
#define PERIPH_CAP_QAS 0x2000
#define PERIPH_CAP_IUS 0x4000
#define PERIPH_REMOVABLE 0x0001
#define PERIPH_MEDIA_LOADED 0x0002
#define PERIPH_WAITING 0x0004
#define PERIPH_OPEN 0x0008
#define PERIPH_WAITDRAIN 0x0010
#define PERIPH_GROW_OPENINGS 0x0020
#define PERIPH_MODE_VALID 0x0040
#define PERIPH_RECOVERING 0x0080
#define PERIPH_RECOVERY_ACTIVE 0x0100
#define PERIPH_KEEP_LABEL 0x0200
#define PERIPH_SENSE 0x0400
#define PERIPH_UNTAG 0x0800
#define PQUIRK_AUTOSAVE 0x00000001
#define PQUIRK_NOSYNC 0x00000002
#define PQUIRK_NOWIDE 0x00000004
#define PQUIRK_NOTAG 0x00000008
#define PQUIRK_NOLUNS 0x00000010
#define PQUIRK_FORCELUNS 0x00000020
#define PQUIRK_NOMODESENSE 0x00000040
#define PQUIRK_NOSYNCCACHE 0x00000100
#define PQUIRK_LITTLETOC 0x00000400
#define PQUIRK_NOCAPACITY 0x00000800
#define PQUIRK_NOTUR 0x00001000
#define PQUIRK_NODOORLOCK 0x00002000
#define PQUIRK_NOSENSE 0x00004000
#define PQUIRK_ONLYBIG 0x00008000
#define PQUIRK_NOBIGMODESENSE 0x00040000
#define PQUIRK_CAP_SYNC 0x00080000
#define PQUIRK_CAP_WIDE16 0x00100000
#define PQUIRK_CAP_NODT 0x00200000
#define PQUIRK_START 0x00400000
#define PQUIRK_NOFUA 0x00800000
#define PQUIRK_NOREPSUPPOPC 0x01000000
#define PQUIRK_NOREADDISCINFO 0x02000000
typedef enum {
XS_NOERROR,
XS_SENSE,
XS_SHORTSENSE,
XS_DRIVER_STUFFUP,
XS_RESOURCE_SHORTAGE,
XS_SELTIMEOUT,
XS_TIMEOUT,
XS_BUSY,
XS_RESET,
XS_REQUEUE
} scsipi_xfer_result_t;
#ifdef _KERNEL
struct scsipi_xfer {
TAILQ_ENTRY(scsipi_xfer) channel_q;
TAILQ_ENTRY(scsipi_xfer) device_q;
callout_t xs_callout;
int xs_control;
volatile int xs_status;
struct scsipi_periph *xs_periph;
int xs_retries;
int xs_requeuecnt;
int timeout;
struct scsipi_generic *cmd;
int cmdlen;
u_char *data;
int datalen;
int resid;
scsipi_xfer_result_t error;
struct buf *bp;
union {
struct scsi_sense_data scsi_sense;
u_int32_t atapi_sense;
} sense;
struct scsipi_xfer *xs_sensefor;
u_int8_t status;
u_int8_t xs_tag_type;
u_int8_t xs_tag_id;
struct scsipi_generic cmdstore
__aligned(4);
#define xs_cv(xs) (&(xs)->xs_periph->periph_channel->chan_cv_xs)
};
#endif
#define XS_CTL_NOSLEEP 0x00000001
#define XS_CTL_POLL 0x00000002
#define XS_CTL_DISCOVERY 0x00000004
#define XS_CTL_ASYNC 0x00000008
#define XS_CTL_USERCMD 0x00000010
#define XS_CTL_SILENT 0x00000020
#define XS_CTL_IGNORE_NOT_READY 0x00000040
#define XS_CTL_IGNORE_MEDIA_CHANGE \
0x00000080
#define XS_CTL_IGNORE_ILLEGAL_REQUEST \
0x00000100
#define XS_CTL_SILENT_NODEV 0x00000200
#define XS_CTL_RESET 0x00000400
#define XS_CTL_DATA_UIO 0x00000800
#define XS_CTL_DATA_IN 0x00001000
#define XS_CTL_DATA_OUT 0x00002000
#define XS_CTL_TARGET 0x00004000
#define XS_CTL_ESCAPE 0x00008000
#define XS_CTL_URGENT 0x00010000
#define XS_CTL_SIMPLE_TAG 0x00020000
#define XS_CTL_ORDERED_TAG 0x00040000
#define XS_CTL_HEAD_TAG 0x00080000
#define XS_CTL_THAW_PERIPH 0x00100000
#define XS_CTL_FREEZE_PERIPH 0x00200000
#define XS_CTL_REQSENSE 0x00800000
#define XS_CTL_TAGMASK (XS_CTL_SIMPLE_TAG|XS_CTL_ORDERED_TAG|XS_CTL_HEAD_TAG)
#define XS_CTL_TAGTYPE(xs) ((xs)->xs_control & XS_CTL_TAGMASK)
#define XS_STS_DONE 0x00000001
#define XS_STS_PRIVATE 0xf0000000
struct scsipi_inquiry_pattern {
u_int8_t type;
boolean removable;
const char *vendor;
const char *product;
const char *revision;
};
struct scsipibus_attach_args {
struct scsipi_periph *sa_periph;
struct scsipi_inquiry_pattern sa_inqbuf;
struct scsipi_inquiry_data *sa_inqptr;
union {
u_int8_t scsi_version;
} scsipi_info;
};
struct scsi_quirk_inquiry_pattern {
struct scsipi_inquiry_pattern pattern;
int quirks;
};
#define SCSIPIRETRIES 4
#ifdef _KERNEL
void scsipi_init(void);
void scsipi_ioctl_init(void);
void scsipi_load_verbose(void);
int scsipi_command(struct scsipi_periph *, struct scsipi_generic *, int,
u_char *, int, int, int, struct buf *, int);
void scsipi_create_completion_thread(void *);
const void *scsipi_inqmatch(struct scsipi_inquiry_pattern *, const void *,
size_t, size_t, int *);
const char *scsipi_dtype(int);
int scsipi_execute_xs(struct scsipi_xfer *);
int scsipi_test_unit_ready(struct scsipi_periph *, int);
int scsipi_prevent(struct scsipi_periph *, int, int);
int scsipi_inquire(struct scsipi_periph *,
struct scsipi_inquiry_data *, int);
int scsipi_mode_select(struct scsipi_periph *, int,
struct scsi_mode_parameter_header_6 *, int, int, int, int);
int scsipi_mode_select_big(struct scsipi_periph *, int,
struct scsi_mode_parameter_header_10 *, int, int, int, int);
int scsipi_mode_sense(struct scsipi_periph *, int, int,
struct scsi_mode_parameter_header_6 *, int, int, int, int);
int scsipi_mode_sense_big(struct scsipi_periph *, int, int,
struct scsi_mode_parameter_header_10 *, int, int, int, int);
int scsipi_start(struct scsipi_periph *, int, int);
void scsipi_done(struct scsipi_xfer *);
void scsipi_user_done(struct scsipi_xfer *);
int scsipi_interpret_sense(struct scsipi_xfer *);
void scsipi_wait_drain(struct scsipi_periph *);
void scsipi_kill_pending(struct scsipi_periph *);
void scsipi_get_opcodeinfo(struct scsipi_periph *periph);
void scsipi_free_opcodeinfo(struct scsipi_periph *periph);
struct scsipi_periph *scsipi_alloc_periph(int);
void scsipi_free_periph(struct scsipi_periph *);
extern int (*scsipi_print_sense)(struct scsipi_xfer *, int);
extern void (*scsipi_print_sense_data)(struct scsi_sense_data *, int);
int scsipi_print_sense_stub(struct scsipi_xfer *, int);
void scsipi_print_sense_data_stub(struct scsi_sense_data *, int);
extern int scsi_verbose_loaded;
void scsipi_print_cdb(struct scsipi_generic *cmd);
int scsipi_thread_call_callback(struct scsipi_channel *,
void (*callback)(struct scsipi_channel *, void *),
void *);
void scsipi_async_event(struct scsipi_channel *,
scsipi_async_event_t, void *);
int scsipi_do_ioctl(struct scsipi_periph *, dev_t, u_long, void *,
int, struct lwp *);
void scsipi_set_xfer_mode(struct scsipi_channel *, int, int);
int scsipi_channel_init(struct scsipi_channel *);
void scsipi_channel_shutdown(struct scsipi_channel *);
void scsipi_insert_periph(struct scsipi_channel *,
struct scsipi_periph *);
void scsipi_remove_periph(struct scsipi_channel *,
struct scsipi_periph *);
struct scsipi_periph *scsipi_lookup_periph(struct scsipi_channel *,
int, int);
struct scsipi_periph *scsipi_lookup_periph_locked(struct scsipi_channel *,
int, int);
int scsipi_target_detach(struct scsipi_channel *, int, int, int);
int scsipi_adapter_addref(struct scsipi_adapter *);
void scsipi_adapter_delref(struct scsipi_adapter *);
void scsipi_channel_freeze(struct scsipi_channel *, int);
void scsipi_channel_thaw(struct scsipi_channel *, int);
void scsipi_channel_timed_thaw(void *);
void scsipi_periph_freeze(struct scsipi_periph *, int);
void scsipi_periph_thaw(struct scsipi_periph *, int);
void scsipi_periph_timed_thaw(void *);
void scsipi_periph_freeze_locked(struct scsipi_periph *, int);
void scsipi_periph_thaw_locked(struct scsipi_periph *, int);
int scsipi_sync_period_to_factor(int);
int scsipi_sync_factor_to_period(int);
int scsipi_sync_factor_to_freq(int);
void show_scsipi_xs(struct scsipi_xfer *);
void show_scsipi_cmd(struct scsipi_xfer *);
void show_mem(u_char *, int);
#endif
static __inline void
_lto2b(u_int32_t val, u_int8_t *bytes)
{
bytes[0] = (val >> 8) & 0xff;
bytes[1] = val & 0xff;
}
static __inline void
_lto3b(u_int32_t val, u_int8_t *bytes)
{
bytes[0] = (val >> 16) & 0xff;
bytes[1] = (val >> 8) & 0xff;
bytes[2] = val & 0xff;
}
static __inline void
_lto4b(u_int32_t val, u_int8_t *bytes)
{
bytes[0] = (val >> 24) & 0xff;
bytes[1] = (val >> 16) & 0xff;
bytes[2] = (val >> 8) & 0xff;
bytes[3] = val & 0xff;
}
static __inline void
_lto8b(u_int64_t val, u_int8_t *bytes)
{
bytes[0] = (val >> 56) & 0xff;
bytes[1] = (val >> 48) & 0xff;
bytes[2] = (val >> 40) & 0xff;
bytes[3] = (val >> 32) & 0xff;
bytes[4] = (val >> 24) & 0xff;
bytes[5] = (val >> 16) & 0xff;
bytes[6] = (val >> 8) & 0xff;
bytes[7] = val & 0xff;
}
static __inline u_int32_t
_2btol(const u_int8_t *bytes)
{
u_int32_t rv;
rv = (bytes[0] << 8) |
bytes[1];
return (rv);
}
static __inline u_int32_t
_3btol(const u_int8_t *bytes)
{
u_int32_t rv;
rv = (bytes[0] << 16) |
(bytes[1] << 8) |
bytes[2];
return (rv);
}
static __inline u_int32_t
_4btol(const u_int8_t *bytes)
{
u_int32_t rv;
rv = ((u_int32_t)bytes[0] << 24) |
((u_int32_t)bytes[1] << 16) |
((u_int32_t)bytes[2] << 8) |
(u_int32_t)bytes[3];
return (rv);
}
static __inline u_int64_t
_5btol(const u_int8_t *bytes)
{
u_int64_t rv;
rv = ((u_int64_t)bytes[0] << 32) |
((u_int64_t)bytes[1] << 24) |
((u_int64_t)bytes[2] << 16) |
((u_int64_t)bytes[3] << 8) |
(u_int64_t)bytes[4];
return (rv);
}
static __inline u_int64_t
_8btol(const u_int8_t *bytes)
{
u_int64_t rv;
rv = ((u_int64_t)bytes[0] << 56) |
((u_int64_t)bytes[1] << 48) |
((u_int64_t)bytes[2] << 40) |
((u_int64_t)bytes[3] << 32) |
((u_int64_t)bytes[4] << 24) |
((u_int64_t)bytes[5] << 16) |
((u_int64_t)bytes[6] << 8) |
(u_int64_t)bytes[7];
return (rv);
}
static __inline void
_lto2l(u_int32_t val, u_int8_t *bytes)
{
bytes[0] = val & 0xff;
bytes[1] = (val >> 8) & 0xff;
}
static __inline void
_lto3l(u_int32_t val, u_int8_t *bytes)
{
bytes[0] = val & 0xff;
bytes[1] = (val >> 8) & 0xff;
bytes[2] = (val >> 16) & 0xff;
}
static __inline void
_lto4l(u_int32_t val, u_int8_t *bytes)
{
bytes[0] = val & 0xff;
bytes[1] = (val >> 8) & 0xff;
bytes[2] = (val >> 16) & 0xff;
bytes[3] = (val >> 24) & 0xff;
}
static __inline u_int32_t
_2ltol(const u_int8_t *bytes)
{
u_int32_t rv;
rv = bytes[0] |
(bytes[1] << 8);
return (rv);
}
static __inline u_int32_t
_3ltol(const u_int8_t *bytes)
{
u_int32_t rv;
rv = bytes[0] |
(bytes[1] << 8) |
(bytes[2] << 16);
return (rv);
}
static __inline u_int32_t
_4ltol(const u_int8_t *bytes)
{
u_int32_t rv;
rv = (u_int32_t)bytes[0] |
((u_int32_t)bytes[1] << 8) |
((u_int32_t)bytes[2] << 16) |
((u_int32_t)bytes[3] << 24);
return (rv);
}
#endif