sbp.c revision 105633
1103285Sikob/*
2103285Sikob * Copyright (c) 1998,1999,2000,2001 Katsushi Kobayashi and Hidetosh Shimokawa
3103285Sikob * All rights reserved.
4103285Sikob *
5103285Sikob * Redistribution and use in source and binary forms, with or without
6103285Sikob * modification, are permitted provided that the following conditions
7103285Sikob * are met:
8103285Sikob * 1. Redistributions of source code must retain the above copyright
9103285Sikob *    notice, this list of conditions and the following disclaimer.
10103285Sikob * 2. Redistributions in binary form must reproduce the above copyright
11103285Sikob *    notice, this list of conditions and the following disclaimer in the
12103285Sikob *    documentation and/or other materials provided with the distribution.
13103285Sikob * 3. All advertising materials mentioning features or use of this software
14103285Sikob *    must display the acknowledgement as bellow:
15103285Sikob *
16103285Sikob *    This product includes software developed by K. Kobayashi and H. Shimokawa
17103285Sikob *
18103285Sikob * 4. The name of the author may not be used to endorse or promote products
19103285Sikob *    derived from this software without specific prior written permission.
20103285Sikob *
21103285Sikob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22103285Sikob * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23103285Sikob * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24103285Sikob * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25103285Sikob * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26103285Sikob * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27103285Sikob * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29103285Sikob * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30103285Sikob * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31103285Sikob * POSSIBILITY OF SUCH DAMAGE.
32103285Sikob *
33103285Sikob * $FreeBSD: head/sys/dev/firewire/sbp.c 105633 2002-10-21 15:36:59Z simokawa $
34103285Sikob *
35103285Sikob */
36103285Sikob
37103285Sikob#include <sys/param.h>
38103285Sikob#include <sys/systm.h>
39103285Sikob#include <sys/module.h>
40103285Sikob#include <sys/bus.h>
41103285Sikob#include <sys/mbuf.h>
42103285Sikob#include <sys/sysctl.h>
43103285Sikob#include <machine/bus.h>
44103285Sikob#include <sys/malloc.h>
45103285Sikob#include <sys/devicestat.h>	/* for struct devstat */
46103285Sikob
47103285Sikob
48103285Sikob#include <cam/cam.h>
49103285Sikob#include <cam/cam_ccb.h>
50103285Sikob#include <cam/cam_sim.h>
51103285Sikob#include <cam/cam_xpt_sim.h>
52103285Sikob#include <cam/cam_debug.h>
53103285Sikob#include <cam/cam_periph.h>
54103285Sikob
55103285Sikob#include <cam/scsi/scsi_all.h>
56103285Sikob#include <cam/scsi/scsi_message.h>
57103285Sikob#include <cam/scsi/scsi_da.h>
58103285Sikob
59103285Sikob#include <sys/kernel.h>
60103285Sikob
61103285Sikob#include <vm/vm.h>
62103285Sikob#include <vm/pmap.h>
63103285Sikob
64103285Sikob#include <dev/firewire/firewire.h>
65103285Sikob#include <dev/firewire/firewirereg.h>
66103285Sikob#include <dev/firewire/iec13213.h>
67103285Sikob
68103285Sikob#define ccb_sdev_ptr	spriv_ptr0
69103285Sikob#define ccb_sbp_ptr	spriv_ptr1
70103285Sikob
71103285Sikob#define SBP_NUM_TARGETS 8
72103285Sikob#define SBP_NUM_LUNS 8	/* limited by CAM_SCSI2_MAXLUN in cam_xpt.c */
73103285Sikob#define SBP_QUEUE_LEN 4
74103285Sikob#define SBP_NUM_OCB (SBP_QUEUE_LEN * SBP_NUM_TARGETS)
75103285Sikob#define SBP_INITIATOR 7
76103285Sikob#define SBP_ESELECT_TIMEOUT 1
77103285Sikob#define SBP_BIND_HI 0x1
78103285Sikob#define SBP_DEV2ADDR(u, t, l)	\
79103285Sikob	((((u) & 0xff) << 16) | (((l) & 0xff) << 8) | (((t) & 0x3f) << 2))
80103285Sikob#define SBP_ADDR2TRG(a)	(((a) >> 2) & 0x3f)
81103285Sikob#define SBP_ADDR2LUN(a)	(((a) >> 8) & 0xff)
82103285Sikob
83103285Sikob#define ORB_NOTIFY	(1 << 31)
84103285Sikob#define	ORB_FMT_STD	(0 << 29)
85103285Sikob#define	ORB_FMT_VED	(2 << 29)
86103285Sikob#define	ORB_FMT_NOP	(3 << 29)
87103285Sikob#define	ORB_FMT_MSK	(3 << 29)
88103285Sikob#define	ORB_EXV		(1 << 28)
89103285Sikob/* */
90103285Sikob#define	ORB_CMD_IN	(1 << 27)
91103285Sikob/* */
92103285Sikob#define	ORB_CMD_SPD(x)	((x) << 24)
93103285Sikob#define	ORB_CMD_MAXP(x)	((x) << 20)
94103285Sikob#define	ORB_RCN_TMO(x)	((x) << 20)
95103285Sikob#define	ORB_CMD_PTBL	(1 << 19)
96103285Sikob#define	ORB_CMD_PSZ(x)	((x) << 16)
97103285Sikob
98103285Sikob#define	ORB_FUN_LGI	(0 << 16)
99103285Sikob#define	ORB_FUN_QLG	(1 << 16)
100103285Sikob#define	ORB_FUN_RCN	(3 << 16)
101103285Sikob#define	ORB_FUN_LGO	(7 << 16)
102103285Sikob#define	ORB_FUN_ATA	(0xb << 16)
103103285Sikob#define	ORB_FUN_ATS	(0xc << 16)
104103285Sikob#define	ORB_FUN_LUR	(0xe << 16)
105103285Sikob#define	ORB_FUN_RST	(0xf << 16)
106103285Sikob#define	ORB_FUN_MSK	(0xf << 16)
107103285Sikob
108103285Sikobstatic char *orb_fun_name[] = {
109103285Sikob	/* 0 */ "LOGIN",
110103285Sikob	/* 1 */ "QUERY LOGINS",
111103285Sikob	/* 2 */ "Reserved",
112103285Sikob	/* 3 */ "RECONNECT",
113103285Sikob	/* 4 */ "SET PASSWORD",
114103285Sikob	/* 5 */ "Reserved",
115103285Sikob	/* 6 */ "Reserved",
116103285Sikob	/* 7 */ "LOGOUT",
117103285Sikob	/* 8 */ "Reserved",
118103285Sikob	/* 9 */ "Reserved",
119103285Sikob	/* A */ "Reserved",
120103285Sikob	/* B */ "ABORT TASK",
121103285Sikob	/* C */ "ABORT TASK SET",
122103285Sikob	/* D */ "Reserved",
123103285Sikob	/* E */ "LOGICAL UNIT RESET",
124103285Sikob	/* F */ "TARGET RESET"
125103285Sikob};
126103285Sikob
127103285Sikob#define ORB_RES_CMPL 0
128103285Sikob#define ORB_RES_FAIL 1
129103285Sikob#define ORB_RES_ILLE 2
130103285Sikob#define ORB_RES_VEND 3
131103285Sikob
132103285Sikobstatic int debug = 1;
133103285Sikobstatic int auto_login = 1;
134103285Sikobstatic int max_speed = 2;
135103285Sikob
136103285SikobSYSCTL_DECL(_hw_firewire);
137103285SikobSYSCTL_NODE(_hw_firewire, OID_AUTO, sbp, CTLFLAG_RD, 0, "SBP-II Subsystem");
138103285SikobSYSCTL_INT(_debug, OID_AUTO, sbp_debug, CTLFLAG_RW, &debug, 0,
139103285Sikob	"SBP debug flag");
140103285SikobSYSCTL_INT(_hw_firewire_sbp, OID_AUTO, auto_login, CTLFLAG_RW, &auto_login, 0,
141103285Sikob	"SBP perform login automatically");
142103285SikobSYSCTL_INT(_hw_firewire_sbp, OID_AUTO, max_speed, CTLFLAG_RW, &max_speed, 0,
143103285Sikob	"SBP transfer max speed");
144103285Sikob
145103285Sikob#define SBP_DEBUG(x)	if (debug > x) {
146103285Sikob#define END_DEBUG	}
147103285Sikob
148103285Sikob#define NEED_RESPONSE 0
149103285Sikob
150103285Sikobstruct ind_ptr {
151103285Sikob	u_int32_t hi,lo;
152103285Sikob};
153103285Sikob#define SBP_IND_MAX 0x20
154103285Sikobstruct sbp_ocb {
155103285Sikob	STAILQ_ENTRY(sbp_ocb)	ocb;
156103285Sikob	union ccb	*ccb;
157103285Sikob	volatile u_int32_t	orb[8];
158103285Sikob	volatile struct ind_ptr  ind_ptr[SBP_IND_MAX];
159103285Sikob	struct sbp_dev	*sdev;
160103285Sikob	int		flags;
161103285Sikob	bus_dmamap_t	dmamap;
162103285Sikob};
163103285Sikob#define OCB_ACT_MGM 0
164103285Sikob#define OCB_ACT_CMD 1
165103285Sikob#define OCB_ACT_MASK 3
166103285Sikob#define OCB_RESERVED 0x10
167103285Sikob#define OCB_DONE 0x20
168103285Sikob
169103285Sikob#define SBP_RESOURCE_SHORTAGE 0x10
170103285Sikob
171103285Sikobstruct sbp_login_res{
172103285Sikob#if FW_ENDIANSWAP == 0 && BYTE_ORDER == LITTLE_ENDIAN
173103285Sikob	u_int16_t	len;
174103285Sikob	u_int16_t	id;
175103285Sikob	u_int16_t	res0;
176103285Sikob	u_int16_t	cmd_hi;
177103285Sikob	u_int32_t	cmd_lo;
178103285Sikob	u_int16_t	res1;
179103285Sikob	u_int16_t	recon_hold;
180103285Sikob#else
181103285Sikob	u_int16_t	id;
182103285Sikob	u_int16_t	len;
183103285Sikob	u_int16_t	cmd_hi;
184103285Sikob	u_int16_t	res0;
185103285Sikob	u_int32_t	cmd_lo;
186103285Sikob	u_int16_t	recon_hold;
187103285Sikob	u_int16_t	res1;
188103285Sikob#endif
189103285Sikob};
190103285Sikobstruct sbp_status{
191103285Sikob#if FW_ENDIANSWAP == 0 && BYTE_ORDER == LITTLE_ENDIAN
192103285Sikob	u_int8_t	len:3,
193103285Sikob			dead:1,
194103285Sikob			resp:2,
195103285Sikob			src:2;
196103285Sikob	u_int8_t	status:8;
197103285Sikob	u_int16_t	orb_hi;
198103285Sikob	u_int32_t	orb_lo;
199103285Sikob	u_int32_t	data[6];
200103285Sikob#else
201103285Sikob	u_int16_t	orb_hi;
202103285Sikob	u_int8_t	status:8;
203103285Sikob	u_int8_t	len:3,
204103285Sikob			dead:1,
205103285Sikob			resp:2,
206103285Sikob			src:2;
207103285Sikob	u_int32_t	orb_lo;
208103285Sikob	u_int32_t	data[6];
209103285Sikob#endif
210103285Sikob};
211103285Sikobstruct sbp_cmd_status{
212103285Sikob#define SBP_SFMT_CURR 0
213103285Sikob#define SBP_SFMT_DEFER 1
214103285Sikob#if FW_ENDIANSWAP == 0 && BYTE_ORDER == LITTLE_ENDIAN
215103285Sikob	u_int8_t	status:6,
216103285Sikob			sfmt:2;
217103285Sikob	u_int8_t	s_key:4,
218103285Sikob			ill_len:1,
219103285Sikob			eom:1,
220103285Sikob			mark:1,
221103285Sikob			valid:1;
222103285Sikob	u_int8_t	s_code;
223103285Sikob	u_int8_t	s_qlfr;
224103285Sikob	u_int32_t	info;
225103285Sikob	u_int32_t	cdb;
226103285Sikob	u_int32_t	fru:8,
227103285Sikob			s_keydep:24;
228103285Sikob	u_int32_t	vend[2];
229103285Sikob#else
230103285Sikob	u_int8_t	s_qlfr;
231103285Sikob	u_int8_t	s_code;
232103285Sikob	u_int8_t	s_key:4,
233103285Sikob			ill_len:1,
234103285Sikob			eom:1,
235103285Sikob			mark:1,
236103285Sikob			valid:1;
237103285Sikob	u_int8_t	status:6,
238103285Sikob			sfmt:2;
239103285Sikob	u_int32_t	info;
240103285Sikob	u_int32_t	cdb;
241103285Sikob	u_int32_t	s_keydep:24,
242103285Sikob			fru:8;
243103285Sikob	u_int32_t	vend[2];
244103285Sikob#endif
245103285Sikob};
246103285Sikob
247103285Sikobstruct sbp_dev{
248103285Sikob#define SBP_DEV_RESET		0	/* accept login */
249103285Sikob#define SBP_DEV_LOGIN		1	/* to login */
250103285Sikob#define SBP_DEV_RECONN		2	/* to reconnect */
251103285Sikob#define SBP_DEV_TOATTACH	3	/* to attach */
252103285Sikob#define SBP_DEV_PROBE		4	/* scan lun */
253103285Sikob#define SBP_DEV_ATTACHED	5	/* in operation */
254103285Sikob#define SBP_DEV_DEAD		6	/* unavailable unit */
255103285Sikob#define SBP_DEV_RETRY		7	/* unavailable unit */
256103285Sikob	int status;
257103285Sikob	int lun_id;
258103285Sikob	struct cam_path *path;
259103285Sikob	struct sbp_target *target;
260103285Sikob	struct sbp_login_res login;
261103285Sikob	STAILQ_HEAD(, sbp_ocb) ocbs;
262103285Sikob	char vendor[32];
263103285Sikob	char product[32];
264103285Sikob	char revision[10];
265103285Sikob};
266103285Sikob
267103285Sikobstruct sbp_target {
268103285Sikob	int target_id;
269103285Sikob	int num_lun;
270103285Sikob	struct sbp_dev	*luns;
271103285Sikob	struct sbp_softc *sbp;
272103285Sikob	struct fw_device *fwdev;
273103285Sikob	u_int32_t mgm_hi, mgm_lo;
274103285Sikob};
275103285Sikob
276103285Sikobstruct sbp_softc {
277103285Sikob	struct firewire_dev_comm fd;
278103285Sikob	unsigned char flags;
279103285Sikob	struct cam_sim  *sim;
280103285Sikob	struct sbp_target targets[SBP_NUM_TARGETS];
281103285Sikob	struct fw_bind fwb;
282103285Sikob	STAILQ_HEAD(, sbp_ocb) free_ocbs;
283103285Sikob	struct sbp_ocb *ocb;
284103285Sikob	bus_dma_tag_t	dmat;
285103285Sikob};
286103285Sikobstatic void sbp_post_explore __P((void *));
287103285Sikobstatic void sbp_recv __P((struct fw_xfer *));
288103285Sikobstatic void sbp_login_callback __P((struct fw_xfer *));
289103285Sikobstatic void sbp_cmd_callback __P((struct fw_xfer *));
290103285Sikobstatic void sbp_orb_pointer __P((struct sbp_dev *, struct sbp_ocb *));
291103285Sikobstatic void sbp_execute_ocb __P((void *,  bus_dma_segment_t *, int, int));
292103285Sikobstatic void sbp_free_ocb __P((struct sbp_softc *, struct sbp_ocb *));
293103285Sikobstatic void sbp_abort_ocb __P((struct sbp_ocb *, int));
294103285Sikobstatic void sbp_abort_all_ocbs __P((struct sbp_dev *, int));
295103285Sikobstatic struct fw_xfer * sbp_write_cmd __P((struct sbp_dev *, int, int));
296103285Sikobstatic struct sbp_ocb * sbp_get_ocb __P((struct sbp_softc *));
297103285Sikobstatic struct sbp_ocb * sbp_enqueue_ocb __P((struct sbp_dev *, struct sbp_ocb *));
298103285Sikobstatic struct sbp_ocb * sbp_dequeue_ocb __P((struct sbp_dev *, u_int32_t));
299103285Sikobstatic void sbp_detach_target __P((struct sbp_target *));
300103285Sikobstatic void sbp_timeout __P((void *arg));
301103285Sikobstatic void sbp_mgm_orb __P((struct sbp_dev *, int));
302103285Sikob
303103285SikobMALLOC_DEFINE(M_SBP, "sbp", "SBP-II/Firewire");
304103285Sikob
305103285Sikob/* cam related functions */
306103285Sikobstatic void	sbp_action(struct cam_sim *sim, union ccb *ccb);
307103285Sikobstatic void	sbp_poll(struct cam_sim *sim);
308103285Sikobstatic void	sbp_cam_callback(struct cam_periph *periph,
309103285Sikob					union ccb *ccb);
310103285Sikobstatic void	sbp_cam_scan_lun(struct sbp_dev *sdev);
311103285Sikob
312103285Sikobstatic char *orb_status0[] = {
313103285Sikob	/* 0 */ "No additional information to report",
314103285Sikob	/* 1 */ "Request type not supported",
315103285Sikob	/* 2 */ "Speed not supported",
316103285Sikob	/* 3 */ "Page size not supported",
317103285Sikob	/* 4 */ "Access denied",
318103285Sikob	/* 5 */ "Logical unit not supported",
319103285Sikob	/* 6 */ "Maximum payload too small",
320103285Sikob	/* 7 */ "Reserved for future standardization",
321103285Sikob	/* 8 */ "Resources unavailable",
322103285Sikob	/* 9 */ "Function rejected",
323103285Sikob	/* A */ "Login ID not recognized",
324103285Sikob	/* B */ "Dummy ORB completed",
325103285Sikob	/* C */ "Request aborted",
326103285Sikob	/* FF */ "Unspecified error"
327103285Sikob#define MAX_ORB_STATUS0 0xd
328103285Sikob};
329103285Sikob
330103285Sikobstatic char *orb_status1_object[] = {
331103285Sikob	/* 0 */ "Operation request block (ORB)",
332103285Sikob	/* 1 */ "Data buffer",
333103285Sikob	/* 2 */ "Page table",
334103285Sikob	/* 3 */ "Unable to specify"
335103285Sikob};
336103285Sikob
337103285Sikobstatic char *orb_status1_serial_bus_error[] = {
338103285Sikob	/* 0 */ "Missing acknowledge",
339103285Sikob	/* 1 */ "Reserved; not to be used",
340103285Sikob	/* 2 */ "Time-out error",
341103285Sikob	/* 3 */ "Reserved; not to be used",
342103285Sikob	/* 4 */ "Busy retry limit exceeded(X)",
343103285Sikob	/* 5 */ "Busy retry limit exceeded(A)",
344103285Sikob	/* 6 */ "Busy retry limit exceeded(B)",
345103285Sikob	/* 7 */ "Reserved for future standardization",
346103285Sikob	/* 8 */ "Reserved for future standardization",
347103285Sikob	/* 9 */ "Reserved for future standardization",
348103285Sikob	/* A */ "Reserved for future standardization",
349103285Sikob	/* B */ "Tardy retry limit exceeded",
350103285Sikob	/* C */ "Conflict error",
351103285Sikob	/* D */ "Data error",
352103285Sikob	/* E */ "Type error",
353103285Sikob	/* F */ "Address error"
354103285Sikob};
355103285Sikob
356103285Sikobstatic void
357103285Sikobsbp_identify(driver_t *driver, device_t parent)
358103285Sikob{
359103285Sikob	device_t child;
360103285SikobSBP_DEBUG(0)
361103285Sikob	printf("sbp_identify\n");
362103285SikobEND_DEBUG
363103285Sikob
364103285Sikob	child = BUS_ADD_CHILD(parent, 0, "sbp", device_get_unit(parent));
365103285Sikob}
366103285Sikob
367103285Sikob/*
368103285Sikob * sbp_probe()
369103285Sikob */
370103285Sikobstatic int
371103285Sikobsbp_probe(device_t dev)
372103285Sikob{
373103285Sikob	device_t pa;
374103285Sikob
375103285SikobSBP_DEBUG(0)
376103285Sikob	printf("sbp_probe\n");
377103285SikobEND_DEBUG
378103285Sikob
379103285Sikob	pa = device_get_parent(dev);
380103285Sikob	if(device_get_unit(dev) != device_get_unit(pa)){
381103285Sikob		return(ENXIO);
382103285Sikob	}
383103285Sikob
384103285Sikob	device_set_desc(dev, "SBP2/SCSI over firewire");
385103285Sikob	return (0);
386103285Sikob}
387103285Sikob
388103285Sikobstatic void
389103285Sikobsbp_show_sdev_info(struct sbp_dev *sdev, int new)
390103285Sikob{
391103285Sikob	int lun;
392103285Sikob	struct fw_device *fwdev;
393103285Sikob
394103285Sikob	printf("%s:%d:%d ",
395103285Sikob		device_get_nameunit(sdev->target->sbp->fd.dev),
396103285Sikob		sdev->target->target_id,
397103285Sikob		sdev->lun_id
398103285Sikob	);
399103285Sikob	if (new == 2) {
400103285Sikob		return;
401103285Sikob	}
402103285Sikob	fwdev = sdev->target->fwdev;
403103285Sikob	lun = getcsrdata(fwdev, 0x14);
404103285Sikob	printf("ordered:%d type:%d EUI:%08x%08x node:%d "
405103285Sikob		"speed:%d maxrec:%d",
406103285Sikob		(lun & 0x00400000) >> 22,
407103285Sikob		(lun & 0x001f0000) >> 16,
408103285Sikob		fwdev->eui.hi,
409103285Sikob		fwdev->eui.lo,
410103285Sikob		fwdev->dst,
411103285Sikob		fwdev->speed,
412103285Sikob		fwdev->maxrec
413103285Sikob	);
414103285Sikob	if (new)
415103285Sikob		printf(" new!\n");
416103285Sikob	else
417103285Sikob		printf("\n");
418103285Sikob	sbp_show_sdev_info(sdev, 2);
419103285Sikob	printf("'%s' '%s' '%s'\n", sdev->vendor, sdev->product, sdev->revision);
420103285Sikob}
421103285Sikob
422103285Sikobstatic struct sbp_target *
423103285Sikobsbp_alloc_target(struct sbp_softc *sbp, struct fw_device *fwdev)
424103285Sikob{
425103285Sikob	int i, lun;
426103285Sikob	struct sbp_target *target;
427103285Sikob	struct sbp_dev *sdev;
428103285Sikob
429103285SikobSBP_DEBUG(1)
430103285Sikob	printf("sbp_alloc_target\n");
431103285SikobEND_DEBUG
432103285Sikob	for (i = 0; i < SBP_NUM_TARGETS; i++)
433103285Sikob		if(sbp->targets[i].fwdev == NULL) break;
434103285Sikob	if (i == SBP_NUM_TARGETS) {
435103285Sikob		printf("increase SBP_NUM_TARGETS!\n");
436103285Sikob		return NULL;
437103285Sikob	}
438103285Sikob	/* new target */
439103285Sikob	target = &sbp->targets[i];
440103285Sikob	target->sbp = sbp;
441103285Sikob	target->fwdev = fwdev;
442103285Sikob	target->target_id = i;
443103285Sikob	if((target->mgm_lo = getcsrdata(fwdev, 0x54)) == 0 ){
444103285Sikob		/* bad target */
445103285Sikob		printf("NULL management address\n");
446103285Sikob		target->fwdev = NULL;
447103285Sikob		return NULL;
448103285Sikob	}
449103285Sikob	target->mgm_hi = 0xffff;
450103285Sikob	target->mgm_lo = 0xf0000000 | target->mgm_lo << 2;
451103285Sikob	/* XXX should probe all luns */
452103285Sikob	/* XXX num_lun may be changed. realloc luns? */
453103285Sikob	lun = getcsrdata(target->fwdev, 0x14) & 0xff;
454103285Sikob	target->num_lun = lun + 1;
455103285Sikob	target->luns = (struct sbp_dev *) malloc(
456103285Sikob				sizeof(struct sbp_dev) * target->num_lun,
457103285Sikob				M_SBP, M_NOWAIT | M_ZERO);
458103285Sikob	for (i = 0; i < target->num_lun; i++) {
459103285Sikob		sdev = &target->luns[i];
460103285Sikob		sdev->lun_id = i;
461103285Sikob		sdev->target = target;
462103285Sikob		STAILQ_INIT(&sdev->ocbs);
463103285Sikob		if (i == lun)
464103285Sikob			sdev->status = SBP_DEV_RESET;
465103285Sikob		else
466103285Sikob			sdev->status = SBP_DEV_DEAD;
467103285Sikob	}
468103285Sikob	return target;
469103285Sikob}
470103285Sikob
471103285Sikobstatic void
472103285Sikobsbp_get_text_leaf(struct fw_device *fwdev, int key, char *buf, int len)
473103285Sikob{
474103285Sikob	static char *nullstr = "(null)";
475103285Sikob	int i, clen, found=0;
476103285Sikob	struct csrhdr *chdr;
477103285Sikob	struct csrreg *creg;
478103285Sikob	u_int32_t *src, *dst;
479103285Sikob
480103285Sikob	chdr = (struct csrhdr *)&fwdev->csrrom[0];
481103285Sikob	creg = (struct csrreg *)chdr;
482103285Sikob	creg += chdr->info_len;
483103285Sikob	for( i = chdr->info_len + 4; i <= fwdev->rommax; i+=4){
484103285Sikob		if((creg++)->key == key){
485103285Sikob			found = 1;
486103285Sikob			break;
487103285Sikob		}
488103285Sikob	}
489103285Sikob	if (!found) {
490103285Sikob		strncpy(buf, nullstr, len);
491103285Sikob		return;
492103285Sikob	}
493103285Sikob	src = (u_int32_t *) creg + creg->val;
494103285Sikob	clen = ((*src >> 16) - 2) * 4;
495103285Sikob	src += 3;
496103285Sikob	dst = (u_int32_t *) buf;
497103285Sikob	if (len < clen)
498103285Sikob		clen = len;
499103285Sikob	for (i = 0; i < clen/4; i++)
500103285Sikob		*dst++ = htonl(*src++);
501103285Sikob	buf[clen] = 0;
502103285Sikob}
503103285Sikob
504103285Sikobstatic void
505103285Sikobsbp_probe_lun(struct sbp_dev *sdev)
506103285Sikob{
507103285Sikob	struct fw_device *fwdev;
508103285Sikob	int rev;
509103285Sikob
510103285Sikob	fwdev = sdev->target->fwdev;
511103285Sikob	bzero(sdev->vendor, sizeof(sdev->vendor));
512103285Sikob	bzero(sdev->product, sizeof(sdev->product));
513103285Sikob	sbp_get_text_leaf(fwdev, 0x03, sdev->vendor, sizeof(sdev->vendor));
514103285Sikob	sbp_get_text_leaf(fwdev, 0x17, sdev->product, sizeof(sdev->product));
515103285Sikob	rev = getcsrdata(sdev->target->fwdev, 0x3c);
516103285Sikob	snprintf(sdev->revision, sizeof(sdev->revision), "%06x", rev);
517103285Sikob}
518103285Sikobstatic void
519103285Sikobsbp_probe_target(struct sbp_target *target, int alive)
520103285Sikob{
521103285Sikob	struct sbp_softc *sbp;
522103285Sikob	struct sbp_dev *sdev;
523103285Sikob	struct firewire_comm *fc;
524103285Sikob	int i;
525103285Sikob
526103285SikobSBP_DEBUG(1)
527103285Sikob	printf("sbp_probe_target %d\n", target->target_id);
528103285Sikob	if (!alive)
529103285Sikob		printf("not alive\n");
530103285SikobEND_DEBUG
531103285Sikob
532103285Sikob	sbp = target->sbp;
533103285Sikob	fc = target->sbp->fd.fc;
534103285Sikob	for (i=0; i < target->num_lun; i++) {
535103285Sikob		sdev = &target->luns[i];
536103285Sikob		if (alive && (sdev->status != SBP_DEV_DEAD)) {
537103285Sikob			if (sdev->path != NULL) {
538103285Sikob				xpt_freeze_devq(sdev->path, 1);
539103285Sikob			}
540103285Sikob			sbp_abort_all_ocbs(sdev, CAM_REQUEUE_REQ);
541103285Sikob			switch (sdev->status) {
542103285Sikob			case SBP_DEV_ATTACHED:
543103285Sikob				sbp_mgm_orb(sdev, ORB_FUN_RCN);
544103285Sikob				break;
545103285Sikob			case SBP_DEV_RETRY:
546103285Sikob				sbp_probe_lun(sdev);
547103285Sikob				sbp_mgm_orb(sdev, ORB_FUN_LGI);
548103285Sikob				break;
549103285Sikob			default:
550103285Sikob				/* new or revived target */
551103285Sikob				sbp_probe_lun(sdev);
552103285Sikob				if (auto_login) {
553103285Sikob					sdev->status = SBP_DEV_TOATTACH;
554103285Sikob					sbp_mgm_orb(sdev, ORB_FUN_LGI);
555103285Sikob				}
556103285Sikob				break;
557103285Sikob			}
558103285Sikob			sbp_show_sdev_info(sdev,
559103285Sikob					(sdev->status == SBP_DEV_TOATTACH));
560103285Sikob		} else {
561103285Sikob			switch (sdev->status) {
562103285Sikob			case SBP_DEV_ATTACHED:
563103285SikobSBP_DEBUG(0)
564103285Sikob				/* the device has gone */
565103285Sikob				sbp_show_sdev_info(sdev, 2);
566103285Sikob				printf("lost target\n");
567103285SikobEND_DEBUG
568103285Sikob				if (sdev->path)
569103285Sikob					xpt_freeze_devq(sdev->path, 1);
570103285Sikob				sdev->status = SBP_DEV_RETRY;
571103285Sikob				sbp_abort_all_ocbs(sdev, CAM_REQUEUE_REQ);
572103285Sikob				break;
573103285Sikob			case SBP_DEV_PROBE:
574103285Sikob			case SBP_DEV_TOATTACH:
575103285Sikob				sdev->status = SBP_DEV_RESET;
576103285Sikob				break;
577103285Sikob			case SBP_DEV_RETRY:
578103285Sikob			case SBP_DEV_RESET:
579103285Sikob			case SBP_DEV_DEAD:
580103285Sikob				break;
581103285Sikob			}
582103285Sikob		}
583103285Sikob	}
584103285Sikob}
585103285Sikob
586103285Sikob#if 0
587103285Sikobstatic void
588103285Sikobsbp_release_queue(void *arg)
589103285Sikob{
590103285Sikob	struct sbp_softc *sbp;
591103285Sikob
592103285SikobSBP_DEBUG(0)
593103285Sikob	printf("sbp_release_queue\n");
594103285SikobEND_DEBUG
595103285Sikob	sbp = (struct sbp_softc *)arg;
596103285Sikob	xpt_release_simq(sbp->sim, 1);
597103285Sikob}
598103285Sikob
599103285Sikobstatic void
600103285Sikobsbp_release_devq(void *arg)
601103285Sikob{
602103285Sikob	struct sbp_dev *sdev;
603103285Sikob	int s;
604103285Sikob
605103285Sikob	sdev = (struct sbp_dev *)arg;
606103285SikobSBP_DEBUG(0)
607103285Sikob	sbp_show_sdev_info(sdev, 2);
608103285Sikob	printf("sbp_release_devq\n");
609103285SikobEND_DEBUG
610103285Sikob	s = splcam();
611103285Sikob	xpt_release_devq(sdev->path, 1, TRUE);
612103285Sikob	splx(s);
613103285Sikob}
614103285Sikob#endif
615103285Sikob
616103285Sikobstatic void
617103285Sikobsbp_post_explore(void *arg)
618103285Sikob{
619103285Sikob	struct sbp_softc *sbp = (struct sbp_softc *)arg;
620103285Sikob	struct sbp_target *target;
621103285Sikob	struct fw_device *fwdev;
622103285Sikob	int i, alive;
623103285Sikob
624103285SikobSBP_DEBUG(1)
625103285Sikob	printf("sbp_post_explore\n");
626103285SikobEND_DEBUG
627103285Sikob#if 0
628103285Sikob	xpt_freeze_simq(sbp->sim, /*count*/ 1);
629103285Sikob#endif
630103285Sikob	/* Gabage Collection */
631103285Sikob	for(i = 0 ; i < SBP_NUM_TARGETS ; i ++){
632103285Sikob		target = &sbp->targets[i];
633103285Sikob		for( fwdev  = TAILQ_FIRST(&sbp->fd.fc->devices);
634103285Sikob			fwdev != NULL; fwdev = TAILQ_NEXT(fwdev, link)){
635103285Sikob			if(target->fwdev == NULL) break;
636103285Sikob			if(target->fwdev == fwdev) break;
637103285Sikob		}
638103285Sikob		if(fwdev == NULL){
639103285Sikob			/* device has removed in lower driver */
640103285Sikob			sbp_detach_target(target);
641103285Sikob		}
642103285Sikob	}
643103285Sikob	/* traverse device list */
644103285Sikob	for( fwdev  = TAILQ_FIRST(&sbp->fd.fc->devices);
645103285Sikob		fwdev != NULL; fwdev = TAILQ_NEXT(fwdev, link)){
646103285SikobSBP_DEBUG(0)
647103285Sikob		printf("sbp_post_explore: EUI:%08x%08x ",
648103285Sikob				fwdev->eui.hi, fwdev->eui.lo);
649103285Sikob		if (fwdev->status == FWDEVATTACHED) {
650103285Sikob			printf("spec=%d key=%d.\n",
651103285Sikob			getcsrdata(fwdev, CSRKEY_SPEC) == CSRVAL_ANSIT10,
652103285Sikob			getcsrdata(fwdev, CSRKEY_VER) == CSRVAL_T10SBP2);
653103285Sikob		} else {
654103285Sikob			printf("not attached, state=%d.\n", fwdev->status);
655103285Sikob		}
656103285SikobEND_DEBUG
657103285Sikob		alive = (fwdev->status == FWDEVATTACHED)
658103285Sikob			&& (getcsrdata(fwdev, CSRKEY_SPEC) == CSRVAL_ANSIT10)
659103285Sikob			&& (getcsrdata(fwdev, CSRKEY_VER) == CSRVAL_T10SBP2);
660103285Sikob		for(i = 0 ; i < SBP_NUM_TARGETS ; i ++){
661103285Sikob			target = &sbp->targets[i];
662103285Sikob			if(target->fwdev == fwdev ) {
663103285Sikob				/* known target */
664103285Sikob				break;
665103285Sikob			}
666103285Sikob		}
667103285Sikob		if(i == SBP_NUM_TARGETS){
668103285Sikob			if (alive) {
669103285Sikob				/* new target */
670103285Sikob				target = sbp_alloc_target(sbp, fwdev);
671103285Sikob				if (target == NULL)
672103285Sikob					continue;
673103285Sikob			} else {
674103285Sikob				continue;
675103285Sikob			}
676103285Sikob		}
677103285Sikob		sbp_probe_target(target, alive);
678103285Sikob	}
679103285Sikob#if 0
680103285Sikob	timeout(sbp_release_queue, (caddr_t)sbp, bus_reset_rest * hz / 1000);
681103285Sikob#endif
682103285Sikob}
683103285Sikob
684103285Sikob#if NEED_RESPONSE
685103285Sikobstatic void
686103285Sikobsbp_loginres_callback(struct fw_xfer *xfer){
687103285SikobSBP_DEBUG(1)
688103285Sikob	struct sbp_dev *sdev;
689103285Sikob	sdev = (struct sbp_dev *)xfer->sc;
690103285Sikob	sbp_show_sdev_info(sdev, 2);
691103285Sikob	printf("sbp_loginres_callback\n");
692103285SikobEND_DEBUG
693103285Sikob	fw_xfer_free(xfer);
694103285Sikob	return;
695103285Sikob}
696103285Sikob#endif
697103285Sikob
698103285Sikobstatic void
699103285Sikobsbp_login_callback(struct fw_xfer *xfer)
700103285Sikob{
701103285SikobSBP_DEBUG(1)
702103285Sikob	struct sbp_dev *sdev;
703103285Sikob	sdev = (struct sbp_dev *)xfer->sc;
704103285Sikob	sbp_show_sdev_info(sdev, 2);
705103285Sikob	printf("sbp_login_callback\n");
706103285SikobEND_DEBUG
707103285Sikob	fw_xfer_free(xfer);
708103285Sikob	return;
709103285Sikob}
710103285Sikob
711103285Sikobstatic void
712103285Sikobsbp_cmd_callback(struct fw_xfer *xfer)
713103285Sikob{
714103285SikobSBP_DEBUG(2)
715103285Sikob	struct sbp_dev *sdev;
716103285Sikob	sdev = (struct sbp_dev *)xfer->sc;
717103285Sikob	sbp_show_sdev_info(sdev, 2);
718103285Sikob	printf("sbp_cmd_callback\n");
719103285SikobEND_DEBUG
720103285Sikob	fw_xfer_free(xfer);
721103285Sikob	return;
722103285Sikob}
723103285Sikob
724103285Sikobstatic void
725103285Sikobsbp_cam_callback(struct cam_periph *periph, union ccb *ccb)
726103285Sikob{
727103285Sikob	struct sbp_dev *sdev;
728103285Sikob	sdev = (struct sbp_dev *) ccb->ccb_h.ccb_sdev_ptr;
729103285SikobSBP_DEBUG(1)
730103285Sikob	sbp_show_sdev_info(sdev, 2);
731103285Sikob	printf("sbp_cam_callback\n");
732103285SikobEND_DEBUG
733103285Sikob	sdev->status = SBP_DEV_ATTACHED;
734103285Sikob	free(ccb, M_SBP);
735103285Sikob}
736103285Sikob
737103285Sikobstatic void
738103285Sikobsbp_cam_scan_lun(struct sbp_dev *sdev)
739103285Sikob{
740103285Sikob	union ccb *ccb = malloc(sizeof(union ccb), M_SBP, M_WAITOK | M_ZERO);
741103285Sikob
742103285SikobSBP_DEBUG(0)
743103285Sikob	sbp_show_sdev_info(sdev, 2);
744103285Sikob	printf("sbp_cam_scan_lun\n");
745103285SikobEND_DEBUG
746103285Sikob	xpt_setup_ccb(&ccb->ccb_h, sdev->path, 5/*priority (low)*/);
747103285Sikob	ccb->ccb_h.func_code = XPT_SCAN_LUN;
748103285Sikob	ccb->ccb_h.cbfcnp = sbp_cam_callback;
749103285Sikob	ccb->crcn.flags = CAM_FLAG_NONE;
750103285Sikob	ccb->ccb_h.ccb_sdev_ptr = sdev;
751103285Sikob	xpt_action(ccb);
752103285Sikob
753103285Sikob	/* The scan is in progress now. */
754103285Sikob}
755103285Sikob
756103285Sikob
757103285Sikobstatic void
758103285Sikobsbp_ping_unit_callback(struct cam_periph *periph, union ccb *ccb)
759103285Sikob{
760103285Sikob	struct sbp_dev *sdev;
761103285Sikob	sdev = (struct sbp_dev *) ccb->ccb_h.ccb_sdev_ptr;
762103285SikobSBP_DEBUG(1)
763103285Sikob	sbp_show_sdev_info(sdev, 2);
764103285Sikob	printf("sbp_ping_unit_callback\n");
765103285SikobEND_DEBUG
766103285Sikob	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
767103285Sikob		if (--ccb->ccb_h.retry_count == 0) {
768103285Sikob			sbp_show_sdev_info(sdev, 2);
769103285Sikob			printf("sbp_tur_callback: retry count exceeded\n");
770103285Sikob			sdev->status = SBP_DEV_RETRY;
771103285Sikob			free(ccb, M_SBP);
772103285Sikob		} else {
773103285Sikob			/* requeue */
774103285Sikob			xpt_action(ccb);
775103285Sikob			xpt_release_devq(sdev->path, 1, TRUE);
776103285Sikob		}
777103285Sikob	} else {
778103285Sikob		free(ccb->csio.data_ptr, M_SBP);
779103285Sikob		free(ccb, M_SBP);
780103285Sikob		sdev->status = SBP_DEV_ATTACHED;
781103285Sikob		xpt_release_devq(sdev->path, 1, TRUE);
782103285Sikob	}
783103285Sikob}
784103285Sikob
785103285Sikob/*
786103285Sikob * XXX Some devices need to execute inquiry or read_capacity
787103285Sikob * after bus_rest during busy transfer.
788103285Sikob * Otherwise they return incorrect result for READ(and WRITE?)
789103285Sikob * command without any SBP-II/SCSI error.
790103285Sikob *
791103285Sikob * e.g. Maxtor 3000XT, Yano A-dish.
792103285Sikob */
793103285Sikobstatic void
794103285Sikobsbp_ping_unit(struct sbp_dev *sdev)
795103285Sikob{
796103285Sikob	union ccb *ccb;
797103285Sikob	struct scsi_inquiry_data *inq_buf;
798103285Sikob
799103285Sikob	ccb = malloc(sizeof(union ccb), M_SBP, M_WAITOK | M_ZERO);
800103285Sikob	inq_buf = (struct scsi_inquiry_data *)
801103285Sikob			malloc(sizeof(*inq_buf), M_SBP, M_WAITOK);
802103285Sikob
803103285SikobSBP_DEBUG(1)
804103285Sikob	sbp_show_sdev_info(sdev, 2);
805103285Sikob	printf("sbp_ping_unit\n");
806103285SikobEND_DEBUG
807103285Sikob
808103285Sikob	/*
809103285Sikob	 * We need to execute this command before any other queued command.
810103285Sikob	 * Make priority 0 and freeze queue after execution for retry.
811103285Sikob	 * cam's scan_lun command doesn't provide this feature.
812103285Sikob	 */
813103285Sikob	xpt_setup_ccb(&ccb->ccb_h, sdev->path, 0/*priority (high)*/);
814103285Sikob	scsi_inquiry(
815103285Sikob		&ccb->csio,
816103285Sikob		/*retries*/ 5,
817103285Sikob		sbp_ping_unit_callback,
818103285Sikob		MSG_SIMPLE_Q_TAG,
819103285Sikob		(u_int8_t *)inq_buf,
820103285Sikob		SHORT_INQUIRY_LENGTH,
821103285Sikob		/*evpd*/FALSE,
822103285Sikob		/*page_code*/0,
823103285Sikob		SSD_MIN_SIZE,
824103285Sikob		/*timeout*/60000
825103285Sikob	);
826103285Sikob	ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
827103285Sikob	xpt_action(ccb);
828103285Sikob}
829103285Sikob
830103285Sikobstatic void
831103285Sikobsbp_do_attach(struct fw_xfer *xfer)
832103285Sikob{
833103285Sikob	struct sbp_dev *sdev;
834103285Sikob
835103285Sikob	sdev = (struct sbp_dev *)xfer->sc;
836103285SikobSBP_DEBUG(0)
837103285Sikob	sbp_show_sdev_info(sdev, 2);
838103285Sikob	printf("sbp_do_attach\n");
839103285SikobEND_DEBUG
840103285Sikob	fw_xfer_free(xfer);
841103285Sikob	if (sdev->path == NULL)
842103285Sikob		xpt_create_path(&sdev->path, xpt_periph,
843103285Sikob			cam_sim_path(sdev->target->sbp->sim),
844103285Sikob			sdev->target->target_id, sdev->lun_id);
845103285Sikob
846103285Sikob	if (sdev->status == SBP_DEV_RETRY) {
847103285Sikob		sdev->status = SBP_DEV_PROBE;
848103285Sikob		sbp_ping_unit(sdev);
849103285Sikob		/* freezed twice */
850103285Sikob		xpt_release_devq(sdev->path, 1, TRUE);
851103285Sikob	} else {
852103285Sikob		sdev->status = SBP_DEV_PROBE;
853103285Sikob		sbp_cam_scan_lun(sdev);
854103285Sikob	}
855103285Sikob	xpt_release_devq(sdev->path, 1, TRUE);
856103285Sikob	return;
857103285Sikob}
858103285Sikob
859103285Sikobstatic void
860103285Sikobsbp_agent_reset_callback(struct fw_xfer *xfer)
861103285Sikob{
862103285Sikob	struct sbp_dev *sdev;
863103285Sikob
864103285Sikob	sdev = (struct sbp_dev *)xfer->sc;
865103285SikobSBP_DEBUG(1)
866103285Sikob	sbp_show_sdev_info(sdev, 2);
867103285Sikob	printf("sbp_cmd_callback\n");
868103285SikobEND_DEBUG
869103285Sikob	fw_xfer_free(xfer);
870103285Sikob	sbp_abort_all_ocbs(sdev, CAM_REQUEUE_REQ);
871103285Sikob	if (sdev->path)
872103285Sikob		xpt_release_devq(sdev->path, 1, TRUE);
873103285Sikob}
874103285Sikob
875103285Sikobstatic void
876103285Sikobsbp_agent_reset(struct sbp_dev *sdev, int attach)
877103285Sikob{
878103285Sikob	struct fw_xfer *xfer;
879103285Sikob	struct fw_pkt *fp;
880103285Sikob
881103285SikobSBP_DEBUG(0)
882103285Sikob	sbp_show_sdev_info(sdev, 2);
883103285Sikob	printf("sbp_agent_reset\n");
884103285SikobEND_DEBUG
885103285Sikob	xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0x04);
886103285Sikob	if (xfer == NULL)
887103285Sikob		return;
888103285Sikob	if (attach)
889103285Sikob		xfer->act.hand = sbp_do_attach;
890103285Sikob	else
891103285Sikob		xfer->act.hand = sbp_agent_reset_callback;
892103285Sikob	fp = (struct fw_pkt *)xfer->send.buf;
893103285Sikob	fp->mode.wreqq.data = htonl(0xf);
894103285Sikob	fw_asyreq(xfer->fc, -1, xfer);
895103285Sikob}
896103285Sikob
897103285Sikobstatic void
898103285Sikobsbp_busy_timeout_callback(struct fw_xfer *xfer)
899103285Sikob{
900103285Sikob	struct sbp_dev *sdev;
901103285Sikob
902103285Sikob	sdev = (struct sbp_dev *)xfer->sc;
903103285SikobSBP_DEBUG(1)
904103285Sikob	sbp_show_sdev_info(sdev, 2);
905103285Sikob	printf("sbp_but_timeout_callback\n");
906103285SikobEND_DEBUG
907103285Sikob	fw_xfer_free(xfer);
908103285Sikob	sbp_agent_reset(sdev, 1);
909103285Sikob}
910103285Sikob
911103285Sikobstatic void
912103285Sikobsbp_busy_timeout(struct sbp_dev *sdev)
913103285Sikob{
914103285Sikob	struct fw_pkt *fp;
915103285Sikob	struct fw_xfer *xfer;
916103285SikobSBP_DEBUG(0)
917103285Sikob	sbp_show_sdev_info(sdev, 2);
918103285Sikob	printf("sbp_busy_timeout\n");
919103285SikobEND_DEBUG
920103285Sikob	xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0);
921103285Sikob
922103285Sikob	xfer->act.hand = sbp_busy_timeout_callback;
923103285Sikob	fp = (struct fw_pkt *)xfer->send.buf;
924103285Sikob	fp->mode.wreqq.dest_hi = htons(0xffff);
925103285Sikob	fp->mode.wreqq.dest_lo = htonl(0xf0000000 | BUS_TIME);
926103285Sikob	fp->mode.wreqq.data = htonl(0xf);
927103285Sikob	fw_asyreq(xfer->fc, -1, xfer);
928103285Sikob}
929103285Sikob
930103285Sikob#if 0
931103285Sikobstatic void
932103285Sikobsbp_reset_start(struct sbp_dev *sdev)
933103285Sikob{
934103285Sikob	struct fw_xfer *xfer;
935103285Sikob	struct fw_pkt *fp;
936103285Sikob
937103285SikobSBP_DEBUG(0)
938103285Sikob	sbp_show_sdev_info(sdev, 2);
939103285Sikob	printf("sbp_reset_start\n");
940103285SikobEND_DEBUG
941103285Sikob	xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0);
942103285Sikob
943103285Sikob	xfer->act.hand = sbp_busy_timeout;
944103285Sikob	fp = (struct fw_pkt *)xfer->send.buf;
945103285Sikob	fp->mode.wreqq.dest_hi = htons(0xffff);
946103285Sikob	fp->mode.wreqq.dest_lo = htonl(0xf0000000 | RESET_START);
947103285Sikob	fp->mode.wreqq.data = htonl(0xf);
948103285Sikob	fw_asyreq(xfer->fc, -1, xfer);
949103285Sikob}
950103285Sikob#endif
951103285Sikob
952103285Sikobstatic void
953103285Sikobsbp_orb_pointer(struct sbp_dev *sdev, struct sbp_ocb *ocb)
954103285Sikob{
955103285Sikob	struct fw_xfer *xfer;
956103285Sikob	struct fw_pkt *fp;
957103285SikobSBP_DEBUG(2)
958103285Sikob	sbp_show_sdev_info(sdev, 2);
959103285Sikob	printf("sbp_orb_pointer\n");
960103285SikobEND_DEBUG
961103285Sikob
962103285Sikob	xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0x08);
963103285Sikob	if (xfer == NULL)
964103285Sikob		return;
965103285Sikob	xfer->act.hand = sbp_cmd_callback;
966103285Sikob
967103285Sikob	fp = (struct fw_pkt *)xfer->send.buf;
968103285Sikob	fp->mode.wreqb.len = htons(8);
969103285Sikob	fp->mode.wreqb.extcode = 0;
970103285Sikob	fp->mode.wreqb.payload[0] =
971103285Sikob		htonl(((sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS )<< 16));
972103285Sikob	fp->mode.wreqb.payload[1] = htonl(vtophys(&ocb->orb[0]));
973103285Sikob
974103285Sikob	if(fw_asyreq(xfer->fc, -1, xfer) != 0){
975103285Sikob			fw_xfer_free(xfer);
976103285Sikob			ocb->ccb->ccb_h.status = CAM_REQ_INVALID;
977103285Sikob			xpt_done(ocb->ccb);
978103285Sikob	}
979103285Sikob}
980103285Sikob
981103285Sikobstatic void
982103285Sikobsbp_doorbell(struct sbp_dev *sdev)
983103285Sikob{
984103285Sikob	struct fw_xfer *xfer;
985103285Sikob	struct fw_pkt *fp;
986103285SikobSBP_DEBUG(1)
987103285Sikob	sbp_show_sdev_info(sdev, 2);
988103285Sikob	printf("sbp_doorbell\n");
989103285SikobEND_DEBUG
990103285Sikob
991103285Sikob	xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0x10);
992103285Sikob	if (xfer == NULL)
993103285Sikob		return;
994103285Sikob	xfer->act.hand = sbp_cmd_callback;
995103285Sikob	fp = (struct fw_pkt *)xfer->send.buf;
996103285Sikob	fp->mode.wreqq.data = htonl(0xf);
997103285Sikob	fw_asyreq(xfer->fc, -1, xfer);
998103285Sikob}
999103285Sikob
1000103285Sikobstatic struct fw_xfer *
1001103285Sikobsbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset)
1002103285Sikob{
1003103285Sikob	struct fw_xfer *xfer;
1004103285Sikob	struct fw_pkt *fp;
1005103285Sikob
1006103285Sikob	xfer = fw_xfer_alloc();
1007103285Sikob	if(xfer == NULL){
1008103285Sikob		return NULL;
1009103285Sikob	}
1010103285Sikob	if (tcode == FWTCODE_WREQQ)
1011103285Sikob		xfer->send.len = 16;
1012103285Sikob	else
1013103285Sikob		xfer->send.len = 24;
1014103285Sikob
1015103285Sikob	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT);
1016103285Sikob	if(xfer->send.buf == NULL){
1017103285Sikob		fw_xfer_free( xfer);
1018103285Sikob		return NULL;
1019103285Sikob	}
1020103285Sikob
1021103285Sikob	xfer->send.off = 0;
1022103285Sikob	xfer->spd = min(sdev->target->fwdev->speed, max_speed);
1023103285Sikob	xfer->sc = (caddr_t)sdev;
1024103285Sikob	xfer->fc = sdev->target->sbp->fd.fc;
1025103285Sikob	xfer->retry_req = fw_asybusy;
1026103285Sikob
1027103285Sikob	fp = (struct fw_pkt *)xfer->send.buf;
1028103285Sikob	fp->mode.wreqq.dest_hi = htons(sdev->login.cmd_hi);
1029103285Sikob	fp->mode.wreqq.dest_lo = htonl(sdev->login.cmd_lo + offset);
1030103285Sikob	fp->mode.wreqq.tlrt = 0;
1031103285Sikob	fp->mode.wreqq.tcode = tcode;
1032103285Sikob	fp->mode.wreqq.pri = 0;
1033103285Sikob	xfer->dst = FWLOCALBUS | sdev->target->fwdev->dst;
1034103285Sikob	fp->mode.wreqq.dst = htons(xfer->dst);
1035103285Sikob
1036103285Sikob	return xfer;
1037103285Sikob
1038103285Sikob}
1039103285Sikob
1040103285Sikobstatic void
1041103285Sikobsbp_mgm_orb(struct sbp_dev *sdev, int func)
1042103285Sikob{
1043103285Sikob	struct fw_xfer *xfer;
1044103285Sikob	struct fw_pkt *fp;
1045103285Sikob	struct sbp_ocb *ocb;
1046103285Sikob	int s, nid;
1047103285Sikob
1048103285Sikob	if ((ocb = sbp_get_ocb(sdev->target->sbp)) == NULL) {
1049103285Sikob		s = splfw();
1050103285Sikob		sdev->target->sbp->flags |= SBP_RESOURCE_SHORTAGE;
1051103285Sikob		splx(s);
1052103285Sikob		return;
1053103285Sikob	}
1054103285Sikob	ocb->flags = OCB_ACT_MGM;
1055103285Sikob	ocb->sdev = sdev;
1056103285Sikob	ocb->ccb = NULL;
1057103285Sikob
1058103285Sikob	nid = sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS;
1059103285Sikob	bzero((void *)(uintptr_t)(volatile void *)ocb->orb, sizeof(ocb->orb));
1060103285Sikob	ocb->orb[6] = htonl((nid << 16) | SBP_BIND_HI);
1061103285Sikob	ocb->orb[7] = htonl(SBP_DEV2ADDR(
1062103285Sikob		device_get_unit(sdev->target->sbp->fd.dev),
1063103285Sikob		sdev->target->target_id,
1064103285Sikob		sdev->lun_id));
1065103285Sikob
1066103285Sikob	sbp_show_sdev_info(sdev, 2);
1067103285Sikob	printf("%s\n", orb_fun_name[(func>>16)&0xf]);
1068103285Sikob	switch (func) {
1069103285Sikob	case ORB_FUN_LGI:
1070103285Sikob		ocb->orb[2] = htonl(nid << 16);
1071103285Sikob		ocb->orb[3] = htonl(vtophys(&sdev->login));
1072103285Sikob		ocb->orb[4] = htonl(ORB_NOTIFY | ORB_EXV | sdev->lun_id);
1073103285Sikob		ocb->orb[5] = htonl(sizeof(struct sbp_login_res));
1074103285Sikob		break;
1075103285Sikob	case ORB_FUN_RCN:
1076103285Sikob	case ORB_FUN_LGO:
1077103285Sikob	case ORB_FUN_LUR:
1078103285Sikob	case ORB_FUN_RST:
1079103285Sikob	case ORB_FUN_ATA:
1080103285Sikob	case ORB_FUN_ATS:
1081103285Sikob		ocb->orb[4] = htonl(ORB_NOTIFY | func | sdev->login.id);
1082103285Sikob		break;
1083103285Sikob	}
1084103285Sikob
1085103285Sikob	xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0);
1086103285Sikob	if(xfer == NULL){
1087103285Sikob		return;
1088103285Sikob	}
1089103285Sikob	xfer->act.hand = sbp_login_callback;
1090103285Sikob
1091103285Sikob	fp = (struct fw_pkt *)xfer->send.buf;
1092103285Sikob	fp->mode.wreqb.dest_hi = htons(sdev->target->mgm_hi);
1093103285Sikob	fp->mode.wreqb.dest_lo = htonl(sdev->target->mgm_lo);
1094103285Sikob	fp->mode.wreqb.len = htons(8);
1095103285Sikob	fp->mode.wreqb.extcode = 0;
1096103285Sikob	fp->mode.wreqb.payload[0] = htonl(((sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS )<< 16));
1097103285Sikob	fp->mode.wreqb.payload[1] = htonl(vtophys(&ocb->orb[0]));
1098103285Sikob	sbp_enqueue_ocb(sdev, ocb);
1099103285Sikob
1100103285Sikob	fw_asyreq(xfer->fc, -1, xfer);
1101103285Sikob}
1102103285Sikob
1103103285Sikobstatic void
1104103285Sikobsbp_scsi_status(struct sbp_status *sbp_status, struct sbp_ocb *ocb)
1105103285Sikob{
1106103285Sikob	struct sbp_cmd_status *sbp_cmd_status;
1107103285Sikob	struct scsi_sense_data *sense;
1108103285Sikob	struct ccb_scsiio *csio;
1109103285Sikob
1110103285Sikob
1111103285Sikob	sbp_cmd_status = (struct sbp_cmd_status *)sbp_status->data;
1112103285Sikob	sense = &ocb->ccb->csio.sense_data;
1113103285Sikob
1114103285SikobSBP_DEBUG(0)
1115103285Sikob	csio = &ocb->ccb->csio;
1116103285Sikob	printf("%s:%d:%d XPT_SCSI_IO: "
1117103285Sikob		"cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x"
1118103285Sikob		", flags: 0x%02x, "
1119103285Sikob		"%db cmd/%db data/%db sense\n",
1120103285Sikob		device_get_nameunit(ocb->sdev->target->sbp->fd.dev),
1121103285Sikob		ocb->ccb->ccb_h.target_id, ocb->ccb->ccb_h.target_lun,
1122103285Sikob		csio->cdb_io.cdb_bytes[0],
1123103285Sikob		csio->cdb_io.cdb_bytes[1],
1124103285Sikob		csio->cdb_io.cdb_bytes[2],
1125103285Sikob		csio->cdb_io.cdb_bytes[3],
1126103285Sikob		csio->cdb_io.cdb_bytes[4],
1127103285Sikob		csio->cdb_io.cdb_bytes[5],
1128103285Sikob		csio->cdb_io.cdb_bytes[6],
1129103285Sikob		csio->cdb_io.cdb_bytes[7],
1130103285Sikob		csio->cdb_io.cdb_bytes[8],
1131103285Sikob		csio->cdb_io.cdb_bytes[9],
1132103285Sikob		ocb->ccb->ccb_h.flags & CAM_DIR_MASK,
1133103285Sikob		csio->cdb_len, csio->dxfer_len,
1134103285Sikob		csio->sense_len);
1135103285Sikob	/* XXX need decode status */
1136103285Sikob	sbp_show_sdev_info(ocb->sdev, 2);
1137103285Sikob	printf("SCSI status %x sfmt %x valid %x key %x code %x qlfr %x len %d",
1138103285Sikob		sbp_cmd_status->status,
1139103285Sikob		sbp_cmd_status->sfmt,
1140103285Sikob		sbp_cmd_status->valid,
1141103285Sikob		sbp_cmd_status->s_key,
1142103285Sikob		sbp_cmd_status->s_code,
1143103285Sikob		sbp_cmd_status->s_qlfr,
1144103285Sikob		sbp_status->len
1145103285Sikob	);
1146103285Sikob#if 0	 /* XXX */
1147103285Sikob	if (sbp_cmd_status->status == SCSI_STATUS_CHECK_COND) {
1148103285Sikob		printf(" %s\n", scsi_sense_key_text[sbp_cmd_status->s_key]);
1149103285Sikob			scsi_sense_desc(
1150103285Sikob				sbp_cmd_status->s_code,
1151103285Sikob				sbp_cmd_status->s_qlfr,
1152103285Sikob				ocb->ccb->ccb_h.path->device->inq_data
1153103285Sikob			)
1154103285Sikob	} else {
1155103285Sikob		printf("\n");
1156103285Sikob	}
1157103285Sikob#else
1158103285Sikob	printf("\n");
1159103285Sikob#endif
1160103285SikobEND_DEBUG
1161103285Sikob
1162103285Sikob
1163103285Sikob	if(sbp_cmd_status->status == SCSI_STATUS_CHECK_COND ||
1164103285Sikob			sbp_cmd_status->status == SCSI_STATUS_CMD_TERMINATED){
1165103285Sikob		if(sbp_cmd_status->sfmt == SBP_SFMT_CURR){
1166103285Sikob			sense->error_code = SSD_CURRENT_ERROR;
1167103285Sikob		}else{
1168103285Sikob			sense->error_code = SSD_DEFERRED_ERROR;
1169103285Sikob		}
1170103285Sikob		if(sbp_cmd_status->valid)
1171103285Sikob			sense->error_code |= SSD_ERRCODE_VALID;
1172103285Sikob		sense->flags = sbp_cmd_status->s_key;
1173103285Sikob		if(sbp_cmd_status->mark)
1174103285Sikob			sense->flags |= SSD_FILEMARK;
1175103285Sikob		if(sbp_cmd_status->eom)
1176103285Sikob			sense->flags |= SSD_EOM;
1177103285Sikob		if(sbp_cmd_status->ill_len)
1178103285Sikob			sense->flags |= SSD_ILI;
1179103285Sikob		sense->info[0] = ntohl(sbp_cmd_status->info) & 0xff;
1180103285Sikob		sense->info[1] =(ntohl(sbp_cmd_status->info) >> 8) & 0xff;
1181103285Sikob		sense->info[2] =(ntohl(sbp_cmd_status->info) >> 16) & 0xff;
1182103285Sikob		sense->info[3] =(ntohl(sbp_cmd_status->info) >> 24) & 0xff;
1183103285Sikob		if (sbp_status->len <= 1)
1184103285Sikob			/* XXX not scsi status. shouldn't be happened */
1185103285Sikob			sense->extra_len = 0;
1186103285Sikob		else if (sbp_status->len <= 4)
1187103285Sikob			/* add_sense_code(_qual), info, cmd_spec_info */
1188103285Sikob			sense->extra_len = 6;
1189103285Sikob		else
1190103285Sikob			/* fru, sense_key_spec */
1191103285Sikob			sense->extra_len = 10;
1192103285Sikob		sense->cmd_spec_info[0] = ntohl(sbp_cmd_status->cdb) & 0xff;
1193103285Sikob		sense->cmd_spec_info[1] = (ntohl(sbp_cmd_status->cdb) >> 8) & 0xff;
1194103285Sikob		sense->cmd_spec_info[2] = (ntohl(sbp_cmd_status->cdb) >> 16) & 0xff;
1195103285Sikob		sense->cmd_spec_info[3] = (ntohl(sbp_cmd_status->cdb) >> 24) & 0xff;
1196103285Sikob		sense->add_sense_code = sbp_cmd_status->s_code;
1197103285Sikob		sense->add_sense_code_qual = sbp_cmd_status->s_qlfr;
1198103285Sikob		sense->fru = sbp_cmd_status->fru;
1199103285Sikob		sense->sense_key_spec[0] = ntohl(sbp_cmd_status->s_keydep) & 0xff;
1200103285Sikob		sense->sense_key_spec[1] = (ntohl(sbp_cmd_status->s_keydep) >>8) & 0xff;
1201103285Sikob		sense->sense_key_spec[2] = (ntohl(sbp_cmd_status->s_keydep) >>16) & 0xff;
1202103285Sikob
1203103285Sikob		ocb->ccb->csio.scsi_status = sbp_cmd_status->status;;
1204103285Sikob		ocb->ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
1205103285Sikob							| CAM_AUTOSNS_VALID;
1206103285Sikob/*
1207103285Sikob{
1208103285Sikob		u_int8_t j, *tmp;
1209103285Sikob		tmp = sense;
1210103285Sikob		for( j = 0 ; j < 32 ; j+=8){
1211103285Sikob			printf("sense %02x%02x %02x%02x %02x%02x %02x%02x\n",
1212103285Sikob				tmp[j], tmp[j+1], tmp[j+2], tmp[j+3],
1213103285Sikob				tmp[j+4], tmp[j+5], tmp[j+6], tmp[j+7]);
1214103285Sikob		}
1215103285Sikob
1216103285Sikob}
1217103285Sikob*/
1218103285Sikob	} else {
1219103285Sikob		printf("sbp_scsi_status: unknown scsi status\n");
1220103285Sikob	}
1221103285Sikob}
1222103285Sikob
1223103285Sikobstatic void
1224103285Sikobsbp_fix_inq_data(struct sbp_ocb *ocb)
1225103285Sikob{
1226103285Sikob	union ccb *ccb;
1227103285Sikob	struct sbp_dev *sdev;
1228103285Sikob	struct scsi_inquiry_data *inq;
1229103285Sikob
1230103285Sikob	ccb = ocb->ccb;
1231103285Sikob	sdev = ocb->sdev;
1232103285Sikob
1233103285Sikob	if (ccb->csio.cdb_io.cdb_bytes[1] & SI_EVPD)
1234103285Sikob		return;
1235103285SikobSBP_DEBUG(1)
1236103285Sikob	sbp_show_sdev_info(sdev, 2);
1237103285Sikob	printf("sbp_fix_inq_data\n");
1238103285SikobEND_DEBUG
1239103285Sikob	inq = (struct scsi_inquiry_data *) ccb->csio.data_ptr;
1240103285Sikob	switch (SID_TYPE(inq)) {
1241103285Sikob	case T_DIRECT:
1242103285Sikob		/*
1243103285Sikob		 * XXX Convert Direct Access device to RBC.
1244103285Sikob		 * I've never seen Firewire DA devices which support READ_6.
1245103285Sikob		 */
1246103285Sikob#if 1
1247103285Sikob		if (SID_TYPE(inq) == T_DIRECT)
1248103285Sikob			inq->device |= T_RBC; /*  T_DIRECT == 0 */
1249103285Sikob#endif
1250103285Sikob		/* fall through */
1251103285Sikob	case T_RBC:
1252103285Sikob		/* disable tag queuing */
1253103285Sikob		inq->flags &= ~SID_CmdQue;
1254103285Sikob		/*
1255103285Sikob		 * Override vendor/product/revision information.
1256103285Sikob		 * Some devices sometimes return strange strings.
1257103285Sikob		 */
1258103285Sikob		bcopy(sdev->vendor, inq->vendor, sizeof(inq->vendor));
1259103285Sikob		bcopy(sdev->product, inq->product, sizeof(inq->product));
1260103285Sikob		bcopy(sdev->revision+2, inq->revision, sizeof(inq->revision));
1261103285Sikob		break;
1262103285Sikob	}
1263103285Sikob}
1264103285Sikob
1265103285Sikobstatic void
1266103285Sikobsbp_recv1(struct fw_xfer *xfer){
1267103285Sikob	struct fw_pkt *rfp;
1268103285Sikob#if NEED_RESPONSE
1269103285Sikob	struct fw_pkt *sfp;
1270103285Sikob#endif
1271103285Sikob	struct sbp_softc *sbp;
1272103285Sikob	struct sbp_dev *sdev;
1273103285Sikob	struct sbp_ocb *ocb;
1274103285Sikob	struct sbp_login_res *login_res = NULL;
1275103285Sikob	struct sbp_status *sbp_status;
1276103285Sikob	struct sbp_target *target;
1277103285Sikob	int	orb_fun, status_valid;
1278103285Sikob	u_int32_t addr;
1279103285Sikob/*
1280103285Sikob	u_int32_t *ld;
1281103285Sikob	ld = xfer->recv.buf;
1282103285Sikobprintf("sbp %x %d %d %08x %08x %08x %08x\n",
1283103285Sikob			xfer->resp, xfer->recv.len, xfer->recv.off, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3]));
1284103285Sikobprintf("sbp %08x %08x %08x %08x\n", ntohl(ld[4]), ntohl(ld[5]), ntohl(ld[6]), ntohl(ld[7]));
1285103285Sikobprintf("sbp %08x %08x %08x %08x\n", ntohl(ld[8]), ntohl(ld[9]), ntohl(ld[10]), ntohl(ld[11]));
1286103285Sikob*/
1287103285Sikob	if(xfer->resp != 0){
1288103285Sikob		printf("sbp_recv: xfer->resp != 0\n");
1289103285Sikob		fw_xfer_free( xfer);
1290103285Sikob		return;
1291103285Sikob	}
1292103285Sikob	if(xfer->recv.buf == NULL){
1293103285Sikob		printf("sbp_recv: xfer->recv.buf == NULL\n");
1294103285Sikob		fw_xfer_free( xfer);
1295103285Sikob		return;
1296103285Sikob	}
1297103285Sikob	sbp = (struct sbp_softc *)xfer->sc;
1298103285Sikob	rfp = (struct fw_pkt *)xfer->recv.buf;
1299103285Sikob	if(rfp->mode.wreqb.tcode != FWTCODE_WREQB){
1300103285Sikob		printf("sbp_recv: tcode = %d\n", rfp->mode.wreqb.tcode);
1301103285Sikob		fw_xfer_free( xfer);
1302103285Sikob		return;
1303103285Sikob	}
1304103285Sikob	sbp_status = (struct sbp_status *)rfp->mode.wreqb.payload;
1305103285Sikob	addr = ntohl(rfp->mode.wreqb.dest_lo);
1306103285SikobSBP_DEBUG(2)
1307103285Sikob	printf("received address 0x%x\n", addr);
1308103285SikobEND_DEBUG
1309103285Sikob	target = &sbp->targets[SBP_ADDR2TRG(addr)];
1310103285Sikob	sdev = &target->luns[SBP_ADDR2LUN(addr)];
1311103285Sikob
1312103285Sikob	status_valid = (sbp_status->resp == ORB_RES_CMPL
1313103285Sikob			&& sbp_status->dead == 0
1314103285Sikob			&& sbp_status->status == 0);
1315103285Sikob
1316103285SikobSBP_DEBUG(0)
1317103285Sikob	if (!status_valid || debug > 1){
1318103285Sikob		int status;
1319103285Sikob
1320103285Sikob		sbp_show_sdev_info(sdev, 2);
1321103285Sikob		printf("ORB status src:%x resp:%x dead:%x"
1322103285Sikob				" len:%x stat:%x orb:%x%08x\n",
1323103285Sikob			sbp_status->src, sbp_status->resp, sbp_status->dead,
1324103285Sikob			sbp_status->len, sbp_status->status,
1325103285Sikob			ntohl(sbp_status->orb_hi), ntohl(sbp_status->orb_lo));
1326103285Sikob		sbp_show_sdev_info(sdev, 2);
1327103285Sikob		status = sbp_status->status;
1328103285Sikob		switch(sbp_status->resp) {
1329103285Sikob		case 0:
1330103285Sikob			if (status > MAX_ORB_STATUS0)
1331103285Sikob				printf("%s\n", orb_status0[MAX_ORB_STATUS0]);
1332103285Sikob			else
1333103285Sikob				printf("%s\n", orb_status0[status]);
1334103285Sikob			break;
1335103285Sikob		case 1:
1336103285Sikob			printf("Object: %s, Serial Bus Error: %s\n",
1337103285Sikob				orb_status1_object[(status>>6) & 3],
1338103285Sikob				orb_status1_serial_bus_error[status & 0xf]);
1339103285Sikob			break;
1340103285Sikob		default:
1341103285Sikob			printf("unknown respose code\n");
1342103285Sikob		}
1343103285Sikob	}
1344103285SikobEND_DEBUG
1345103285Sikob	ocb = sbp_dequeue_ocb(sdev, ntohl(sbp_status->orb_lo));
1346103285Sikob
1347103285Sikob	/* we have to reset the fetch agent if it's dead */
1348103285Sikob	if (sbp_status->dead) {
1349103285Sikob		if (sdev->path)
1350103285Sikob			xpt_freeze_devq(sdev->path, 1);
1351103285Sikob		sbp_agent_reset(sdev, 0);
1352103285Sikob	}
1353103285Sikob
1354103285Sikob
1355103285Sikob	if (ocb == NULL) {
1356103285Sikob		printf("No ocb on the queue for target %d.\n", sdev->target->target_id);
1357103285Sikob		fw_xfer_free( xfer);
1358103285Sikob		return;
1359103285Sikob	}
1360103285Sikob
1361103285Sikob	switch(ntohl(ocb->orb[4]) & ORB_FMT_MSK){
1362103285Sikob	case ORB_FMT_NOP:
1363103285Sikob		break;
1364103285Sikob	case ORB_FMT_VED:
1365103285Sikob		break;
1366103285Sikob	case ORB_FMT_STD:
1367103285Sikob		switch(ocb->flags & OCB_ACT_MASK){
1368103285Sikob		case OCB_ACT_MGM:
1369103285Sikob			orb_fun = ntohl(ocb->orb[4]) & ORB_FUN_MSK;
1370103285Sikob			switch(orb_fun) {
1371103285Sikob			case ORB_FUN_LGI:
1372103285Sikob				login_res = &sdev->login;
1373103285Sikob				login_res->len = ntohs(login_res->len);
1374103285Sikob				login_res->id = ntohs(login_res->id);
1375103285Sikob				login_res->cmd_hi = ntohs(login_res->cmd_hi);
1376103285Sikob				login_res->cmd_lo = ntohl(login_res->cmd_lo);
1377103285Sikob				if (status_valid) {
1378103285SikobSBP_DEBUG(0)
1379103285Sikobsbp_show_sdev_info(sdev, 2);
1380103285Sikobprintf("login: len %d, ID %d, cmd %08x%08x, recon_hold %d\n", login_res->len, login_res->id, login_res->cmd_hi, login_res->cmd_lo, ntohs(login_res->recon_hold));
1381103285SikobEND_DEBUG
1382103285Sikob#if 1
1383103285Sikob					sbp_busy_timeout(sdev);
1384103285Sikob#else
1385103285Sikob					sbp_mgm_orb(sdev, ORB_FUN_ATS);
1386103285Sikob#endif
1387103285Sikob				} else {
1388103285Sikob					/* forgot logout ? */
1389103285Sikob					printf("login failed\n");
1390103285Sikob					sdev->status = SBP_DEV_RESET;
1391103285Sikob				}
1392103285Sikob				break;
1393103285Sikob			case ORB_FUN_RCN:
1394103285Sikob				login_res = &sdev->login;
1395103285Sikob				if (status_valid) {
1396103285Sikob					sdev->status = SBP_DEV_ATTACHED;
1397103285SikobSBP_DEBUG(0)
1398103285Sikobsbp_show_sdev_info(sdev, 2);
1399103285Sikobprintf("reconnect: len %d, ID %d, cmd %08x%08x\n", login_res->len, login_res->id, login_res->cmd_hi, login_res->cmd_lo);
1400103285SikobEND_DEBUG
1401103285Sikob#if 1
1402103285Sikob					sbp_ping_unit(sdev);
1403103285Sikob					xpt_release_devq(sdev->path, 1, TRUE);
1404103285Sikob#else
1405103285Sikob					sbp_mgm_orb(sdev, ORB_FUN_ATS);
1406103285Sikob#endif
1407103285Sikob				} else {
1408103285Sikob					/* reconnection hold time exceed? */
1409103285Sikob					printf("reconnect failed\n");
1410103285Sikob					sbp_mgm_orb(sdev, ORB_FUN_LGI);
1411103285Sikob				}
1412103285Sikob				break;
1413103285Sikob			case ORB_FUN_LGO:
1414103285Sikob				sdev->status = SBP_DEV_RESET;
1415103285Sikob				break;
1416103285Sikob			case ORB_FUN_LUR:
1417103285Sikob			case ORB_FUN_RST:
1418103285Sikob			case ORB_FUN_ATA:
1419103285Sikob			case ORB_FUN_ATS:
1420103285Sikob				if (sdev->status == SBP_DEV_ATTACHED) {
1421103285Sikob					xpt_release_devq(sdev->path, 1, TRUE);
1422103285Sikob				} else {
1423103285Sikob					sbp_busy_timeout(sdev);
1424103285Sikob				}
1425103285Sikob				break;
1426103285Sikob			default:
1427103285Sikob				break;
1428103285Sikob			}
1429103285Sikob			break;
1430103285Sikob		case OCB_ACT_CMD:
1431103285Sikob			if(ocb->ccb != NULL){
1432103285Sikob				union ccb *ccb;
1433103285Sikob/*
1434103285Sikob				u_int32_t *ld;
1435103285Sikob				ld = ocb->ccb->csio.data_ptr;
1436103285Sikob				if(ld != NULL && ocb->ccb->csio.dxfer_len != 0)
1437103285Sikob					printf("ptr %08x %08x %08x %08x\n", ld[0], ld[1], ld[2], ld[3]);
1438103285Sikob				else
1439103285Sikob					printf("ptr NULL\n");
1440103285Sikobprintf("len %d\n", sbp_status->len);
1441103285Sikob*/
1442103285Sikob				ccb = ocb->ccb;
1443103285Sikob				if(sbp_status->len > 1){
1444103285Sikob					sbp_scsi_status(sbp_status, ocb);
1445103285Sikob				}else{
1446103285Sikob					if(sbp_status->resp != ORB_RES_CMPL){
1447103285Sikob						ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1448103285Sikob					}else{
1449103285Sikob						ccb->ccb_h.status = CAM_REQ_CMP;
1450103285Sikob					}
1451103285Sikob				}
1452103285Sikob				/* fix up inq data */
1453103285Sikob				if (ccb->csio.cdb_io.cdb_bytes[0] == INQUIRY)
1454103285Sikob					sbp_fix_inq_data(ocb);
1455103285Sikob				xpt_done(ccb);
1456103285Sikob			}
1457103285Sikob			break;
1458103285Sikob		default:
1459103285Sikob			break;
1460103285Sikob		}
1461103285Sikob	}
1462103285Sikob
1463103285Sikob	if (!(ocb->flags & OCB_RESERVED))
1464103285Sikob		sbp_free_ocb(sbp, ocb);
1465103285Sikob
1466103285Sikob/* The received packet is usually small enough to be stored within
1467103285Sikob * the buffer. In that case, the controller return ack_complete and
1468103285Sikob * no respose is necessary.
1469103285Sikob *
1470103285Sikob * XXX fwohci.c and firewire.c should inform event_code such as
1471103285Sikob * ack_complete or ack_pending to upper driver.
1472103285Sikob */
1473103285Sikob#if NEED_RESPONSE
1474103285Sikob	xfer->send.buf = malloc(12, M_SBP, M_NOWAIT | M_ZERO);
1475103285Sikob	xfer->send.len = 12;
1476103285Sikob	xfer->send.off = 0;
1477103285Sikob	sfp = (struct fw_pkt *)xfer->send.buf;
1478103285Sikob	sfp->mode.wres.dst = rfp->mode.wreqb.src;
1479103285Sikob	xfer->dst = ntohs(sfp->mode.wres.dst);
1480103285Sikob	xfer->spd = min(sdev->target->fwdev->speed, max_speed);
1481103285Sikob	xfer->act.hand = sbp_loginres_callback;
1482103285Sikob	xfer->retry_req = fw_asybusy;
1483103285Sikob
1484103285Sikob	sfp->mode.wres.tlrt = rfp->mode.wreqb.tlrt;
1485103285Sikob	sfp->mode.wres.tcode = FWTCODE_WRES;
1486103285Sikob	sfp->mode.wres.rtcode = 0;
1487103285Sikob	sfp->mode.wres.pri = 0;
1488103285Sikob
1489103285Sikob	fw_asyreq(xfer->fc, -1, xfer);
1490103285Sikob#else
1491103285Sikob	fw_xfer_free(xfer);
1492103285Sikob#endif
1493103285Sikob
1494103285Sikob	return;
1495103285Sikob
1496103285Sikob}
1497103285Sikob
1498103285Sikobstatic void
1499103285Sikobsbp_recv(struct fw_xfer *xfer)
1500103285Sikob{
1501103285Sikob	int s;
1502103285Sikob
1503103285Sikob	s = splcam();
1504103285Sikob	sbp_recv1(xfer);
1505103285Sikob	splx(s);
1506103285Sikob}
1507103285Sikob/*
1508103285Sikob * sbp_attach()
1509103285Sikob */
1510103285Sikobstatic int
1511103285Sikobsbp_attach(device_t dev)
1512103285Sikob{
1513103285Sikob	struct sbp_softc *sbp;
1514103285Sikob	struct cam_devq *devq;
1515103285Sikob	struct fw_xfer *xfer;
1516103285Sikob	int i, s, error;
1517103285Sikob
1518103285SikobSBP_DEBUG(0)
1519103285Sikob	printf("sbp_attach\n");
1520103285SikobEND_DEBUG
1521103285Sikob
1522103285Sikob	sbp = ((struct sbp_softc *)device_get_softc(dev));
1523103285Sikob	bzero(sbp, sizeof(struct sbp_softc));
1524103285Sikob	sbp->fd.dev = dev;
1525103285Sikob	sbp->fd.fc = device_get_ivars(dev);
1526103285Sikob	error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1,
1527103285Sikob				/*boundary*/0,
1528103285Sikob				/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
1529103285Sikob				/*highaddr*/BUS_SPACE_MAXADDR,
1530103285Sikob				/*filter*/NULL, /*filterarg*/NULL,
1531103285Sikob				/*maxsize*/0x100000, /*nsegments*/SBP_IND_MAX,
1532103285Sikob				/*maxsegsz*/0x8000,
1533103285Sikob				/*flags*/BUS_DMA_ALLOCNOW,
1534103285Sikob				&sbp->dmat);
1535103285Sikob	if (error != 0) {
1536103285Sikob		printf("sbp_attach: Could not allocate DMA tag "
1537103285Sikob			"- error %d\n", error);
1538103285Sikob			return (ENOMEM);
1539103285Sikob	}
1540103285Sikob
1541103285Sikob	devq = cam_simq_alloc(/*maxopenings*/SBP_NUM_OCB);
1542103285Sikob	if (devq == NULL)
1543103285Sikob		return (ENXIO);
1544103285Sikob
1545103285Sikob	for( i = 0 ; i < SBP_NUM_TARGETS ; i++){
1546103285Sikob		sbp->targets[i].fwdev = NULL;
1547103285Sikob		sbp->targets[i].luns = NULL;
1548103285Sikob	}
1549103285Sikob
1550103285Sikob	sbp->sim = cam_sim_alloc(sbp_action, sbp_poll, "sbp", sbp,
1551103285Sikob				 device_get_unit(dev),
1552103285Sikob				 /*untagged*/ SBP_QUEUE_LEN,
1553103285Sikob				 /*tagged*/0, devq);
1554103285Sikob
1555103285Sikob	if (sbp->sim == NULL) {
1556103285Sikob		cam_simq_free(devq);
1557103285Sikob		return (ENXIO);
1558103285Sikob	}
1559103285Sikob
1560103285Sikob	sbp->ocb = (struct sbp_ocb *) contigmalloc(
1561103285Sikob		sizeof (struct sbp_ocb) * SBP_NUM_OCB,
1562103285Sikob		M_SBP, M_DONTWAIT, 0x10000, 0xffffffff, PAGE_SIZE, 0ul);
1563103285Sikob	bzero(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB);
1564103285Sikob
1565103285Sikob	if (sbp->ocb == NULL) {
1566103285Sikob		printf("sbp0: ocb alloction failure\n");
1567103285Sikob		return (ENOMEM);
1568103285Sikob	}
1569103285Sikob
1570103285Sikob	STAILQ_INIT(&sbp->free_ocbs);
1571103285Sikob	for (i = 0; i < SBP_NUM_OCB; i++) {
1572103285Sikob		sbp_free_ocb(sbp, &sbp->ocb[i]);
1573103285Sikob	}
1574103285Sikob
1575103285Sikob	if (xpt_bus_register(sbp->sim, /*bus*/0) != CAM_SUCCESS) {
1576103285Sikob		cam_sim_free(sbp->sim, /*free_devq*/TRUE);
1577103285Sikob		contigfree(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB,
1578103285Sikob									M_SBP);
1579103285Sikob		return (ENXIO);
1580103285Sikob	}
1581103285Sikob
1582103285Sikob	xfer = fw_xfer_alloc();
1583103285Sikob	xfer->act.hand = sbp_recv;
1584103285Sikob	xfer->act_type = FWACT_XFER;
1585103285Sikob#if NEED_RESPONSE
1586103285Sikob	xfer->fc = sbp->fd.fc;
1587103285Sikob#endif
1588103285Sikob	xfer->sc = (caddr_t)sbp;
1589103285Sikob
1590103285Sikob	sbp->fwb.start_hi = SBP_BIND_HI;
1591103285Sikob	sbp->fwb.start_lo = SBP_DEV2ADDR(device_get_unit(sbp->fd.dev), 0, 0);
1592103285Sikob	/* We reserve 16 bit space (4 bytes X 64 targets X 256 luns) */
1593103285Sikob	sbp->fwb.addrlen = 0xffff;
1594103285Sikob	sbp->fwb.xfer = xfer;
1595103285Sikob	fw_bindadd(sbp->fd.fc, &sbp->fwb);
1596103285Sikob
1597103285Sikob	sbp->fd.post_explore = sbp_post_explore;
1598103285Sikob	s = splfw();
1599103285Sikob	sbp_post_explore((void *)sbp);
1600103285Sikob	splx(s);
1601103285Sikob
1602103285Sikob	return (0);
1603103285Sikob}
1604103285Sikob
1605103285Sikobstatic int
1606103285Sikobsbp_detach(device_t dev)
1607103285Sikob{
1608103285Sikob	struct sbp_softc *sbp = ((struct sbp_softc *)device_get_softc(dev));
1609103285Sikob	struct firewire_comm *fc = sbp->fd.fc;
1610103285Sikob	int i;
1611103285Sikob
1612103285SikobSBP_DEBUG(0)
1613103285Sikob	printf("sbp_detach\n");
1614103285SikobEND_DEBUG
1615103285Sikob
1616103285Sikob	/* bus reset for logout */
1617103285Sikob	sbp->fd.post_explore = NULL;
1618103285Sikob	fc->ibr(fc);
1619103285Sikob
1620103285Sikob	contigfree(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB, M_SBP);
1621103285Sikob	fw_bindremove(fc, &sbp->fwb);
1622103285Sikob	for (i = 0; i < SBP_NUM_TARGETS; i ++)
1623103285Sikob		sbp_detach_target(&sbp->targets[i]);
1624103285Sikob	xpt_bus_deregister(cam_sim_path(sbp->sim));
1625103285Sikob	bus_dma_tag_destroy(sbp->dmat);
1626103285Sikob	return (0);
1627103285Sikob}
1628103285Sikob
1629103285Sikobstatic void
1630103285Sikobsbp_detach_target(struct sbp_target *target)
1631103285Sikob{
1632103285Sikob	int i;
1633103285Sikob	struct sbp_dev *sdev;
1634103285Sikob
1635103285Sikob	if (target->luns != NULL) {
1636103285Sikob		printf("sbp_detach_target %d\n", target->target_id);
1637103285Sikob		for (i=0; i < target->num_lun; i++) {
1638103285Sikob			sdev = &target->luns[i];
1639103285Sikob			if (sdev->status == SBP_DEV_RESET ||
1640103285Sikob					sdev->status == SBP_DEV_DEAD)
1641103285Sikob				continue;
1642103285Sikob			if (sdev->path)
1643103285Sikob				xpt_async(AC_LOST_DEVICE, sdev->path, NULL);
1644103285Sikob			xpt_free_path(sdev->path);
1645103285Sikob			sdev->path = NULL;
1646103285Sikob			sbp_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE);
1647103285Sikob		}
1648103285Sikob		free(target->luns, M_SBP);
1649103285Sikob		target->luns = NULL;
1650103285Sikob	}
1651103285Sikob	target->fwdev = NULL;
1652103285Sikob}
1653103285Sikob
1654103285Sikobstatic void
1655103285Sikobsbp_timeout(void *arg)
1656103285Sikob{
1657103285Sikob	struct sbp_ocb *ocb = (struct sbp_ocb *)arg;
1658103285Sikob	struct sbp_dev *sdev = ocb->sdev;
1659103285Sikob	int s;
1660103285Sikob
1661103285Sikob	sbp_show_sdev_info(sdev, 2);
1662103285Sikob	printf("request timeout ... requeue\n");
1663103285Sikob
1664103285Sikob	/* XXX need reset? */
1665103285Sikob
1666103285Sikob	s = splfw();
1667105633Ssimokawa#if 1
1668105633Ssimokawa	sbp_abort_all_ocbs(sdev, CAM_CMD_TIMEOUT);
1669105633Ssimokawa#else
1670103285Sikob	sbp_abort_ocb(ocb, CAM_CMD_TIMEOUT);
1671105633Ssimokawa#endif
1672103285Sikob	splx(s);
1673103285Sikob	return;
1674103285Sikob}
1675103285Sikob
1676103285Sikobstatic void
1677103285Sikobsbp_action1(struct cam_sim *sim, union ccb *ccb)
1678103285Sikob{
1679103285Sikob
1680103285Sikob	struct sbp_softc *sbp = (struct sbp_softc *)sim->softc;
1681103285Sikob	struct sbp_target *target = NULL;
1682103285Sikob	struct sbp_dev *sdev = NULL;
1683103285Sikob
1684103285Sikob	/* target:lun -> sdev mapping */
1685103285Sikob	if (sbp != NULL
1686103285Sikob			&& ccb->ccb_h.target_id != CAM_TARGET_WILDCARD
1687103285Sikob			&& ccb->ccb_h.target_id < SBP_NUM_TARGETS) {
1688103285Sikob		target = &sbp->targets[ccb->ccb_h.target_id];
1689103285Sikob		if (target->fwdev != NULL
1690103285Sikob				&& ccb->ccb_h.target_lun != CAM_LUN_WILDCARD
1691103285Sikob				&& ccb->ccb_h.target_lun < target->num_lun) {
1692103285Sikob			sdev = &target->luns[ccb->ccb_h.target_lun];
1693103285Sikob			if (sdev->status != SBP_DEV_ATTACHED &&
1694103285Sikob				sdev->status != SBP_DEV_PROBE)
1695103285Sikob				sdev = NULL;
1696103285Sikob		}
1697103285Sikob	}
1698103285Sikob
1699103285SikobSBP_DEBUG(1)
1700103285Sikob	if (sdev == NULL)
1701103285Sikob		printf("invalid target %d lun %d\n",
1702103285Sikob			ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
1703103285SikobEND_DEBUG
1704103285Sikob
1705103285Sikob	switch (ccb->ccb_h.func_code) {
1706103285Sikob	case XPT_SCSI_IO:
1707103285Sikob	case XPT_RESET_DEV:
1708103285Sikob	case XPT_GET_TRAN_SETTINGS:
1709103285Sikob	case XPT_SET_TRAN_SETTINGS:
1710103285Sikob	case XPT_CALC_GEOMETRY:
1711103285Sikob		if (sdev == NULL) {
1712103285SikobSBP_DEBUG(1)
1713103285Sikob			printf("%s:%d:%d:func_code 0x%04x: "
1714103285Sikob				"Invalid target (target needed)\n",
1715103285Sikob				device_get_nameunit(sbp->fd.dev),
1716103285Sikob				ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
1717103285Sikob				ccb->ccb_h.func_code);
1718103285SikobEND_DEBUG
1719103285Sikob
1720103285Sikob			ccb->ccb_h.status = CAM_TID_INVALID;
1721103285Sikob			xpt_done(ccb);
1722103285Sikob			return;
1723103285Sikob		}
1724103285Sikob		break;
1725103285Sikob	case XPT_PATH_INQ:
1726103285Sikob	case XPT_NOOP:
1727103285Sikob		/* The opcodes sometimes aimed at a target (sc is valid),
1728103285Sikob		 * sometimes aimed at the SIM (sc is invalid and target is
1729103285Sikob		 * CAM_TARGET_WILDCARD)
1730103285Sikob		 */
1731103285Sikob		if (sbp == NULL &&
1732103285Sikob			ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
1733103285SikobSBP_DEBUG(0)
1734103285Sikob			printf("%s:%d:%d func_code 0x%04x: "
1735103285Sikob				"Invalid target (no wildcard)\n",
1736103285Sikob				device_get_nameunit(sbp->fd.dev),
1737103285Sikob				ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
1738103285Sikob				ccb->ccb_h.func_code);
1739103285SikobEND_DEBUG
1740103285Sikob			ccb->ccb_h.status = CAM_TID_INVALID;
1741103285Sikob			xpt_done(ccb);
1742103285Sikob			return;
1743103285Sikob		}
1744103285Sikob		break;
1745103285Sikob	default:
1746103285Sikob		/* XXX Hm, we should check the input parameters */
1747103285Sikob		break;
1748103285Sikob	}
1749103285Sikob
1750103285Sikob	switch (ccb->ccb_h.func_code) {
1751103285Sikob	case XPT_SCSI_IO:
1752103285Sikob	{
1753103285Sikob		struct ccb_scsiio *csio;
1754103285Sikob		struct sbp_ocb *ocb;
1755103285Sikob		int s, speed;
1756103285Sikob
1757103285Sikob		csio = &ccb->csio;
1758103285Sikob
1759103285SikobSBP_DEBUG(1)
1760103285Sikob		printf("%s:%d:%d XPT_SCSI_IO: "
1761103285Sikob			"cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x"
1762103285Sikob			", flags: 0x%02x, "
1763103285Sikob			"%db cmd/%db data/%db sense\n",
1764103285Sikob			device_get_nameunit(sbp->fd.dev),
1765103285Sikob			ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
1766103285Sikob			csio->cdb_io.cdb_bytes[0],
1767103285Sikob			csio->cdb_io.cdb_bytes[1],
1768103285Sikob			csio->cdb_io.cdb_bytes[2],
1769103285Sikob			csio->cdb_io.cdb_bytes[3],
1770103285Sikob			csio->cdb_io.cdb_bytes[4],
1771103285Sikob			csio->cdb_io.cdb_bytes[5],
1772103285Sikob			csio->cdb_io.cdb_bytes[6],
1773103285Sikob			csio->cdb_io.cdb_bytes[7],
1774103285Sikob			csio->cdb_io.cdb_bytes[8],
1775103285Sikob			csio->cdb_io.cdb_bytes[9],
1776103285Sikob			ccb->ccb_h.flags & CAM_DIR_MASK,
1777103285Sikob			csio->cdb_len, csio->dxfer_len,
1778103285Sikob			csio->sense_len);
1779103285SikobEND_DEBUG
1780103285Sikob		if(sdev == NULL){
1781103285Sikob			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
1782103285Sikob			xpt_done(ccb);
1783103285Sikob			return;
1784103285Sikob		}
1785103285Sikob#if 0
1786103285Sikob		/* if we are in probe stage, pass only probe commands */
1787103285Sikob		if (sdev->status == SBP_DEV_PROBE) {
1788103285Sikob			char *name;
1789103285Sikob			name = xpt_path_periph(ccb->ccb_h.path)->periph_name;
1790103285Sikob			printf("probe stage, periph name: %s\n", name);
1791103285Sikob			if (strcmp(name, "probe") != 0) {
1792103285Sikob				ccb->ccb_h.status = CAM_REQUEUE_REQ;
1793103285Sikob				xpt_done(ccb);
1794103285Sikob				return;
1795103285Sikob			}
1796103285Sikob		}
1797103285Sikob#endif
1798103285Sikob		if ((ocb = sbp_get_ocb(sbp)) == NULL) {
1799103285Sikob			s = splfw();
1800103285Sikob			sbp->flags |= SBP_RESOURCE_SHORTAGE;
1801103285Sikob			splx(s);
1802103285Sikob			return;
1803103285Sikob		}
1804103285Sikob		ocb->flags = OCB_ACT_CMD;
1805103285Sikob		ocb->sdev = sdev;
1806103285Sikob		ocb->ccb = ccb;
1807103285Sikob		ccb->ccb_h.ccb_sdev_ptr = sdev;
1808103285Sikob		ocb->orb[0] = htonl(1 << 31);
1809103285Sikob		ocb->orb[1] = 0;
1810103285Sikob		ocb->orb[2] = htonl(((sbp->fd.fc->nodeid | FWLOCALBUS )<< 16) );
1811103285Sikob		ocb->orb[3] = htonl(vtophys(ocb->ind_ptr));
1812103285Sikob		speed = min(target->fwdev->speed, max_speed);
1813103285Sikob		ocb->orb[4] = htonl(ORB_NOTIFY | ORB_CMD_SPD(speed)
1814103285Sikob						| ORB_CMD_MAXP(speed + 7));
1815103285Sikob		if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN){
1816103285Sikob			ocb->orb[4] |= htonl(ORB_CMD_IN);
1817103285Sikob		}
1818103285Sikob
1819103285Sikob		if (csio->ccb_h.flags & CAM_SCATTER_VALID)
1820103285Sikob			printf("sbp: CAM_SCATTER_VALID\n");
1821103285Sikob		if (csio->ccb_h.flags & CAM_DATA_PHYS)
1822103285Sikob			printf("sbp: CAM_DATA_PHYS\n");
1823103285Sikob
1824103285Sikob		if (csio->ccb_h.flags & CAM_CDB_POINTER) {
1825103285Sikob			bcopy(csio->cdb_io.cdb_ptr,
1826103285Sikob			(void *)(uintptr_t)(volatile void *)&ocb->orb[5],
1827103285Sikob			(csio->cdb_len + 3) & ~0x3);
1828103285Sikob		} else {
1829103285Sikob			bcopy(&csio->cdb_io.cdb_bytes,
1830103285Sikob			(void *)(uintptr_t)(volatile void *)&ocb->orb[5],
1831103285Sikob			(csio->cdb_len + 3) &~0x3);
1832103285Sikob		}
1833103285Sikob/*
1834103285Sikobprintf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[0]), ntohl(ocb->orb[1]), ntohl(ocb->orb[2]), ntohl(ocb->orb[3]));
1835103285Sikobprintf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[4]), ntohl(ocb->orb[5]), ntohl(ocb->orb[6]), ntohl(ocb->orb[7]));
1836103285Sikob*/
1837103285Sikob		if (ccb->csio.dxfer_len > 0) {
1838103285Sikob			int s;
1839103285Sikob
1840103285Sikob			if (bus_dmamap_create(sbp->dmat, 0, &ocb->dmamap)) {
1841103285Sikob				printf("sbp_action1: cannot create dmamap\n");
1842103285Sikob				break;
1843103285Sikob			}
1844103285Sikob
1845103285Sikob			s = splsoftvm();
1846103285Sikob			bus_dmamap_load(/*dma tag*/sbp->dmat,
1847103285Sikob					/*dma map*/ocb->dmamap,
1848103285Sikob					ccb->csio.data_ptr,
1849103285Sikob					ccb->csio.dxfer_len,
1850103285Sikob					sbp_execute_ocb,
1851103285Sikob					ocb,
1852103285Sikob					/*flags*/0);
1853103285Sikob			splx(s);
1854103285Sikob		} else
1855103285Sikob			sbp_execute_ocb(ocb, NULL, 0, 0);
1856103285Sikob		break;
1857103285Sikob	}
1858103285Sikob	case XPT_CALC_GEOMETRY:
1859103285Sikob	{
1860103285Sikob		struct ccb_calc_geometry *ccg;
1861103285Sikob		u_int32_t size_mb;
1862103285Sikob		u_int32_t secs_per_cylinder;
1863103285Sikob		int extended = 1;
1864103285Sikob		ccg = &ccb->ccg;
1865103285Sikob
1866103285Sikob		if (ccg->block_size == 0) {
1867103285Sikob			printf("sbp_action1: block_size is 0.\n");
1868103285Sikob			ccb->ccb_h.status = CAM_REQ_INVALID;
1869103285Sikob			xpt_done(ccb);
1870103285Sikob			break;
1871103285Sikob		}
1872103285SikobSBP_DEBUG(1)
1873103285Sikob		printf("%s:%d:%d:%d:XPT_CALC_GEOMETRY: "
1874103285Sikob			"Volume size = %d\n",
1875103285Sikob			device_get_nameunit(sbp->fd.dev), cam_sim_path(sbp->sim),
1876103285Sikob			ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
1877103285Sikob			ccg->volume_size);
1878103285SikobEND_DEBUG
1879103285Sikob
1880103285Sikob		size_mb = ccg->volume_size
1881103285Sikob			/ ((1024L * 1024L) / ccg->block_size);
1882103285Sikob
1883103285Sikob		if (size_mb >= 1024 && extended) {
1884103285Sikob			ccg->heads = 255;
1885103285Sikob			ccg->secs_per_track = 63;
1886103285Sikob		} else {
1887103285Sikob			ccg->heads = 64;
1888103285Sikob			ccg->secs_per_track = 32;
1889103285Sikob		}
1890103285Sikob		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
1891103285Sikob		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
1892103285Sikob		ccb->ccb_h.status = CAM_REQ_CMP;
1893103285Sikob		xpt_done(ccb);
1894103285Sikob		break;
1895103285Sikob	}
1896103285Sikob	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
1897103285Sikob	{
1898103285Sikob
1899103285SikobSBP_DEBUG(1)
1900103285Sikob		printf("%s:%d:XPT_RESET_BUS: \n",
1901103285Sikob			device_get_nameunit(sbp->fd.dev), cam_sim_path(sbp->sim));
1902103285SikobEND_DEBUG
1903103285Sikob
1904103285Sikob		ccb->ccb_h.status = CAM_REQ_INVALID;
1905103285Sikob		xpt_done(ccb);
1906103285Sikob		break;
1907103285Sikob	}
1908103285Sikob	case XPT_PATH_INQ:		/* Path routing inquiry */
1909103285Sikob	{
1910103285Sikob		struct ccb_pathinq *cpi = &ccb->cpi;
1911103285Sikob
1912103285SikobSBP_DEBUG(1)
1913103285Sikob		printf("%s:%d:%d XPT_PATH_INQ:.\n",
1914103285Sikob			device_get_nameunit(sbp->fd.dev),
1915103285Sikob			ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
1916103285SikobEND_DEBUG
1917103285Sikob		cpi->version_num = 1; /* XXX??? */
1918103285Sikob		cpi->hba_inquiry = 0;
1919103285Sikob		cpi->target_sprt = 0;
1920103285Sikob		cpi->hba_misc = 0;
1921103285Sikob		cpi->hba_eng_cnt = 0;
1922103285Sikob		cpi->max_target = SBP_NUM_TARGETS - 1;
1923103285Sikob		cpi->max_lun = SBP_NUM_LUNS - 1;
1924103285Sikob		cpi->initiator_id = SBP_INITIATOR;
1925103285Sikob		cpi->bus_id = sim->bus_id;
1926103285Sikob		cpi->base_transfer_speed = 400 * 1000 / 8;
1927103285Sikob		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1928103285Sikob		strncpy(cpi->hba_vid, "SBP", HBA_IDLEN);
1929103285Sikob		strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
1930103285Sikob		cpi->unit_number = sim->unit_number;
1931103285Sikob
1932103285Sikob		cpi->ccb_h.status = CAM_REQ_CMP;
1933103285Sikob		xpt_done(ccb);
1934103285Sikob		break;
1935103285Sikob	}
1936103285Sikob	case XPT_GET_TRAN_SETTINGS:
1937103285Sikob	{
1938103285Sikob		struct ccb_trans_settings *cts = &ccb->cts;
1939103285SikobSBP_DEBUG(1)
1940103285Sikob		printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:.\n",
1941103285Sikob			device_get_nameunit(sbp->fd.dev),
1942103285Sikob			ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
1943103285SikobEND_DEBUG
1944103285Sikob		/* Disable disconnect and tagged queuing */
1945103285Sikob		cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
1946103285Sikob		cts->flags = 0;
1947103285Sikob
1948103285Sikob		cts->ccb_h.status = CAM_REQ_CMP;
1949103285Sikob		xpt_done(ccb);
1950103285Sikob		break;
1951103285Sikob	}
1952103285Sikob	case XPT_ABORT:
1953103285Sikob		ccb->ccb_h.status = CAM_UA_ABORT;
1954103285Sikob		xpt_done(ccb);
1955103285Sikob		break;
1956103285Sikob	default:
1957103285Sikob		ccb->ccb_h.status = CAM_REQ_INVALID;
1958103285Sikob		xpt_done(ccb);
1959103285Sikob		break;
1960103285Sikob	}
1961103285Sikob	return;
1962103285Sikob}
1963103285Sikob
1964103285Sikobstatic void
1965103285Sikobsbp_action(struct cam_sim *sim, union ccb *ccb)
1966103285Sikob{
1967103285Sikob	int s;
1968103285Sikob
1969103285Sikob	s = splfw();
1970103285Sikob	sbp_action1(sim, ccb);
1971103285Sikob	splx(s);
1972103285Sikob}
1973103285Sikob
1974103285Sikobstatic void
1975103285Sikobsbp_execute_ocb(void *arg,  bus_dma_segment_t *segments, int seg, int error)
1976103285Sikob{
1977103285Sikob	int i;
1978103285Sikob	struct sbp_ocb *ocb;
1979103285Sikob	struct sbp_ocb *prev;
1980103285Sikob	union ccb *ccb;
1981105633Ssimokawa	bus_dma_segment_t *s;
1982103285Sikob
1983103285Sikob	if (error)
1984103285Sikob		printf("sbp_execute_ocb: error=%d\n", error);
1985103285Sikob
1986103285Sikob	ocb = (struct sbp_ocb *)arg;
1987103285Sikob	if (seg == 1) {
1988103285Sikob		/* direct pointer */
1989103285Sikob		ocb->orb[3] = htonl(segments[0].ds_addr);
1990103285Sikob		ocb->orb[4] |= htonl(segments[0].ds_len);
1991103285Sikob	} else if(seg > 1) {
1992103285Sikob		/* page table */
1993103285SikobSBP_DEBUG(1)
1994103285Sikob		printf("sbp_execute_ocb: seg %d", seg);
1995103285Sikob		for (i = 0; i < seg; i++)
1996103285Sikob			printf(", %x:%d", segments[i].ds_addr,
1997103285Sikob						segments[i].ds_len);
1998103285Sikob		printf("\n");
1999103285SikobEND_DEBUG
2000103285Sikob		for (i = 0; i < seg; i++) {
2001105633Ssimokawa			s = &segments[i];
2002105633Ssimokawa#if 1			/* XXX LSI Logic "< 16 byte" bug might be hit */
2003105633Ssimokawa			if (s->ds_len < 16)
2004105633Ssimokawa				printf("sbp_execute_ocb: warning, "
2005105633Ssimokawa					"segment length(%d) is less than 16."
2006105633Ssimokawa					"(seg=%d/%d)\n", s->ds_len, i+1, seg);
2007105633Ssimokawa#endif
2008105633Ssimokawa			ocb->ind_ptr[i].hi = htonl(s->ds_len << 16);
2009105633Ssimokawa			ocb->ind_ptr[i].lo = htonl(s->ds_addr);
2010103285Sikob		}
2011103285Sikob		ocb->orb[4] |= htonl(ORB_CMD_PTBL | seg);
2012103285Sikob	}
2013103285Sikob
2014103285Sikob	ccb = ocb->ccb;
2015103285Sikob	prev = sbp_enqueue_ocb(ocb->sdev, ocb);
2016103285Sikob	if (prev)
2017103285Sikob		sbp_doorbell(ocb->sdev);
2018103285Sikob	else
2019103285Sikob		sbp_orb_pointer(ocb->sdev, ocb);
2020103285Sikob}
2021103285Sikob
2022103285Sikobstatic void
2023103285Sikobsbp_poll(struct cam_sim *sim)
2024103285Sikob{
2025103285Sikob	/* should call fwohci_intr? */
2026103285Sikob	return;
2027103285Sikob}
2028103285Sikobstatic struct sbp_ocb *
2029103285Sikobsbp_dequeue_ocb(struct sbp_dev *sdev, u_int32_t orb_lo)
2030103285Sikob{
2031103285Sikob	struct sbp_ocb *ocb;
2032103285Sikob	struct sbp_ocb *next;
2033103285Sikob	int s = splfw(), order = 0;
2034103285Sikob	int flags;
2035103285Sikob
2036103285Sikob	for (ocb = STAILQ_FIRST(&sdev->ocbs); ocb != NULL; ocb = next) {
2037103285Sikob		next = STAILQ_NEXT(ocb, ocb);
2038103285Sikob		flags = ocb->flags;
2039103285SikobSBP_DEBUG(1)
2040103285Sikob		printf("orb: 0x%x next: 0x%x, flags %x\n",
2041103285Sikob			vtophys(&ocb->orb[0]), ntohl(ocb->orb[1]), flags);
2042103285SikobEND_DEBUG
2043103285Sikob		if (vtophys(&ocb->orb[0]) == orb_lo) {
2044103285Sikob			/* found */
2045103285Sikob			if (ocb->flags & OCB_RESERVED)
2046103285Sikob				ocb->flags |= OCB_DONE;
2047103285Sikob			else
2048103285Sikob				STAILQ_REMOVE(&sdev->ocbs, ocb, sbp_ocb, ocb);
2049103285Sikob			if (ocb->ccb != NULL)
2050103285Sikob				untimeout(sbp_timeout, (caddr_t)ocb,
2051103285Sikob						ocb->ccb->ccb_h.timeout_ch);
2052103285Sikob			if (ocb->dmamap != NULL) {
2053103285Sikob				bus_dmamap_destroy(sdev->target->sbp->dmat,
2054103285Sikob							ocb->dmamap);
2055103285Sikob				ocb->dmamap = NULL;
2056103285Sikob			}
2057103285Sikob			break;
2058103285Sikob		} else {
2059103285Sikob			if ((ocb->flags & OCB_RESERVED) &&
2060103285Sikob					(ocb->flags & OCB_DONE)) {
2061103285Sikob				/* next orb must be fetched already */
2062103285Sikob				STAILQ_REMOVE(&sdev->ocbs, ocb, sbp_ocb, ocb);
2063103285Sikob				sbp_free_ocb(sdev->target->sbp, ocb);
2064103285Sikob			} else
2065103285Sikob				order ++;
2066103285Sikob		}
2067103285Sikob	}
2068103285Sikob	splx(s);
2069103285SikobSBP_DEBUG(0)
2070103285Sikob	if (ocb && order > 0) {
2071103285Sikob		sbp_show_sdev_info(sdev, 2);
2072103285Sikob		printf("unordered execution order:%d\n", order);
2073103285Sikob	}
2074103285SikobEND_DEBUG
2075103285Sikob	return (ocb);
2076103285Sikob}
2077103285Sikob
2078103285Sikobstatic struct sbp_ocb *
2079103285Sikobsbp_enqueue_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb)
2080103285Sikob{
2081103285Sikob	int s = splfw();
2082103285Sikob	struct sbp_ocb *prev;
2083103285Sikob
2084103285SikobSBP_DEBUG(2)
2085103285Sikob	sbp_show_sdev_info(sdev, 2);
2086103285Sikob	printf("sbp_enqueue_ocb orb=0x%x in physical memory\n", vtophys(&ocb->orb[0]));
2087103285SikobEND_DEBUG
2088103285Sikob	prev = STAILQ_LAST(&sdev->ocbs, sbp_ocb, ocb);
2089103285Sikob	STAILQ_INSERT_TAIL(&sdev->ocbs, ocb, ocb);
2090103285Sikob
2091103285Sikob	if (ocb->ccb != NULL)
2092103285Sikob		ocb->ccb->ccb_h.timeout_ch = timeout(sbp_timeout, (caddr_t)ocb,
2093103285Sikob					(ocb->ccb->ccb_h.timeout * hz) / 1000);
2094103285Sikob
2095103285Sikob	if (prev != NULL
2096103285Sikob		&& ((prev->flags & OCB_ACT_MASK) == OCB_ACT_CMD)
2097103285Sikob		&& ((ocb->flags & OCB_ACT_MASK) == OCB_ACT_CMD)) {
2098103285SikobSBP_DEBUG(1)
2099103285Sikob	printf("linking chain 0x%x -> 0x%x\n", vtophys(&prev->orb[0]),
2100103285Sikob			vtophys(&ocb->orb[0]));
2101103285SikobEND_DEBUG
2102103285Sikob		prev->flags |= OCB_RESERVED;
2103103285Sikob		prev->orb[1] = htonl(vtophys(&ocb->orb[0]));
2104103285Sikob		prev->orb[0] = 0;
2105103285Sikob	} else {
2106103285Sikob		prev = NULL;
2107103285Sikob	}
2108103285Sikob	splx(s);
2109103285Sikob
2110103285Sikob	return prev;
2111103285Sikob}
2112103285Sikob
2113103285Sikobstatic struct sbp_ocb *
2114103285Sikobsbp_get_ocb(struct sbp_softc *sbp)
2115103285Sikob{
2116103285Sikob	struct sbp_ocb *ocb;
2117103285Sikob	int s = splfw();
2118103285Sikob	ocb = STAILQ_FIRST(&sbp->free_ocbs);
2119103285Sikob	if (ocb == NULL) {
2120103285Sikob		printf("ocb shortage!!!\n");
2121103285Sikob		return NULL;
2122103285Sikob	}
2123103285Sikob	STAILQ_REMOVE(&sbp->free_ocbs, ocb, sbp_ocb, ocb);
2124103285Sikob	splx(s);
2125103285Sikob	ocb->ccb = NULL;
2126103285Sikob	return (ocb);
2127103285Sikob}
2128103285Sikob
2129103285Sikobstatic void
2130103285Sikobsbp_free_ocb(struct sbp_softc *sbp, struct sbp_ocb *ocb)
2131103285Sikob{
2132103285Sikob#if 0 /* XXX make sure that ocb has ccb */
2133103285Sikob	if ((sbp->flags & SBP_RESOURCE_SHORTAGE) != 0 &&
2134103285Sikob	    (ocb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
2135103285Sikob		ocb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2136103285Sikob		sbp->flags &= ~SBP_RESOURCE_SHORTAGE;
2137103285Sikob	}
2138103285Sikob#else
2139103285Sikob	if ((sbp->flags & SBP_RESOURCE_SHORTAGE) != 0)
2140103285Sikob		sbp->flags &= ~SBP_RESOURCE_SHORTAGE;
2141103285Sikob#endif
2142103285Sikob	ocb->flags = 0;
2143103285Sikob	ocb->ccb = NULL;
2144103285Sikob	STAILQ_INSERT_TAIL(&sbp->free_ocbs, ocb, ocb);
2145103285Sikob}
2146103285Sikob
2147103285Sikobstatic void
2148103285Sikobsbp_abort_ocb(struct sbp_ocb *ocb, int status)
2149103285Sikob{
2150103285Sikob	struct sbp_dev *sdev;
2151103285Sikob
2152103285Sikob	sdev = ocb->sdev;
2153103285SikobSBP_DEBUG(0)
2154103285Sikob	sbp_show_sdev_info(sdev, 2);
2155103285Sikob	printf("sbp_abort_ocb 0x%x\n", status);
2156103285SikobEND_DEBUG
2157103285Sikob	STAILQ_REMOVE(&sdev->ocbs, ocb, sbp_ocb, ocb);
2158103285Sikob	if (ocb->ccb != NULL && !(ocb->flags & OCB_DONE)) {
2159103285Sikob		if (status != CAM_CMD_TIMEOUT)
2160103285Sikob			untimeout(sbp_timeout, (caddr_t)ocb,
2161103285Sikob						ocb->ccb->ccb_h.timeout_ch);
2162103285Sikob		ocb->ccb->ccb_h.status = status;
2163103285Sikob		xpt_done(ocb->ccb);
2164103285Sikob	}
2165103285Sikob	if (ocb->dmamap != NULL) {
2166103285Sikob		bus_dmamap_destroy(sdev->target->sbp->dmat, ocb->dmamap);
2167103285Sikob		ocb->dmamap = NULL;
2168103285Sikob	}
2169103285Sikob	sbp_free_ocb(sdev->target->sbp, ocb);
2170103285Sikob}
2171103285Sikob
2172103285Sikobstatic void
2173103285Sikobsbp_abort_all_ocbs(struct sbp_dev *sdev, int status)
2174103285Sikob{
2175103285Sikob	int s;
2176103285Sikob	struct sbp_ocb *ocb;
2177103285Sikob
2178103285Sikob	s = splfw();
2179103285Sikob	while ((ocb = STAILQ_FIRST(&sdev->ocbs))) {
2180103285Sikob		sbp_abort_ocb(ocb, status);
2181103285Sikob	}
2182103285Sikob	splx(s);
2183103285Sikob}
2184103285Sikob
2185103285Sikobstatic devclass_t sbp_devclass;
2186103285Sikob
2187103285Sikobstatic device_method_t sbp_methods[] = {
2188103285Sikob	/* device interface */
2189103285Sikob	DEVMETHOD(device_identify,	sbp_identify),
2190103285Sikob	DEVMETHOD(device_probe,		sbp_probe),
2191103285Sikob	DEVMETHOD(device_attach,	sbp_attach),
2192103285Sikob	DEVMETHOD(device_detach,	sbp_detach),
2193103285Sikob
2194103285Sikob	{ 0, 0 }
2195103285Sikob};
2196103285Sikob
2197103285Sikobstatic driver_t sbp_driver = {
2198103285Sikob	"sbp",
2199103285Sikob	sbp_methods,
2200103285Sikob	sizeof(struct sbp_softc),
2201103285Sikob};
2202103285SikobDRIVER_MODULE(sbp, firewire, sbp_driver, sbp_devclass, 0, 0);
2203103285SikobMODULE_VERSION(sbp, 1);
2204103285SikobMODULE_DEPEND(sbp, firewire, 1, 1, 1);
2205103285SikobMODULE_DEPEND(sbp, cam, 1, 1, 1);
2206