| @@ -1,3246 +0,0 @@ | | | @@ -1,3246 +0,0 @@ |
1 | /* $NetBSD: sbp.c,v 1.23 2009/01/03 03:43:22 yamt Exp $ */ | | | |
2 | /*- | | | |
3 | * Copyright (c) 2003 Hidetoshi Shimokawa | | | |
4 | * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa | | | |
5 | * All rights reserved. | | | |
6 | * | | | |
7 | * Redistribution and use in source and binary forms, with or without | | | |
8 | * modification, are permitted provided that the following conditions | | | |
9 | * are met: | | | |
10 | * 1. Redistributions of source code must retain the above copyright | | | |
11 | * notice, this list of conditions and the following disclaimer. | | | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | | |
13 | * notice, this list of conditions and the following disclaimer in the | | | |
14 | * documentation and/or other materials provided with the distribution. | | | |
15 | * 3. All advertising materials mentioning features or use of this software | | | |
16 | * must display the acknowledgement as bellow: | | | |
17 | * | | | |
18 | * This product includes software developed by K. Kobayashi and H. Shimokawa | | | |
19 | * | | | |
20 | * 4. The name of the author may not be used to endorse or promote products | | | |
21 | * derived from this software without specific prior written permission. | | | |
22 | * | | | |
23 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | | |
24 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | | | |
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | | | |
26 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | | | |
27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | | | |
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | | |
29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | | |
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | | | |
31 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | | | |
32 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | | |
33 | * POSSIBILITY OF SUCH DAMAGE. | | | |
34 | * | | | |
35 | * $FreeBSD: src/sys/dev/firewire/sbp.c,v 1.92 2007/06/06 14:31:36 simokawa Exp $ | | | |
36 | * | | | |
37 | */ | | | |
38 | | | | |
39 | #include <sys/cdefs.h> | | | |
40 | __KERNEL_RCSID(0, "$NetBSD: sbp.c,v 1.23 2009/01/03 03:43:22 yamt Exp $"); | | | |
41 | | | | |
42 | #if defined(__FreeBSD__) | | | |
43 | #include <sys/param.h> | | | |
44 | #include <sys/systm.h> | | | |
45 | #include <sys/conf.h> | | | |
46 | #include <sys/module.h> | | | |
47 | #include <sys/bus.h> | | | |
48 | #include <sys/kernel.h> | | | |
49 | #include <sys/sysctl.h> | | | |
50 | #include <sys/bus.h> | | | |
51 | #include <sys/malloc.h> | | | |
52 | #if defined(__FreeBSD__) && __FreeBSD_version >= 501102 | | | |
53 | #include <sys/lock.h> | | | |
54 | #include <sys/mutex.h> | | | |
55 | #endif | | | |
56 | | | | |
57 | #if defined(__DragonFly__) || __FreeBSD_version < 500106 | | | |
58 | #include <sys/devicestat.h> /* for struct devstat */ | | | |
59 | #endif | | | |
60 | | | | |
61 | #ifdef __DragonFly__ | | | |
62 | #include <bus/cam/cam.h> | | | |
63 | #include <bus/cam/cam_ccb.h> | | | |
64 | #include <bus/cam/cam_sim.h> | | | |
65 | #include <bus/cam/cam_xpt_sim.h> | | | |
66 | #include <bus/cam/cam_debug.h> | | | |
67 | #include <bus/cam/cam_periph.h> | | | |
68 | #include <bus/cam/scsi/scsi_all.h> | | | |
69 | | | | |
70 | #include <bus/firewire/fw_port.h> | | | |
71 | #include <bus/firewire/firewire.h> | | | |
72 | #include <bus/firewire/firewirereg.h> | | | |
73 | #include <bus/firewire/fwdma.h> | | | |
74 | #include <bus/firewire/iec13213.h> | | | |
75 | #include "sbp.h" | | | |
76 | #else | | | |
77 | #include <cam/cam.h> | | | |
78 | #include <cam/cam_ccb.h> | | | |
79 | #include <cam/cam_sim.h> | | | |
80 | #include <cam/cam_xpt_sim.h> | | | |
81 | #include <cam/cam_debug.h> | | | |
82 | #include <cam/cam_periph.h> | | | |
83 | #include <cam/scsi/scsi_all.h> | | | |
84 | | | | |
85 | #include <dev/firewire/fw_port.h> | | | |
86 | #include <dev/firewire/firewire.h> | | | |
87 | #include <dev/firewire/firewirereg.h> | | | |
88 | #include <dev/firewire/fwdma.h> | | | |
89 | #include <dev/firewire/iec13213.h> | | | |
90 | #include <dev/firewire/sbp.h> | | | |
91 | #endif | | | |
92 | #elif defined(__NetBSD__) | | | |
93 | #include <sys/param.h> | | | |
94 | #include <sys/device.h> | | | |
95 | #include <sys/errno.h> | | | |
96 | #include <sys/buf.h> | | | |
97 | #include <sys/kernel.h> | | | |
98 | #include <sys/kthread.h> | | | |
99 | #include <sys/malloc.h> | | | |
100 | #include <sys/proc.h> | | | |
101 | #include <sys/sysctl.h> | | | |
102 | | | | |
103 | #include <sys/bus.h> | | | |
104 | | | | |
105 | #include <dev/scsipi/scsi_spc.h> | | | |
106 | #include <dev/scsipi/scsi_all.h> | | | |
107 | #include <dev/scsipi/scsipi_all.h> | | | |
108 | #include <dev/scsipi/scsiconf.h> | | | |
109 | #include <dev/scsipi/scsipiconf.h> | | | |
110 | | | | |
111 | #include <dev/ieee1394/fw_port.h> | | | |
112 | #include <dev/ieee1394/firewire.h> | | | |
113 | #include <dev/ieee1394/firewirereg.h> | | | |
114 | #include <dev/ieee1394/fwdma.h> | | | |
115 | #include <dev/ieee1394/iec13213.h> | | | |
116 | #include <dev/ieee1394/sbp.h> | | | |
117 | | | | |
118 | #include "locators.h" | | | |
119 | #endif | | | |
120 | | | | |
121 | #define ccb_sdev_ptr spriv_ptr0 | | | |
122 | #define ccb_sbp_ptr spriv_ptr1 | | | |
123 | | | | |
124 | #define SBP_NUM_TARGETS 8 /* MAX 64 */ | | | |
125 | /* | | | |
126 | * Scan_bus doesn't work for more than 8 LUNs | | | |
127 | * because of CAM_SCSI2_MAXLUN in cam_xpt.c | | | |
128 | */ | | | |
129 | #define SBP_NUM_LUNS 64 | | | |
130 | #define SBP_MAXPHYS MIN(MAXPHYS, (512*1024) /* 512KB */) | | | |
131 | #define SBP_DMA_SIZE PAGE_SIZE | | | |
132 | #define SBP_LOGIN_SIZE sizeof(struct sbp_login_res) | | | |
133 | #define SBP_QUEUE_LEN ((SBP_DMA_SIZE - SBP_LOGIN_SIZE) / sizeof(struct sbp_ocb)) | | | |
134 | #define SBP_NUM_OCB (SBP_QUEUE_LEN * SBP_NUM_TARGETS) | | | |
135 | | | | |
136 | /* | | | |
137 | * STATUS FIFO addressing | | | |
138 | * bit | | | |
139 | * ----------------------- | | | |
140 | * 0- 1( 2): 0 (alignment) | | | |
141 | * 2- 9( 8): lun | | | |
142 | * 10-31(14): unit | | | |
143 | * 32-47(16): SBP_BIND_HI | | | |
144 | * 48-64(16): bus_id, node_id | | | |
145 | */ | | | |
146 | #define SBP_BIND_HI 0x1 | | | |
147 | #define SBP_DEV2ADDR(u, l) \ | | | |
148 | (((u_int64_t)SBP_BIND_HI << 32) \ | | | |
149 | | (((u) & 0x3fff) << 10) \ | | | |
150 | | (((l) & 0xff) << 2)) | | | |
151 | #define SBP_ADDR2UNIT(a) (((a) >> 10) & 0x3fff) | | | |
152 | #define SBP_ADDR2LUN(a) (((a) >> 2) & 0xff) | | | |
153 | #define SBP_INITIATOR 7 | | | |
154 | | | | |
155 | static const char *orb_fun_name[] = { | | | |
156 | ORB_FUN_NAMES | | | |
157 | }; | | | |
158 | | | | |
159 | static int debug = 0; | | | |
160 | static int auto_login = 1; | | | |
161 | static int max_speed = -1; | | | |
162 | static int sbp_cold = 1; | | | |
163 | static int ex_login = 1; | | | |
164 | static int login_delay = 1000; /* msec */ | | | |
165 | static int scan_delay = 500; /* msec */ | | | |
166 | static int use_doorbell = 0; | | | |
167 | static int sbp_tags = 0; | | | |
168 | | | | |
169 | #if defined(__FreeBSD__) | | | |
170 | SYSCTL_DECL(_hw_firewire); | | | |
171 | SYSCTL_NODE(_hw_firewire, OID_AUTO, sbp, CTLFLAG_RD, 0, "SBP-II Subsystem"); | | | |
172 | SYSCTL_INT(_debug, OID_AUTO, sbp_debug, CTLFLAG_RW, &debug, 0, | | | |
173 | "SBP debug flag"); | | | |
174 | SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, auto_login, CTLFLAG_RW, &auto_login, 0, | | | |
175 | "SBP perform login automatically"); | | | |
176 | SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, max_speed, CTLFLAG_RW, &max_speed, 0, | | | |
177 | "SBP transfer max speed"); | | | |
178 | SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, exclusive_login, CTLFLAG_RW, | | | |
179 | &ex_login, 0, "SBP enable exclusive login"); | | | |
180 | SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, login_delay, CTLFLAG_RW, | | | |
181 | &login_delay, 0, "SBP login delay in msec"); | | | |
182 | SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, scan_delay, CTLFLAG_RW, | | | |
183 | &scan_delay, 0, "SBP scan delay in msec"); | | | |
184 | SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, use_doorbell, CTLFLAG_RW, | | | |
185 | &use_doorbell, 0, "SBP use doorbell request"); | | | |
186 | SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, tags, CTLFLAG_RW, &sbp_tags, 0, | | | |
187 | "SBP tagged queuing support"); | | | |
188 | | | | |
189 | TUNABLE_INT("hw.firewire.sbp.auto_login", &auto_login); | | | |
190 | TUNABLE_INT("hw.firewire.sbp.max_speed", &max_speed); | | | |
191 | TUNABLE_INT("hw.firewire.sbp.exclusive_login", &ex_login); | | | |
192 | TUNABLE_INT("hw.firewire.sbp.login_delay", &login_delay); | | | |
193 | TUNABLE_INT("hw.firewire.sbp.scan_delay", &scan_delay); | | | |
194 | TUNABLE_INT("hw.firewire.sbp.use_doorbell", &use_doorbell); | | | |
195 | TUNABLE_INT("hw.firewire.sbp.tags", &sbp_tags); | | | |
196 | #elif defined(__NetBSD__) | | | |
197 | static int sysctl_sbp_verify(SYSCTLFN_PROTO, int lower, int upper); | | | |
198 | static int sysctl_sbp_verify_max_speed(SYSCTLFN_PROTO); | | | |
199 | static int sysctl_sbp_verify_tags(SYSCTLFN_PROTO); | | | |
200 | | | | |
201 | /* | | | |
202 | * Setup sysctl(3) MIB, hw.sbp.* | | | |
203 | * | | | |
204 | * TBD condition CTLFLAG_PERMANENT on being a module or not | | | |
205 | */ | | | |
206 | SYSCTL_SETUP(sysctl_sbp, "sysctl sbp(4) subtree setup") | | | |
207 | { | | | |
208 | int rc, sbp_node_num; | | | |
209 | const struct sysctlnode *node; | | | |
210 | | | | |
211 | if ((rc = sysctl_createv(clog, 0, NULL, NULL, | | | |
212 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL, | | | |
213 | NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) { | | | |
214 | goto err; | | | |
215 | } | | | |
216 | | | | |
217 | if ((rc = sysctl_createv(clog, 0, NULL, &node, | | | |
218 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "sbp", | | | |
219 | SYSCTL_DESCR("sbp controls"), NULL, 0, NULL, | | | |
220 | 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) { | | | |
221 | goto err; | | | |
222 | } | | | |
223 | sbp_node_num = node->sysctl_num; | | | |
224 | | | | |
225 | /* sbp auto login flag */ | | | |
226 | if ((rc = sysctl_createv(clog, 0, NULL, &node, | | | |
227 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | | | |
228 | "auto_login", SYSCTL_DESCR("SBP perform login automatically"), | | | |
229 | NULL, 0, &auto_login, | | | |
230 | 0, CTL_HW, sbp_node_num, CTL_CREATE, CTL_EOL)) != 0) { | | | |
231 | goto err; | | | |
232 | } | | | |
233 | | | | |
234 | /* sbp max speed */ | | | |
235 | if ((rc = sysctl_createv(clog, 0, NULL, &node, | | | |
236 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | | | |
237 | "max_speed", SYSCTL_DESCR("SBP transfer max speed"), | | | |
238 | sysctl_sbp_verify_max_speed, 0, &max_speed, | | | |
239 | 0, CTL_HW, sbp_node_num, CTL_CREATE, CTL_EOL)) != 0) { | | | |
240 | goto err; | | | |
241 | } | | | |
242 | | | | |
243 | /* sbp exclusive login flag */ | | | |
244 | if ((rc = sysctl_createv(clog, 0, NULL, &node, | | | |
245 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | | | |
246 | "exclusive_login", SYSCTL_DESCR("SBP enable exclusive login"), | | | |
247 | NULL, 0, &ex_login, | | | |
248 | 0, CTL_HW, sbp_node_num, CTL_CREATE, CTL_EOL)) != 0) { | | | |
249 | goto err; | | | |
250 | } | | | |
251 | | | | |
252 | /* sbp login delay */ | | | |
253 | if ((rc = sysctl_createv(clog, 0, NULL, &node, | | | |
254 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | | | |
255 | "login_delay", SYSCTL_DESCR("SBP login delay in msec"), | | | |
256 | NULL, 0, &login_delay, | | | |
257 | 0, CTL_HW, sbp_node_num, CTL_CREATE, CTL_EOL)) != 0) { | | | |
258 | goto err; | | | |
259 | } | | | |
260 | | | | |
261 | /* sbp scan delay */ | | | |
262 | if ((rc = sysctl_createv(clog, 0, NULL, &node, | | | |
263 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | | | |
264 | "scan_delay", SYSCTL_DESCR("SBP scan delay in msec"), | | | |
265 | NULL, 0, &scan_delay, | | | |
266 | 0, CTL_HW, sbp_node_num, CTL_CREATE, CTL_EOL)) != 0) { | | | |
267 | goto err; | | | |
268 | } | | | |
269 | | | | |
270 | /* sbp use doorbell flag */ | | | |
271 | if ((rc = sysctl_createv(clog, 0, NULL, &node, | | | |
272 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | | | |
273 | "use_doorbell", SYSCTL_DESCR("SBP use doorbell request"), | | | |
274 | NULL, 0, &use_doorbell, | | | |
275 | 0, CTL_HW, sbp_node_num, CTL_CREATE, CTL_EOL)) != 0) { | | | |
276 | goto err; | | | |
277 | } | | | |
278 | | | | |
279 | /* sbp force tagged queuing */ | | | |
280 | if ((rc = sysctl_createv(clog, 0, NULL, &node, | | | |
281 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | | | |
282 | "tags", SYSCTL_DESCR("SBP tagged queuing support"), | | | |
283 | sysctl_sbp_verify_tags, 0, &sbp_tags, | | | |
284 | 0, CTL_HW, sbp_node_num, CTL_CREATE, CTL_EOL)) != 0) { | | | |
285 | goto err; | | | |
286 | } | | | |
287 | | | | |
288 | /* sbp driver debug flag */ | | | |
289 | if ((rc = sysctl_createv(clog, 0, NULL, &node, | | | |
290 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | | | |
291 | "sbp_debug", SYSCTL_DESCR("SBP debug flag"), | | | |
292 | NULL, 0, &debug, | | | |
293 | 0, CTL_HW, sbp_node_num, CTL_CREATE, CTL_EOL)) != 0) { | | | |
294 | goto err; | | | |
295 | } | | | |
296 | | | | |
297 | return; | | | |
298 | | | | |
299 | err: | | | |
300 | printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); | | | |
301 | } | | | |
302 | | | | |
303 | static int | | | |
304 | sysctl_sbp_verify(SYSCTLFN_ARGS, int lower, int upper) | | | |
305 | { | | | |
306 | int error, t; | | | |
307 | struct sysctlnode node; | | | |
308 | | | | |
309 | node = *rnode; | | | |
310 | t = *(int*)rnode->sysctl_data; | | | |
311 | node.sysctl_data = &t; | | | |
312 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); | | | |
313 | if (error || newp == NULL) | | | |
314 | return (error); | | | |
315 | | | | |
316 | if (t < lower || t > upper) | | | |
317 | return (EINVAL); | | | |
318 | | | | |
319 | *(int*)rnode->sysctl_data = t; | | | |
320 | | | | |
321 | return (0); | | | |
322 | } | | | |
323 | | | | |
324 | static int | | | |
325 | sysctl_sbp_verify_max_speed(SYSCTLFN_ARGS) | | | |
326 | { | | | |
327 | return (sysctl_sbp_verify(SYSCTLFN_CALL(rnode), 0, FWSPD_S400)); | | | |
328 | } | | | |
329 | | | | |
330 | static int | | | |
331 | sysctl_sbp_verify_tags(SYSCTLFN_ARGS) | | | |
332 | { | | | |
333 | return (sysctl_sbp_verify(SYSCTLFN_CALL(rnode), -1, 1)); | | | |
334 | } | | | |
335 | #endif | | | |
336 | | | | |
337 | #define NEED_RESPONSE 0 | | | |
338 | | | | |
339 | #define SBP_SEG_MAX rounddown(0xffff, PAGE_SIZE) | | | |
340 | #ifdef __sparc64__ /* iommu */ | | | |
341 | #define SBP_IND_MAX howmany(SBP_MAXPHYS, SBP_SEG_MAX) | | | |
342 | #else | | | |
343 | #define SBP_IND_MAX howmany(SBP_MAXPHYS, PAGE_SIZE) | | | |
344 | #endif | | | |
345 | struct sbp_ocb { | | | |
346 | STAILQ_ENTRY(sbp_ocb) ocb; | | | |
347 | sbp_scsi_xfer *sxfer; | | | |
348 | bus_addr_t bus_addr; | | | |
349 | uint32_t orb[8]; | | | |
350 | #define IND_PTR_OFFSET (8*sizeof(uint32_t)) | | | |
351 | struct ind_ptr ind_ptr[SBP_IND_MAX]; | | | |
352 | struct sbp_dev *sdev; | | | |
353 | int flags; /* XXX should be removed */ | | | |
354 | bus_dmamap_t dmamap; | | | |
355 | }; | | | |
356 | | | | |
357 | #define OCB_ACT_MGM 0 | | | |
358 | #define OCB_ACT_CMD 1 | | | |
359 | #define OCB_MATCH(o,s) ((o)->bus_addr == ntohl((s)->orb_lo)) | | | |
360 | | | | |
361 | struct sbp_dev{ | | | |
362 | #define SBP_DEV_RESET 0 /* accept login */ | | | |
363 | #define SBP_DEV_LOGIN 1 /* to login */ | | | |
364 | #if 0 | | | |
365 | #define SBP_DEV_RECONN 2 /* to reconnect */ | | | |
366 | #endif | | | |
367 | #define SBP_DEV_TOATTACH 3 /* to attach */ | | | |
368 | #define SBP_DEV_PROBE 4 /* scan lun */ | | | |
369 | #define SBP_DEV_ATTACHED 5 /* in operation */ | | | |
370 | #define SBP_DEV_DEAD 6 /* unavailable unit */ | | | |
371 | #define SBP_DEV_RETRY 7 /* unavailable unit */ | | | |
372 | uint8_t status:4, | | | |
373 | timeout:4; | | | |
374 | uint8_t type; | | | |
375 | uint16_t lun_id; | | | |
376 | uint16_t freeze; | | | |
377 | #define ORB_LINK_DEAD (1 << 0) | | | |
378 | #define VALID_LUN (1 << 1) | | | |
379 | #define ORB_POINTER_ACTIVE (1 << 2) | | | |
380 | #define ORB_POINTER_NEED (1 << 3) | | | |
381 | #define ORB_DOORBELL_ACTIVE (1 << 4) | | | |
382 | #define ORB_DOORBELL_NEED (1 << 5) | | | |
383 | #define ORB_SHORTAGE (1 << 6) | | | |
384 | uint16_t flags; | | | |
385 | #if defined(__FreeBSD__) | | | |
386 | struct cam_path *path; | | | |
387 | #elif defined(__NetBSD__) | | | |
388 | struct scsipi_periph *periph; | | | |
389 | #endif | | | |
390 | struct sbp_target *target; | | | |
391 | struct fwdma_alloc dma; | | | |
392 | struct sbp_login_res *login; | | | |
393 | struct callout login_callout; | | | |
394 | struct sbp_ocb *ocb; | | | |
395 | STAILQ_HEAD(, sbp_ocb) ocbs; | | | |
396 | STAILQ_HEAD(, sbp_ocb) free_ocbs; | | | |
397 | struct sbp_ocb *last_ocb; | | | |
398 | char vendor[32]; | | | |
399 | char product[32]; | | | |
400 | char revision[10]; | | | |
401 | }; | | | |
402 | | | | |
403 | struct sbp_target { | | | |
404 | int target_id; | | | |
405 | int num_lun; | | | |
406 | struct sbp_dev **luns; | | | |
407 | struct sbp_softc *sbp; | | | |
408 | struct fw_device *fwdev; | | | |
409 | uint32_t mgm_hi, mgm_lo; | | | |
410 | struct sbp_ocb *mgm_ocb_cur; | | | |
411 | STAILQ_HEAD(, sbp_ocb) mgm_ocb_queue; | | | |
412 | struct callout mgm_ocb_timeout; | | | |
413 | struct callout scan_callout; | | | |
414 | STAILQ_HEAD(, fw_xfer) xferlist; | | | |
415 | int n_xfer; | | | |
416 | }; | | | |
417 | | | | |
418 | struct sbp_softc { | | | |
419 | struct firewire_dev_comm fd; | | | |
420 | #if defined(__FreeBSD__) | | | |
421 | struct cam_sim *sim; | | | |
422 | struct cam_path *path; | | | |
423 | #elif defined(__NetBSD__) | | | |
424 | struct scsipi_adapter sc_adapter; | | | |
425 | struct scsipi_channel sc_channel; | | | |
426 | device_t sc_bus; | | | |
427 | struct lwp *lwp; | | | |
428 | #endif | | | |
429 | struct sbp_target target; | | | |
430 | struct fw_bind fwb; | | | |
431 | fw_bus_dma_tag_t dmat; | | | |
432 | struct timeval last_busreset; | | | |
433 | #define SIMQ_FREEZED 1 | | | |
434 | int flags; | | | |
435 | fw_mtx_t mtx; | | | |
436 | }; | | | |
437 | #define SBP_LOCK(sbp) fw_mtx_lock(&(sbp)->mtx) | | | |
438 | #define SBP_UNLOCK(sbp) fw_mtx_unlock(&(sbp)->mtx) | | | |
439 | | | | |
440 | #if defined(__NetBSD__) | | | |
441 | int sbpmatch (device_t, struct cfdata *, void *); | | | |
442 | void sbpattach (device_t parent, device_t self, void *aux); | | | |
443 | int sbpdetach (device_t self, int flags); | | | |
444 | #endif | | | |
445 | static void sbp_post_explore (void *); | | | |
446 | static void sbp_recv (struct fw_xfer *); | | | |
447 | static void sbp_mgm_callback (struct fw_xfer *); | | | |
448 | #if 0 | | | |
449 | static void sbp_cmd_callback (struct fw_xfer *); | | | |
450 | #endif | | | |
451 | static void sbp_orb_pointer (struct sbp_dev *, struct sbp_ocb *); | | | |
452 | static void sbp_doorbell(struct sbp_dev *); | | | |
453 | static void sbp_execute_ocb (void *, bus_dma_segment_t *, int, int); | | | |
454 | static void sbp_free_ocb (struct sbp_dev *, struct sbp_ocb *); | | | |
455 | static void sbp_abort_ocb (struct sbp_ocb *, int); | | | |
456 | static void sbp_abort_all_ocbs (struct sbp_dev *, int); | | | |
457 | static struct fw_xfer * sbp_write_cmd (struct sbp_dev *, int, int); | | | |
458 | static struct sbp_ocb * sbp_get_ocb (struct sbp_dev *); | | | |
459 | static struct sbp_ocb * sbp_enqueue_ocb (struct sbp_dev *, struct sbp_ocb *); | | | |
460 | static struct sbp_ocb * sbp_dequeue_ocb (struct sbp_dev *, struct sbp_status *); | | | |
461 | static void sbp_free_sdev(struct sbp_dev *); | | | |
462 | static void sbp_free_target (struct sbp_target *); | | | |
463 | static void sbp_mgm_timeout (void *arg); | | | |
464 | static void sbp_timeout (void *arg); | | | |
465 | static void sbp_mgm_orb (struct sbp_dev *, int, struct sbp_ocb *); | | | |
466 | #if defined(__FreeBSD__) | | | |
467 | | | | |
468 | MALLOC_DEFINE(M_SBP, "sbp", "SBP-II/FireWire"); | | | |
469 | #elif defined(__NetBSD__) | | | |
470 | static void sbp_scsipi_request( | | | |
471 | struct scsipi_channel *, scsipi_adapter_req_t, void *); | | | |
472 | static void sbp_minphys(struct buf *); | | | |
473 | | | | |
474 | MALLOC_DEFINE(M_SBP, "sbp", "SBP-II/IEEE1394"); | | | |
475 | #endif | | | |
476 | | | | |
477 | #if defined(__FreeBSD__) | | | |
478 | /* cam related functions */ | | | |
479 | static void sbp_action(struct cam_sim *, sbp_scsi_xfer *sxfer); | | | |
480 | static void sbp_poll(struct cam_sim *); | | | |
481 | static void sbp_cam_scan_lun(struct cam_periph *, sbp_scsi_xfer *); | | | |
482 | static void sbp_cam_scan_target(void *); | | | |
483 | static void sbp_cam_detach_sdev(struct sbp_dev *); | | | |
484 | static void sbp_cam_detach_target (struct sbp_target *); | | | |
485 | #define SBP_DETACH_SDEV(sd) sbp_cam_detach_sdev((sd)) | | | |
486 | #define SBP_DETACH_TARGET(st) sbp_cam_detach_target((st)) | | | |
487 | #elif defined(__NetBSD__) | | | |
488 | /* scsipi related functions */ | | | |
489 | static void sbp_scsipi_scan_target(void *); | | | |
490 | static void sbp_scsipi_detach_sdev(struct sbp_dev *); | | | |
491 | static void sbp_scsipi_detach_target (struct sbp_target *); | | | |
492 | #define SBP_DETACH_SDEV(sd) sbp_scsipi_detach_sdev((sd)) | | | |
493 | #define SBP_DETACH_TARGET(st) sbp_scsipi_detach_target((st)) | | | |
494 | #endif | | | |
495 | | | | |
496 | static const char *orb_status0[] = { | | | |
497 | /* 0 */ "No additional information to report", | | | |
498 | /* 1 */ "Request type not supported", | | | |
499 | /* 2 */ "Speed not supported", | | | |
500 | /* 3 */ "Page size not supported", | | | |
501 | /* 4 */ "Access denied", | | | |
502 | /* 5 */ "Logical unit not supported", | | | |
503 | /* 6 */ "Maximum payload too small", | | | |
504 | /* 7 */ "Reserved for future standardization", | | | |
505 | /* 8 */ "Resources unavailable", | | | |
506 | /* 9 */ "Function rejected", | | | |
507 | /* A */ "Login ID not recognized", | | | |
508 | /* B */ "Dummy ORB completed", | | | |
509 | /* C */ "Request aborted", | | | |
510 | /* FF */ "Unspecified error" | | | |
511 | #define MAX_ORB_STATUS0 0xd | | | |
512 | }; | | | |
513 | | | | |
514 | static const char *orb_status1_object[] = { | | | |
515 | /* 0 */ "Operation request block (ORB)", | | | |
516 | /* 1 */ "Data buffer", | | | |
517 | /* 2 */ "Page table", | | | |
518 | /* 3 */ "Unable to specify" | | | |
519 | }; | | | |
520 | | | | |
521 | static const char *orb_status1_serial_bus_error[] = { | | | |
522 | /* 0 */ "Missing acknowledge", | | | |
523 | /* 1 */ "Reserved; not to be used", | | | |
524 | /* 2 */ "Time-out error", | | | |
525 | /* 3 */ "Reserved; not to be used", | | | |
526 | /* 4 */ "Busy retry limit exceeded(X)", | | | |
527 | /* 5 */ "Busy retry limit exceeded(A)", | | | |
528 | /* 6 */ "Busy retry limit exceeded(B)", | | | |
529 | /* 7 */ "Reserved for future standardization", | | | |
530 | /* 8 */ "Reserved for future standardization", | | | |
531 | /* 9 */ "Reserved for future standardization", | | | |
532 | /* A */ "Reserved for future standardization", | | | |
533 | /* B */ "Tardy retry limit exceeded", | | | |
534 | /* C */ "Conflict error", | | | |
535 | /* D */ "Data error", | | | |
536 | /* E */ "Type error", | | | |
537 | /* F */ "Address error" | | | |
538 | }; | | | |
539 | | | | |
540 | #if defined(__FreeBSD__) | | | |
541 | #if 0 | | | |
542 | static void | | | |
543 | sbp_identify(driver_t *driver, device_t parent) | | | |
544 | { | | | |
545 | device_t child; | | | |
546 | SBP_DEBUG(0) | | | |
547 | printf("sbp_identify\n"); | | | |
548 | END_DEBUG | | | |
549 | | | | |
550 | child = BUS_ADD_CHILD(parent, 0, "sbp", fw_get_unit(parent)); | | | |
551 | } | | | |
552 | #endif | | | |
553 | | | | |
554 | /* | | | |
555 | * sbp_probe() | | | |
556 | */ | | | |
557 | static int | | | |
558 | sbp_probe(device_t dev) | | | |
559 | { | | | |
560 | device_t pa; | | | |
561 | | | | |
562 | SBP_DEBUG(0) | | | |
563 | printf("sbp_probe\n"); | | | |
564 | END_DEBUG | | | |
565 | | | | |
566 | pa = device_get_parent(dev); | | | |
567 | if(fw_get_unit(dev) != fw_get_unit(pa)){ | | | |
568 | return(ENXIO); | | | |
569 | } | | | |
570 | | | | |
571 | device_set_desc(dev, "SBP-2/SCSI over FireWire"); | | | |
572 | | | | |
573 | #if 0 | | | |
574 | if (bootverbose) | | | |
575 | debug = bootverbose; | | | |
576 | #endif | | | |
577 | | | | |
578 | return (0); | | | |
579 | } | | | |
580 | #elif defined(__NetBSD__) | | | |
581 | int | | | |
582 | sbpmatch(device_t parent, struct cfdata *cf, void *aux) | | | |
583 | { | | | |
584 | struct fw_attach_args *fwa = aux; | | | |
585 | | | | |
586 | if (strcmp(fwa->name, "sbp") == 0) | | | |
587 | return 1; | | | |
588 | return 0; | | | |
589 | } | | | |
590 | #endif | | | |
591 | | | | |
592 | static void | | | |
593 | sbp_show_sdev_info(struct sbp_dev *sdev, int new) | | | |
594 | { | | | |
595 | struct fw_device *fwdev; | | | |
596 | | | | |
597 | printf("%s:%d:%d ", | | | |
598 | fw_get_nameunit(sdev->target->sbp->fd.dev), | | | |
599 | sdev->target->target_id, | | | |
600 | sdev->lun_id | | | |
601 | ); | | | |
602 | if (new == 2) { | | | |
603 | return; | | | |
604 | } | | | |
605 | fwdev = sdev->target->fwdev; | | | |
606 | printf("ordered:%d type:%d EUI:%08x%08x node:%d " | | | |
607 | "speed:%d maxrec:%d", | | | |
608 | (sdev->type & 0x40) >> 6, | | | |
609 | (sdev->type & 0x1f), | | | |
610 | fwdev->eui.hi, | | | |
611 | fwdev->eui.lo, | | | |
612 | fwdev->dst, | | | |
613 | fwdev->speed, | | | |
614 | fwdev->maxrec | | | |
615 | ); | | | |
616 | if (new) | | | |
617 | printf(" new!\n"); | | | |
618 | else | | | |
619 | printf("\n"); | | | |
620 | sbp_show_sdev_info(sdev, 2); | | | |
621 | printf("'%s' '%s' '%s'\n", sdev->vendor, sdev->product, sdev->revision); | | | |
622 | } | | | |
623 | | | | |
624 | static void | | | |
625 | sbp_alloc_lun(struct sbp_target *target) | | | |
626 | { | | | |
627 | struct crom_context cc; | | | |
628 | struct csrreg *reg; | | | |
629 | struct sbp_dev *sdev, **newluns; | | | |
630 | struct sbp_softc *sbp; | | | |
631 | int maxlun, lun, i; | | | |
632 | | | | |
633 | sbp = target->sbp; | | | |
634 | crom_init_context(&cc, target->fwdev->csrrom); | | | |
635 | /* XXX shoud parse appropriate unit directories only */ | | | |
636 | maxlun = -1; | | | |
637 | while (cc.depth >= 0) { | | | |
638 | reg = crom_search_key(&cc, CROM_LUN); | | | |
639 | if (reg == NULL) | | | |
640 | break; | | | |
641 | lun = reg->val & 0xffff; | | | |
642 | SBP_DEBUG(0) | | | |
643 | printf("target %d lun %d found\n", target->target_id, lun); | | | |
644 | END_DEBUG | | | |
645 | if (maxlun < lun) | | | |
646 | maxlun = lun; | | | |
647 | crom_next(&cc); | | | |
648 | } | | | |
649 | if (maxlun < 0) | | | |
650 | printf("%s:%d no LUN found\n", | | | |
651 | fw_get_nameunit(target->sbp->fd.dev), | | | |
652 | target->target_id); | | | |
653 | | | | |
654 | maxlun ++; | | | |
655 | if (maxlun >= SBP_NUM_LUNS) | | | |
656 | maxlun = SBP_NUM_LUNS; | | | |
657 | | | | |
658 | /* Invalidiate stale devices */ | | | |
659 | for (lun = 0; lun < target->num_lun; lun ++) { | | | |
660 | sdev = target->luns[lun]; | | | |
661 | if (sdev == NULL) | | | |
662 | continue; | | | |
663 | sdev->flags &= ~VALID_LUN; | | | |
664 | if (lun >= maxlun) { | | | |
665 | /* lost device */ | | | |
666 | SBP_DETACH_SDEV(sdev); | | | |
667 | sbp_free_sdev(sdev); | | | |
668 | } | | | |
669 | } | | | |
670 | | | | |
671 | /* Reallocate */ | | | |
672 | if (maxlun != target->num_lun) { | | | |
673 | newluns = (struct sbp_dev **) realloc(target->luns, | | | |
674 | sizeof(struct sbp_dev *) * maxlun, | | | |
675 | M_SBP, M_NOWAIT | M_ZERO); | | | |
676 | | | | |
677 | if (newluns == NULL) { | | | |
678 | printf("%s: realloc failed\n", __func__); | | | |
679 | newluns = target->luns; | | | |
680 | maxlun = target->num_lun; | | | |
681 | } | | | |
682 | | | | |
683 | /* | | | |
684 | * We must zero the extended region for the case | | | |
685 | * realloc() doesn't allocate new buffer. | | | |
686 | */ | | | |
687 | if (maxlun > target->num_lun) | | | |
688 | bzero(&newluns[target->num_lun], | | | |
689 | sizeof(struct sbp_dev *) * | | | |
690 | (maxlun - target->num_lun)); | | | |
691 | | | | |
692 | target->luns = newluns; | | | |
693 | target->num_lun = maxlun; | | | |
694 | } | | | |
695 | | | | |
696 | crom_init_context(&cc, target->fwdev->csrrom); | | | |
697 | while (cc.depth >= 0) { | | | |
698 | int new = 0; | | | |
699 | | | | |
700 | reg = crom_search_key(&cc, CROM_LUN); | | | |
701 | if (reg == NULL) | | | |
702 | break; | | | |
703 | lun = reg->val & 0xffff; | | | |
704 | if (lun >= SBP_NUM_LUNS) { | | | |
705 | printf("too large lun %d\n", lun); | | | |
706 | goto next; | | | |
707 | } | | | |
708 | | | | |
709 | sdev = target->luns[lun]; | | | |
710 | if (sdev == NULL) { | | | |
711 | sdev = malloc(sizeof(struct sbp_dev), | | | |
712 | M_SBP, M_NOWAIT | M_ZERO); | | | |
713 | if (sdev == NULL) { | | | |
714 | printf("%s: malloc failed\n", __func__); | | | |
715 | goto next; | | | |
716 | } | | | |
717 | target->luns[lun] = sdev; | | | |
718 | sdev->lun_id = lun; | | | |
719 | sdev->target = target; | | | |
720 | STAILQ_INIT(&sdev->ocbs); | | | |
721 | fw_callout_init(&sdev->login_callout); | | | |
722 | sdev->status = SBP_DEV_RESET; | | | |
723 | new = 1; | | | |
724 | SBP_DEVICE_PREATTACH(); | | | |
725 | } | | | |
726 | sdev->flags |= VALID_LUN; | | | |
727 | sdev->type = (reg->val & 0xff0000) >> 16; | | | |
728 | | | | |
729 | if (new == 0) | | | |
730 | goto next; | | | |
731 | | | | |
732 | fwdma_malloc(sbp->fd.fc, | | | |
733 | /* alignment */ sizeof(uint32_t), | | | |
734 | SBP_DMA_SIZE, &sdev->dma, BUS_DMA_NOWAIT); | | | |
735 | if (sdev->dma.v_addr == NULL) { | | | |
736 | printf("%s: dma space allocation failed\n", | | | |
737 | __func__); | | | |
738 | free(sdev, M_SBP); | | | |
739 | target->luns[lun] = NULL; | | | |
740 | goto next; | | | |
741 | } | | | |
742 | sdev->login = (struct sbp_login_res *) sdev->dma.v_addr; | | | |
743 | sdev->ocb = (struct sbp_ocb *) | | | |
744 | ((char *)sdev->dma.v_addr + SBP_LOGIN_SIZE); | | | |
745 | bzero((char *)sdev->ocb, | | | |
746 | sizeof (struct sbp_ocb) * SBP_QUEUE_LEN); | | | |
747 | | | | |
748 | STAILQ_INIT(&sdev->free_ocbs); | | | |
749 | for (i = 0; i < SBP_QUEUE_LEN; i++) { | | | |
750 | struct sbp_ocb *ocb; | | | |
751 | ocb = &sdev->ocb[i]; | | | |
752 | ocb->bus_addr = sdev->dma.bus_addr | | | |
753 | + SBP_LOGIN_SIZE | | | |
754 | + sizeof(struct sbp_ocb) * i | | | |
755 | + offsetof(struct sbp_ocb, orb[0]); | | | |
756 | if (fw_bus_dmamap_create(sbp->dmat, 0, &ocb->dmamap)) { | | | |
757 | printf("sbp_attach: cannot create dmamap\n"); | | | |
758 | /* XXX */ | | | |
759 | goto next; | | | |
760 | } | | | |
761 | sbp_free_ocb(sdev, ocb); | | | |
762 | } | | | |
763 | next: | | | |
764 | crom_next(&cc); | | | |
765 | } | | | |
766 | | | | |
767 | for (lun = 0; lun < target->num_lun; lun ++) { | | | |
768 | sdev = target->luns[lun]; | | | |
769 | if (sdev != NULL && (sdev->flags & VALID_LUN) == 0) { | | | |
770 | SBP_DETACH_SDEV(sdev); | | | |
771 | sbp_free_sdev(sdev); | | | |
772 | target->luns[lun] = NULL; | | | |
773 | } | | | |
774 | } | | | |
775 | } | | | |
776 | | | | |
777 | static struct sbp_target * | | | |
778 | sbp_alloc_target(struct sbp_softc *sbp, struct fw_device *fwdev) | | | |
779 | { | | | |
780 | struct sbp_target *target; | | | |
781 | struct crom_context cc; | | | |
782 | struct csrreg *reg; | | | |
783 | | | | |
784 | SBP_DEBUG(1) | | | |
785 | printf("sbp_alloc_target\n"); | | | |
786 | END_DEBUG | | | |
787 | /* new target */ | | | |
788 | target = &sbp->target; | | | |
789 | target->sbp = sbp; | | | |
790 | target->fwdev = fwdev; | | | |
791 | target->target_id = 0; | | | |
792 | /* XXX we may want to reload mgm port after each bus reset */ | | | |
793 | /* XXX there might be multiple management agents */ | | | |
794 | crom_init_context(&cc, target->fwdev->csrrom); | | | |
795 | reg = crom_search_key(&cc, CROM_MGM); | | | |
796 | if (reg == NULL || reg->val == 0) { | | | |
797 | printf("NULL management address\n"); | | | |
798 | target->fwdev = NULL; | | | |
799 | return NULL; | | | |
800 | } | | | |
801 | target->mgm_hi = 0xffff; | | | |
802 | target->mgm_lo = 0xf0000000 | (reg->val << 2); | | | |
803 | target->mgm_ocb_cur = NULL; | | | |
804 | SBP_DEBUG(1) | | | |
805 | printf("target: mgm_port: %x\n", target->mgm_lo); | | | |
806 | END_DEBUG | | | |
807 | STAILQ_INIT(&target->xferlist); | | | |
808 | target->n_xfer = 0; | | | |
809 | STAILQ_INIT(&target->mgm_ocb_queue); | | | |
810 | fw_callout_init(&target->mgm_ocb_timeout); | | | |
811 | fw_callout_init(&target->scan_callout); | | | |
812 | | | | |
813 | target->luns = NULL; | | | |
814 | target->num_lun = 0; | | | |
815 | return target; | | | |
816 | } | | | |
817 | | | | |
818 | static void | | | |
819 | sbp_probe_lun(struct sbp_dev *sdev) | | | |
820 | { | | | |
821 | struct fw_device *fwdev; | | | |
822 | struct crom_context c, *cc = &c; | | | |
823 | struct csrreg *reg; | | | |
824 | | | | |
825 | bzero(sdev->vendor, sizeof(sdev->vendor)); | | | |
826 | bzero(sdev->product, sizeof(sdev->product)); | | | |
827 | | | | |
828 | fwdev = sdev->target->fwdev; | | | |
829 | crom_init_context(cc, fwdev->csrrom); | | | |
830 | /* get vendor string */ | | | |
831 | crom_search_key(cc, CSRKEY_VENDOR); | | | |
832 | crom_next(cc); | | | |
833 | crom_parse_text(cc, sdev->vendor, sizeof(sdev->vendor)); | | | |
834 | /* skip to the unit directory for SBP-2 */ | | | |
835 | while ((reg = crom_search_key(cc, CSRKEY_VER)) != NULL) { | | | |
836 | if (reg->val == CSRVAL_T10SBP2) | | | |
837 | break; | | | |
838 | crom_next(cc); | | | |
839 | } | | | |
840 | /* get firmware revision */ | | | |
841 | reg = crom_search_key(cc, CSRKEY_FIRM_VER); | | | |
842 | if (reg != NULL) | | | |
843 | snprintf(sdev->revision, sizeof(sdev->revision), | | | |
844 | "%06x", reg->val); | | | |
845 | /* get product string */ | | | |
846 | crom_search_key(cc, CSRKEY_MODEL); | | | |
847 | crom_next(cc); | | | |
848 | crom_parse_text(cc, sdev->product, sizeof(sdev->product)); | | | |
849 | } | | | |
850 | | | | |
851 | static void | | | |
852 | sbp_login_callout(void *arg) | | | |
853 | { | | | |
854 | struct sbp_dev *sdev = (struct sbp_dev *)arg; | | | |
855 | sbp_mgm_orb(sdev, ORB_FUN_LGI, NULL); | | | |
856 | } | | | |
857 | | | | |
858 | static void | | | |
859 | sbp_login(struct sbp_dev *sdev) | | | |
860 | { | | | |
861 | struct timeval delta; | | | |
862 | struct timeval t; | | | |
863 | int ticks = 0; | | | |
864 | | | | |
865 | microtime(&delta); | | | |
866 | fw_timevalsub(&delta, &sdev->target->sbp->last_busreset); | | | |
867 | t.tv_sec = login_delay / 1000; | | | |
868 | t.tv_usec = (login_delay % 1000) * 1000; | | | |
869 | fw_timevalsub(&t, &delta); | | | |
870 | if (t.tv_sec >= 0 && t.tv_usec > 0) | | | |
871 | ticks = (t.tv_sec * 1000 + t.tv_usec / 1000) * hz / 1000; | | | |
872 | SBP_DEBUG(0) | | | |
873 | printf("%s: sec = %jd usec = %ld ticks = %d\n", __func__, | | | |
874 | (intmax_t)t.tv_sec, t.tv_usec, ticks); | | | |
875 | END_DEBUG | | | |
876 | fw_callout_reset(&sdev->login_callout, ticks, | | | |
877 | sbp_login_callout, (void *)(sdev)); | | | |
878 | } | | | |
879 | | | | |
880 | static void | | | |
881 | sbp_probe_target(void *arg) | | | |
882 | { | | | |
883 | struct sbp_target *target = (struct sbp_target *)arg; | | | |
884 | struct sbp_softc *sbp; | | | |
885 | struct sbp_dev *sdev; | | | |
886 | struct firewire_comm *fc; | | | |
887 | int i; | | | |
888 | | | | |
889 | SBP_DEBUG(1) | | | |
890 | printf("sbp_probe_target %d\n", target->target_id); | | | |
891 | END_DEBUG | | | |
892 | | | | |
893 | sbp = target->sbp; | | | |
894 | fc = target->sbp->fd.fc; | | | |
895 | sbp_alloc_lun(target); | | | |
896 | | | | |
897 | /* XXX untimeout mgm_ocb and dequeue */ | | | |
898 | for (i=0; i < target->num_lun; i++) { | | | |
899 | sdev = target->luns[i]; | | | |
900 | if (sdev == NULL) | | | |
901 | continue; | | | |
902 | if (sdev->status != SBP_DEV_DEAD) { | | | |
903 | if (SBP_DEVICE(sdev) != NULL) { | | | |
904 | SBP_LOCK(sbp); | | | |
905 | SBP_DEVICE_FREEZE(sdev, 1); | | | |
906 | sdev->freeze ++; | | | |
907 | SBP_UNLOCK(sbp); | | | |
908 | } | | | |
909 | sbp_probe_lun(sdev); | | | |
910 | SBP_DEBUG(0) | | | |
911 | sbp_show_sdev_info(sdev, | | | |
912 | (sdev->status == SBP_DEV_RESET)); | | | |
913 | END_DEBUG | | | |
914 | | | | |
915 | sbp_abort_all_ocbs(sdev, XS_SCSI_BUS_RESET); | | | |
916 | switch (sdev->status) { | | | |
917 | case SBP_DEV_RESET: | | | |
918 | /* new or revived target */ | | | |
919 | if (auto_login) | | | |
920 | sbp_login(sdev); | | | |
921 | break; | | | |
922 | case SBP_DEV_TOATTACH: | | | |
923 | case SBP_DEV_PROBE: | | | |
924 | case SBP_DEV_ATTACHED: | | | |
925 | case SBP_DEV_RETRY: | | | |
926 | default: | | | |
927 | sbp_mgm_orb(sdev, ORB_FUN_RCN, NULL); | | | |
928 | break; | | | |
929 | } | | | |
930 | } else { | | | |
931 | switch (sdev->status) { | | | |
932 | case SBP_DEV_ATTACHED: | | | |
933 | SBP_DEBUG(0) | | | |
934 | /* the device has gone */ | | | |
935 | sbp_show_sdev_info(sdev, 2); | | | |
936 | printf("lost target\n"); | | | |
937 | END_DEBUG | | | |
938 | if (SBP_DEVICE(sdev) != NULL) { | | | |
939 | SBP_LOCK(sbp); | | | |
940 | SBP_DEVICE_FREEZE(sdev, 1); | | | |
941 | sdev->freeze ++; | | | |
942 | SBP_UNLOCK(sbp); | | | |
943 | } | | | |
944 | sdev->status = SBP_DEV_RETRY; | | | |
945 | sbp_abort_all_ocbs(sdev, XS_SCSI_BUS_RESET); | | | |
946 | break; | | | |
947 | case SBP_DEV_PROBE: | | | |
948 | case SBP_DEV_TOATTACH: | | | |
949 | sdev->status = SBP_DEV_RESET; | | | |
950 | break; | | | |
951 | case SBP_DEV_RETRY: | | | |
952 | case SBP_DEV_RESET: | | | |
953 | case SBP_DEV_DEAD: | | | |
954 | break; | | | |
955 | } | | | |
956 | } | | | |
957 | } | | | |
958 | } | | | |
959 | | | | |
960 | #define SBP_FWDEV_ALIVE(fwdev) (((fwdev)->status == FWDEVATTACHED) \ | | | |
961 | && crom_has_specver((fwdev)->csrrom, CSRVAL_ANSIT10, CSRVAL_T10SBP2)) | | | |
962 | | | | |
963 | static void | | | |
964 | sbp_post_busreset(void *arg) | | | |
965 | { | | | |
966 | struct sbp_softc *sbp = (struct sbp_softc *)arg; | | | |
967 | struct sbp_target *target = &sbp->target; | | | |
968 | struct fw_device *fwdev = target->fwdev; | | | |
969 | int alive; | | | |
970 | | | | |
971 | alive = SBP_FWDEV_ALIVE(fwdev); | | | |
972 | SBP_DEBUG(0) | | | |
973 | printf("sbp_post_busreset\n"); | | | |
974 | if (!alive) | | | |
975 | printf("not alive\n"); | | | |
976 | END_DEBUG | | | |
977 | microtime(&sbp->last_busreset); | | | |
978 | | | | |
979 | if (!alive) | | | |
980 | return; | | | |
981 | | | | |
982 | SBP_LOCK(sbp); | | | |
983 | SBP_BUS_FREEZE(sbp); | | | |
984 | SBP_UNLOCK(sbp); | | | |
985 | } | | | |
986 | | | | |
987 | static void | | | |
988 | sbp_post_explore(void *arg) | | | |
989 | { | | | |
990 | struct sbp_softc *sbp = (struct sbp_softc *)arg; | | | |
991 | struct sbp_target *target = &sbp->target; | | | |
992 | struct fw_device *fwdev = target->fwdev; | | | |
993 | int alive; | | | |
994 | | | | |
995 | alive = SBP_FWDEV_ALIVE(fwdev); | | | |
996 | SBP_DEBUG(0) | | | |
997 | printf("sbp_post_explore (sbp_cold=%d)\n", sbp_cold); | | | |
998 | if (!alive) | | | |
999 | printf("not alive\n"); | | | |
1000 | END_DEBUG | | | |
1001 | if (!alive) | | | |
1002 | return; | | | |
1003 | | | | |
1004 | if (sbp_cold > 0) | | | |
1005 | sbp_cold --; | | | |
1006 | | | | |
1007 | #if 0 | | | |
1008 | /* | | | |
1009 | * XXX don't let CAM the bus rest. | | | |
1010 | * CAM tries to do something with freezed (DEV_RETRY) devices. | | | |
1011 | */ | | | |
1012 | xpt_async(AC_BUS_RESET, sbp->path, /*arg*/ NULL); | | | |
1013 | #endif | | | |
1014 | | | | |
1015 | SBP_DEBUG(0) | | | |
1016 | printf("sbp_post_explore: EUI:%08x%08x ", fwdev->eui.hi, fwdev->eui.lo); | | | |
1017 | END_DEBUG | | | |
1018 | sbp_probe_target((void *)target); | | | |
1019 | if (target->num_lun == 0) | | | |
1020 | sbp_free_target(target); | | | |
1021 | | | | |
1022 | SBP_LOCK(sbp); | | | |
1023 | SBP_BUS_THAW(sbp); | | | |
1024 | SBP_UNLOCK(sbp); | | | |
1025 | } | | | |
1026 | | | | |
1027 | #if NEED_RESPONSE | | | |
1028 | static void | | | |
1029 | sbp_loginres_callback(struct fw_xfer *xfer){ | | | |
1030 | int s; | | | |
1031 | struct sbp_dev *sdev; | | | |
1032 | sdev = (struct sbp_dev *)xfer->sc; | | | |
1033 | SBP_DEBUG(1) | | | |
1034 | sbp_show_sdev_info(sdev, 2); | | | |
1035 | printf("sbp_loginres_callback\n"); | | | |
1036 | END_DEBUG | | | |
1037 | /* recycle */ | | | |
1038 | s = splfw(); | | | |
1039 | STAILQ_INSERT_TAIL(&sdev->target->sbp->fwb.xferlist, xfer, link); | | | |
1040 | splx(s); | | | |
1041 | return; | | | |
1042 | } | | | |
1043 | #endif | | | |
1044 | | | | |
1045 | static inline void | | | |
1046 | sbp_xfer_free(struct fw_xfer *xfer) | | | |
1047 | { | | | |
1048 | struct sbp_dev *sdev; | | | |
1049 | int s; | | | |
1050 | | | | |
1051 | sdev = (struct sbp_dev *)xfer->sc; | | | |
1052 | fw_xfer_unload(xfer); | | | |
1053 | s = splfw(); | | | |
1054 | SBP_LOCK(sdev->target->sbp); | | | |
1055 | STAILQ_INSERT_TAIL(&sdev->target->xferlist, xfer, link); | | | |
1056 | SBP_UNLOCK(sdev->target->sbp); | | | |
1057 | splx(s); | | | |
1058 | } | | | |
1059 | | | | |
1060 | static void | | | |
1061 | sbp_reset_start_callback(struct fw_xfer *xfer) | | | |
1062 | { | | | |
1063 | struct sbp_dev *tsdev, *sdev = (struct sbp_dev *)xfer->sc; | | | |
1064 | struct sbp_target *target = sdev->target; | | | |
1065 | int i; | | | |
1066 | | | | |
1067 | if (xfer->resp != 0) { | | | |
1068 | sbp_show_sdev_info(sdev, 2); | | | |
1069 | printf("sbp_reset_start failed: resp=%d\n", xfer->resp); | | | |
1070 | } | | | |
1071 | | | | |
1072 | for (i = 0; i < target->num_lun; i++) { | | | |
1073 | tsdev = target->luns[i]; | | | |
1074 | if (tsdev != NULL && tsdev->status == SBP_DEV_LOGIN) | | | |
1075 | sbp_login(tsdev); | | | |
1076 | } | | | |
1077 | } | | | |
1078 | | | | |
1079 | static void | | | |
1080 | sbp_reset_start(struct sbp_dev *sdev) | | | |
1081 | { | | | |
1082 | struct fw_xfer *xfer; | | | |
1083 | struct fw_pkt *fp; | | | |
1084 | | | | |
1085 | SBP_DEBUG(0) | | | |
1086 | sbp_show_sdev_info(sdev, 2); | | | |
1087 | printf("sbp_reset_start\n"); | | | |
1088 | END_DEBUG | | | |
1089 | | | | |
1090 | xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0); | | | |
1091 | xfer->hand = sbp_reset_start_callback; | | | |
1092 | fp = &xfer->send.hdr; | | | |
1093 | fp->mode.wreqq.dest_hi = 0xffff; | | | |
1094 | fp->mode.wreqq.dest_lo = 0xf0000000 | RESET_START; | | | |
1095 | fp->mode.wreqq.data = htonl(0xf); | | | |
1096 | fw_asyreq(xfer->fc, -1, xfer); | | | |
1097 | } | | | |
1098 | | | | |
1099 | static void | | | |
1100 | sbp_mgm_callback(struct fw_xfer *xfer) | | | |
1101 | { | | | |
1102 | struct sbp_dev *sdev; | | | |
1103 | int resp; | | | |
1104 | | | | |
1105 | sdev = (struct sbp_dev *)xfer->sc; | | | |
1106 | | | | |
1107 | SBP_DEBUG(1) | | | |
1108 | sbp_show_sdev_info(sdev, 2); | | | |
1109 | printf("sbp_mgm_callback\n"); | | | |
1110 | END_DEBUG | | | |
1111 | resp = xfer->resp; | | | |
1112 | sbp_xfer_free(xfer); | | | |
1113 | #if 0 | | | |
1114 | if (resp != 0) { | | | |
1115 | sbp_show_sdev_info(sdev, 2); | | | |
1116 | printf("management ORB failed(%d) ... RESET_START\n", resp); | | | |
1117 | sbp_reset_start(sdev); | | | |
1118 | } | | | |
1119 | #endif | | | |
1120 | return; | | | |
1121 | } | | | |
1122 | | | | |
1123 | #if defined(__FreeBSD__) | | | |
1124 | static struct sbp_dev * | | | |
1125 | sbp_next_dev(struct sbp_target *target, int lun) | | | |
1126 | { | | | |
1127 | struct sbp_dev **sdevp; | | | |
1128 | int i; | | | |
1129 | | | | |
1130 | for (i = lun, sdevp = &target->luns[lun]; i < target->num_lun; | | | |
1131 | i++, sdevp++) | | | |
1132 | if (*sdevp != NULL && (*sdevp)->status == SBP_DEV_PROBE) | | | |
1133 | return(*sdevp); | | | |
1134 | return(NULL); | | | |
1135 | } | | | |
1136 | | | | |
1137 | #define SCAN_PRI 1 | | | |
1138 | static void | | | |
1139 | sbp_cam_scan_lun(struct cam_periph *periph, sbp_scsi_xfer *sxfer) | | | |
1140 | { | | | |
1141 | struct sbp_target *target; | | | |
1142 | struct sbp_dev *sdev; | | | |
1143 | | | | |
1144 | sdev = (struct sbp_dev *) sxfer->ccb_h.ccb_sdev_ptr; | | | |
1145 | target = sdev->target; | | | |
1146 | SBP_DEBUG(0) | | | |
1147 | sbp_show_sdev_info(sdev, 2); | | | |
1148 | printf("sbp_cam_scan_lun\n"); | | | |
1149 | END_DEBUG | | | |
1150 | if ((SCSI_XFER_ERROR(sxfer) & CAM_STATUS_MASK) == XS_REQ_CMP) { | | | |
1151 | sdev->status = SBP_DEV_ATTACHED; | | | |
1152 | } else { | | | |
1153 | sbp_show_sdev_info(sdev, 2); | | | |
1154 | printf("scan failed\n"); | | | |
1155 | } | | | |
1156 | sdev = sbp_next_dev(target, sdev->lun_id + 1); | | | |
1157 | if (sdev == NULL) { | | | |
1158 | free(sxfer, M_SBP); | | | |
1159 | return; | | | |
1160 | } | | | |
1161 | /* reuse sxfer */ | | | |
1162 | xpt_setup_ccb(&sxfer->ccb_h, sdev->path, SCAN_PRI); | | | |
1163 | sxfer->ccb_h.ccb_sdev_ptr = sdev; | | | |
1164 | xpt_action(sxfer); | | | |
1165 | xpt_release_devq(sdev->path, sdev->freeze, TRUE); | | | |
1166 | sdev->freeze = 1; | | | |
1167 | } | | | |
1168 | | | | |
1169 | static void | | | |
1170 | sbp_cam_scan_target(void *arg) | | | |
1171 | { | | | |
1172 | struct sbp_target *target = (struct sbp_target *)arg; | | | |
1173 | struct sbp_dev *sdev; | | | |
1174 | sbp_scsi_xfer *sxfer; | | | |
1175 | | | | |
1176 | sdev = sbp_next_dev(target, 0); | | | |
1177 | if (sdev == NULL) { | | | |
1178 | printf("sbp_cam_scan_target: nothing to do for target%d\n", | | | |
1179 | target->target_id); | | | |
1180 | return; | | | |
1181 | } | | | |
1182 | SBP_DEBUG(0) | | | |
1183 | sbp_show_sdev_info(sdev, 2); | | | |
1184 | printf("sbp_cam_scan_target\n"); | | | |
1185 | END_DEBUG | | | |
1186 | sxfer = malloc(sizeof(sbp_scsi_xfer), M_SBP, M_NOWAIT | M_ZERO); | | | |
1187 | if (sxfer == NULL) { | | | |
1188 | printf("sbp_cam_scan_target: malloc failed\n"); | | | |
1189 | return; | | | |
1190 | } | | | |
1191 | xpt_setup_ccb(&sxfer->ccb_h, sdev->path, SCAN_PRI); | | | |
1192 | sxfer->ccb_h.func_code = XPT_SCAN_LUN; | | | |
1193 | sxfer->ccb_h.cbfcnp = sbp_cam_scan_lun; | | | |
1194 | sxfer->ccb_h.flags |= CAM_DEV_QFREEZE; | | | |
1195 | sxfer->crcn.flags = CAM_FLAG_NONE; | | | |
1196 | sxfer->ccb_h.ccb_sdev_ptr = sdev; | | | |
1197 | | | | |
1198 | /* The scan is in progress now. */ | | | |
1199 | SBP_LOCK(target->sbp); | | | |
1200 | xpt_action(sxfer); | | | |
1201 | xpt_release_devq(sdev->path, sdev->freeze, TRUE); | | | |
1202 | sdev->freeze = 1; | | | |
1203 | SBP_UNLOCK(target->sbp); | | | |
1204 | } | | | |
1205 | | | | |
1206 | static inline void | | | |
1207 | sbp_scan_dev(struct sbp_dev *sdev) | | | |
1208 | { | | | |
1209 | sdev->status = SBP_DEV_PROBE; | | | |
1210 | fw_callout_reset(&sdev->target->scan_callout, scan_delay * hz / 1000, | | | |
1211 | sbp_cam_scan_target, (void *)sdev->target); | | | |
1212 | } | | | |
1213 | #elif defined(__NetBSD__) | | | |
1214 | static void | | | |
1215 | sbp_scsipi_scan_target(void *arg) | | | |
1216 | { | | | |
1217 | struct sbp_target *target = (struct sbp_target *)arg; | | | |
1218 | struct sbp_softc *sbp = target->sbp; | | | |
1219 | struct sbp_dev *sdev; | | | |
1220 | struct scsipi_channel *chan = &sbp->sc_channel; | | | |
1221 | struct scsibus_softc *sc_bus = device_private(sbp->sc_bus); | | | |
1222 | int lun, yet; | | | |
1223 | | | | |
1224 | do { | | | |
1225 | tsleep(target, PWAIT|PCATCH, "-", 0); | | | |
1226 | yet = 0; | | | |
1227 | | | | |
1228 | for (lun = 0; lun < target->num_lun; lun ++) { | | | |
1229 | sdev = target->luns[lun]; | | | |
1230 | if (sdev == NULL) | | | |
1231 | continue; | | | |
1232 | if (sdev->status != SBP_DEV_PROBE) { | | | |
1233 | yet ++; | | | |
1234 | continue; | | | |
1235 | } | | | |
1236 | | | | |
1237 | if (sdev->periph == NULL) { | | | |
1238 | if (chan->chan_nluns < target->num_lun) | | | |
1239 | chan->chan_nluns = target->num_lun; | | | |
1240 | | | | |
1241 | scsi_probe_bus(sc_bus, | | | |
1242 | target->target_id, sdev->lun_id); | | | |
1243 | sdev->periph = scsipi_lookup_periph( | | | |
1244 | chan, target->target_id, lun); | | | |
1245 | } | | | |
1246 | sdev->status = SBP_DEV_ATTACHED; | | | |
1247 | } | | | |
1248 | } while (yet > 0); | | | |
1249 | | | | |
1250 | sbp->lwp = NULL; | | | |
1251 | kthread_exit(0); | | | |
1252 | } | | | |
1253 | | | | |
1254 | static inline void | | | |
1255 | sbp_scan_dev(struct sbp_dev *sdev) | | | |
1256 | { | | | |
1257 | sdev->status = SBP_DEV_PROBE; | | | |
1258 | wakeup(sdev->target); | | | |
1259 | } | | | |
1260 | #endif | | | |
1261 | | | | |
1262 | | | | |
1263 | static void | | | |
1264 | sbp_do_attach(struct fw_xfer *xfer) | | | |
1265 | { | | | |
1266 | struct sbp_dev *sdev; | | | |
1267 | struct sbp_target *target; | | | |
1268 | struct sbp_softc *sbp; | | | |
1269 | | | | |
1270 | sdev = (struct sbp_dev *)xfer->sc; | | | |
1271 | target = sdev->target; | | | |
1272 | sbp = target->sbp; | | | |
1273 | | | | |
1274 | SBP_DEBUG(0) | | | |
1275 | sbp_show_sdev_info(sdev, 2); | | | |
1276 | printf("sbp_do_attach\n"); | | | |
1277 | END_DEBUG | | | |
1278 | sbp_xfer_free(xfer); | | | |
1279 | | | | |
1280 | #if defined(__FreeBSD__) | | | |
1281 | if (sdev->path == NULL) | | | |
1282 | xpt_create_path(&sdev->path, xpt_periph, | | | |
1283 | cam_sim_path(target->sbp->sim), | | | |
1284 | target->target_id, sdev->lun_id); | | | |
1285 | | | | |
1286 | /* | | | |
1287 | * Let CAM scan the bus if we are in the boot process. | | | |
1288 | * XXX xpt_scan_bus cannot detect LUN larger than 0 | | | |
1289 | * if LUN 0 doesn't exists. | | | |
1290 | */ | | | |
1291 | if (sbp_cold > 0) { | | | |
1292 | sdev->status = SBP_DEV_ATTACHED; | | | |
1293 | return; | | | |
1294 | } | | | |
1295 | #endif | | | |
1296 | | | | |
1297 | sbp_scan_dev(sdev); | | | |
1298 | return; | | | |
1299 | } | | | |
1300 | | | | |
1301 | static void | | | |
1302 | sbp_agent_reset_callback(struct fw_xfer *xfer) | | | |
1303 | { | | | |
1304 | struct sbp_dev *sdev; | | | |
1305 | | | | |
1306 | sdev = (struct sbp_dev *)xfer->sc; | | | |
1307 | SBP_DEBUG(1) | | | |
1308 | sbp_show_sdev_info(sdev, 2); | | | |
1309 | printf("%s\n", __func__); | | | |
1310 | END_DEBUG | | | |
1311 | if (xfer->resp != 0) { | | | |
1312 | sbp_show_sdev_info(sdev, 2); | | | |
1313 | printf("%s: resp=%d\n", __func__, xfer->resp); | | | |
1314 | } | | | |
1315 | | | | |
1316 | sbp_xfer_free(xfer); | | | |
1317 | if (SBP_DEVICE(sdev)) { | | | |
1318 | SBP_LOCK(sdev->target->sbp); | | | |
1319 | SBP_DEVICE_THAW(sdev, sdev->freeze); | | | |
1320 | sdev->freeze = 0; | | | |
1321 | SBP_UNLOCK(sdev->target->sbp); | | | |
1322 | } | | | |
1323 | } | | | |
1324 | | | | |
1325 | static void | | | |
1326 | sbp_agent_reset(struct sbp_dev *sdev) | | | |
1327 | { | | | |
1328 | struct fw_xfer *xfer; | | | |
1329 | struct fw_pkt *fp; | | | |
1330 | | | | |
1331 | SBP_DEBUG(0) | | | |
1332 | sbp_show_sdev_info(sdev, 2); | | | |
1333 | printf("sbp_agent_reset\n"); | | | |
1334 | END_DEBUG | | | |
1335 | xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0x04); | | | |
1336 | if (xfer == NULL) | | | |
1337 | return; | | | |
1338 | if (sdev->status == SBP_DEV_ATTACHED || sdev->status == SBP_DEV_PROBE) | | | |
1339 | xfer->hand = sbp_agent_reset_callback; | | | |
1340 | else | | | |
1341 | xfer->hand = sbp_do_attach; | | | |
1342 | fp = &xfer->send.hdr; | | | |
1343 | fp->mode.wreqq.data = htonl(0xf); | | | |
1344 | fw_asyreq(xfer->fc, -1, xfer); | | | |
1345 | sbp_abort_all_ocbs(sdev, XS_BDR_SENT); | | | |
1346 | } | | | |
1347 | | | | |
1348 | static void | | | |
1349 | sbp_busy_timeout_callback(struct fw_xfer *xfer) | | | |
1350 | { | | | |
1351 | struct sbp_dev *sdev; | | | |
1352 | | | | |
1353 | sdev = (struct sbp_dev *)xfer->sc; | | | |
1354 | SBP_DEBUG(1) | | | |
1355 | sbp_show_sdev_info(sdev, 2); | | | |
1356 | printf("sbp_busy_timeout_callback\n"); | | | |
1357 | END_DEBUG | | | |
1358 | sbp_xfer_free(xfer); | | | |
1359 | sbp_agent_reset(sdev); | | | |
1360 | } | | | |
1361 | | | | |
1362 | static void | | | |
1363 | sbp_busy_timeout(struct sbp_dev *sdev) | | | |
1364 | { | | | |
1365 | struct fw_pkt *fp; | | | |
1366 | struct fw_xfer *xfer; | | | |
1367 | SBP_DEBUG(0) | | | |
1368 | sbp_show_sdev_info(sdev, 2); | | | |
1369 | printf("sbp_busy_timeout\n"); | | | |
1370 | END_DEBUG | | | |
1371 | xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0); | | | |
1372 | | | | |
1373 | xfer->hand = sbp_busy_timeout_callback; | | | |
1374 | fp = &xfer->send.hdr; | | | |
1375 | fp->mode.wreqq.dest_hi = 0xffff; | | | |
1376 | fp->mode.wreqq.dest_lo = 0xf0000000 | BUSY_TIMEOUT; | | | |
1377 | fp->mode.wreqq.data = htonl((1 << (13+12)) | 0xf); | | | |
1378 | fw_asyreq(xfer->fc, -1, xfer); | | | |
1379 | } | | | |
1380 | | | | |
1381 | static void | | | |
1382 | sbp_orb_pointer_callback(struct fw_xfer *xfer) | | | |
1383 | { | | | |
1384 | struct sbp_dev *sdev; | | | |
1385 | sdev = (struct sbp_dev *)xfer->sc; | | | |
1386 | | | | |
1387 | SBP_DEBUG(1) | | | |
1388 | sbp_show_sdev_info(sdev, 2); | | | |
1389 | printf("%s\n", __func__); | | | |
1390 | END_DEBUG | | | |
1391 | if (xfer->resp != 0) { | | | |
1392 | /* XXX */ | | | |
1393 | printf("%s: xfer->resp = %d\n", __func__, xfer->resp); | | | |
1394 | } | | | |
1395 | sbp_xfer_free(xfer); | | | |
1396 | sdev->flags &= ~ORB_POINTER_ACTIVE; | | | |
1397 | | | | |
1398 | if ((sdev->flags & ORB_POINTER_NEED) != 0) { | | | |
1399 | struct sbp_ocb *ocb; | | | |
1400 | | | | |
1401 | sdev->flags &= ~ORB_POINTER_NEED; | | | |
1402 | ocb = STAILQ_FIRST(&sdev->ocbs); | | | |
1403 | if (ocb != NULL) | | | |
1404 | sbp_orb_pointer(sdev, ocb); | | | |
1405 | } | | | |
1406 | return; | | | |
1407 | } | | | |
1408 | | | | |
1409 | static void | | | |
1410 | sbp_orb_pointer(struct sbp_dev *sdev, struct sbp_ocb *ocb) | | | |
1411 | { | | | |
1412 | struct fw_xfer *xfer; | | | |
1413 | struct fw_pkt *fp; | | | |
1414 | SBP_DEBUG(1) | | | |
1415 | sbp_show_sdev_info(sdev, 2); | | | |
1416 | printf("%s: 0x%08x\n", __func__, (uint32_t)ocb->bus_addr); | | | |
1417 | END_DEBUG | | | |
1418 | | | | |
1419 | if ((sdev->flags & ORB_POINTER_ACTIVE) != 0) { | | | |
1420 | SBP_DEBUG(0) | | | |
1421 | printf("%s: orb pointer active\n", __func__); | | | |
1422 | END_DEBUG | | | |
1423 | sdev->flags |= ORB_POINTER_NEED; | | | |
1424 | return; | | | |
1425 | } | | | |
1426 | | | | |
1427 | sdev->flags |= ORB_POINTER_ACTIVE; | | | |
1428 | xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0x08); | | | |
1429 | if (xfer == NULL) | | | |
1430 | return; | | | |
1431 | xfer->hand = sbp_orb_pointer_callback; | | | |
1432 | | | | |
1433 | fp = &xfer->send.hdr; | | | |
1434 | fp->mode.wreqb.len = 8; | | | |
1435 | fp->mode.wreqb.extcode = 0; | | | |
1436 | xfer->send.payload[0] = | | | |
1437 | htonl(((sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS )<< 16)); | | | |
1438 | xfer->send.payload[1] = htonl((uint32_t)ocb->bus_addr); | | | |
1439 | | | | |
1440 | if(fw_asyreq(xfer->fc, -1, xfer) != 0){ | | | |
1441 | sbp_xfer_free(xfer); | | | |
1442 | SCSI_XFER_ERROR(ocb->sxfer) = XS_REQ_INVALID; | | | |
1443 | SCSI_TRANSFER_DONE(ocb->sxfer); | | | |
1444 | } | | | |
1445 | } | | | |
1446 | | | | |
1447 | static void | | | |
1448 | sbp_doorbell_callback(struct fw_xfer *xfer) | | | |
1449 | { | | | |
1450 | struct sbp_dev *sdev; | | | |
1451 | sdev = (struct sbp_dev *)xfer->sc; | | | |
1452 | | | | |
1453 | SBP_DEBUG(1) | | | |
1454 | sbp_show_sdev_info(sdev, 2); | | | |
1455 | printf("sbp_doorbell_callback\n"); | | | |
1456 | END_DEBUG | | | |
1457 | if (xfer->resp != 0) { | | | |
1458 | /* XXX */ | | | |
1459 | printf("%s: xfer->resp = %d\n", __func__, xfer->resp); | | | |
1460 | } | | | |
1461 | sbp_xfer_free(xfer); | | | |
1462 | sdev->flags &= ~ORB_DOORBELL_ACTIVE; | | | |
1463 | if ((sdev->flags & ORB_DOORBELL_NEED) != 0) { | | | |
1464 | sdev->flags &= ~ORB_DOORBELL_NEED; | | | |
1465 | sbp_doorbell(sdev); | | | |
1466 | } | | | |
1467 | return; | | | |
1468 | } | | | |
1469 | | | | |
1470 | static void | | | |
1471 | sbp_doorbell(struct sbp_dev *sdev) | | | |
1472 | { | | | |
1473 | struct fw_xfer *xfer; | | | |
1474 | struct fw_pkt *fp; | | | |
1475 | SBP_DEBUG(1) | | | |
1476 | sbp_show_sdev_info(sdev, 2); | | | |
1477 | printf("sbp_doorbell\n"); | | | |
1478 | END_DEBUG | | | |
1479 | | | | |
1480 | if ((sdev->flags & ORB_DOORBELL_ACTIVE) != 0) { | | | |
1481 | sdev->flags |= ORB_DOORBELL_NEED; | | | |
1482 | return; | | | |
1483 | } | | | |
1484 | sdev->flags |= ORB_DOORBELL_ACTIVE; | | | |
1485 | xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0x10); | | | |
1486 | if (xfer == NULL) | | | |
1487 | return; | | | |
1488 | xfer->hand = sbp_doorbell_callback; | | | |
1489 | fp = &xfer->send.hdr; | | | |
1490 | fp->mode.wreqq.data = htonl(0xf); | | | |
1491 | fw_asyreq(xfer->fc, -1, xfer); | | | |
1492 | } | | | |
1493 | | | | |
1494 | static struct fw_xfer * | | | |
1495 | sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset) | | | |
1496 | { | | | |
1497 | struct fw_xfer *xfer; | | | |
1498 | struct fw_pkt *fp; | | | |
1499 | struct sbp_target *target; | | | |
1500 | int s, new = 0; | | | |
1501 | | | | |
1502 | target = sdev->target; | | | |
1503 | s = splfw(); | | | |
1504 | xfer = STAILQ_FIRST(&target->xferlist); | | | |
1505 | if (xfer == NULL) { | | | |
1506 | if (target->n_xfer > 5 /* XXX */) { | | | |
1507 | printf("sbp: no more xfer for this target\n"); | | | |
1508 | splx(s); | | | |
1509 | return(NULL); | | | |
1510 | } | | | |
1511 | xfer = fw_xfer_alloc_buf(M_SBP, 8, 0); | | | |
1512 | if(xfer == NULL){ | | | |
1513 | printf("sbp: fw_xfer_alloc_buf failed\n"); | | | |
1514 | splx(s); | | | |
1515 | return NULL; | | | |
1516 | } | | | |
1517 | target->n_xfer ++; | | | |
1518 | if (debug) | | | |
1519 | printf("sbp: alloc %d xfer\n", target->n_xfer); | | | |
1520 | new = 1; | | | |
1521 | } else { | | | |
1522 | STAILQ_REMOVE_HEAD(&target->xferlist, link); | | | |
1523 | } | | | |
1524 | splx(s); | | | |
1525 | | | | |
1526 | microtime(&xfer->tv); | | | |
1527 | | | | |
1528 | if (new) { | | | |
1529 | xfer->recv.pay_len = 0; | | | |
1530 | xfer->send.spd = min(sdev->target->fwdev->speed, max_speed); | | | |
1531 | xfer->fc = sdev->target->sbp->fd.fc; | | | |
1532 | } | | | |
1533 | | | | |
1534 | if (tcode == FWTCODE_WREQB) | | | |
1535 | xfer->send.pay_len = 8; | | | |
1536 | else | | | |
1537 | xfer->send.pay_len = 0; | | | |
1538 | | | | |
1539 | xfer->sc = (void *)sdev; | | | |
1540 | fp = &xfer->send.hdr; | | | |
1541 | fp->mode.wreqq.dest_hi = sdev->login->cmd_hi; | | | |
1542 | fp->mode.wreqq.dest_lo = sdev->login->cmd_lo + offset; | | | |
1543 | fp->mode.wreqq.tlrt = 0; | | | |
1544 | fp->mode.wreqq.tcode = tcode; | | | |
1545 | fp->mode.wreqq.pri = 0; | | | |
1546 | fp->mode.wreqq.dst = FWLOCALBUS | sdev->target->fwdev->dst; | | | |
1547 | | | | |
1548 | return xfer; | | | |
1549 | } | | | |
1550 | | | | |
1551 | static void | | | |
1552 | sbp_mgm_orb(struct sbp_dev *sdev, int func, struct sbp_ocb *aocb) | | | |
1553 | { | | | |
1554 | struct fw_xfer *xfer; | | | |
1555 | struct fw_pkt *fp; | | | |
1556 | struct sbp_ocb *ocb; | | | |
1557 | struct sbp_target *target; | | | |
1558 | int s, nid, dv_unit; | | | |
1559 | | | | |
1560 | target = sdev->target; | | | |
1561 | nid = target->sbp->fd.fc->nodeid | FWLOCALBUS; | | | |
1562 | dv_unit = fw_get_unit(target->sbp->fd.dev); | | | |
1563 | | | | |
1564 | s = splfw(); | | | |
1565 | SBP_LOCK(target->sbp); | | | |
1566 | if (func == ORB_FUN_RUNQUEUE) { | | | |
1567 | ocb = STAILQ_FIRST(&target->mgm_ocb_queue); | | | |
1568 | if (target->mgm_ocb_cur != NULL || ocb == NULL) { | | | |
1569 | SBP_UNLOCK(target->sbp); | | | |
1570 | splx(s); | | | |
1571 | return; | | | |
1572 | } | | | |
1573 | STAILQ_REMOVE_HEAD(&target->mgm_ocb_queue, ocb); | | | |
1574 | SBP_UNLOCK(target->sbp); | | | |
1575 | goto start; | | | |
1576 | } | | | |
1577 | if ((ocb = sbp_get_ocb(sdev)) == NULL) { | | | |
1578 | SBP_UNLOCK(target->sbp); | | | |
1579 | splx(s); | | | |
1580 | /* XXX */ | | | |
1581 | return; | | | |
1582 | } | | | |
1583 | SBP_UNLOCK(target->sbp); | | | |
1584 | ocb->flags = OCB_ACT_MGM; | | | |
1585 | ocb->sdev = sdev; | | | |
1586 | | | | |
1587 | bzero((void *)ocb->orb, sizeof(ocb->orb)); | | | |
1588 | ocb->orb[6] = htonl((nid << 16) | SBP_BIND_HI); | | | |
1589 | ocb->orb[7] = htonl(SBP_DEV2ADDR(dv_unit, sdev->lun_id)); | | | |
1590 | | | | |
1591 | SBP_DEBUG(0) | | | |
1592 | sbp_show_sdev_info(sdev, 2); | | | |
1593 | printf("%s\n", orb_fun_name[(func>>16)&0xf]); | | | |
1594 | END_DEBUG | | | |
1595 | switch (func) { | | | |
1596 | case ORB_FUN_LGI: | | | |
1597 | ocb->orb[0] = ocb->orb[1] = 0; /* password */ | | | |
1598 | ocb->orb[2] = htonl(nid << 16); | | | |
1599 | ocb->orb[3] = htonl(sdev->dma.bus_addr); | | | |
1600 | ocb->orb[4] = htonl(ORB_NOTIFY | sdev->lun_id); | | | |
1601 | if (ex_login) | | | |
1602 | ocb->orb[4] |= htonl(ORB_EXV); | | | |
1603 | ocb->orb[5] = htonl(SBP_LOGIN_SIZE); | | | |
1604 | break; | | | |
1605 | case ORB_FUN_ATA: | | | |
1606 | ocb->orb[0] = htonl((0 << 16) | 0); | | | |
1607 | ocb->orb[1] = htonl(aocb->bus_addr & 0xffffffff); | | | |
1608 | /* fall through */ | | | |
1609 | case ORB_FUN_RCN: | | | |
1610 | case ORB_FUN_LGO: | | | |
1611 | case ORB_FUN_LUR: | | | |
1612 | case ORB_FUN_RST: | | | |
1613 | case ORB_FUN_ATS: | | | |
1614 | ocb->orb[4] = htonl(ORB_NOTIFY | func | sdev->login->id); | | | |
1615 | break; | | | |
1616 | } | | | |
1617 | | | | |
1618 | if (target->mgm_ocb_cur != NULL) { | | | |
1619 | /* there is a standing ORB */ | | | |
1620 | SBP_LOCK(target->sbp); | | | |
1621 | STAILQ_INSERT_TAIL(&sdev->target->mgm_ocb_queue, ocb, ocb); | | | |
1622 | SBP_UNLOCK(target->sbp); | | | |
1623 | splx(s); | | | |
1624 | return; | | | |
1625 | } | | | |
1626 | start: | | | |
1627 | target->mgm_ocb_cur = ocb; | | | |
1628 | splx(s); | | | |
1629 | | | | |
1630 | fw_callout_reset(&target->mgm_ocb_timeout, 5*hz, | | | |
1631 | sbp_mgm_timeout, (void *)ocb); | | | |
1632 | xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0); | | | |
1633 | if(xfer == NULL){ | | | |
1634 | return; | | | |
1635 | } | | | |
1636 | xfer->hand = sbp_mgm_callback; | | | |
1637 | | | | |
1638 | fp = &xfer->send.hdr; | | | |
1639 | fp->mode.wreqb.dest_hi = sdev->target->mgm_hi; | | | |
1640 | fp->mode.wreqb.dest_lo = sdev->target->mgm_lo; | | | |
1641 | fp->mode.wreqb.len = 8; | | | |
1642 | fp->mode.wreqb.extcode = 0; | | | |
1643 | xfer->send.payload[0] = htonl(nid << 16); | | | |
1644 | xfer->send.payload[1] = htonl(ocb->bus_addr & 0xffffffff); | | | |
1645 | SBP_DEBUG(0) | | | |
1646 | sbp_show_sdev_info(sdev, 2); | | | |
1647 | printf("mgm orb: %08x\n", (uint32_t)ocb->bus_addr); | | | |
1648 | END_DEBUG | | | |
1649 | | | | |
1650 | /* cache writeback & invalidate(required ORB_FUN_LGI func) */ | | | |
1651 | /* when abort_ocb, should sync POST ope ? */ | | | |
1652 | fwdma_sync(&sdev->dma, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | | | |
1653 | fw_asyreq(xfer->fc, -1, xfer); | | | |
1654 | } | | | |
1655 | | | | |
1656 | static void | | | |
1657 | sbp_print_scsi_cmd(struct sbp_ocb *ocb) | | | |
1658 | { | | | |
1659 | #if defined(__FreeBSD__) | | | |
1660 | struct ccb_scsiio *csio; | | | |
1661 | | | | |
1662 | csio = &ocb->sxfer->csio; | | | |
1663 | #endif | | | |
1664 | printf("%s:%d:%d XPT_SCSI_IO: " | | | |
1665 | "cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x" | | | |
1666 | ", flags: 0x%02x, " | | | |
1667 | "%db cmd/%db data/%db sense\n", | | | |
1668 | fw_get_nameunit(ocb->sdev->target->sbp->fd.dev), | | | |
1669 | SCSI_XFER_TARGET(ocb->sxfer), SCSI_XFER_LUN(ocb->sxfer), | | | |
1670 | SCSI_XFER_10BCMD_DUMP(ocb->sxfer), | | | |
1671 | SCSI_XFER_DIR(ocb->sxfer), | | | |
1672 | SCSI_XFER_CMDLEN(ocb->sxfer), SCSI_XFER_DATALEN(ocb->sxfer), | | | |
1673 | SCSI_XFER_SENSELEN(ocb->sxfer)); | | | |
1674 | } | | | |
1675 | | | | |
1676 | static void | | | |
1677 | sbp_scsi_status(struct sbp_status *sbp_status, struct sbp_ocb *ocb) | | | |
1678 | { | | | |
1679 | struct sbp_cmd_status *sbp_cmd_status; | | | |
1680 | scsi3_sense_data_t sense = | | | |
1681 | (scsi3_sense_data_t)SCSI_SENSE_DATA(ocb->sxfer); | | | |
1682 | | | | |
1683 | sbp_cmd_status = (struct sbp_cmd_status *)sbp_status->data; | | | |
1684 | | | | |
1685 | SBP_DEBUG(0) | | | |
1686 | sbp_print_scsi_cmd(ocb); | | | |
1687 | /* XXX need decode status */ | | | |
1688 | sbp_show_sdev_info(ocb->sdev, 2); | | | |
1689 | printf("SCSI status %x sfmt %x valid %x key %x code %x qlfr %x len %d\n", | | | |
1690 | sbp_cmd_status->status, | | | |
1691 | sbp_cmd_status->sfmt, | | | |
1692 | sbp_cmd_status->valid, | | | |
1693 | sbp_cmd_status->s_key, | | | |
1694 | sbp_cmd_status->s_code, | | | |
1695 | sbp_cmd_status->s_qlfr, | | | |
1696 | sbp_status->len | | | |
1697 | ); | | | |
1698 | END_DEBUG | | | |
1699 | | | | |
1700 | switch (sbp_cmd_status->status) { | | | |
1701 | case SCSI_STATUS_CHECK_COND: | | | |
1702 | case SCSI_STATUS_BUSY: | | | |
1703 | case SCSI_STATUS_CMD_TERMINATED: | | | |
1704 | if(sbp_cmd_status->sfmt == SBP_SFMT_CURR){ | | | |
1705 | sense->response_code = SSD_CURRENT_ERROR; | | | |
1706 | }else{ | | | |
1707 | sense->response_code = SSD_DEFERRED_ERROR; | | | |
1708 | } | | | |
1709 | if(sbp_cmd_status->valid) | | | |
1710 | sense->response_code |= SSD_RESPONSE_CODE_VALID; | | | |
1711 | sense->flags = sbp_cmd_status->s_key; | | | |
1712 | if(sbp_cmd_status->mark) | | | |
1713 | sense->flags |= SSD_FILEMARK; | | | |
1714 | if(sbp_cmd_status->eom) | | | |
1715 | sense->flags |= SSD_EOM; | | | |
1716 | if(sbp_cmd_status->ill_len) | | | |
1717 | sense->flags |= SSD_ILI; | | | |
1718 | | | | |
1719 | bcopy(&sbp_cmd_status->info, &sense->information[0], 4); | | | |
1720 | | | | |
1721 | if (sbp_status->len <= 1) | | | |
1722 | /* XXX not scsi status. shouldn't be happened */ | | | |
1723 | sense->asl = 0; | | | |
1724 | else if (sbp_status->len <= 4) | | | |
1725 | /* add_sense_code(_qual), info, cmd_spec_info */ | | | |
1726 | sense->asl = 6; | | | |
1727 | else | | | |
1728 | /* fru, sense_key_spec */ | | | |
1729 | sense->asl = 10; | | | |
1730 | | | | |
1731 | bcopy(&sbp_cmd_status->cdb, &sense->csi[0], 4); | | | |
1732 | | | | |
1733 | sense->asc = sbp_cmd_status->s_code; | | | |
1734 | sense->ascq = sbp_cmd_status->s_qlfr; | | | |
1735 | sense->fruc = sbp_cmd_status->fru; | | | |
1736 | | | | |
1737 | bcopy(&sbp_cmd_status->s_keydep[0], &sense->sks[0], 3); | | | |
1738 | SCSI_XFER_ERROR(ocb->sxfer) = XS_SENSE; | | | |
1739 | SCSI_XFER_STATUS(ocb->sxfer) = sbp_cmd_status->status; | | | |
1740 | /* | | | |
1741 | { | | | |
1742 | uint8_t j, *tmp; | | | |
1743 | tmp = sense; | | | |
1744 | for( j = 0 ; j < 32 ; j+=8){ | | | |
1745 | printf("sense %02x%02x %02x%02x %02x%02x %02x%02x\n", | | | |
1746 | tmp[j], tmp[j+1], tmp[j+2], tmp[j+3], | | | |
1747 | tmp[j+4], tmp[j+5], tmp[j+6], tmp[j+7]); | | | |
1748 | } | | | |
1749 | | | | |
1750 | } | | | |
1751 | */ | | | |
1752 | break; | | | |
1753 | default: | | | |
1754 | sbp_show_sdev_info(ocb->sdev, 2); | | | |
1755 | printf("sbp_scsi_status: unknown scsi status 0x%x\n", | | | |
1756 | sbp_cmd_status->status); | | | |
1757 | } | | | |
1758 | } | | | |
1759 | | | | |
1760 | static void | | | |
1761 | sbp_fix_inq_data(struct sbp_ocb *ocb) | | | |
1762 | { | | | |
1763 | sbp_scsi_xfer *sxfer = ocb->sxfer; | | | |
1764 | struct sbp_dev *sdev; | | | |
1765 | scsi3_inquiry_data_t inq = | | | |
1766 | (scsi3_inquiry_data_t)SCSI_INQUIRY_DATA(sxfer); | | | |
1767 | sdev = ocb->sdev; | | | |
1768 | | | | |
1769 | if (SCSI_XFER_EVPD(sxfer)) | | | |
1770 | return; | | | |
1771 | SBP_DEBUG(1) | | | |
1772 | sbp_show_sdev_info(sdev, 2); | | | |
1773 | printf("sbp_fix_inq_data\n"); | | | |
1774 | END_DEBUG | | | |
1775 | switch (inq->device & SID_TYPE) { | | | |
1776 | case T_DIRECT: | | | |
1777 | #if 0 | | | |
1778 | /* | | | |
1779 | * XXX Convert Direct Access device to RBC. | | | |
1780 | * I've never seen FireWire DA devices which support READ_6. | | | |
1781 | */ | | | |
1782 | if ((inq->device & SID_TYPE) == T_DIRECT) | | | |
1783 | inq->device |= T_RBC; /* T_DIRECT == 0 */ | | | |
1784 | #endif | | | |
1785 | /* fall through */ | | | |
1786 | case T_RBC: | | | |
1787 | /* | | | |
1788 | * Override vendor/product/revision information. | | | |
1789 | * Some devices sometimes return strange strings. | | | |
1790 | */ | | | |
1791 | #if 1 | | | |
1792 | bcopy(sdev->vendor, inq->vendor, sizeof(inq->vendor)); | | | |
1793 | bcopy(sdev->product, inq->product, sizeof(inq->product)); | | | |
1794 | bcopy(sdev->revision+2, inq->revision, sizeof(inq->revision)); | | | |
1795 | #endif | | | |
1796 | break; | | | |
1797 | } | | | |
1798 | /* | | | |
1799 | * Force to enable/disable tagged queuing. | | | |
1800 | * XXX CAM also checks SCP_QUEUE_DQUE flag in the control mode page. | | | |
1801 | */ | | | |
1802 | if (sbp_tags > 0) | | | |
1803 | inq->flags[1] |= SID_CmdQue; | | | |
1804 | else if (sbp_tags < 0) | | | |
1805 | inq->flags[1] &= ~SID_CmdQue; | | | |
1806 | | | | |
1807 | } | | | |
1808 | | | | |
1809 | static void | | | |
1810 | sbp_recv1(struct fw_xfer *xfer) | | | |
1811 | { | | | |
1812 | struct fw_pkt *rfp; | | | |
1813 | #if NEED_RESPONSE | | | |
1814 | struct fw_pkt *sfp; | | | |
1815 | #endif | | | |
1816 | struct sbp_softc *sbp; | | | |
1817 | struct sbp_dev *sdev; | | | |
1818 | struct sbp_ocb *ocb; | | | |
1819 | struct sbp_login_res *login_res = NULL; | | | |
1820 | struct sbp_status *sbp_status; | | | |
1821 | struct sbp_target *target; | | | |
1822 | int orb_fun, status_valid0, status_valid, l, reset_agent = 0; | | | |
1823 | uint32_t addr; | | | |
1824 | /* | | | |
1825 | uint32_t *ld; | | | |
1826 | ld = xfer->recv.buf; | | | |
1827 | printf("sbp %x %d %d %08x %08x %08x %08x\n", | | | |
1828 | xfer->resp, xfer->recv.len, xfer->recv.off, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3])); | | | |
1829 | printf("sbp %08x %08x %08x %08x\n", ntohl(ld[4]), ntohl(ld[5]), ntohl(ld[6]), ntohl(ld[7])); | | | |
1830 | printf("sbp %08x %08x %08x %08x\n", ntohl(ld[8]), ntohl(ld[9]), ntohl(ld[10]), ntohl(ld[11])); | | | |
1831 | */ | | | |
1832 | sbp = (struct sbp_softc *)xfer->sc; | | | |
1833 | if (xfer->resp != 0){ | | | |
1834 | printf("sbp_recv: xfer->resp = %d\n", xfer->resp); | | | |
1835 | goto done0; | | | |
1836 | } | | | |
1837 | if (xfer->recv.payload == NULL){ | | | |
1838 | printf("sbp_recv: xfer->recv.payload == NULL\n"); | | | |
1839 | goto done0; | | | |
1840 | } | | | |
1841 | rfp = &xfer->recv.hdr; | | | |
1842 | if(rfp->mode.wreqb.tcode != FWTCODE_WREQB){ | | | |
1843 | printf("sbp_recv: tcode = %d\n", rfp->mode.wreqb.tcode); | | | |
1844 | goto done0; | | | |
1845 | } | | | |
1846 | sbp_status = (struct sbp_status *)xfer->recv.payload; | | | |
1847 | addr = rfp->mode.wreqb.dest_lo; | | | |
1848 | SBP_DEBUG(2) | | | |
1849 | printf("received address 0x%x\n", addr); | | | |
1850 | END_DEBUG | | | |
1851 | target = &sbp->target; | | | |
1852 | l = SBP_ADDR2LUN(addr); | | | |
1853 | if (l >= target->num_lun || target->luns[l] == NULL) { | | | |
1854 | fw_printf(sbp->fd.dev, | | | |
1855 | "sbp_recv1: invalid lun %d (target=%d)\n", | | | |
1856 | l, target->target_id); | | | |
1857 | goto done0; | | | |
1858 | } | | | |
1859 | sdev = target->luns[l]; | | | |
1860 | | | | |
1861 | fwdma_sync(&sdev->dma, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | | | |
1862 | | | | |
1863 | ocb = NULL; | | | |
1864 | switch (sbp_status->src) { | | | |
1865 | case SRC_NEXT_EXISTS: | | | |
1866 | case SRC_NO_NEXT: | | | |
1867 | /* check mgm_ocb_cur first */ | | | |
1868 | ocb = target->mgm_ocb_cur; | | | |
1869 | if (ocb != NULL) { | | | |
1870 | if (OCB_MATCH(ocb, sbp_status)) { | | | |
1871 | fw_callout_stop(&target->mgm_ocb_timeout); | | | |
1872 | target->mgm_ocb_cur = NULL; | | | |
1873 | break; | | | |
1874 | } | | | |
1875 | } | | | |
1876 | ocb = sbp_dequeue_ocb(sdev, sbp_status); | | | |
1877 | if (ocb == NULL) { | | | |
1878 | sbp_show_sdev_info(sdev, 2); | | | |
1879 | #if defined(__DragonFly__) || \ | | | |
1880 | (defined(__FreeBSD__) && __FreeBSD_version < 500000) | | | |
1881 | printf("No ocb(%lx) on the queue\n", | | | |
1882 | #else | | | |
1883 | printf("No ocb(%x) on the queue\n", | | | |
1884 | #endif | | | |
1885 | ntohl(sbp_status->orb_lo)); | | | |
1886 | } | | | |
1887 | break; | | | |
1888 | case SRC_UNSOL: | | | |
1889 | /* unsolicit */ | | | |
1890 | sbp_show_sdev_info(sdev, 2); | | | |
1891 | printf("unsolicit status received\n"); | | | |
1892 | break; | | | |
1893 | default: | | | |
1894 | sbp_show_sdev_info(sdev, 2); | | | |
1895 | printf("unknown sbp_status->src\n"); | | | |
1896 | } | | | |
1897 | | | | |
1898 | status_valid0 = (sbp_status->src < 2 | | | |
1899 | && sbp_status->resp == SBP_REQ_CMP | | | |
1900 | && sbp_status->dead == 0); | | | |
1901 | status_valid = (status_valid0 && sbp_status->status == 0); | | | |
1902 | | | | |
1903 | if (!status_valid0 || debug > 2){ | | | |
1904 | int status; | | | |
1905 | SBP_DEBUG(0) | | | |
1906 | sbp_show_sdev_info(sdev, 2); | | | |
1907 | printf("ORB status src:%x resp:%x dead:%x" | | | |
1908 | #if defined(__DragonFly__) || \ | | | |
1909 | (defined(__FreeBSD__) && __FreeBSD_version < 500000) | | | |
1910 | " len:%x stat:%x orb:%x%08lx\n", | | | |
1911 | #else | | | |
1912 | " len:%x stat:%x orb:%x%08x\n", | | | |
1913 | #endif | | | |
1914 | sbp_status->src, sbp_status->resp, sbp_status->dead, | | | |
1915 | sbp_status->len, sbp_status->status, | | | |
1916 | ntohs(sbp_status->orb_hi), ntohl(sbp_status->orb_lo)); | | | |
1917 | END_DEBUG | | | |
1918 | sbp_show_sdev_info(sdev, 2); | | | |
1919 | status = sbp_status->status; | | | |
1920 | switch(sbp_status->resp) { | | | |
1921 | case SBP_REQ_CMP: | | | |
1922 | if (status > MAX_ORB_STATUS0) | | | |
1923 | printf("%s\n", orb_status0[MAX_ORB_STATUS0]); | | | |
1924 | else | | | |
1925 | printf("%s\n", orb_status0[status]); | | | |
1926 | break; | | | |
1927 | case SBP_TRANS_FAIL: | | | |
1928 | printf("Obj: %s, Error: %s\n", | | | |
1929 | orb_status1_object[(status>>6) & 3], | | | |
1930 | orb_status1_serial_bus_error[status & 0xf]); | | | |
1931 | break; | | | |
1932 | case SBP_ILLE_REQ: | | | |
1933 | printf("Illegal request\n"); | | | |
1934 | break; | | | |
1935 | case SBP_VEND_DEP: | | | |
1936 | printf("Vendor dependent\n"); | | | |
1937 | break; | | | |
1938 | default: | | | |
1939 | printf("unknown respose code %d\n", sbp_status->resp); | | | |
1940 | } | | | |
1941 | } | | | |
1942 | | | | |
1943 | /* we have to reset the fetch agent if it's dead */ | | | |
1944 | if (sbp_status->dead) { | | | |
1945 | if (SBP_DEVICE(sdev) != NULL) { | | | |
1946 | SBP_LOCK(sbp); | | | |
1947 | SBP_DEVICE_FREEZE(sdev, 1); | | | |
1948 | sdev->freeze ++; | | | |
1949 | SBP_UNLOCK(sbp); | | | |
1950 | } | | | |
1951 | reset_agent = 1; | | | |
1952 | } | | | |
1953 | | | | |
1954 | if (ocb == NULL) | | | |
1955 | goto done; | | | |
1956 | | | | |
1957 | switch(ntohl(ocb->orb[4]) & ORB_FMT_MSK){ | | | |
1958 | case ORB_FMT_NOP: | | | |
1959 | break; | | | |
1960 | case ORB_FMT_VED: | | | |
1961 | break; | | | |
1962 | case ORB_FMT_STD: | | | |
1963 | switch(ocb->flags) { | | | |
1964 | case OCB_ACT_MGM: | | | |
1965 | orb_fun = ntohl(ocb->orb[4]) & ORB_FUN_MSK; | | | |
1966 | reset_agent = 0; | | | |
1967 | switch(orb_fun) { | | | |
1968 | case ORB_FUN_LGI: | | | |
1969 | login_res = sdev->login; | | | |
1970 | login_res->len = ntohs(login_res->len); | | | |
1971 | login_res->id = ntohs(login_res->id); | | | |
1972 | login_res->cmd_hi = ntohs(login_res->cmd_hi); | | | |
1973 | login_res->cmd_lo = ntohl(login_res->cmd_lo); | | | |
1974 | if (status_valid) { | | | |
1975 | SBP_DEBUG(0) | | | |
1976 | sbp_show_sdev_info(sdev, 2); | | | |
1977 | printf("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)); | | | |
1978 | END_DEBUG | | | |
1979 | sbp_busy_timeout(sdev); | | | |
1980 | } else { | | | |
1981 | /* forgot logout? */ | | | |
1982 | sbp_show_sdev_info(sdev, 2); | | | |
1983 | printf("login failed\n"); | | | |
1984 | sdev->status = SBP_DEV_RESET; | | | |
1985 | } | | | |
1986 | break; | | | |
1987 | case ORB_FUN_RCN: | | | |
1988 | login_res = sdev->login; | | | |
1989 | if (status_valid) { | | | |
1990 | SBP_DEBUG(0) | | | |
1991 | sbp_show_sdev_info(sdev, 2); | | | |
1992 | printf("reconnect: len %d, ID %d, cmd %08x%08x\n", login_res->len, login_res->id, login_res->cmd_hi, login_res->cmd_lo); | | | |
1993 | END_DEBUG | | | |
1994 | #if 1 | | | |
1995 | #if defined(__FreeBSD__) | | | |
1996 | if (sdev->status == SBP_DEV_ATTACHED) | | | |
1997 | sbp_scan_dev(sdev); | | | |
1998 | else | | | |
1999 | #endif | | | |
2000 | sbp_agent_reset(sdev); | | | |
2001 | #else | | | |
2002 | sdev->status = SBP_DEV_ATTACHED; | | | |
2003 | sbp_mgm_orb(sdev, ORB_FUN_ATS, NULL); | | | |
2004 | #endif | | | |
2005 | } else { | | | |
2006 | /* reconnection hold time exceed? */ | | | |
2007 | SBP_DEBUG(0) | | | |
2008 | sbp_show_sdev_info(sdev, 2); | | | |
2009 | printf("reconnect failed\n"); | | | |
2010 | END_DEBUG | | | |
2011 | sbp_login(sdev); | | | |
2012 | } | | | |
2013 | break; | | | |
2014 | case ORB_FUN_LGO: | | | |
2015 | sdev->status = SBP_DEV_RESET; | | | |
2016 | break; | | | |
2017 | case ORB_FUN_RST: | | | |
2018 | sbp_busy_timeout(sdev); | | | |
2019 | break; | | | |
2020 | case ORB_FUN_LUR: | | | |
2021 | case ORB_FUN_ATA: | | | |
2022 | case ORB_FUN_ATS: | | | |
2023 | sbp_agent_reset(sdev); | | | |
2024 | break; | | | |
2025 | default: | | | |
2026 | sbp_show_sdev_info(sdev, 2); | | | |
2027 | printf("unknown function %d\n", orb_fun); | | | |
2028 | break; | | | |
2029 | } | | | |
2030 | sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL); | | | |
2031 | break; | | | |
2032 | case OCB_ACT_CMD: | | | |
2033 | sdev->timeout = 0; | | | |
2034 | if(ocb->sxfer != NULL){ | | | |
2035 | sbp_scsi_xfer *sxfer = ocb->sxfer; | | | |
2036 | /* | | | |
2037 | uint32_t *ld = SCSI_XFER_DATA(ocb->sxfer); | | | |
2038 | if(ld != NULL && | | | |
2039 | SCSI_XFER_DATALEN(ocb->sxfer) != 0) | | | |
2040 | printf("ptr %08x %08x %08x %08x\n", ld[0], ld[1], ld[2], ld[3]); | | | |
2041 | else | | | |
2042 | printf("ptr NULL\n"); | | | |
2043 | printf("len %d\n", sbp_status->len); | | | |
2044 | */ | | | |
2045 | if(sbp_status->len > 1){ | | | |
2046 | sbp_scsi_status(sbp_status, ocb); | | | |
2047 | }else{ | | | |
2048 | if(sbp_status->resp != SBP_REQ_CMP){ | | | |
2049 | SCSI_XFER_ERROR(sxfer) = | | | |
2050 | XS_REQ_CMP_ERR; | | | |
2051 | }else{ | | | |
2052 | SCSI_XFER_ERROR(sxfer) = | | | |
2053 | XS_REQ_CMP; | | | |
2054 | SCSI_XFER_REQUEST_COMPLETE( | | | |
2055 | sxfer); | | | |
2056 | } | | | |
2057 | } | | | |
2058 | /* fix up inq data */ | | | |
2059 | if (SCSI_XFER_OPECODE(sxfer) == INQUIRY) | | | |
2060 | sbp_fix_inq_data(ocb); | | | |
2061 | SBP_LOCK(sbp); | | | |
2062 | SCSI_TRANSFER_DONE(sxfer); | | | |
2063 | SBP_UNLOCK(sbp); | | | |
2064 | } | | | |
2065 | break; | | | |
2066 | default: | | | |
2067 | break; | | | |
2068 | } | | | |
2069 | } | | | |
2070 | | | | |
2071 | if (!use_doorbell) | | | |
2072 | sbp_free_ocb(sdev, ocb); | | | |
2073 | done: | | | |
2074 | if (reset_agent) | | | |
2075 | sbp_agent_reset(sdev); | | | |
2076 | | | | |
2077 | done0: | | | |
2078 | xfer->recv.pay_len = SBP_RECV_LEN; | | | |
2079 | /* The received packet is usually small enough to be stored within | | | |
2080 | * the buffer. In that case, the controller return ack_complete and | | | |
2081 | * no respose is necessary. | | | |
2082 | * | | | |
2083 | * XXX fwohci.c and firewire.c should inform event_code such as | | | |
2084 | * ack_complete or ack_pending to upper driver. | | | |
2085 | */ | | | |
2086 | #if NEED_RESPONSE | | | |
2087 | xfer->send.off = 0; | | | |
2088 | sfp = (struct fw_pkt *)xfer->send.buf; | | | |
2089 | sfp->mode.wres.dst = rfp->mode.wreqb.src; | | | |
2090 | xfer->dst = sfp->mode.wres.dst; | | | |
2091 | xfer->spd = min(sdev->target->fwdev->speed, max_speed); | | | |
2092 | xfer->hand = sbp_loginres_callback; | | | |
2093 | | | | |
2094 | sfp->mode.wres.tlrt = rfp->mode.wreqb.tlrt; | | | |
2095 | sfp->mode.wres.tcode = FWTCODE_WRES; | | | |
2096 | sfp->mode.wres.rtcode = 0; | | | |
2097 | sfp->mode.wres.pri = 0; | | | |
2098 | | | | |
2099 | fw_asyreq(xfer->fc, -1, xfer); | | | |
2100 | #else | | | |
2101 | /* recycle */ | | | |
2102 | STAILQ_INSERT_TAIL(&sbp->fwb.xferlist, xfer, link); | | | |
2103 | #endif | | | |
2104 | | | | |
2105 | return; | | | |
2106 | | | | |
2107 | } | | | |
2108 | | | | |
2109 | static void | | | |
2110 | sbp_recv(struct fw_xfer *xfer) | | | |
2111 | { | | | |
2112 | int s; | | | |
2113 | | | | |
2114 | s = splfwsbp(); | | | |
2115 | sbp_recv1(xfer); | | | |
2116 | splx(s); | | | |
2117 | } | | | |
2118 | /* | | | |
2119 | * sbp_attach() | | | |
2120 | */ | | | |
2121 | FW_ATTACH(sbp) | | | |
2122 | { | | | |
2123 | FW_ATTACH_START(sbp, sbp, fwa); | | | |
2124 | int dv_unit, error, s; | | | |
2125 | struct firewire_comm *fc; | | | |
2126 | SBP_ATTACH_START; | | | |
2127 | | | | |
2128 | if (DFLTPHYS > SBP_MAXPHYS) | | | |
2129 | fw_printf(sbp->fd.dev, | | | |
2130 | "Warning, DFLTPHYS(%dKB) is larger than " | | | |
2131 | "SBP_MAXPHYS(%dKB).\n", DFLTPHYS / 1024, | | | |
2132 | SBP_MAXPHYS / 1024); | | | |
2133 | SBP_DEBUG(0) | | | |
2134 | printf("sbp_attach (cold=%d)\n", cold); | | | |
2135 | END_DEBUG | | | |
2136 | | | | |
2137 | if (cold) | | | |
2138 | sbp_cold ++; | | | |
2139 | sbp->fd.fc = fc = fwa->fc; | | | |
2140 | fw_mtx_init(&sbp->mtx, "sbp", NULL, MTX_DEF); | | | |
2141 | | | | |
2142 | if (max_speed < 0) | | | |
2143 | max_speed = fc->speed; | | | |
2144 | | | | |
2145 | error = fw_bus_dma_tag_create(/*parent*/fc->dmat, | | | |
2146 | /* XXX shoud be 4 for sane backend? */ | | | |
2147 | /*alignment*/1, | | | |
2148 | /*boundary*/0, | | | |
2149 | /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, | | | |
2150 | /*highaddr*/BUS_SPACE_MAXADDR, | | | |
2151 | /*filter*/NULL, /*filterarg*/NULL, | | | |
2152 | /*maxsize*/0x100000, /*nsegments*/SBP_IND_MAX, | | | |
2153 | /*maxsegsz*/SBP_SEG_MAX, | | | |
2154 | /*flags*/BUS_DMA_ALLOCNOW, | | | |
2155 | /*lockfunc*/busdma_lock_mutex, | | | |
2156 | /*lockarg*/&sbp->mtx, | | | |
2157 | &sbp->dmat); | | | |
2158 | if (error != 0) { | | | |
2159 | printf("sbp_attach: Could not allocate DMA tag " | | | |
2160 | "- error %d\n", error); | | | |
2161 | FW_ATTACH_RETURN(ENOMEM); | | | |
2162 | } | | | |
2163 | | | | |
2164 | #if defined(__FreeBSD__) | | | |
2165 | devq = cam_simq_alloc(/*maxopenings*/SBP_NUM_OCB); | | | |
2166 | if (devq == NULL) | | | |
2167 | return (ENXIO); | | | |
2168 | #endif | | | |
2169 | | | | |
2170 | sbp->target.fwdev = NULL; | | | |
2171 | sbp->target.luns = NULL; | | | |
2172 | | | | |
2173 | if (sbp_alloc_target(sbp, fwa->fwdev) == NULL) | | | |
2174 | FW_ATTACH_RETURN(ENXIO); | | | |
2175 | | | | |
2176 | SBP_SCSIBUS_ATTACH; | | | |
2177 | | | | |
2178 | /* We reserve 16 bit space (4 bytes X 64 unit X 256 luns) */ | | | |
2179 | dv_unit = fw_get_unit(sbp->fd.dev); | | | |
2180 | sbp->fwb.start = SBP_DEV2ADDR(dv_unit, 0); | | | |
2181 | sbp->fwb.end = SBP_DEV2ADDR(dv_unit, -1); | | | |
2182 | /* pre-allocate xfer */ | | | |
2183 | STAILQ_INIT(&sbp->fwb.xferlist); | | | |
2184 | fw_xferlist_add(&sbp->fwb.xferlist, M_SBP, | | | |
2185 | /*send*/ 0, /*recv*/ SBP_RECV_LEN, SBP_NUM_OCB/2, | | | |
2186 | fc, (void *)sbp, sbp_recv); | | | |
2187 | fw_bindadd(fc, &sbp->fwb); | | | |
2188 | | | | |
2189 | sbp->fd.post_busreset = sbp_post_busreset; | | | |
2190 | sbp->fd.post_explore = sbp_post_explore; | | | |
2191 | | | | |
2192 | if (fc->status != FWBUSNOTREADY) { | | | |
2193 | s = splfw(); | | | |
2194 | sbp_post_busreset((void *)sbp); | | | |
2195 | sbp_post_explore((void *)sbp); | | | |
2196 | splx(s); | | | |
2197 | } | | | |
2198 | | | | |
2199 | FW_ATTACH_RETURN(0); | | | |
2200 | #if defined(__FreeBSD__) | | | |
2201 | fail: | | | |
2202 | SBP_UNLOCK(sbp); | | | |
2203 | cam_sim_free(sbp->sim, /*free_devq*/TRUE); | | | |
2204 | return (ENXIO); | | | |
2205 | #endif | | | |
2206 | } | | | |
2207 | | | | |
2208 | static int | | | |
2209 | sbp_logout_all(struct sbp_softc *sbp) | | | |
2210 | { | | | |
2211 | struct sbp_target *target; | | | |
2212 | struct sbp_dev *sdev; | | | |
2213 | int i; | | | |
2214 | | | | |
2215 | SBP_DEBUG(0) | | | |
2216 | printf("sbp_logout_all\n"); | | | |
2217 | END_DEBUG | | | |
2218 | target = &sbp->target; | | | |
2219 | if (target->luns != NULL) | | | |
2220 | for (i = 0; i < target->num_lun; i++) { | | | |
2221 | sdev = target->luns[i]; | | | |
2222 | if (sdev == NULL) | | | |
2223 | continue; | | | |
2224 | fw_callout_stop(&sdev->login_callout); | | | |
2225 | if (sdev->status >= SBP_DEV_TOATTACH && | | | |
2226 | sdev->status <= SBP_DEV_ATTACHED) | | | |
2227 | sbp_mgm_orb(sdev, ORB_FUN_LGO, NULL); | | | |
2228 | } | | | |
2229 | | | | |
2230 | return 0; | | | |
2231 | } | | | |
2232 | | | | |
2233 | #if defined(__FreeBSD__) | | | |
2234 | static int | | | |
2235 | sbp_shutdown(device_t dev) | | | |
2236 | { | | | |
2237 | struct sbp_softc *sbp = ((struct sbp_softc *)device_get_softc(dev)); | | | |
2238 | | | | |
2239 | sbp_logout_all(sbp); | | | |
2240 | return (0); | | | |
2241 | } | | | |
2242 | #endif | | | |
2243 | | | | |
2244 | static void | | | |
2245 | sbp_free_sdev(struct sbp_dev *sdev) | | | |
2246 | { | | | |
2247 | int i; | | | |
2248 | | | | |
2249 | if (sdev == NULL) | | | |
2250 | return; | | | |
2251 | for (i = 0; i < SBP_QUEUE_LEN; i++) | | | |
2252 | fw_bus_dmamap_destroy(sdev->target->sbp->dmat, | | | |
2253 | sdev->ocb[i].dmamap); | | | |
2254 | fwdma_free(sdev->target->sbp->fd.fc, &sdev->dma); | | | |
2255 | free(sdev, M_SBP); | | | |
2256 | } | | | |
2257 | | | | |
2258 | static void | | | |
2259 | sbp_free_target(struct sbp_target *target) | | | |
2260 | { | | | |
2261 | struct sbp_softc *sbp; | | | |
2262 | struct fw_xfer *xfer, *next; | | | |
2263 | int i; | | | |
2264 | | | | |
2265 | if (target->luns == NULL) | | | |
2266 | return; | | | |
2267 | fw_callout_stop(&target->mgm_ocb_timeout); | | | |
2268 | sbp = target->sbp; | | | |
2269 | for (i = 0; i < target->num_lun; i++) | | | |
2270 | sbp_free_sdev(target->luns[i]); | | | |
2271 | | | | |
2272 | for (xfer = STAILQ_FIRST(&target->xferlist); | | | |
2273 | xfer != NULL; xfer = next) { | | | |
2274 | next = STAILQ_NEXT(xfer, link); | | | |
2275 | fw_xfer_free_buf(xfer); | | | |
2276 | } | | | |
2277 | STAILQ_INIT(&target->xferlist); | | | |
2278 | free(target->luns, M_SBP); | | | |
2279 | target->num_lun = 0; | | | |
2280 | target->luns = NULL; | | | |
2281 | target->fwdev = NULL; | | | |
2282 | } | | | |
2283 | | | | |
2284 | FW_DETACH(sbp) | | | |
2285 | { | | | |
2286 | FW_DETACH_START(sbp, sbp); | | | |
2287 | struct firewire_comm *fc = sbp->fd.fc; | | | |
2288 | int i; | | | |
2289 | | | | |
2290 | SBP_DEBUG(0) | | | |
2291 | printf("sbp_detach\n"); | | | |
2292 | END_DEBUG | | | |
2293 | | | | |
2294 | SBP_DETACH_TARGET(&sbp->target); | | | |
2295 | #if defined(__FreeBSD__) | | | |
2296 | SBP_LOCK(sbp); | | | |
2297 | xpt_async(AC_LOST_DEVICE, sbp->path, NULL); | | | |
2298 | xpt_free_path(sbp->path); | | | |
2299 | xpt_bus_deregister(cam_sim_path(sbp->sim)); | | | |
2300 | cam_sim_free(sbp->sim, /*free_devq*/ TRUE), | | | |
2301 | SBP_UNLOCK(sbp); | | | |
2302 | #endif | | | |
2303 | | | | |
2304 | sbp_logout_all(sbp); | | | |
2305 | | | | |
2306 | /* XXX wait for logout completion */ | | | |
2307 | tsleep(&i, FWPRI, "sbpdtc", hz/2); | | | |
2308 | | | | |
2309 | sbp_free_target(&sbp->target); | | | |
2310 | | | | |
2311 | fw_bindremove(fc, &sbp->fwb); | | | |
2312 | fw_xferlist_remove(&sbp->fwb.xferlist); | | | |
2313 | | | | |
2314 | fw_bus_dma_tag_destroy(sbp->dmat); | | | |
2315 | fw_mtx_destroy(&sbp->mtx); | | | |
2316 | | | | |
2317 | return (0); | | | |
2318 | } | | | |
2319 | | | | |
2320 | #if defined(__FreeBSD__) | | | |
2321 | static void | | | |
2322 | sbp_cam_detach_sdev(struct sbp_dev *sdev) | | | |
2323 | { | | | |
2324 | if (sdev == NULL) | | | |
2325 | return; | | | |
2326 | if (sdev->status == SBP_DEV_DEAD) | | | |
2327 | return; | | | |
2328 | if (sdev->status == SBP_DEV_RESET) | | | |
2329 | return; | | | |
2330 | sbp_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE); | | | |
2331 | if (sdev->path) { | | | |
2332 | SBP_LOCK(sdev->target->sbp); | | | |
2333 | xpt_release_devq(sdev->path, | | | |
2334 | sdev->freeze, TRUE); | | | |
2335 | sdev->freeze = 0; | | | |
2336 | xpt_async(AC_LOST_DEVICE, sdev->path, NULL); | | | |
2337 | xpt_free_path(sdev->path); | | | |
2338 | sdev->path = NULL; | | | |
2339 | SBP_UNLOCK(sdev->target->sbp); | | | |
2340 | } | | | |
2341 | } | | | |
2342 | | | | |
2343 | static void | | | |
2344 | sbp_cam_detach_target(struct sbp_target *target) | | | |
2345 | { | | | |
2346 | int i; | | | |
2347 | | | | |
2348 | if (target->luns != NULL) { | | | |
2349 | SBP_DEBUG(0) | | | |
2350 | printf("sbp_detach_target %d\n", target->target_id); | | | |
2351 | END_DEBUG | | | |
2352 | fw_callout_stop(&target->scan_callout); | | | |
2353 | for (i = 0; i < target->num_lun; i++) | | | |
2354 | sbp_cam_detach_sdev(target->luns[i]); | | | |
2355 | } | | | |
2356 | } | | | |
2357 | #elif defined(__NetBSD__) | | | |
2358 | static void | | | |
2359 | sbp_scsipi_detach_sdev(struct sbp_dev *sdev) | | | |
2360 | { | | | |
2361 | struct sbp_target *target; | | | |
2362 | struct sbp_softc *sbp; | | | |
2363 | | | | |
2364 | if (sdev == NULL) | | | |
2365 | return; | | | |
2366 | | | | |
2367 | target = sdev->target; | | | |
2368 | if (target == NULL) | | | |
2369 | return; | | | |
2370 | | | | |
2371 | sbp = target->sbp; | | | |
2372 | | | | |
2373 | if (sdev->status == SBP_DEV_DEAD) | | | |
2374 | return; | | | |
2375 | if (sdev->status == SBP_DEV_RESET) | | | |
2376 | return; | | | |
2377 | if (sdev->periph) { | | | |
2378 | scsipi_periph_thaw(sdev->periph, sdev->freeze); | | | |
2379 | scsipi_channel_thaw(&sbp->sc_channel, 0); /* XXXX */ | | | |
2380 | sdev->freeze = 0; | | | |
2381 | if (scsipi_target_detach(&sbp->sc_channel, | | | |
2382 | target->target_id, sdev->lun_id, DETACH_FORCE) != 0) { | | | |
2383 | sbp_show_sdev_info(sdev, 2); | | | |
2384 | printf("detach failed\n"); | | | |
2385 | } | | | |
2386 | sdev->periph = NULL; | | | |
2387 | } | | | |
2388 | sbp_abort_all_ocbs(sdev, XS_DEV_NOT_THERE); | | | |
2389 | } | | | |
2390 | | | | |
2391 | static void | | | |
2392 | sbp_scsipi_detach_target(struct sbp_target *target) | | | |
2393 | { | | | |
2394 | struct sbp_softc *sbp = target->sbp; | | | |
2395 | int i; | | | |
2396 | | | | |
2397 | if (target->luns != NULL) { | | | |
2398 | SBP_DEBUG(0) | | | |
2399 | printf("sbp_detach_target %d\n", target->target_id); | | | |
2400 | END_DEBUG | | | |
2401 | fw_callout_stop(&target->scan_callout); | | | |
2402 | for (i = 0; i < target->num_lun; i++) | | | |
2403 | sbp_scsipi_detach_sdev(target->luns[i]); | | | |
2404 | if (config_detach(sbp->sc_bus, DETACH_FORCE) != 0) | | | |
2405 | fw_printf(sbp->fd.dev, "%d detach failed\n", | | | |
2406 | target->target_id); | | | |
2407 | sbp->sc_bus = NULL; | | | |
2408 | } | | | |
2409 | } | | | |
2410 | #endif | | | |
2411 | | | | |
2412 | static void | | | |
2413 | sbp_target_reset(struct sbp_dev *sdev, int method) | | | |
2414 | { | | | |
2415 | int i; | | | |
2416 | struct sbp_target *target = sdev->target; | | | |
2417 | struct sbp_dev *tsdev; | | | |
2418 | | | | |
2419 | for (i = 0; i < target->num_lun; i++) { | | | |
2420 | tsdev = target->luns[i]; | | | |
2421 | if (tsdev == NULL) | | | |
2422 | continue; | | | |
2423 | if (tsdev->status == SBP_DEV_DEAD) | | | |
2424 | continue; | | | |
2425 | if (tsdev->status == SBP_DEV_RESET) | | | |
2426 | continue; | | | |
2427 | SBP_LOCK(target->sbp); | | | |
2428 | SBP_DEVICE_FREEZE(tsdev, 1); | | | |
2429 | tsdev->freeze ++; | | | |
2430 | SBP_UNLOCK(target->sbp); | | | |
2431 | sbp_abort_all_ocbs(tsdev, XS_CMD_TIMEOUT); | | | |
2432 | if (method == 2) | | | |
2433 | tsdev->status = SBP_DEV_LOGIN; | | | |
2434 | } | | | |
2435 | switch(method) { | | | |
2436 | case 1: | | | |
2437 | printf("target reset\n"); | | | |
2438 | sbp_mgm_orb(sdev, ORB_FUN_RST, NULL); | | | |
2439 | break; | | | |
2440 | case 2: | | | |
2441 | printf("reset start\n"); | | | |
2442 | sbp_reset_start(sdev); | | | |
2443 | break; | | | |
2444 | } | | | |
2445 | | | | |
2446 | } | | | |
2447 | | | | |
2448 | static void | | | |
2449 | sbp_mgm_timeout(void *arg) | | | |
2450 | { | | | |
2451 | struct sbp_ocb *ocb = (struct sbp_ocb *)arg; | | | |
2452 | struct sbp_dev *sdev = ocb->sdev; | | | |
2453 | struct sbp_target *target = sdev->target; | | | |
2454 | | | | |
2455 | sbp_show_sdev_info(sdev, 2); | | | |
2456 | printf("request timeout(mgm orb:0x%08x) ... ", | | | |
2457 | (uint32_t)ocb->bus_addr); | | | |
2458 | target->mgm_ocb_cur = NULL; | | | |
2459 | sbp_free_ocb(sdev, ocb); | | | |
2460 | #if 0 | | | |
2461 | /* XXX */ | | | |
2462 | printf("run next request\n"); | | | |
2463 | sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL); | | | |
2464 | #endif | | | |
2465 | #if 1 | | | |
2466 | printf("reset start\n"); | | | |
2467 | sbp_reset_start(sdev); | | | |
2468 | #endif | | | |
2469 | } | | | |
2470 | | | | |
2471 | static void | | | |
2472 | sbp_timeout(void *arg) | | | |
2473 | { | | | |
2474 | struct sbp_ocb *ocb = (struct sbp_ocb *)arg; | | | |
2475 | struct sbp_dev *sdev = ocb->sdev; | | | |
2476 | | | | |
2477 | sbp_show_sdev_info(sdev, 2); | | | |
2478 | printf("request timeout(cmd orb:0x%08x) ... ", | | | |
2479 | (uint32_t)ocb->bus_addr); | | | |
2480 | | | | |
2481 | sdev->timeout ++; | | | |
2482 | switch(sdev->timeout) { | | | |
2483 | case 1: | | | |
2484 | printf("agent reset\n"); | | | |
2485 | SBP_LOCK(sdev->target->sbp); | | | |
2486 | SBP_DEVICE_FREEZE(sdev, 1); | | | |
2487 | sdev->freeze ++; | | | |
2488 | SBP_UNLOCK(sdev->target->sbp); | | | |
2489 | sbp_abort_all_ocbs(sdev, XS_CMD_TIMEOUT); | | | |
2490 | sbp_agent_reset(sdev); | | | |
2491 | break; | | | |
2492 | case 2: | | | |
2493 | case 3: | | | |
2494 | sbp_target_reset(sdev, sdev->timeout - 1); | | | |
2495 | break; | | | |
2496 | #if 0 | | | |
2497 | default: | | | |
2498 | /* XXX give up */ | | | |
2499 | SBP_DETACH_TARGET(target); | | | |
2500 | if (target->luns != NULL) | | | |
2501 | free(target->luns, M_SBP); | | | |
2502 | target->num_lun = 0; | | | |
2503 | target->luns = NULL; | | | |
2504 | target->fwdev = NULL; | | | |
2505 | #endif | | | |
2506 | } | | | |
2507 | } | | | |
2508 | | | | |
2509 | static void | | | |
2510 | sbp_action1(struct sbp_softc *sbp, sbp_scsi_xfer *sxfer) | | | |
2511 | { | | | |
2512 | | | | |
2513 | struct sbp_target *target = NULL; | | | |
2514 | struct sbp_dev *sdev = NULL; | | | |
2515 | | | | |
2516 | /* target:lun -> sdev mapping */ | | | |
2517 | if (sbp != NULL) { | | | |
2518 | target = &sbp->target; | | | |
2519 | if (target->fwdev != NULL | | | |
2520 | && NOT_LUN_WILDCARD(SCSI_XFER_LUN(sxfer)) | | | |
2521 | && SCSI_XFER_LUN(sxfer) < target->num_lun) { | | | |
2522 | sdev = target->luns[SCSI_XFER_LUN(sxfer)]; | | | |
2523 | if (sdev != NULL && sdev->status != SBP_DEV_ATTACHED && | | | |
2524 | sdev->status != SBP_DEV_PROBE) | | | |
2525 | sdev = NULL; | | | |
2526 | } | | | |
2527 | } | | | |
2528 | | | | |
2529 | SBP_DEBUG(1) | | | |
2530 | if (sdev == NULL) | | | |
2531 | printf("invalid target %d lun %d\n", | | | |
2532 | SCSI_XFER_TARGET(sxfer), SCSI_XFER_LUN(sxfer)); | | | |
2533 | END_DEBUG | | | |
2534 | | | | |
2535 | switch (SCSI_XFER_FUNCCODE(sxfer)) { | | | |
2536 | case XPT_SCSI_IO: | | | |
2537 | #if defined(__FreeBSD__) | | | |
2538 | case XPT_RESET_DEV: | | | |
2539 | case XPT_GET_TRAN_SETTINGS: | | | |
2540 | case XPT_SET_TRAN_SETTINGS: | | | |
2541 | case XPT_CALC_GEOMETRY: | | | |
2542 | #endif | | | |
2543 | if (sdev == NULL) { | | | |
2544 | SBP_DEBUG(1) | | | |
2545 | printf("%s:%d:%d:func_code 0x%04x: " | | | |
2546 | "Invalid target (target needed)\n", | | | |
2547 | sbp ? fw_get_nameunit(sbp->fd.dev) : "???", | | | |
2548 | SCSI_XFER_TARGET(sxfer), SCSI_XFER_LUN(sxfer), | | | |
2549 | SCSI_XFER_FUNCCODE(sxfer)); | | | |
2550 | END_DEBUG | | | |
2551 | | | | |
2552 | SCSI_XFER_ERROR(sxfer) = XS_DEV_NOT_THERE; | | | |
2553 | SCSI_TRANSFER_DONE(sxfer); | | | |
2554 | return; | | | |
2555 | } | | | |
2556 | break; | | | |
2557 | #if defined(__FreeBSD__) | | | |
2558 | case XPT_PATH_INQ: | | | |
2559 | case XPT_NOOP: | | | |
2560 | /* The opcodes sometimes aimed at a target (sc is valid), | | | |
2561 | * sometimes aimed at the SIM (sc is invalid and target is | | | |
2562 | * CAM_TARGET_WILDCARD) | | | |
2563 | */ | | | |
2564 | if (sbp == NULL && | | | |
2565 | sxfer->ccb_h.target_id != CAM_TARGET_WILDCARD) { | | | |
2566 | SBP_DEBUG(0) | | | |
2567 | printf("%s:%d:%d func_code 0x%04x: " | | | |
2568 | "Invalid target (no wildcard)\n", | | | |
2569 | fw_get_nameunit(sbp->fd.dev), | | | |
2570 | sxfer->ccb_h.target_id, sxfer->ccb_h.target_lun, | | | |
2571 | sxfer->ccb_h.func_code); | | | |
2572 | END_DEBUG | | | |
2573 | SCSI_XFER_ERROR(sxfer) = XS_DEV_NOT_THERE; | | | |
2574 | SCSI_TRANSFER_DONE(sxfer); | | | |
2575 | return; | | | |
2576 | } | | | |
2577 | break; | | | |
2578 | #endif | | | |
2579 | default: | | | |
2580 | /* XXX Hm, we should check the input parameters */ | | | |
2581 | break; | | | |
2582 | } | | | |
2583 | | | | |
2584 | switch (SCSI_XFER_FUNCCODE(sxfer)) { | | | |
2585 | case XPT_SCSI_IO: | | | |
2586 | { | | | |
2587 | struct sbp_ocb *ocb; | | | |
2588 | int speed; | | | |
2589 | void *cdb; | | | |
2590 | fw_mtx_assert(sim->mtx, MA_OWNED); | | | |
2591 | | | | |
2592 | SBP_DEBUG(2) | | | |
2593 | printf("%s:%d:%d XPT_SCSI_IO: " | | | |
2594 | "cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x" | | | |
2595 | ", flags: 0x%02x, " | | | |
2596 | "%db cmd/%db data/%db sense\n", | | | |
2597 | fw_get_nameunit(sbp->fd.dev), | | | |
2598 | SCSI_XFER_TARGET(sxfer), SCSI_XFER_LUN(sxfer), | | | |
2599 | SCSI_XFER_10BCMD_DUMP(sxfer), | | | |
2600 | SCSI_XFER_DIR(sxfer), | | | |
2601 | SCSI_XFER_CMDLEN(sxfer), SCSI_XFER_DATALEN(sxfer), | | | |
2602 | SCSI_XFER_SENSELEN(sxfer)); | | | |
2603 | END_DEBUG | | | |
2604 | if(sdev == NULL){ | | | |
2605 | SCSI_XFER_ERROR(sxfer) = XS_DEV_NOT_THERE; | | | |
2606 | SCSI_TRANSFER_DONE(sxfer); | | | |
2607 | return; | | | |
2608 | } | | | |
2609 | #if 0 | | | |
2610 | /* if we are in probe stage, pass only probe commands */ | | | |
2611 | if (sdev->status == SBP_DEV_PROBE) { | | | |
2612 | char *name; | | | |
2613 | name = xpt_path_periph(sxfer->ccb_h.path)->periph_name; | | | |
2614 | printf("probe stage, periph name: %s\n", name); | | | |
2615 | if (strcmp(name, "probe") != 0) { | | | |
2616 | SCSI_XFER_ERROR(sxfer) = XS_REQUEUE_REQ; | | | |
2617 | SCSI_TRANSFER_DONE(sxfer); | | | |
2618 | return; | | | |
2619 | } | | | |
2620 | } | | | |
2621 | #endif | | | |
2622 | if ((ocb = sbp_get_ocb(sdev)) == NULL) { | | | |
2623 | SCSI_XFER_ERROR(sxfer) = XS_REQUEUE_REQ; | | | |
2624 | if (sdev->freeze == 0) { | | | |
2625 | SBP_LOCK(sdev->target->sbp); | | | |
2626 | SBP_DEVICE_FREEZE(sdev, 1); | | | |
2627 | sdev->freeze ++; | | | |
2628 | SBP_UNLOCK(sdev->target->sbp); | | | |
2629 | } | | | |
2630 | SCSI_TRANSFER_DONE(sxfer); | | | |
2631 | return; | | | |
2632 | } | | | |
2633 | | | | |
2634 | ocb->flags = OCB_ACT_CMD; | | | |
2635 | ocb->sdev = sdev; | | | |
2636 | ocb->sxfer = sxfer; | | | |
2637 | #if defined(__FreeBSD__) | | | |
2638 | sxfer->ccb_h.ccb_sdev_ptr = sdev; | | | |
2639 | #endif | | | |
2640 | ocb->orb[0] = htonl(1 << 31); | | | |
2641 | ocb->orb[1] = 0; | | | |
2642 | ocb->orb[2] = htonl(((sbp->fd.fc->nodeid | FWLOCALBUS )<< 16) ); | | | |
2643 | ocb->orb[3] = htonl(ocb->bus_addr + IND_PTR_OFFSET); | | | |
2644 | speed = min(target->fwdev->speed, max_speed); | | | |
2645 | ocb->orb[4] = htonl(ORB_NOTIFY | ORB_CMD_SPD(speed) | | | |
2646 | | ORB_CMD_MAXP(speed + 7)); | | | |
2647 | if(SCSI_XFER_DIR(sxfer) == SCSI_XFER_DATA_IN){ | | | |
2648 | ocb->orb[4] |= htonl(ORB_CMD_IN); | | | |
2649 | } | | | |
2650 | | | | |
2651 | if (CAM_XFER_FLAGS(sxfer) & CAM_SCATTER_VALID) | | | |
2652 | printf("sbp: CAM_SCATTER_VALID\n"); | | | |
2653 | if (CAM_XFER_FLAGS(sxfer) & CAM_DATA_PHYS) | | | |
2654 | printf("sbp: CAM_DATA_PHYS\n"); | | | |
2655 | | | | |
2656 | cdb = SCSI_XFER_CMD(sxfer); | | | |
2657 | bcopy(cdb, (void *)&ocb->orb[5], SCSI_XFER_CMDLEN(sxfer)); | | | |
2658 | /* | | | |
2659 | printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[0]), ntohl(ocb->orb[1]), ntohl(ocb->orb[2]), ntohl(ocb->orb[3])); | | | |
2660 | printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[4]), ntohl(ocb->orb[5]), ntohl(ocb->orb[6]), ntohl(ocb->orb[7])); | | | |
2661 | */ | | | |
2662 | if (SCSI_XFER_DATALEN(sxfer) > 0) { | | | |
2663 | int s, error; | | | |
2664 | | | | |
2665 | s = splsoftvm(); | | | |
2666 | error = fw_bus_dmamap_load(/*dma tag*/sbp->dmat, | | | |
2667 | /*dma map*/ocb->dmamap, | | | |
2668 | SCSI_XFER_DATA(sxfer), | | | |
2669 | SCSI_XFER_DATALEN(sxfer), | | | |
2670 | sbp_execute_ocb, | | | |
2671 | ocb, | | | |
2672 | /*flags*/0); | | | |
2673 | splx(s); | | | |
2674 | if (error) | | | |
2675 | printf("sbp: bus_dmamap_load error %d\n", error); | | | |
2676 | } else | | | |
2677 | sbp_execute_ocb(ocb, NULL, 0, 0); | | | |
2678 | break; | | | |
2679 | } | | | |
2680 | #if defined(__FreeBSD__) | | | |
2681 | case XPT_CALC_GEOMETRY: | | | |
2682 | { | | | |
2683 | struct ccb_calc_geometry *ccg; | | | |
2684 | #if defined(__DragonFly__) || __FreeBSD_version < 501100 | | | |
2685 | uint32_t size_mb; | | | |
2686 | uint32_t secs_per_cylinder; | | | |
2687 | int extended = 1; | | | |
2688 | #endif | | | |
2689 | | | | |
2690 | ccg = &sxfer->ccg; | | | |
2691 | if (ccg->block_size == 0) { | | | |
2692 | printf("sbp_action1: block_size is 0.\n"); | | | |
2693 | SCSI_XFER_ERROR(sxfer) = XS_REQ_INVALID; | | | |
2694 | SCSI_TRANSFER_DONE(sxfer); | | | |
2695 | break; | | | |
2696 | } | | | |
2697 | SBP_DEBUG(1) | | | |
2698 | printf("%s:%d:%d:%d:XPT_CALC_GEOMETRY: " | | | |
2699 | #if defined(__DragonFly__) || __FreeBSD_version < 500000 | | | |
2700 | "Volume size = %d\n", | | | |
2701 | #else | | | |
2702 | "Volume size = %jd\n", | | | |
2703 | #endif | | | |
2704 | fw_get_nameunit(sbp->fd.dev), | | | |
2705 | cam_sim_path(sbp->sim), | | | |
2706 | sxfer->ccb_h.target_id, sxfer->ccb_h.target_lun, | | | |
2707 | #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 | | | |
2708 | (uintmax_t) | | | |
2709 | #endif | | | |
2710 | ccg->volume_size); | | | |
2711 | END_DEBUG | | | |
2712 | | | | |
2713 | #if defined(__DragonFly__) || __FreeBSD_version < 501100 | | | |
2714 | size_mb = ccg->volume_size | | | |
2715 | / ((1024L * 1024L) / ccg->block_size); | | | |
2716 | | | | |
2717 | if (size_mb > 1024 && extended) { | | | |
2718 | ccg->heads = 255; | | | |
2719 | ccg->secs_per_track = 63; | | | |
2720 | } else { | | | |
2721 | ccg->heads = 64; | | | |
2722 | ccg->secs_per_track = 32; | | | |
2723 | } | | | |
2724 | secs_per_cylinder = ccg->heads * ccg->secs_per_track; | | | |
2725 | ccg->cylinders = ccg->volume_size / secs_per_cylinder; | | | |
2726 | SCSI_XFER_ERROR(sxfer) = XS_REQ_CMP; | | | |
2727 | #else | | | |
2728 | cam_calc_geometry(ccg, /*extended*/1); | | | |
2729 | #endif | | | |
2730 | SCSI_TRANSFER_DONE(sxfer); | | | |
2731 | break; | | | |
2732 | } | | | |
2733 | case XPT_RESET_BUS: /* Reset the specified SCSI bus */ | | | |
2734 | { | | | |
2735 | | | | |
2736 | SBP_DEBUG(1) | | | |
2737 | printf("%s:%d:XPT_RESET_BUS: \n", | | | |
2738 | fw_get_nameunit(sbp->fd.dev), cam_sim_path(sbp->sim)); | | | |
2739 | END_DEBUG | | | |
2740 | | | | |
2741 | SCSI_XFER_ERROR(sxfer) = XS_REQ_INVALID; | | | |
2742 | SCSI_TRANSFER_DONE(sxfer); | | | |
2743 | break; | | | |
2744 | } | | | |
2745 | case XPT_PATH_INQ: /* Path routing inquiry */ | | | |
2746 | { | | | |
2747 | struct ccb_pathinq *cpi = &sxfer->cpi; | | | |
2748 | struct cam_sim *sim = sbp->sim; | | | |
2749 | | | | |
2750 | SBP_DEBUG(1) | | | |
2751 | printf("%s:%d:%d XPT_PATH_INQ:.\n", | | | |
2752 | fw_get_nameunit(sbp->fd.dev), | | | |
2753 | sxfer->ccb_h.target_id, sxfer->ccb_h.target_lun); | | | |
2754 | END_DEBUG | | | |
2755 | cpi->version_num = 1; /* XXX??? */ | | | |
2756 | cpi->hba_inquiry = PI_TAG_ABLE; | | | |
2757 | cpi->target_sprt = 0; | | | |
2758 | cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE; | | | |
2759 | cpi->hba_eng_cnt = 0; | | | |
2760 | cpi->max_target = SBP_NUM_TARGETS - 1; | | | |
2761 | cpi->max_lun = SBP_NUM_LUNS - 1; | | | |
2762 | cpi->initiator_id = SBP_INITIATOR; | | | |
2763 | cpi->bus_id = sim->bus_id; | | | |
2764 | cpi->base_transfer_speed = 400 * 1000 / 8; | | | |
2765 | strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); | | | |
2766 | strncpy(cpi->hba_vid, "SBP", HBA_IDLEN); | | | |
2767 | strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); | | | |
2768 | cpi->unit_number = sim->unit_number; | | | |
2769 | cpi->transport = XPORT_SPI; /* XX should havea FireWire */ | | | |
2770 | cpi->transport_version = 2; | | | |
2771 | cpi->protocol = PROTO_SCSI; | | | |
2772 | cpi->protocol_version = SCSI_REV_2; | | | |
2773 | | | | |
2774 | SCSI_XFER_ERROR(cpi) = XS_REQ_CMP; | | | |
2775 | SCSI_TRANSFER_DONE(sxfer); | | | |
2776 | break; | | | |
2777 | } | | | |
2778 | case XPT_GET_TRAN_SETTINGS: | | | |
2779 | { | | | |
2780 | struct ccb_trans_settings *cts = &sxfer->cts; | | | |
2781 | struct ccb_trans_settings_scsi *scsi = | | | |
2782 | &cts->proto_specific.scsi; | | | |
2783 | struct ccb_trans_settings_spi *spi = | | | |
2784 | &cts->xport_specific.spi; | | | |
2785 | | | | |
2786 | cts->protocol = PROTO_SCSI; | | | |
2787 | cts->protocol_version = SCSI_REV_2; | | | |
2788 | cts->transport = XPORT_SPI; /* should have a FireWire */ | | | |
2789 | cts->transport_version = 2; | | | |
2790 | spi->valid = CTS_SPI_VALID_DISC; | | | |
2791 | spi->flags = CTS_SPI_FLAGS_DISC_ENB; | | | |
2792 | scsi->valid = CTS_SCSI_VALID_TQ; | | | |
2793 | scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; | | | |
2794 | SBP_DEBUG(1) | | | |
2795 | printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:.\n", | | | |
2796 | fw_get_nameunit(sbp->fd.dev), | | | |
2797 | sxfer->ccb_h.target_id, sxfer->ccb_h.target_lun); | | | |
2798 | END_DEBUG | | | |
2799 | SCSI_XFER_ERROR(cts) = XS_REQ_CMP; | | | |
2800 | SCSI_TRANSFER_DONE(sxfer); | | | |
2801 | break; | | | |
2802 | } | | | |
2803 | case XPT_ABORT: | | | |
2804 | SCSI_XFER_ERROR(sxfer) = XS_UA_ABORT; | | | |
2805 | SCSI_TRANSFER_DONE(sxfer); | | | |
2806 | break; | | | |
2807 | case XPT_SET_TRAN_SETTINGS: | | | |
2808 | /* XXX */ | | | |
2809 | default: | | | |
2810 | SCSI_XFER_ERROR(sxfer) = XS_REQ_INVALID; | | | |
2811 | SCSI_TRANSFER_DONE(sxfer); | | | |
2812 | break; | | | |
2813 | #endif | | | |
2814 | } | | | |
2815 | return; | | | |
2816 | } | | | |
2817 | | | | |
2818 | #if defined(__FreeBSD__) | | | |
2819 | static void | | | |
2820 | sbp_action(struct cam_sim *sim, sbp_scsi_xfer *sxfer) | | | |
2821 | { | | | |
2822 | int s; | | | |
2823 | | | | |
2824 | s = splfw(); | | | |
2825 | sbp_action1(sim->softc, sxfer); | | | |
2826 | splx(s); | | | |
2827 | } | | | |
2828 | #endif | | | |
2829 | | | | |
2830 | static void | | | |
2831 | sbp_execute_ocb(void *arg, bus_dma_segment_t *segments, int seg, int error) | | | |
2832 | { | | | |
2833 | int i; | | | |
2834 | struct sbp_ocb *ocb; | | | |
2835 | struct sbp_ocb *prev; | | | |
2836 | bus_dma_segment_t *s; | | | |
2837 | | | | |
2838 | if (error) | | | |
2839 | printf("sbp_execute_ocb: error=%d\n", error); | | | |
2840 | | | | |
2841 | ocb = (struct sbp_ocb *)arg; | | | |
2842 | | | | |
2843 | SBP_DEBUG(2) | | | |
2844 | printf("sbp_execute_ocb: seg %d", seg); | | | |
2845 | for (i = 0; i < seg; i++) | | | |
2846 | #if defined(__DragonFly__) || \ | | | |
2847 | (defined(__FreeBSD__) && __FreeBSD_version < 500000) | | | |
2848 | printf(", %x:%d", segments[i].ds_addr, segments[i].ds_len); | | | |
2849 | #else | | | |
2850 | printf(", %jx:%jd", (uintmax_t)segments[i].ds_addr, | | | |
2851 | (uintmax_t)segments[i].ds_len); | | | |
2852 | #endif | | | |
2853 | printf("\n"); | | | |
2854 | END_DEBUG | | | |
2855 | | | | |
2856 | if (seg == 1) { | | | |
2857 | /* direct pointer */ | | | |
2858 | s = &segments[0]; | | | |
2859 | if (s->ds_len > SBP_SEG_MAX) | | | |
2860 | panic("ds_len > SBP_SEG_MAX, fix busdma code"); | | | |
2861 | ocb->orb[3] = htonl(s->ds_addr); | | | |
2862 | ocb->orb[4] |= htonl(s->ds_len); | | | |
2863 | } else if(seg > 1) { | | | |
2864 | /* page table */ | | | |
2865 | for (i = 0; i < seg; i++) { | | | |
2866 | s = &segments[i]; | | | |
2867 | SBP_DEBUG(0) | | | |
2868 | /* XXX LSI Logic "< 16 byte" bug might be hit */ | | | |
2869 | if (s->ds_len < 16) | | | |
2870 | printf("sbp_execute_ocb: warning, " | | | |
2871 | #if defined(__DragonFly__) || \ | | | |
2872 | (defined(__FreeBSD__) && __FreeBSD_version < 500000) | | | |
2873 | "segment length(%d) is less than 16." | | | |
2874 | #else | | | |
2875 | "segment length(%jd) is less than 16." | | | |
2876 | #endif | | | |
2877 | "(seg=%d/%d)\n", (uintmax_t)s->ds_len, i+1, seg); | | | |
2878 | END_DEBUG | | | |
2879 | if (s->ds_len > SBP_SEG_MAX) | | | |
2880 | panic("ds_len > SBP_SEG_MAX, fix busdma code"); | | | |
2881 | ocb->ind_ptr[i].hi = htonl(s->ds_len << 16); | | | |
2882 | ocb->ind_ptr[i].lo = htonl(s->ds_addr); | | | |
2883 | } | | | |
2884 | ocb->orb[4] |= htonl(ORB_CMD_PTBL | seg); | | | |
2885 | } | | | |
2886 | | | | |
2887 | if (seg > 0) | | | |
2888 | fw_bus_dmamap_sync(ocb->sdev->target->sbp->dmat, ocb->dmamap, | | | |
2889 | (ntohl(ocb->orb[4]) & ORB_CMD_IN) ? | | | |
2890 | BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | | | |
2891 | prev = sbp_enqueue_ocb(ocb->sdev, ocb); | | | |
2892 | fwdma_sync(&ocb->sdev->dma, BUS_DMASYNC_PREWRITE); | | | |
2893 | if (use_doorbell) { | | | |
2894 | if (prev == NULL) { | | | |
2895 | if (ocb->sdev->last_ocb != NULL) | | | |
2896 | sbp_doorbell(ocb->sdev); | | | |
2897 | else | | | |
2898 | sbp_orb_pointer(ocb->sdev, ocb); | | | |
2899 | } | | | |
2900 | } else { | | | |
2901 | if (prev == NULL || (ocb->sdev->flags & ORB_LINK_DEAD) != 0) { | | | |
2902 | ocb->sdev->flags &= ~ORB_LINK_DEAD; | | | |
2903 | sbp_orb_pointer(ocb->sdev, ocb); | | | |
2904 | } | | | |
2905 | } | | | |
2906 | } | | | |
2907 | | | | |
2908 | #if defined(__FreeBSD__) | | | |
2909 | static void | | | |
2910 | sbp_poll(struct cam_sim *sim) | | | |
2911 | { | | | |
2912 | struct sbp_softc *sbp; | | | |
2913 | struct firewire_comm *fc; | | | |
2914 | | | | |
2915 | sbp = (struct sbp_softc *)sim->softc; | | | |
2916 | fc = sbp->fd.fc; | | | |
2917 | | | | |
2918 | fc->poll(fc, 0, -1); | | | |
2919 | | | | |
2920 | return; | | | |
2921 | } | | | |
2922 | | | | |
2923 | #endif | | | |
2924 | static struct sbp_ocb * | | | |
2925 | sbp_dequeue_ocb(struct sbp_dev *sdev, struct sbp_status *sbp_status) | | | |
2926 | { | | | |
2927 | struct sbp_ocb *ocb; | | | |
2928 | struct sbp_ocb *next; | | | |
2929 | int s = splfw(), order = 0; | | | |
2930 | int flags; | | | |
2931 | | | | |
2932 | SBP_DEBUG(1) | | | |
2933 | sbp_show_sdev_info(sdev, 2); | | | |
2934 | #if defined(__DragonFly__) || \ | | | |
2935 | (defined(__FreeBSD__) && __FreeBSD_version < 500000) | | | |
2936 | printf("%s: 0x%08lx src %d\n", | | | |
2937 | #else | | | |
2938 | printf("%s: 0x%08x src %d\n", | | | |
2939 | #endif | | | |
2940 | __func__, ntohl(sbp_status->orb_lo), sbp_status->src); | | | |
2941 | END_DEBUG | | | |
2942 | SBP_LOCK(sdev->target->sbp); | | | |
2943 | for (ocb = STAILQ_FIRST(&sdev->ocbs); ocb != NULL; ocb = next) { | | | |
2944 | next = STAILQ_NEXT(ocb, ocb); | | | |
2945 | flags = ocb->flags; | | | |
2946 | if (OCB_MATCH(ocb, sbp_status)) { | | | |
2947 | /* found */ | | | |
2948 | STAILQ_REMOVE(&sdev->ocbs, ocb, sbp_ocb, ocb); | | | |
2949 | if (ocb->sxfer != NULL) | | | |
2950 | #if defined(__DragonFly__) || defined(__NetBSD__) | | | |
2951 | fw_callout_stop(&SCSI_XFER_CALLOUT(ocb->sxfer)); | | | |
2952 | #else | | | |
2953 | untimeout(sbp_timeout, (void *)ocb, | | | |
2954 | SCSI_XFER_CALLOUT(ocb->sxfer)); | | | |
2955 | #endif | | | |
2956 | if (ntohl(ocb->orb[4]) & 0xffff) { | | | |
2957 | fw_bus_dmamap_sync(sdev->target->sbp->dmat, | | | |
2958 | ocb->dmamap, | | | |
2959 | (ntohl(ocb->orb[4]) & ORB_CMD_IN) ? | | | |
2960 | BUS_DMASYNC_POSTREAD : | | | |
2961 | BUS_DMASYNC_POSTWRITE); | | | |
2962 | fw_bus_dmamap_unload(sdev->target->sbp->dmat, | | | |
2963 | ocb->dmamap); | | | |
2964 | } | | | |
2965 | if (!use_doorbell) { | | | |
2966 | if (sbp_status->src == SRC_NO_NEXT) { | | | |
2967 | if (next != NULL) | | | |
2968 | sbp_orb_pointer(sdev, next); | | | |
2969 | else if (order > 0) { | | | |
2970 | /* | | | |
2971 | * Unordered execution | | | |
2972 | * We need to send pointer for | | | |
2973 | * next ORB | | | |
2974 | */ | | | |
2975 | sdev->flags |= ORB_LINK_DEAD; | | | |
2976 | } | | | |
2977 | } | | | |
2978 | } else { | | | |
2979 | /* | | | |
2980 | * XXX this is not correct for unordered | | | |
2981 | * execution. | | | |
2982 | */ | | | |
2983 | if (sdev->last_ocb != NULL) | | | |
2984 | sbp_free_ocb(sdev, sdev->last_ocb); | | | |
2985 | sdev->last_ocb = ocb; | | | |
2986 | if (next != NULL && | | | |
2987 | sbp_status->src == SRC_NO_NEXT) | | | |
2988 | sbp_doorbell(sdev); | | | |
2989 | } | | | |
2990 | break; | | | |
2991 | } else | | | |
2992 | order ++; | | | |
2993 | } | | | |
2994 | SBP_UNLOCK(sdev->target->sbp); | | | |
2995 | splx(s); | | | |
2996 | SBP_DEBUG(0) | | | |
2997 | if (ocb && order > 0) { | | | |
2998 | sbp_show_sdev_info(sdev, 2); | | | |
2999 | printf("unordered execution order:%d\n", order); | | | |
3000 | } | | | |
3001 | END_DEBUG | | | |
3002 | return (ocb); | | | |
3003 | } | | | |
3004 | | | | |
3005 | static struct sbp_ocb * | | | |
3006 | sbp_enqueue_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb) | | | |
3007 | { | | | |
3008 | int s = splfw(); | | | |
3009 | struct sbp_ocb *prev, *prev2; | | | |
3010 | | | | |
3011 | SBP_DEBUG(1) | | | |
3012 | sbp_show_sdev_info(sdev, 2); | | | |
3013 | #if defined(__DragonFly__) || \ | | | |
3014 | (defined(__FreeBSD__) && __FreeBSD_version < 500000) | | | |
3015 | printf("%s: 0x%08x\n", __func__, ocb->bus_addr); | | | |
3016 | #else | | | |
3017 | printf("%s: 0x%08jx\n", __func__, (uintmax_t)ocb->bus_addr); | | | |
3018 | #endif | | | |
3019 | END_DEBUG | | | |
3020 | prev2 = prev = STAILQ_LAST(&sdev->ocbs, sbp_ocb, ocb); | | | |
3021 | STAILQ_INSERT_TAIL(&sdev->ocbs, ocb, ocb); | | | |
3022 | | | | |
3023 | if (ocb->sxfer != NULL) | | | |
3024 | #if defined(__DragonFly__) || defined(__NetBSD__) | | | |
3025 | fw_callout_reset(&SCSI_XFER_CALLOUT(ocb->sxfer), | | | |
3026 | mstohz(SCSI_XFER_TIMEOUT(ocb->sxfer)), sbp_timeout, ocb); | | | |
3027 | #else | | | |
3028 | SCSI_XFER_CALLOUT(ocb->sxfer) = timeout(sbp_timeout, | | | |
3029 | (void *)ocb, mstohz(SCSI_XFER_TIMEOUT(ocb->sxfer))); | | | |
3030 | #endif | | | |
3031 | | | | |
3032 | if (use_doorbell && prev == NULL) | | | |
3033 | prev2 = sdev->last_ocb; | | | |
3034 | | | | |
3035 | if (prev2 != NULL) { | | | |
3036 | SBP_DEBUG(2) | | | |
3037 | #if defined(__DragonFly__) || \ | | | |
3038 | (defined(__FreeBSD__) && __FreeBSD_version < 500000) | | | |
3039 | printf("linking chain 0x%x -> 0x%x\n", | | | |
3040 | prev2->bus_addr, ocb->bus_addr); | | | |
3041 | #else | | | |
3042 | printf("linking chain 0x%jx -> 0x%jx\n", | | | |
3043 | (uintmax_t)prev2->bus_addr, (uintmax_t)ocb->bus_addr); | | | |
3044 | #endif | | | |
3045 | END_DEBUG | | | |
3046 | prev2->orb[1] = htonl(ocb->bus_addr); | | | |
3047 | prev2->orb[0] = 0; | | | |
3048 | } | | | |
3049 | splx(s); | | | |
3050 | | | | |
3051 | return prev; | | | |
3052 | } | | | |
3053 | | | | |
3054 | static struct sbp_ocb * | | | |
3055 | sbp_get_ocb(struct sbp_dev *sdev) | | | |
3056 | { | | | |
3057 | struct sbp_ocb *ocb; | | | |
3058 | int s = splfw(); | | | |
3059 | | | | |
3060 | fw_mtx_assert(&sdev->target->sbp->mtx, MA_OWNED); | | | |
3061 | ocb = STAILQ_FIRST(&sdev->free_ocbs); | | | |
3062 | if (ocb == NULL) { | | | |
3063 | sdev->flags |= ORB_SHORTAGE; | | | |
3064 | printf("ocb shortage!!!\n"); | | | |
3065 | splx(s); | | | |
3066 | return NULL; | | | |
3067 | } | | | |
3068 | STAILQ_REMOVE_HEAD(&sdev->free_ocbs, ocb); | | | |
3069 | splx(s); | | | |
3070 | ocb->sxfer = NULL; | | | |
3071 | return (ocb); | | | |
3072 | } | | | |
3073 | | | | |
3074 | static void | | | |
3075 | sbp_free_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb) | | | |
3076 | { | | | |
3077 | ocb->flags = 0; | | | |
3078 | ocb->sxfer = NULL; | | | |
3079 | | | | |
3080 | SBP_LOCK(sdev->target->sbp); | | | |
3081 | STAILQ_INSERT_TAIL(&sdev->free_ocbs, ocb, ocb); | | | |
3082 | if ((sdev->flags & ORB_SHORTAGE) != 0) { | | | |
3083 | int count; | | | |
3084 | | | | |
3085 | sdev->flags &= ~ORB_SHORTAGE; | | | |
3086 | count = sdev->freeze; | | | |
3087 | sdev->freeze = 0; | | | |
3088 | SBP_DEVICE_THAW(sdev, count); | | | |
3089 | } | | | |
3090 | SBP_UNLOCK(sdev->target->sbp); | | | |
3091 | } | | | |
3092 | | | | |
3093 | static void | | | |
3094 | sbp_abort_ocb(struct sbp_ocb *ocb, int status) | | | |
3095 | { | | | |
3096 | struct sbp_dev *sdev; | | | |
3097 | | | | |
3098 | sdev = ocb->sdev; | | | |
3099 | SBP_DEBUG(0) | | | |
3100 | sbp_show_sdev_info(sdev, 2); | | | |
3101 | #if defined(__DragonFly__) || \ | | | |
3102 | (defined(__FreeBSD__) && __FreeBSD_version < 500000) | | | |
3103 | printf("sbp_abort_ocb 0x%x\n", ocb->bus_addr); | | | |
3104 | #else | | | |
3105 | printf("sbp_abort_ocb 0x%jx\n", (uintmax_t)ocb->bus_addr); | | | |
3106 | #endif | | | |
3107 | END_DEBUG | | | |
3108 | SBP_DEBUG(1) | | | |
3109 | if (ocb->sxfer != NULL) | | | |
3110 | sbp_print_scsi_cmd(ocb); | | | |
3111 | END_DEBUG | | | |
3112 | if (ntohl(ocb->orb[4]) & 0xffff) { | | | |
3113 | fw_bus_dmamap_sync(sdev->target->sbp->dmat, ocb->dmamap, | | | |
3114 | (ntohl(ocb->orb[4]) & ORB_CMD_IN) ? | | | |
3115 | BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | | | |
3116 | fw_bus_dmamap_unload(sdev->target->sbp->dmat, ocb->dmamap); | | | |
3117 | } | | | |
3118 | if (ocb->sxfer != NULL) { | | | |
3119 | #if defined(__DragonFly__ ) || defined(__NetBSD__) | | | |
3120 | fw_callout_stop(&SCSI_XFER_CALLOUT(ocb->sxfer)); | | | |
3121 | #else | | | |
3122 | untimeout(sbp_timeout, (void *)ocb, | | | |
3123 | SCSI_XFER_CALLOUT(ocb->sxfer)); | | | |
3124 | #endif | | | |
3125 | SCSI_XFER_ERROR(ocb->sxfer) = status; | | | |
3126 | SBP_LOCK(sdev->target->sbp); | | | |
3127 | SCSI_TRANSFER_DONE(ocb->sxfer); | | | |
3128 | SBP_UNLOCK(sdev->target->sbp); | | | |
3129 | } | | | |
3130 | sbp_free_ocb(sdev, ocb); | | | |
3131 | } | | | |
3132 | | | | |
3133 | static void | | | |
3134 | sbp_abort_all_ocbs(struct sbp_dev *sdev, int status) | | | |
3135 | { | | | |
3136 | int s; | | | |
3137 | struct sbp_ocb *ocb, *next; | | | |
3138 | STAILQ_HEAD(, sbp_ocb) temp; | | | |
3139 | | | | |
3140 | s = splfw(); | | | |
3141 | | | | |
3142 | bcopy(&sdev->ocbs, &temp, sizeof(temp)); | | | |
3143 | STAILQ_INIT(&sdev->ocbs); | | | |
3144 | for (ocb = STAILQ_FIRST(&temp); ocb != NULL; ocb = next) { | | | |
3145 | next = STAILQ_NEXT(ocb, ocb); | | | |
3146 | sbp_abort_ocb(ocb, status); | | | |
3147 | } | | | |
3148 | if (sdev->last_ocb != NULL) { | | | |
3149 | sbp_free_ocb(sdev, sdev->last_ocb); | | | |
3150 | sdev->last_ocb = NULL; | | | |
3151 | } | | | |
3152 | | | | |
3153 | splx(s); | | | |
3154 | } | | | |
3155 | | | | |
3156 | #if defined(__FreeBSD__) | | | |
3157 | static devclass_t sbp_devclass; | | | |
3158 | | | | |
3159 | static device_method_t sbp_methods[] = { | | | |
3160 | /* device interface */ | | | |
3161 | DEVMETHOD(device_probe, sbp_probe), | | | |
3162 | DEVMETHOD(device_attach, sbp_attach), | | | |
3163 | DEVMETHOD(device_detach, sbp_detach), | | | |
3164 | DEVMETHOD(device_shutdown, sbp_shutdown), | | | |
3165 | | | | |
3166 | { 0, 0 } | | | |
3167 | }; | | | |
3168 | | | | |
3169 | static driver_t sbp_driver = { | | | |
3170 | "sbp", | | | |
3171 | sbp_methods, | | | |
3172 | sizeof(struct sbp_softc), | | | |
3173 | }; | | | |
3174 | #ifdef __DragonFly__ | | | |
3175 | DECLARE_DUMMY_MODULE(sbp); | | | |
3176 | #endif | | | |
3177 | DRIVER_MODULE(sbp, firewire, sbp_driver, sbp_devclass, 0, 0); | | | |
3178 | MODULE_VERSION(sbp, 1); | | | |
3179 | MODULE_DEPEND(sbp, firewire, 1, 1, 1); | | | |
3180 | MODULE_DEPEND(sbp, cam, 1, 1, 1); | | | |
3181 | #elif defined(__NetBSD__) | | | |
3182 | static void | | | |
3183 | sbp_scsipi_request( | | | |
3184 | struct scsipi_channel *channel, scsipi_adapter_req_t req, void *arg) | | | |
3185 | { | | | |
3186 | int i, s; | | | |
3187 | struct sbp_softc *sbp = | | | |
3188 | device_private(channel->chan_adapter->adapt_dev); | | | |
3189 | struct scsipi_xfer *xs = arg; | | | |
3190 | | | | |
3191 | if (debug > 1) | | | |
3192 | printf("Called sbpscsi_scsipi_request\n"); | | | |
3193 | | | | |
3194 | switch (req) { | | | |
3195 | case ADAPTER_REQ_RUN_XFER: | | | |
3196 | if (debug > 1) { | | | |
3197 | printf("Got req_run_xfer\n"); | | | |
3198 | printf("xs control: 0x%08x, timeout: %d\n", | | | |
3199 | xs->xs_control, xs->timeout); | | | |
3200 | printf("opcode: 0x%02x\n", (int)xs->cmd->opcode); | | | |
3201 | for (i = 0; i < 15; i++) | | | |
3202 | printf("0x%02x ",(int)xs->cmd->bytes[i]); | | | |
3203 | printf("\n"); | | | |
3204 | } | | | |
3205 | if (xs->xs_control & XS_CTL_RESET) { | | | |
3206 | if (debug > 1) | | | |
3207 | printf("XS_CTL_RESET not support\n"); | | | |
3208 | break; | | | |
3209 | } | | | |
3210 | #define SBPSCSI_SBP2_MAX_CDB 12 | | | |
3211 | if (xs->cmdlen > SBPSCSI_SBP2_MAX_CDB) { | | | |
3212 | if (debug > 0) | | | |
3213 | printf( | | | |
3214 | "sbp doesn't support cdb's larger than %d " | | | |
3215 | "bytes\n", SBPSCSI_SBP2_MAX_CDB); | | | |
3216 | SCSI_XFER_ERROR(xs) = XS_REQ_INVALID; | | | |
3217 | SCSI_TRANSFER_DONE(xs); | | | |
3218 | return; | | | |
3219 | } | | | |
3220 | s = splfw(); | | | |
3221 | sbp_action1(sbp, xs); | | | |
3222 | splx(s); | | | |
3223 | | | | |
3224 | break; | | | |
3225 | case ADAPTER_REQ_GROW_RESOURCES: | | | |
3226 | if (debug > 1) | | | |
3227 | printf("Got req_grow_resources\n"); | | | |
3228 | break; | | | |
3229 | case ADAPTER_REQ_SET_XFER_MODE: | | | |
3230 | if (debug > 1) | | | |
3231 | printf("Got set xfer mode\n"); | | | |
3232 | break; | | | |
3233 | default: | | | |
3234 | panic("Unknown request: %d\n", (int)req); | | | |
3235 | } | | | |
3236 | } | | | |
3237 | | | | |
3238 | static void | | | |
3239 | sbp_minphys(struct buf *bp) | | | |
3240 | { | | | |
3241 | minphys(bp); | | | |
3242 | } | | | |
3243 | | | | |
3244 | CFATTACH_DECL_NEW(sbp, sizeof(struct sbp_softc), | | | |
3245 | sbpmatch, sbpattach, sbpdetach, NULL); | | | |
3246 | #endif | | | |