1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #ifndef	_SYS_1394_TARGETS_SCSA1394_IMPL_H
27 #define	_SYS_1394_TARGETS_SCSA1394_IMPL_H
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 /*
32  * scsa1394 definitions
33  */
34 
35 #include <sys/1394/t1394.h>
36 #include <sys/sbp2/driver.h>
37 #include <sys/scsi/scsi.h>
38 #include <sys/cdio.h>
39 #include <sys/1394/targets/scsa1394/cmd.h>
40 
41 #ifdef	__cplusplus
42 extern "C" {
43 #endif
44 
45 /*
46  * each lun uses a worker thread for various deferred processing
47  */
48 typedef enum {
49 	SCSA1394_THR_INIT,			/* initial state */
50 	SCSA1394_THR_RUN,			/* thread is running */
51 	SCSA1394_THR_EXIT			/* thread exited */
52 } scsa1394_thr_state_t;
53 
54 /* thread requests */
55 enum {
56 	SCSA1394_THREQ_EXIT		= 0x1,	/* thread has to exit */
57 	SCSA1394_THREQ_TASK_STATUS	= 0x2,	/* task status received */
58 	SCSA1394_THREQ_NUDGE		= 0x4,	/* nudge SBP-2 layer */
59 	SCSA1394_THREQ_BUS_RESET	= 0x8,
60 	SCSA1394_THREQ_DISCONNECT	= 0x10,
61 	SCSA1394_THREQ_RECONNECT	= 0x20
62 };
63 
64 typedef struct scsa1394_thread {
65 	void			(*thr_func)(void *);	/* function to be run */
66 	void			*thr_arg;	/* function argument */
67 	struct scsa1394_lun	*thr_lun;	/* lun we belong to */
68 	scsa1394_thr_state_t	thr_state;	/* state */
69 	kcondvar_t		thr_cv;		/* cv for request wait */
70 	int			thr_req;	/* request mask */
71 } scsa1394_thread_t;
72 
73 
74 /* 1394 device state */
75 typedef enum {
76 	SCSA1394_DEV_INIT		= 0,
77 	SCSA1394_DEV_ONLINE,
78 	SCSA1394_DEV_BUS_RESET,
79 	SCSA1394_DEV_DISCONNECTED,
80 	SCSA1394_DEV_PWRED_DOWN,
81 	SCSA1394_DEV_SUSPENDED
82 } scsa1394_dev_state_t;
83 
84 enum { SCSA1394_STAT_NCMD_LAST = 8 };
85 
86 /* per-lun statistics */
87 typedef struct scsa1394_lun_stat {
88 	/*
89 	 * ring buffer of the last N failed commands. stat_cmd_fail_last_idx
90 	 * is an index into stat_cmd_fail_last the array and points to the
91 	 * entry to be written next. The first 16 bytes are CDB bytes,
92 	 * the last 8 bytes are a timestamp (lbolt).
93 	 */
94 	uint64_t		stat_cmd_last_fail[SCSA1394_STAT_NCMD_LAST][3];
95 	int			stat_cmd_last_fail_idx;
96 
97 	uint_t			stat_cmd_cnt;	/* # of commands submitted */
98 	uint_t			stat_cmd_buf_max_nsegs;
99 	uint_t			stat_cmd_buf_dma_partial;
100 
101 	/*
102 	 * errors
103 	 */
104 	uint_t			stat_err_pkt_kmem_alloc;
105 	uint_t			stat_err_cmd_cdb_dmem_alloc;
106 	uint_t			stat_err_cmd_cdb_dbind;
107 	uint_t			stat_err_cmd_cdb_addr_alloc;
108 	uint_t			stat_err_cmd_buf_dbind;
109 	uint_t			stat_err_cmd_buf_addr_alloc;
110 	uint_t			stat_err_cmd_pt_kmem_alloc;
111 	uint_t			stat_err_cmd_pt_dmem_alloc;
112 	uint_t			stat_err_cmd_pt_addr_alloc;
113 	uint_t			stat_err_status_tran_err;
114 	uint_t			stat_err_status_conv;
115 	uint_t			stat_err_status_resp;
116 } scsa1394_lun_stat_t;
117 
118 /* logical unit */
119 typedef struct scsa1394_lun {
120 	kmutex_t		l_mutex;	/* structure lock */
121 	struct scsa1394_state	*l_sp;		/* soft state */
122 	sbp2_lun_t		*l_lun;		/* SBP2 lun */
123 	sbp2_ses_t		*l_ses;		/* login session */
124 	dev_info_t		*l_cdip;	/* child devinfo */
125 	scsa1394_thread_t	l_worker_thread; /* worker thread */
126 	ddi_softintr_t		l_softintr_id;	/* soft interrupt */
127 	boolean_t		l_softintr_triggered; /* trigger indicator */
128 	int			l_softintr_req;	/* soft intr request mask */
129 
130 	/* workarounds */
131 	int			l_lba_size;	/* LBA size */
132 	int			l_dtype_orig;	/* original DTYPE value */
133 	int			l_rmb_orig;	/* original RMB value */
134 	int			l_start_stop_fail_cnt; /* start/stop failures */
135 	boolean_t		l_start_stop_fake; /* fake start/stop unit */
136 	int			l_mode_sense_fail_cnt; /* mode sense failures */
137 	boolean_t		l_mode_sense_fake; /* fake mode sense command */
138 	boolean_t		l_nosup_tur;
139 	boolean_t		l_nosup_start_stop;
140 	boolean_t		l_nosup_inquiry;
141 
142 	struct scsi_inquiry	l_fake_inq;
143 
144 	scsa1394_lun_stat_t	l_stat;		/* statistics */
145 } scsa1394_lun_t;
146 
147 _NOTE(MUTEX_PROTECTS_DATA(scsa1394_lun::l_mutex, scsa1394_lun))
148 _NOTE(SCHEME_PROTECTS_DATA("stable data", scsa1394_lun::{
149     l_sp l_lun l_ses l_cdip l_worker_thread l_softintr_id
150     l_nosup_tur l_nosup_start_stop l_nosup_inquiry }))
151 _NOTE(SCHEME_PROTECTS_DATA("statistics", scsa1394_lun::l_stat))
152 
153 /* l_softintr_req */
154 enum {
155 	SCSA1394_SOFTINTR_STATUS_RCVD	= 0x1,	/* task status received */
156 	SCSA1394_SOFTINTR_RECONNECT	= 0x2	/* perform reconnect */
157 };
158 
159 /* per-instance statistics */
160 typedef struct scsa1394_inst_stat {
161 	uint_t			stat_bus_reset_cnt;
162 	uint_t			stat_disconnect_cnt;
163 	uint_t			stat_reconnect_cnt;
164 	/*
165 	 * errors
166 	 */
167 } scsa1394_inst_stat_t;
168 
169 /* per-instance soft state structure */
170 typedef struct scsa1394_state {
171 	kmutex_t		s_mutex;	/* structure mutex */
172 	dev_info_t		*s_dip;		/* device information */
173 	int			s_instance;	/* instance number */
174 	scsa1394_dev_state_t	s_dev_state;	/* device state */
175 	t1394_handle_t		s_t1394_hdl;	/* 1394 handle */
176 	t1394_attachinfo_t	s_attachinfo;	/* 1394 attach info */
177 	t1394_targetinfo_t	s_targetinfo;	/* 1394 target info */
178 	ddi_callback_id_t	s_reset_cb_id;	/* reset event cb id */
179 	ddi_callback_id_t	s_remove_cb_id;	/* remove event cb id */
180 	ddi_callback_id_t	s_insert_cb_id;	/* insert event cb id */
181 	boolean_t		s_event_entered; /* event serialization */
182 	kcondvar_t		s_event_cv;	/* event serialization cv */
183 	ddi_dma_attr_t		s_buf_dma_attr;	/* data buffer DMA attrs */
184 	ddi_dma_attr_t		s_pt_dma_attr;	/* page table DMA attrs */
185 	scsi_hba_tran_t		*s_tran;	/* SCSA HBA tran structure */
186 	sbp2_tgt_t		*s_tgt;		/* SBP-2 target */
187 	sbp2_cfgrom_t		*s_cfgrom;	/* Config ROM */
188 	int			s_nluns;	/* # of logical units */
189 	scsa1394_lun_t		*s_lun;		/* logical units */
190 	kmem_cache_t		*s_cmd_cache;	/* command kmem cache */
191 	ddi_taskq_t		*s_taskq;	/* common taskq for all luns */
192 	boolean_t		s_symbios;	/* need Symbios workaround? */
193 	boolean_t		s_disconnect_warned; /* disconnect warning */
194 	size_t			s_totalsec;	/* total sectors */
195 	size_t			s_secsz;	/* sector size */
196 	scsa1394_inst_stat_t	s_stat;		/* statistics */
197 } scsa1394_state_t;
198 
199 _NOTE(MUTEX_PROTECTS_DATA(scsa1394_state::s_mutex, scsa1394_state))
200 _NOTE(SCHEME_PROTECTS_DATA("stable data", scsa1394_state::{
201     s_dip s_instance s_t1394_hdl s_attachinfo s_reset_cb_id s_remove_cb_id
202     s_insert_cb_id s_buf_dma_attr s_pt_dma_attr s_tran s_tgt s_cfgrom
203     s_nluns s_lun s_cmd_cache s_taskq s_symbios s_targetinfo
204     s_totalsec s_secsz}))
205 _NOTE(SCHEME_PROTECTS_DATA("statistics", scsa1394_state::s_stat))
206 
207 _NOTE(LOCK_ORDER(scsa1394_state::s_mutex scsa1394_lun::l_mutex))
208 
209 /* for sbp2_bus_buf.bb_hdl */
210 typedef struct scsa1394_bus_buf {
211 	scsa1394_state_t	*sbb_state;	/* soft state */
212 	t1394_addr_handle_t	sbb_addr_hdl;	/* 1394 address handle */
213 	ddi_dma_handle_t	sbb_dma_hdl;	/* DMA handle */
214 	ddi_acc_handle_t	sbb_acc_hdl;	/* access handle */
215 } scsa1394_bus_buf_t;
216 
217 _NOTE(SCHEME_PROTECTS_DATA("unique per task", scsa1394_bus_buf))
218 _NOTE(SCHEME_PROTECTS_DATA("dev_info::devi_lock", dev_info::devi_state))
219 
220 /* various translation macros */
221 #define	ADDR2TRAN(ap)	((ap)->a_hba_tran)
222 #define	TRAN2STATE(hba)	((scsa1394_state_t *)(hba)->tran_hba_private)
223 #define	ADDR2STATE(ap)	(TRAN2STATE(ADDR2TRAN(ap)))
224 
225 #define	SCSA1394_NODEID(sp)	((sp)->s_attachinfo.localinfo.local_nodeID)
226 #define	SCSA1394_BUSGEN(sp)	((sp)->s_attachinfo.localinfo.bus_generation)
227 
228 #define	SCSA1394_ORB_SIZE_ROUNDUP(sp, sz) SBP2_ORB_SIZE_ROUNDUP(sp->s_tgt, sz)
229 #define	SCSA1394_ADDR_SET(sp, var, addr) \
230     SBP2_ADDR_SET(var, addr, SCSA1394_NODEID(sp))
231 
232 /* macros to calculate LBA for 6/10/12-byte commands */
233 #define	SCSA1394_LBA_6BYTE(pkt)						\
234 	(((pkt)->pkt_cdbp[1] & 0x1f) << 16) +				\
235 	((pkt)->pkt_cdbp[2] << 8) + (pkt)->pkt_cdbp[3]
236 #define	SCSA1394_LEN_6BYTE(pkt)						\
237 	(pkt)->pkt_cdbp[4]
238 
239 #define	SCSA1394_LEN_10BYTE(pkt)					\
240 	((pkt)->pkt_cdbp[7] << 8) + (pkt)->pkt_cdbp[8]
241 #define	SCSA1394_LBA_10BYTE(pkt)					\
242 	((pkt)->pkt_cdbp[2] << 24) + ((pkt)->pkt_cdbp[3] << 16) + 	\
243 	((pkt)->pkt_cdbp[4] << 8) +  (pkt)->pkt_cdbp[5]
244 
245 #define	SCSA1394_LEN_12BYTE(pkt)					\
246 	((pkt)->pkt_cdbp[6] << 24) + ((pkt)->pkt_cdbp[7] << 16) +	\
247 	((pkt)->pkt_cdbp[8] << 8) +  (pkt)->pkt_cdbp[9]
248 #define	SCSA1394_LBA_12BYTE(pkt)					\
249 	((pkt)->pkt_cdbp[2] << 24) + ((pkt)->pkt_cdbp[3] << 16) +	\
250 	((pkt)->pkt_cdbp[4] << 8) +  (pkt)->pkt_cdbp[5]
251 
252 /* macro to calculate LEN for SCMD_READ_CD command */
253 #define	SCSA1394_LEN_READ_CD(pkt)					\
254 	(((pkt)->pkt_cdbp[6] << 16) + ((pkt)->pkt_cdbp[7] << 8) +	\
255 	(pkt)->pkt_cdbp[8])
256 
257 /* calculate block size for CD-RW writes */
258 #define	SCSA1394_CDRW_BLKSZ(bcount, len)	((bcount) / (len))
259 #define	SCSA1394_VALID_CDRW_BLKSZ(blksz)				\
260 	(((blksz) == CDROM_BLK_2048) || ((blksz) == CDROM_BLK_2352) ||	\
261 	((blksz) == CDROM_BLK_2336) || ((blksz) == CDROM_BLK_2324))
262 
263 /* black/white list */
264 typedef struct scsa1394_bw_list {
265 	int	vid_match;
266 	int	vid;
267 } scsa1394_bw_list_t;
268 
269 /* match type */
270 enum {
271 	SCSA1394_BW_ONE,
272 	SCSA1394_BW_ALL
273 };
274 
275 #define	NELEM(a)	(sizeof (a) / sizeof (*(a)))
276 
277 /* misc constants */
278 enum {
279 	SCSA1394_COMPAT_MAX		= 1,	/* max @ of compatible names */
280 	SCSA1394_CLEANUP_LEVEL_MAX	= 256,
281 	SCSA1394_START_STOP_FAIL_MAX	= 3,	/* max start/stop failures */
282 	SCSA1394_MODE_SENSE_FAIL_MAX	= 3,	/* max mode sense failures */
283 	SCSA1394_START_STOP_TIMEOUT_MAX	= 30,
284 	SCSA1394_MAPIN_SIZE_MAX		= 512,
285 	SCSA1394_PROBE_TIMEOUT		= 15,	/* in seconds */
286 
287 	SCSA1394_DTYPE_RBC		= 0x0E
288 };
289 
290 
291 /* SBP-2 routines */
292 int	scsa1394_sbp2_attach(scsa1394_state_t *);
293 void	scsa1394_sbp2_detach(scsa1394_state_t *);
294 void	scsa1394_sbp2_fake_inquiry(scsa1394_state_t *, struct scsi_inquiry *);
295 int	scsa1394_sbp2_threads_init(scsa1394_state_t *);
296 void	scsa1394_sbp2_threads_fini(scsa1394_state_t *);
297 int	scsa1394_sbp2_get_lun_type(scsa1394_lun_t *);
298 int	scsa1394_sbp2_login(scsa1394_state_t *, int);
299 void	scsa1394_sbp2_logout(scsa1394_state_t *, int, boolean_t);
300 void	scsa1394_sbp2_req(scsa1394_state_t *, int, int);
301 void	scsa1394_sbp2_disconnect(scsa1394_state_t *);
302 void	scsa1394_sbp2_seg2pt(scsa1394_lun_t *, scsa1394_cmd_t *);
303 void	scsa1394_sbp2_cmd2orb(scsa1394_lun_t *, scsa1394_cmd_t *);
304 int	scsa1394_sbp2_start(scsa1394_lun_t *, scsa1394_cmd_t *);
305 void	scsa1394_sbp2_nudge(scsa1394_lun_t *);
306 int	scsa1394_sbp2_reset(scsa1394_lun_t *, int, scsa1394_cmd_t *);
307 void	scsa1394_sbp2_flush_cmds(scsa1394_lun_t *, int, int, int);
308 
309 
310 /* HBA public routines */
311 int	scsa1394_thr_dispatch(scsa1394_thread_t *);
312 void	scsa1394_thr_cancel(scsa1394_thread_t *);
313 void	scsa1394_thr_wake(scsa1394_thread_t *, int);
314 void	scsa1394_thr_clear_req(scsa1394_thread_t *, int);
315 void	scsa1394_cmd_status_proc(scsa1394_lun_t *, scsa1394_cmd_t *);
316 boolean_t scsa1394_dev_is_online(scsa1394_state_t *);
317 void	scsa1394_sbp2_req_bus_reset(scsa1394_lun_t *);
318 void	scsa1394_sbp2_req_reconnect(scsa1394_lun_t *);
319 
320 
321 #ifdef	__cplusplus
322 }
323 #endif
324 
325 #endif	/* _SYS_1394_TARGETS_SCSA1394_IMPL_H */
326