Deleted Added
full compact
1/*
2 * Copyright (C) 2003
3 * Hidetoshi Shimokawa. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 *
16 * This product includes software developed by Hidetoshi Shimokawa.
17 *
18 * 4. Neither the name of the author nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * $FreeBSD: head/sys/dev/firewire/sbp_targ.c 121186 2003-10-18 05:41:31Z simokawa $
34 * $FreeBSD: head/sys/dev/firewire/sbp_targ.c 122529 2003-11-12 04:06:21Z simokawa $
35 */
36
37#include <sys/param.h>
38#include <sys/kernel.h>
39#include <sys/systm.h>
40#include <sys/sysctl.h>
41#include <sys/types.h>
42#include <sys/conf.h>
43#include <sys/malloc.h>
44#if __FreeBSD_version < 500000
45#include <sys/devicestat.h>
46#endif
47
48#include <sys/bus.h>
49#include <machine/bus.h>
50
51#include <dev/firewire/firewire.h>
52#include <dev/firewire/firewirereg.h>
53#include <dev/firewire/iec13213.h>
54#include <dev/firewire/sbp.h>
55#include <dev/firewire/fwmem.h>
56
57#include <cam/cam.h>
58#include <cam/cam_ccb.h>
59#include <cam/cam_sim.h>
60#include <cam/cam_xpt_sim.h>
61#include <cam/cam_debug.h>
62#include <cam/cam_periph.h>
63#include <cam/scsi/scsi_all.h>
64
65#define SBP_TARG_RECV_LEN (8)
66#define MAX_LUN 63
67/*
68 * management/command block agent registers
69 *
70 * BASE 0xffff f001 0000 management port
71 * BASE 0xffff f001 0020 command port for lun0
72 * BASE 0xffff f001 0040 command port for lun1
73 *
74 */
75#define SBP_TARG_MGM 0x10000 /* offset from 0xffff f000 000 */
76#define SBP_TARG_BIND_HI 0xffff
77#define SBP_TARG_BIND_LO(l) (0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1))
78#define SBP_TARG_BIND_START (((u_int64_t)SBP_TARG_BIND_HI << 32) | \
79 SBP_TARG_BIND_LO(-1))
80#define SBP_TARG_BIND_END (((u_int64_t)SBP_TARG_BIND_HI << 32) | \
81 SBP_TARG_BIND_LO(MAX_LUN))
82#define SBP_TARG_LUN(lo) (((lo) - SBP_TARG_BIND_LO(0))/0x20)
83
84#define FETCH_MGM 0
85#define FETCH_CMD 1
86#define FETCH_POINTER 2
87
88MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode");
89
90static int debug = 0;
91
92SYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0,
93 "SBP target mode debug flag");
94
95struct sbp_targ_softc {
96 struct firewire_dev_comm fd;
97 struct cam_sim *sim;
98 struct cam_path *path;
99 struct fw_bind fwb;
100 int ndevs;
101 struct crom_chunk unit;
102 struct sbp_targ_lstate *lstate[MAX_LUN];
103 struct sbp_targ_lstate *black_hole;
104};
105
106struct sbp_targ_lstate {
107 struct sbp_targ_softc *sc;
108 struct cam_path *path;
109 struct ccb_hdr_slist accept_tios;
110 struct ccb_hdr_slist immed_notifies;
111 struct crom_chunk model;
112 /* XXX per initiater data */
113 struct fw_device *fwdev;
114 struct sbp_login_res loginres;
115 u_int32_t flags;
116#define LINK_ACTIVE 1
117#define ATIO_STARVED 2
118 u_int16_t fifo_hi;
119 u_int16_t last_hi;
120 u_int32_t fifo_lo;
121 u_int32_t last_lo;
122 STAILQ_HEAD(, orb_info) orbs;
123 u_int16_t login_id;
124 u_int16_t lun;
125};
126
127struct corb4 {
128#if BYTE_ORDER == BIG_ENDIAN
129 u_int32_t n:1,
130 rq_fmt:2,
131 :1,
132 dir:1,
133 spd:3,
134 max_payload:4,
135 page_table_present:1,
136 page_size:3,
137 data_size:16;
138#else
139 u_int32_t data_size:16,
140 page_size:3,
141 page_table_present:1,
142 max_payload:4,
143 spd:3,
144 dir:1,
145 :1,
146 rq_fmt:2,
147 n:1;
148#endif
149};
150
151struct morb4 {
152#if BYTE_ORDER == BIG_ENDIAN
153 u_int32_t n:1,
154 rq_fmt:2,
155 :9,
156 fun:4,
157 id:16;
158#else
159 u_int32_t id:16,
160 fun:4,
161 :9,
162 rq_fmt:2,
163 n:1;
164#endif
165};
166
167struct orb_info {
168 struct sbp_targ_softc *sc;
169 struct fw_device *fwdev;
170 struct sbp_targ_lstate *lstate;
171 union ccb *ccb;
172 struct ccb_accept_tio *atio;
173 u_int8_t state;
174#define ORBI_STATUS_NONE 0
175#define ORBI_STATUS_FETCH 1
176#define ORBI_STATUS_ATIO 2
177#define ORBI_STATUS_CTIO 3
178#define ORBI_STATUS_STATUS 4
179#define ORBI_STATUS_POINTER 5
180#define ORBI_STATUS_ABORTED 7
181 u_int8_t refcount;
182 u_int16_t orb_hi;
183 u_int32_t orb_lo;
184 u_int32_t data_hi;
185 u_int32_t data_lo;
186 struct corb4 orb4;
187 STAILQ_ENTRY(orb_info) link;
188 u_int32_t orb[8];
189 u_int32_t *page_table;
190 struct sbp_status status;
191};
192
193static char *orb_fun_name[] = {
194 ORB_FUN_NAMES
195};
196
197static void sbp_targ_recv(struct fw_xfer *);
198static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
199 u_int16_t, u_int32_t, struct sbp_targ_lstate *, int);
200
201static void
202sbp_targ_identify(driver_t *driver, device_t parent)
203{
204 BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent));
205}
206
207static int
208sbp_targ_probe(device_t dev)
209{
210 device_t pa;
211
212 pa = device_get_parent(dev);
213 if(device_get_unit(dev) != device_get_unit(pa)){
214 return(ENXIO);
215 }
216
217 device_set_desc(dev, "SBP-2/SCSI over FireWire target mode");
218 return (0);
219}
220
221static void
222sbp_targ_post_busreset(void *arg)
223{
224 struct sbp_targ_softc *sc;
225 struct crom_src *src;
226 struct crom_chunk *root;
227 struct crom_chunk *unit;
228 struct sbp_targ_lstate *lstate;
229 int i;
230
231 sc = (struct sbp_targ_softc *) arg;
232 src = sc->fd.fc->crom_src;
233 root = sc->fd.fc->crom_root;
234
235 unit = &sc->unit;
236
237 bzero(unit, sizeof(struct crom_chunk));
238
239 crom_add_chunk(src, root, unit, CROM_UDIR);
240 crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10);
241 crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2);
242 crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
243 crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI);
244
245 crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2);
246 crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8);
247
248 for (i = 0; i < MAX_LUN; i ++) {
249 lstate = sc->lstate[i];
250 if (lstate == NULL)
251 continue;
252 crom_add_entry(unit, CSRKEY_FIRM_VER, 1);
253 crom_add_entry(unit, CROM_LUN, i);
254 crom_add_entry(unit, CSRKEY_MODEL, 1);
255 crom_add_simple_text(src, unit, &lstate->model, "TargetMode");
256 }
257}
258
259static cam_status
260sbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb,
261 struct sbp_targ_lstate **lstate, int notfound_failure)
262{
263 u_int lun;
264
265 /* XXX 0 is the only vaild target_id */
266 if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD &&
267 ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
268 *lstate = sc->black_hole;
269 return (CAM_REQ_CMP);
270 }
271
272 if (ccb->ccb_h.target_id != 0)
273 return (CAM_TID_INVALID);
274
275 lun = ccb->ccb_h.target_lun;
276 if (lun >= MAX_LUN)
277 return (CAM_LUN_INVALID);
278
279 *lstate = sc->lstate[lun];
280
281 if (notfound_failure != 0 && *lstate == NULL)
282 return (CAM_PATH_INVALID);
283
284 return (CAM_REQ_CMP);
285}
286
287static void
288sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb)
289{
290 struct ccb_en_lun *cel = &ccb->cel;
291 struct sbp_targ_lstate *lstate;
292 struct orb_info *orbi, *next;
293 cam_status status;
294
295 status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
296 if (status != CAM_REQ_CMP) {
297 ccb->ccb_h.status = status;
298 return;
299 }
300
301 if (cel->enable != 0) {
302 if (lstate != NULL) {
303 xpt_print_path(ccb->ccb_h.path);
304 printf("Lun already enabled\n");
305 ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
306 return;
307 }
308 if (cel->grp6_len != 0 || cel->grp7_len != 0) {
309 ccb->ccb_h.status = CAM_REQ_INVALID;
310 printf("Non-zero Group Codes\n");
311 return;
312 }
313 lstate = (struct sbp_targ_lstate *)
314 malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO);
315 if (lstate == NULL) {
316 xpt_print_path(ccb->ccb_h.path);
317 printf("Couldn't allocate lstate\n");
318 ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
319 return;
320 }
321 if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
322 sc->black_hole = lstate;
323 else
324 sc->lstate[ccb->ccb_h.target_lun] = lstate;
325 memset(lstate, 0, sizeof(*lstate));
326 lstate->sc = sc;
327 status = xpt_create_path(&lstate->path, /*periph*/NULL,
328 xpt_path_path_id(ccb->ccb_h.path),
329 xpt_path_target_id(ccb->ccb_h.path),
330 xpt_path_lun_id(ccb->ccb_h.path));
331 if (status != CAM_REQ_CMP) {
332 free(lstate, M_SBP_TARG);
333 xpt_print_path(ccb->ccb_h.path);
334 printf("Couldn't allocate path\n");
335 ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
336 return;
337 }
338 SLIST_INIT(&lstate->accept_tios);
339 SLIST_INIT(&lstate->immed_notifies);
340 STAILQ_INIT(&lstate->orbs);
341 lstate->last_hi = 0xffff;
342 lstate->last_lo = 0xffffffff;
343
344 ccb->ccb_h.status = CAM_REQ_CMP;
345 xpt_print_path(ccb->ccb_h.path);
346 printf("Lun now enabled for target mode\n");
347 /* bus reset */
348 sc->fd.fc->ibr(sc->fd.fc);
349 } else {
350 if (lstate == NULL) {
351 ccb->ccb_h.status = CAM_LUN_INVALID;
352 return;
353 }
354 ccb->ccb_h.status = CAM_REQ_CMP;
355
356 if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
357 printf("ATIOs pending\n");
358 ccb->ccb_h.status = CAM_REQ_INVALID;
359 }
360
361 if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
362 printf("INOTs pending\n");
363 ccb->ccb_h.status = CAM_REQ_INVALID;
364 }
365
366 if (ccb->ccb_h.status != CAM_REQ_CMP) {
367 return;
368 }
369
370 xpt_print_path(ccb->ccb_h.path);
371 printf("Target mode disabled\n");
372 xpt_free_path(lstate->path);
373
374 for (orbi = STAILQ_FIRST(&lstate->orbs); orbi != NULL;
375 orbi = next) {
376 next = STAILQ_NEXT(orbi, link);
377 free(orbi, M_SBP_TARG);
378 }
379
380 if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
381 sc->black_hole = NULL;
382 else
383 sc->lstate[ccb->ccb_h.target_lun] = NULL;
384 free(lstate, M_SBP_TARG);
385
386 /* bus reset */
387 sc->fd.fc->ibr(sc->fd.fc);
388 }
389}
390
391static void
392sbp_targ_send_lstate_events(struct sbp_targ_softc *sc,
393 struct sbp_targ_lstate *lstate)
394{
395#if 0
396 struct ccb_hdr *ccbh;
397 struct ccb_immed_notify *inot;
398
399 printf("%s: not implemented yet\n", __FUNCTION__);
400#endif
401}
402
403static __inline void
404sbp_targ_remove_orb_info(struct sbp_targ_lstate *lstate, struct orb_info *orbi)
405{
406 STAILQ_REMOVE(&lstate->orbs, orbi, orb_info, link);
407}
408
409/*
410 * tag_id/init_id encoding
411 *
412 * tag_id and init_id has only 32bit for each.
413 * scsi_target can handle very limited number(up to 15) of init_id.
414 * we have to encode 48bit orb and 64bit EUI64 into these
415 * variables.
416 *
417 * tag_id represents lower 32bit of ORB address.
418 * init_id represents node_id now.
419 *
420 */
421
422static struct orb_info *
423sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate,
424 u_int tag_id, u_int init_id)
425{
426 struct orb_info *orbi;
427
428 STAILQ_FOREACH(orbi, &lstate->orbs, link)
429 if (orbi->orb_lo == tag_id &&
430#if 0
431 orbi->orb_hi == (init_id & 0xffff) &&
432 orbi->fwdev->dst == (init_id >> 16))
433#else
434 orbi->fwdev->dst == init_id)
435#endif
436 goto found;
437 printf("%s: orb not found\n", __FUNCTION__);
438 return (NULL);
439found:
440 return (orbi);
441}
442
443static void
444sbp_targ_abort(struct orb_info *orbi)
445{
446 struct orb_info *norbi;
447
448 for (; orbi != NULL; orbi = norbi) {
449 printf("%s: status=%d\n", __FUNCTION__, orbi->state);
450 norbi = STAILQ_NEXT(orbi, link);
451 if (orbi->state != ORBI_STATUS_ABORTED) {
452 if (orbi->ccb != NULL) {
453 orbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
454 xpt_done(orbi->ccb);
455 orbi->ccb = NULL;
456 }
457 if (orbi->state <= ORBI_STATUS_ATIO) {
458 sbp_targ_remove_orb_info(orbi->lstate, orbi);
459 free(orbi, M_SBP_TARG);
460 } else
461 orbi->state = ORBI_STATUS_ABORTED;
462 }
463 }
464}
465
466static void
467sbp_targ_free_orbi(struct fw_xfer *xfer)
468{
469 struct orb_info *orbi;
470
471 orbi = (struct orb_info *)xfer->sc;
472 if (xfer->resp != 0) {
473 /* XXX */
474 printf("%s: xfer->resp != 0\n", __FUNCTION__);
474 printf("%s: xfer->resp = %d\n", __FUNCTION__, xfer->resp);
475 }
476 free(orbi, M_SBP_TARG);
477 fw_xfer_free(xfer);
478}
479
480static void
481sbp_targ_status_FIFO(struct orb_info *orbi,
482 u_int32_t fifo_hi, u_int32_t fifo_lo, int dequeue)
483{
484 struct fw_xfer *xfer;
485
486 if (dequeue)
487 sbp_targ_remove_orb_info(orbi->lstate, orbi);
488
489 xfer = fwmem_write_block(orbi->fwdev, (void *)orbi,
490 /*spd*/2, fifo_hi, fifo_lo,
491 sizeof(u_int32_t) * (orbi->status.len + 1), (char *)&orbi->status,
492 sbp_targ_free_orbi);
493
494 if (xfer == NULL) {
495 /* XXX */
496 printf("%s: xfer == NULL\n", __FUNCTION__);
497 }
498}
499
500static void
501sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
502{
503 struct sbp_status *sbp_status;
504
505 sbp_status = &orbi->status;
506
507 orbi->state = ORBI_STATUS_STATUS;
508
509 sbp_status->resp = 0; /* XXX */
510 sbp_status->status = 0; /* XXX */
511 sbp_status->dead = 0; /* XXX */
512
513 switch (ccb->csio.scsi_status) {
514 case SCSI_STATUS_OK:
515 if (debug)
516 printf("%s: STATUS_OK\n", __FUNCTION__);
517 sbp_status->len = 1;
518 break;
519 case SCSI_STATUS_CHECK_COND:
520 case SCSI_STATUS_BUSY:
521 case SCSI_STATUS_CMD_TERMINATED:
522 {
523 struct sbp_cmd_status *sbp_cmd_status;
524 struct scsi_sense_data *sense;
525
526 if (debug)
527 printf("%s: STATUS %d\n", __FUNCTION__,
528 ccb->csio.scsi_status);
529 sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0];
530 sbp_cmd_status->status = ccb->csio.scsi_status;
531 sense = &ccb->csio.sense_data;
532
533 sbp_targ_abort(STAILQ_NEXT(orbi, link));
534
535 if ((sense->error_code & SSD_ERRCODE) == SSD_CURRENT_ERROR)
536 sbp_cmd_status->sfmt = SBP_SFMT_CURR;
537 else
538 sbp_cmd_status->sfmt = SBP_SFMT_DEFER;
539
540 sbp_cmd_status->valid = (sense->error_code & SSD_ERRCODE_VALID)
541 ? 1 : 0;
542 sbp_cmd_status->s_key = sense->flags & SSD_KEY;
543 sbp_cmd_status->mark = (sense->flags & SSD_FILEMARK)? 1 : 0;
544 sbp_cmd_status->eom = (sense->flags & SSD_EOM) ? 1 : 0;
545 sbp_cmd_status->ill_len = (sense->flags & SSD_ILI) ? 1 : 0;
546
547 bcopy(&sense->info[0], &sbp_cmd_status->info, 4);
548
549 if (sense->extra_len <= 6)
550 /* add_sense_code(_qual), info, cmd_spec_info */
551 sbp_status->len = 4;
552 else
553 /* fru, sense_key_spec */
554 sbp_status->len = 5;
555
556 bcopy(&sense->cmd_spec_info[0], &sbp_cmd_status->cdb, 4);
557
558 sbp_cmd_status->s_code = sense->add_sense_code;
559 sbp_cmd_status->s_qlfr = sense->add_sense_code_qual;
560 sbp_cmd_status->fru = sense->fru;
561
562 bcopy(&sense->sense_key_spec[0],
563 &sbp_cmd_status->s_keydep[0], 3);
564
565 break;
566 }
567 default:
568 printf("%s: unknown scsi status 0x%x\n", __FUNCTION__,
569 sbp_status->status);
570 }
571
572 sbp_targ_status_FIFO(orbi,
573 orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/1);
574
575 if (orbi->page_table != NULL)
576 free(orbi->page_table, M_SBP_TARG);
577}
578
579static void
580sbp_targ_cam_done(struct fw_xfer *xfer)
581{
582 struct orb_info *orbi;
583 union ccb *ccb;
584
585 orbi = (struct orb_info *)xfer->sc;
586
587 if (debug)
588 printf("%s: resp=%d refcount=%d\n", __FUNCTION__,
589 xfer->resp, orbi->refcount);
590
591 if (xfer->resp != 0) {
592 printf("%s: xfer->resp != 0\n", __FUNCTION__);
592 printf("%s: xfer->resp = %d\n", __FUNCTION__, xfer->resp);
593 orbi->status.resp = SBP_TRANS_FAIL;
594 orbi->status.status = htonl(OBJ_DATA | SBE_TIMEOUT /*XXX*/);
595 orbi->status.dead = 1;
596 sbp_targ_abort(STAILQ_NEXT(orbi, link));
597 }
598
599 orbi->refcount --;
600
601 ccb = orbi->ccb;
602 if (orbi->refcount == 0) {
603 if (orbi->state == ORBI_STATUS_ABORTED) {
604 if (debug)
605 printf("%s: orbi aborted\n", __FUNCTION__);
606 sbp_targ_remove_orb_info(orbi->lstate, orbi);
607 if (orbi->page_table != NULL)
608 free(orbi->page_table, M_SBP_TARG);
609 free(orbi, M_SBP_TARG);
610 } else if (orbi->status.resp == 0) {
611 if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
612 sbp_targ_send_status(orbi, ccb);
613 ccb->ccb_h.status = CAM_REQ_CMP;
614 xpt_done(ccb);
615 } else {
616 orbi->status.len = 1;
617 sbp_targ_status_FIFO(orbi,
618 orbi->lstate->fifo_hi, orbi->lstate->fifo_lo,
619 /*dequeue*/1);
620 ccb->ccb_h.status = CAM_REQ_ABORTED;
621 xpt_done(ccb);
622 }
623 }
624
625 fw_xfer_free(xfer);
626}
627
628static cam_status
629sbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb)
630{
631 union ccb *accb;
632 struct sbp_targ_lstate *lstate;
633 struct ccb_hdr_slist *list;
634 struct ccb_hdr *curelm;
635 int found;
636 cam_status status;
637
638 status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
639 if (status != CAM_REQ_CMP)
640 return (status);
641
642 accb = ccb->cab.abort_ccb;
643
644 if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
645 list = &lstate->accept_tios;
646 else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY)
647 list = &lstate->immed_notifies;
648 else
649 return (CAM_UA_ABORT);
650
651 curelm = SLIST_FIRST(list);
652 found = 0;
653 if (curelm == &accb->ccb_h) {
654 found = 1;
655 SLIST_REMOVE_HEAD(list, sim_links.sle);
656 } else {
657 while(curelm != NULL) {
658 struct ccb_hdr *nextelm;
659
660 nextelm = SLIST_NEXT(curelm, sim_links.sle);
661 if (nextelm == &accb->ccb_h) {
662 found = 1;
663 SLIST_NEXT(curelm, sim_links.sle) =
664 SLIST_NEXT(nextelm, sim_links.sle);
665 break;
666 }
667 curelm = nextelm;
668 }
669 }
670 if (found) {
671 accb->ccb_h.status = CAM_REQ_ABORTED;
672 xpt_done(accb);
673 return (CAM_REQ_CMP);
674 }
675 printf("%s: not found\n", __FUNCTION__);
676 return (CAM_PATH_INVALID);
677}
678
679static void
680sbp_targ_xfer_buf(struct orb_info *orbi, u_int offset,
681 u_int16_t dst_hi, u_int32_t dst_lo, u_int size,
682 void (*hand)(struct fw_xfer *))
683{
684 struct fw_xfer *xfer;
685 u_int len, ccb_dir, off = 0;
686 char *ptr;
687
688 if (debug)
689 printf("%s: offset=%d size=%d\n", __FUNCTION__, offset, size);
690 ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK;
691 ptr = (char *)orbi->ccb->csio.data_ptr + offset;
692
693 while (size > 0) {
694 /* XXX assume dst_lo + off doesn't overflow */
695 len = MIN(size, 2048 /* XXX */);
696 size -= len;
697 orbi->refcount ++;
698 if (ccb_dir == CAM_DIR_OUT)
699 xfer = fwmem_read_block(orbi->fwdev,
700 (void *)orbi, /*spd*/2,
701 dst_hi, dst_lo + off, len,
702 ptr + off, hand);
703 else
704 xfer = fwmem_write_block(orbi->fwdev,
705 (void *)orbi, /*spd*/2,
706 dst_hi, dst_lo + off, len,
707 ptr + off, hand);
708 if (xfer == NULL) {
709 printf("%s: xfer == NULL", __FUNCTION__);
710 /* XXX what should we do?? */
711 orbi->refcount --;
712 }
713 off += len;
714 }
715}
716
717static void
718sbp_targ_pt_done(struct fw_xfer *xfer)
719{
720 struct orb_info *orbi;
721 union ccb *ccb;
722 u_int i, offset, res, len;
723 u_int32_t t1, t2, *p;
724
725 orbi = (struct orb_info *)xfer->sc;
726 ccb = orbi->ccb;
727 if (orbi->state == ORBI_STATUS_ABORTED) {
728 if (debug)
729 printf("%s: orbi aborted\n", __FUNCTION__);
730 sbp_targ_remove_orb_info(orbi->lstate, orbi);
731 free(orbi->page_table, M_SBP_TARG);
732 free(orbi, M_SBP_TARG);
733 fw_xfer_free(xfer);
734 return;
735 }
736 if (xfer->resp != 0) {
737 printf("%s: xfer->resp != 0\n", __FUNCTION__);
737 printf("%s: xfer->resp = %d\n", __FUNCTION__, xfer->resp);
738 orbi->status.resp = SBP_TRANS_FAIL;
739 orbi->status.status = htonl(OBJ_PT | SBE_TIMEOUT /*XXX*/);
740 orbi->status.dead = 1;
741 orbi->status.len = 1;
742 sbp_targ_abort(STAILQ_NEXT(orbi, link));
743
744 sbp_targ_status_FIFO(orbi,
745 orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/1);
746 free(orbi->page_table, M_SBP_TARG);
747 fw_xfer_free(xfer);
748 return;
749 }
750 res = ccb->csio.dxfer_len;
751 offset = 0;
752 if (debug)
753 printf("%s: dxfer_len=%d\n", __FUNCTION__, res);
754 orbi->refcount ++;
755 for (p = orbi->page_table, i = orbi->orb4.data_size; i > 0; i --) {
756 t1 = ntohl(*p++);
757 t2 = ntohl(*p++);
758 if (debug)
759 printf("page_table: %04x:%08x %d\n",
760 t1 & 0xffff, t2, t1>>16);
761 len = MIN(t1 >> 16, res);
762 res -= len;
763 sbp_targ_xfer_buf(orbi, offset, t1 & 0xffff, t2, len,
764 sbp_targ_cam_done);
765 offset += len;
766 if (res == 0)
767 break;
768 }
769 orbi->refcount --;
770 if (orbi->refcount == 0)
771 printf("%s: refcount == 0\n", __FUNCTION__);
772 if (res !=0)
773 /* XXX handle res != 0 case */
774 printf("%s: page table is too small(%d)\n", __FUNCTION__, res);
775
776 fw_xfer_free(xfer);
777 return;
778}
779
780static void
781sbp_targ_fetch_pt(struct orb_info *orbi)
782{
783 struct fw_xfer *xfer;
784
785 if (debug)
786 printf("%s: page_table_size=%d\n",
787 __FUNCTION__, orbi->orb4.data_size);
788 orbi->page_table = malloc(orbi->orb4.data_size*8, M_SBP_TARG, M_NOWAIT);
789 if (orbi->page_table == NULL)
790 goto error;
791 xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/2,
792 orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*8,
793 (void *)orbi->page_table, sbp_targ_pt_done);
794 if (xfer != NULL)
795 return;
796error:
797 orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
798 xpt_done(orbi->ccb);
799 return;
800}
801
802static void
803sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
804{
805 struct sbp_targ_softc *sc;
806 struct sbp_targ_lstate *lstate;
807 cam_status status;
808 u_int ccb_dir;
809
810 sc = (struct sbp_targ_softc *)cam_sim_softc(sim);
811
812 status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE);
813
814 switch (ccb->ccb_h.func_code) {
815 case XPT_CONT_TARGET_IO:
816 {
817 struct orb_info *orbi;
818
819 if (debug)
820 printf("%s: XPT_CONT_TARGET_IO\n", __FUNCTION__);
821
822 if (status != CAM_REQ_CMP) {
823 ccb->ccb_h.status = status;
824 xpt_done(ccb);
825 break;
826 }
827 /* XXX transfer from/to initiator */
828 orbi = sbp_targ_get_orb_info(lstate,
829 ccb->csio.tag_id, ccb->csio.init_id);
830 if (orbi == NULL) {
831 printf("%s: no such ORB found, aborted?\n",
832 __FUNCTION__);
833 ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */
834 xpt_done(ccb);
835 break;
836 }
837 if (orbi->state == ORBI_STATUS_ABORTED) {
838 if (debug)
839 printf("%s: ctio aborted\n", __FUNCTION__);
840 sbp_targ_remove_orb_info(orbi->lstate, orbi);
841 free(orbi, M_SBP_TARG);
842 break;
843 }
844 orbi->state = ORBI_STATUS_CTIO;
845
846 orbi->ccb = ccb;
847 ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
848
849 /* XXX */
850 if (ccb->csio.dxfer_len == 0)
851 ccb_dir = CAM_DIR_NONE;
852
853 /* Sanity check */
854 if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0)
855 printf("%s: direction mismatch\n", __FUNCTION__);
856
857 /* check page table */
858 if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) {
859 if (debug)
860 printf("%s: page_table_present\n",
861 __FUNCTION__);
862 if (orbi->orb4.page_size != 0) {
863 printf("%s: unsupported pagesize %d != 0\n",
864 __FUNCTION__, orbi->orb4.page_size);
865 ccb->ccb_h.status = CAM_REQ_INVALID;
866 xpt_done(ccb);
867 break;
868 }
869 sbp_targ_fetch_pt(orbi);
870 break;
871 }
872
873 /* Sanity check */
874 if (ccb_dir != CAM_DIR_NONE &&
875 orbi->orb4.data_size != ccb->csio.dxfer_len)
876 printf("%s: data_size(%d) != dxfer_len(%d)\n",
877 __FUNCTION__, orbi->orb4.data_size,
878 ccb->csio.dxfer_len);
879
880 if (ccb_dir != CAM_DIR_NONE)
881 sbp_targ_xfer_buf(orbi, 0, orbi->data_hi,
882 orbi->data_lo,
883 MIN(orbi->orb4.data_size, ccb->csio.dxfer_len),
884 sbp_targ_cam_done);
885
886 if (ccb_dir == CAM_DIR_NONE) {
887 if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
888 sbp_targ_send_status(orbi, ccb);
889 ccb->ccb_h.status = CAM_REQ_CMP;
890 xpt_done(ccb);
891 }
892 break;
893 }
894 case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */
895 if (status != CAM_REQ_CMP) {
896 ccb->ccb_h.status = status;
897 xpt_done(ccb);
898 break;
899 }
900 SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
901 sim_links.sle);
902 ccb->ccb_h.status = CAM_REQ_INPROG;
903 if ((lstate->flags & ATIO_STARVED) != 0) {
904 if (debug)
905 printf("%s: new atio arrived\n", __FUNCTION__);
906 lstate->flags &= ~ATIO_STARVED;
907 sbp_targ_fetch_orb(lstate->sc, lstate->fwdev,
908 lstate->last_hi, lstate->last_lo,
909 lstate, FETCH_CMD);
910 }
911 break;
912 case XPT_NOTIFY_ACK: /* recycle notify ack */
913 case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */
914 if (status != CAM_REQ_CMP) {
915 ccb->ccb_h.status = status;
916 xpt_done(ccb);
917 break;
918 }
919 SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
920 sim_links.sle);
921 ccb->ccb_h.status = CAM_REQ_INPROG;
922 sbp_targ_send_lstate_events(sc, lstate);
923 break;
924 case XPT_EN_LUN:
925 sbp_targ_en_lun(sc, ccb);
926 xpt_done(ccb);
927 break;
928 case XPT_PATH_INQ:
929 {
930 struct ccb_pathinq *cpi = &ccb->cpi;
931
932 cpi->version_num = 1; /* XXX??? */
933 cpi->hba_inquiry = PI_TAG_ABLE;
934 cpi->target_sprt = PIT_PROCESSOR
935 | PIT_DISCONNECT
936 | PIT_TERM_IO;
937 cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE;
938 cpi->hba_eng_cnt = 0;
939 cpi->max_target = 7; /* XXX */
940 cpi->max_lun = MAX_LUN - 1;
941 cpi->initiator_id = 7; /* XXX */
942 cpi->bus_id = sim->bus_id;
943 cpi->base_transfer_speed = 400 * 1000 / 8;
944 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
945 strncpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN);
946 strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
947 cpi->unit_number = sim->unit_number;
948
949 cpi->ccb_h.status = CAM_REQ_CMP;
950 xpt_done(ccb);
951 break;
952 }
953 case XPT_ABORT:
954 {
955 union ccb *accb = ccb->cab.abort_ccb;
956
957 switch (accb->ccb_h.func_code) {
958 case XPT_ACCEPT_TARGET_IO:
959 case XPT_IMMED_NOTIFY:
960 ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb);
961 break;
962 case XPT_CONT_TARGET_IO:
963 /* XXX */
964 ccb->ccb_h.status = CAM_UA_ABORT;
965 break;
966 default:
967 printf("%s: aborting unknown function %d\n",
968 __FUNCTION__, accb->ccb_h.func_code);
969 ccb->ccb_h.status = CAM_REQ_INVALID;
970 break;
971 }
972 xpt_done(ccb);
973 break;
974 }
975 default:
976 printf("%s: unknown function %d\n",
977 __FUNCTION__, ccb->ccb_h.func_code);
978 ccb->ccb_h.status = CAM_REQ_INVALID;
979 xpt_done(ccb);
980 break;
981 }
982 return;
983}
984
985static void
986sbp_targ_action(struct cam_sim *sim, union ccb *ccb)
987{
988 int s;
989
990 s = splfw();
991 sbp_targ_action1(sim, ccb);
992 splx(s);
993}
994
995static void
996sbp_targ_poll(struct cam_sim *sim)
997{
998 /* XXX */
999 return;
1000}
1001
1002static void
1003sbp_targ_cmd_handler(struct fw_xfer *xfer)
1004{
1005 struct fw_pkt *fp;
1006 u_int32_t *orb;
1007 struct corb4 *orb4;
1008 struct orb_info *orbi;
1009 struct ccb_accept_tio *atio;
1010 struct sbp_targ_lstate *lstate;
1011 u_char *bytes;
1012 int i;
1013
1014 orbi = (struct orb_info *)xfer->sc;
1015 if (xfer->resp != 0) {
1016 printf("%s: xfer->resp != 0\n", __FUNCTION__);
1016 printf("%s: xfer->resp = %d\n", __FUNCTION__, xfer->resp);
1017 orbi->status.resp = SBP_TRANS_FAIL;
1018 orbi->status.status = htonl(OBJ_ORB | SBE_TIMEOUT /*XXX*/);
1019 orbi->status.dead = 1;
1020 orbi->status.len = 1;
1021 sbp_targ_abort(STAILQ_NEXT(orbi, link));
1022
1023 sbp_targ_status_FIFO(orbi,
1024 orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/1);
1025 fw_xfer_free(xfer);
1026 return;
1027 }
1028 fp = &xfer->recv.hdr;
1029
1030 if (orbi->state == ORBI_STATUS_ABORTED) {
1031 printf("%s: aborted\n", __FUNCTION__);
1032 sbp_targ_remove_orb_info(orbi->lstate, orbi);
1033 free(orbi, M_SBP_TARG);
1034 goto done0;
1035 }
1036 orbi->state = ORBI_STATUS_ATIO;
1037
1038 lstate = orbi->lstate;
1039
1040 orb = orbi->orb;
1041 /* swap payload except SCSI command */
1042 for (i = 0; i < 5; i ++)
1043 orb[i] = ntohl(orb[i]);
1044
1045 orb4 = (struct corb4 *)&orb[4];
1046 if (orb4->rq_fmt != 0) {
1047 /* XXX */
1048 printf("%s: rq_fmt(%d) != 0\n", __FUNCTION__, orb4->rq_fmt);
1049 }
1050
1051 atio = orbi->atio;
1052 atio->ccb_h.target_id = 0; /* XXX */
1053 atio->ccb_h.target_lun = lstate->lun;
1054 atio->sense_len = 0;
1055 atio->tag_action = 1; /* XXX */
1056 atio->tag_id = orbi->orb_lo;
1057#if 0
1058 atio->init_id = (orbi->fwdev->dst << 16) | (orbi->orb_hi & 0xffff);
1059#else
1060 atio->init_id = orbi->fwdev->dst;
1061#endif
1062 atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
1063 bytes = (char *)&orb[5];
1064 if (debug)
1065 printf("%s: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
1066 __FUNCTION__,
1067 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
1068 bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
1069 switch (bytes[0] >> 5) {
1070 case 0:
1071 atio->cdb_len = 6;
1072 break;
1073 case 1:
1074 case 2:
1075 atio->cdb_len = 10;
1076 break;
1077 case 4:
1078 atio->cdb_len = 16;
1079 break;
1080 case 5:
1081 atio->cdb_len = 12;
1082 break;
1083 case 3:
1084 default:
1085 /* Only copy the opcode. */
1086 atio->cdb_len = 1;
1087 printf("Reserved or VU command code type encountered\n");
1088 break;
1089 }
1090
1091 memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len);
1092
1093 atio->ccb_h.status |= CAM_CDB_RECVD;
1094
1095 /* next ORB */
1096 if ((orb[0] & (1<<31)) == 0) {
1097 if (debug)
1098 printf("%s: fetch next orb\n", __FUNCTION__);
1099 orbi->status.src = SRC_NEXT_EXISTS;
1100 sbp_targ_fetch_orb(orbi->sc, orbi->fwdev,
1101 orb[0], orb[1], orbi->lstate, FETCH_CMD);
1102 } else {
1103 orbi->status.src = SRC_NO_NEXT;
1104 orbi->lstate->flags &= ~LINK_ACTIVE;
1105 }
1106
1107 orbi->data_hi = orb[2];
1108 orbi->data_lo = orb[3];
1109 orbi->orb4 = *orb4;
1110
1111 xpt_done((union ccb*)atio);
1112done0:
1113 fw_xfer_free(xfer);
1114 return;
1115}
1116
1117static void
1118sbp_targ_mgm_handler(struct fw_xfer *xfer)
1119{
1120 struct sbp_targ_lstate *lstate;
1121 struct fw_pkt *fp;
1122 u_int32_t *orb;
1123 struct morb4 *orb4;
1124 struct orb_info *orbi;
1125 int i;
1126
1127 orbi = (struct orb_info *)xfer->sc;
1128 if (xfer->resp != 0) {
1129 printf("%s: xfer->resp != 0\n", __FUNCTION__);
1129 printf("%s: xfer->resp = %d\n", __FUNCTION__, xfer->resp);
1130 orbi->status.resp = SBP_TRANS_FAIL;
1131 orbi->status.status = htonl(OBJ_ORB | SBE_TIMEOUT /*XXX*/);
1132 orbi->status.dead = 1;
1133 orbi->status.len = 1;
1134 sbp_targ_abort(STAILQ_NEXT(orbi, link));
1135
1136 sbp_targ_status_FIFO(orbi,
1137 orbi->lstate->fifo_hi, orbi->lstate->fifo_lo, /*dequeue*/0);
1138 fw_xfer_free(xfer);
1139 return;
1140 }
1141 fp = &xfer->recv.hdr;
1142
1143 orb = orbi->orb;
1144 /* swap payload */
1145 for (i = 0; i < 8; i ++) {
1146 orb[i] = ntohl(orb[i]);
1147 }
1148 orb4 = (struct morb4 *)&orb[4];
1149 if (debug)
1150 printf("%s: %s\n", __FUNCTION__, orb_fun_name[orb4->fun]);
1151
1152 orbi->status.src = SRC_NO_NEXT;
1153
1154 switch (orb4->fun << 16) {
1155 case ORB_FUN_LGI:
1156 {
1157
1158 if (orb4->id >= MAX_LUN || orbi->sc->lstate[orb4->id] == NULL) {
1159 /* error */
1160 orbi->status.dead = 1;
1161 orbi->status.status = STATUS_ACCESS_DENY;
1162 orbi->status.len = 1;
1163 sbp_targ_status_FIFO(orbi, orb[6], orb[7],
1164 /*dequeue*/0);
1165 break;
1166 }
1167 /* XXX check exclusive login */
1168 lstate = orbi->sc->lstate[orb4->id];
1169 lstate->fifo_hi = orb[6];
1170 lstate->fifo_lo = orb[7];
1171 lstate->login_id = 0; /* XXX random number? */
1172 lstate->lun = orb4->id;
1173 lstate->loginres.len = htons(sizeof(u_int32_t) * 4);
1174 lstate->loginres.id = htons(lstate->login_id);
1175 lstate->loginres.cmd_hi = htons(SBP_TARG_BIND_HI);
1176 lstate->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(orb4->id));
1177 lstate->loginres.recon_hold = htons(0); /* XXX */
1178 fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3],
1179 sizeof(struct sbp_login_res), (void *)&lstate->loginres,
1180 fw_asy_callback_free);
1181 break;
1182 }
1183 case ORB_FUN_RCN:
1184 orbi->status.dead = 1;
1185 orbi->status.status = STATUS_ACCESS_DENY;
1186 break;
1187 default:
1188 printf("%s: %s not implemented yet\n",
1189 __FUNCTION__, orb_fun_name[orb4->fun]);
1190 break;
1191 }
1192 orbi->status.len = 1;
1193 sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0);
1194 fw_xfer_free(xfer);
1195 return;
1196}
1197
1198static void
1199sbp_targ_pointer_handler(struct fw_xfer *xfer)
1200{
1201 struct orb_info *orbi;
1202 u_int32_t orb0, orb1;
1203
1204 orbi = (struct orb_info *)xfer->sc;
1205 if (xfer->resp != 0) {
1206 printf("%s: xfer->resp != 0\n", __FUNCTION__);
1206 printf("%s: xfer->resp = %d\n", __FUNCTION__, xfer->resp);
1207 goto done;
1208 }
1209
1210 orb0 = ntohl(orbi->orb[0]);
1211 orb1 = ntohl(orbi->orb[1]);
1212 if ((orb0 & (1 << 31)) != 0) {
1213 printf("%s: invalid pointer\n", __FUNCTION__);
1214 goto done;
1215 }
1216 sbp_targ_fetch_orb(orbi->lstate->sc, orbi->fwdev,
1217 (u_int16_t)orb0, orb1, orbi->lstate, FETCH_CMD);
1218done:
1219 free(orbi, M_SBP_TARG);
1220 fw_xfer_free(xfer);
1221 return;
1222}
1223
1224static void
1225sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
1226 u_int16_t orb_hi, u_int32_t orb_lo, struct sbp_targ_lstate *lstate,
1227 int mode)
1228{
1229 struct orb_info *orbi;
1230
1231 if (debug)
1232 printf("%s: fetch orb %04x:%08x\n", __FUNCTION__, orb_hi, orb_lo);
1233 orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO);
1234 if (orbi == NULL) {
1235 printf("%s: malloc failed\n", __FUNCTION__);
1236 return;
1237 }
1238 orbi->sc = sc;
1239 orbi->fwdev = fwdev;
1240 orbi->lstate = lstate;
1241 orbi->orb_hi = orb_hi;
1242 orbi->orb_lo = orb_lo;
1243 orbi->status.orb_hi = htons(orb_hi);
1244 orbi->status.orb_lo = htonl(orb_lo);
1245
1246 switch (mode) {
1247 case FETCH_MGM:
1248 fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1249 sizeof(u_int32_t) * 8, &orbi->orb[0],
1250 sbp_targ_mgm_handler);
1251 break;
1252 case FETCH_CMD:
1253 orbi->state = ORBI_STATUS_FETCH;
1254 lstate->last_hi = orb_hi;
1255 lstate->last_lo = orb_lo;
1256 lstate->flags |= LINK_ACTIVE;
1257 /* dequeue */
1258 orbi->atio = (struct ccb_accept_tio *)
1259 SLIST_FIRST(&lstate->accept_tios);
1260 if (orbi->atio == NULL) {
1261 printf("%s: no free atio\n", __FUNCTION__);
1262 lstate->flags |= ATIO_STARVED;
1263 lstate->fwdev = fwdev;
1264 break;
1265 }
1266 SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle);
1267 fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1268 sizeof(u_int32_t) * 8, &orbi->orb[0],
1269 sbp_targ_cmd_handler);
1270 STAILQ_INSERT_TAIL(&lstate->orbs, orbi, link);
1271 break;
1272 case FETCH_POINTER:
1273 orbi->state = ORBI_STATUS_POINTER;
1274 fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1275 sizeof(u_int32_t) * 2, &orbi->orb[0],
1276 sbp_targ_pointer_handler);
1277 break;
1278 default:
1279 printf("%s: invalid mode %d\n", __FUNCTION__, mode);
1280 }
1281}
1282
1283static void
1284sbp_targ_resp_callback(struct fw_xfer *xfer)
1285{
1286 struct sbp_targ_softc *sc;
1287 int s;
1288
1289 if (debug)
1290 printf("%s: xfer=%p\n", __FUNCTION__, xfer);
1291 sc = (struct sbp_targ_softc *)xfer->sc;
1292 fw_xfer_unload(xfer);
1293 xfer->recv.pay_len = SBP_TARG_RECV_LEN;
1294 xfer->act.hand = sbp_targ_recv;
1295 s = splfw();
1296 STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
1297 splx(s);
1298}
1299
1300static int
1301sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int lun, int reg)
1302{
1303 struct sbp_targ_lstate *lstate;
1304 struct sbp_targ_softc *sc;
1305 int rtcode = 0;
1306
1307 if (lun < 0 || lun >= MAX_LUN)
1308 return(RESP_ADDRESS_ERROR);
1309
1310 sc = (struct sbp_targ_softc *)xfer->sc;
1311 lstate = sc->lstate[lun];
1312 if (lstate == NULL)
1313 return(RESP_ADDRESS_ERROR);
1314
1315 /* XXX check logined? */
1316 switch (reg) {
1317 case 0x08: /* ORB_POINTER */
1318 if (debug)
1319 printf("%s: ORB_POINTER\n", __FUNCTION__);
1320 sbp_targ_fetch_orb(lstate->sc, fwdev,
1321 ntohl(xfer->recv.payload[0]),
1322 ntohl(xfer->recv.payload[1]),
1323 lstate, FETCH_CMD);
1324 break;
1325 case 0x04: /* AGENT_RESET */
1326 if (debug)
1327 printf("%s: AGENT RESET\n", __FUNCTION__);
1328 lstate->last_hi = 0xffff;
1329 lstate->last_lo = 0xffffffff;
1330 sbp_targ_abort(STAILQ_FIRST(&lstate->orbs));
1331 break;
1332 case 0x10: /* DOORBELL */
1333 if (debug)
1334 printf("%s: DOORBELL\n", __FUNCTION__);
1335 if (lstate->last_hi == 0xffff &&
1336 lstate->last_lo == 0xffffffff) {
1337 printf("%s: no previous pointer(DOORBELL)\n",
1338 __FUNCTION__);
1339 break;
1340 }
1341 if ((lstate->flags & LINK_ACTIVE) != 0) {
1342 if (debug)
1343 printf("link active (DOORBELL)\n");
1344 break;
1345 }
1346 lstate->flags |= LINK_ACTIVE;
1347 sbp_targ_fetch_orb(lstate->sc, fwdev,
1348 lstate->last_hi, lstate->last_lo,
1349 lstate, FETCH_POINTER);
1350 break;
1351 case 0x00: /* AGENT_STATE */
1352 printf("%s: AGENT_STATE (ignore)\n", __FUNCTION__);
1353 break;
1354 case 0x14: /* UNSOLICITED_STATE_ENABLE */
1355 printf("%s: UNSOLICITED_STATE_ENABLE (ignore)\n", __FUNCTION__);
1356 break;
1357 default:
1358 printf("%s: invalid register %d\n", __FUNCTION__, reg);
1359 rtcode = RESP_ADDRESS_ERROR;
1360 }
1361
1362 return (rtcode);
1363}
1364
1365static int
1366sbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev)
1367{
1368 struct sbp_targ_softc *sc;
1369 struct fw_pkt *fp;
1370
1371 sc = (struct sbp_targ_softc *)xfer->sc;
1372
1373 fp = &xfer->recv.hdr;
1374 if (fp->mode.wreqb.tcode != FWTCODE_WREQB){
1375 printf("%s: tcode = %d\n", __FUNCTION__, fp->mode.wreqb.tcode);
1376 return(RESP_TYPE_ERROR);
1377 }
1378
1379 sbp_targ_fetch_orb(sc, fwdev,
1380 ntohl(xfer->recv.payload[0]),
1381 ntohl(xfer->recv.payload[1]),
1382 NULL, FETCH_MGM);
1383
1384 return(0);
1385}
1386
1387
1388static void
1389sbp_targ_recv(struct fw_xfer *xfer)
1390{
1391 struct fw_pkt *fp, *sfp;
1392 struct fw_device *fwdev;
1393 u_int32_t lo;
1394 int s, rtcode;
1395 struct sbp_targ_softc *sc;
1396
1397 s = splfw();
1398 sc = (struct sbp_targ_softc *)xfer->sc;
1399 fp = &xfer->recv.hdr;
1400 fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f);
1401 if (fwdev == NULL) {
1402 printf("%s: cannot resolve nodeid=%d\n",
1403 __FUNCTION__, fp->mode.wreqb.src & 0x3f);
1404 rtcode = RESP_TYPE_ERROR; /* XXX */
1405 goto done;
1406 }
1407 lo = fp->mode.wreqb.dest_lo;
1408 if (lo == SBP_TARG_BIND_LO(-1))
1409 rtcode = sbp_targ_mgm(xfer, fwdev);
1410 else if (lo >= SBP_TARG_BIND_LO(0))
1411 rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LUN(lo), lo % 0x20);
1412 else
1413 rtcode = RESP_ADDRESS_ERROR;
1414
1415done:
1416 if (rtcode != 0)
1417 printf("%s: rtcode = %d\n", __FUNCTION__, rtcode);
1418 sfp = &xfer->send.hdr;
1419 xfer->send.spd = 2; /* XXX */
1420 xfer->act.hand = sbp_targ_resp_callback;
1421 xfer->retry_req = fw_asybusy;
1422 sfp->mode.wres.dst = fp->mode.wreqb.src;
1423 sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;
1424 sfp->mode.wres.tcode = FWTCODE_WRES;
1425 sfp->mode.wres.rtcode = rtcode;
1426 sfp->mode.wres.pri = 0;
1427
1428 fw_asyreq(xfer->fc, -1, xfer);
1429 splx(s);
1430}
1431
1432static int
1433sbp_targ_attach(device_t dev)
1434{
1435 struct sbp_targ_softc *sc;
1436 struct cam_devq *devq;
1437 struct fw_xfer *xfer;
1438 int i;
1439
1440 sc = (struct sbp_targ_softc *) device_get_softc(dev);
1441 bzero((void *)sc, sizeof(struct sbp_targ_softc));
1442
1443 sc->fd.fc = device_get_ivars(dev);
1444 sc->fd.dev = dev;
1445 sc->fd.post_explore = NULL;
1446 sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
1447
1448 devq = cam_simq_alloc(/*maxopenings*/1);
1449 if (devq == NULL)
1450 return (ENXIO);
1451
1452 sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
1453 "sbp_targ", sc, device_get_unit(dev),
1454 /*untagged*/ 1, /*tagged*/ 1, devq);
1455 if (sc->sim == NULL) {
1456 cam_simq_free(devq);
1457 return (ENXIO);
1458 }
1459
1460 if (xpt_bus_register(sc->sim, /*bus*/0) != CAM_SUCCESS)
1461 goto fail;
1462
1463 if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim),
1464 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1465 xpt_bus_deregister(cam_sim_path(sc->sim));
1466 goto fail;
1467 }
1468
1469 sc->fwb.start = SBP_TARG_BIND_START;
1470 sc->fwb.end = SBP_TARG_BIND_END;
1471 sc->fwb.act_type = FWACT_XFER;
1472
1473 /* pre-allocate xfer */
1474 STAILQ_INIT(&sc->fwb.xferlist);
1475 for (i = 0; i < MAX_LUN /* XXX */; i ++) {
1476 xfer = fw_xfer_alloc_buf(M_SBP_TARG,
1477 /* send */ 0,
1478 /* recv */ SBP_TARG_RECV_LEN);
1479 xfer->act.hand = sbp_targ_recv;
1480 xfer->fc = sc->fd.fc;
1481 xfer->sc = (caddr_t)sc;
1482 STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
1483 }
1484 fw_bindadd(sc->fd.fc, &sc->fwb);
1485 return 0;
1486
1487fail:
1488 cam_sim_free(sc->sim, /*free_devq*/TRUE);
1489 return (ENXIO);
1490}
1491
1492static int
1493sbp_targ_detach(device_t dev)
1494{
1495 struct sbp_targ_softc *sc;
1496 struct sbp_targ_lstate *lstate;
1497 struct fw_xfer *xfer, *next;
1498 int i;
1499
1500 sc = (struct sbp_targ_softc *)device_get_softc(dev);
1501 sc->fd.post_busreset = NULL;
1502
1503 xpt_free_path(sc->path);
1504 xpt_bus_deregister(cam_sim_path(sc->sim));
1505 cam_sim_free(sc->sim, /*free_devq*/TRUE);
1506
1507 for (i = 0; i < MAX_LUN; i ++) {
1508 lstate = sc->lstate[i];
1509 if (lstate != NULL) {
1510 xpt_free_path(lstate->path);
1511 free(lstate, M_SBP_TARG);
1512 }
1513 }
1514 if (sc->black_hole != NULL) {
1515 xpt_free_path(sc->black_hole->path);
1516 free(sc->black_hole, M_SBP_TARG);
1517 }
1518
1519 for (xfer = STAILQ_FIRST(&sc->fwb.xferlist);
1520 xfer != NULL; xfer = next) {
1521 next = STAILQ_NEXT(xfer, link);
1522 fw_xfer_free_buf(xfer);
1523 }
1524 STAILQ_INIT(&sc->fwb.xferlist);
1525 fw_bindremove(sc->fd.fc, &sc->fwb);
1526
1527 return 0;
1528}
1529
1530static devclass_t sbp_targ_devclass;
1531
1532static device_method_t sbp_targ_methods[] = {
1533 /* device interface */
1534 DEVMETHOD(device_identify, sbp_targ_identify),
1535 DEVMETHOD(device_probe, sbp_targ_probe),
1536 DEVMETHOD(device_attach, sbp_targ_attach),
1537 DEVMETHOD(device_detach, sbp_targ_detach),
1538 { 0, 0 }
1539};
1540
1541static driver_t sbp_targ_driver = {
1542 "sbp_targ",
1543 sbp_targ_methods,
1544 sizeof(struct sbp_targ_softc),
1545};
1546
1547DRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, sbp_targ_devclass, 0, 0);
1548MODULE_VERSION(sbp_targ, 1);
1549MODULE_DEPEND(sbp_targ, firewire, 1, 1, 1);
1550MODULE_DEPEND(sbp_targ, cam, 1, 1, 1);