]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/dev/firewire/sbp_targ.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / dev / firewire / sbp_targ.c
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$
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_INITIATORS          8
67 #define MAX_LUN                 63
68 #define MAX_LOGINS              63
69 #define MAX_NODES               63
70 /*
71  * management/command block agent registers
72  *
73  * BASE 0xffff f001 0000 management port
74  * BASE 0xffff f001 0020 command port for login id 0
75  * BASE 0xffff f001 0040 command port for login id 1
76  *
77  */
78 #define SBP_TARG_MGM     0x10000        /* offset from 0xffff f000 000 */
79 #define SBP_TARG_BIND_HI        0xffff
80 #define SBP_TARG_BIND_LO(l)     (0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1))
81 #define SBP_TARG_BIND_START     (((u_int64_t)SBP_TARG_BIND_HI << 32) | \
82                                     SBP_TARG_BIND_LO(-1))
83 #define SBP_TARG_BIND_END       (((u_int64_t)SBP_TARG_BIND_HI << 32) | \
84                                     SBP_TARG_BIND_LO(MAX_LOGINS))
85 #define SBP_TARG_LOGIN_ID(lo)   (((lo) - SBP_TARG_BIND_LO(0))/0x20)
86
87 #define FETCH_MGM       0
88 #define FETCH_CMD       1
89 #define FETCH_POINTER   2
90
91 #define F_LINK_ACTIVE   (1 << 0)
92 #define F_ATIO_STARVED  (1 << 1)
93 #define F_LOGIN         (1 << 2)
94 #define F_HOLD          (1 << 3)
95 #define F_FREEZED       (1 << 4)
96
97 MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode");
98
99 static int debug = 0;
100
101 SYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0,
102         "SBP target mode debug flag");
103
104 struct sbp_targ_login {
105         struct sbp_targ_lstate *lstate;
106         struct fw_device *fwdev;
107         struct sbp_login_res loginres;
108         uint16_t fifo_hi; 
109         uint16_t last_hi;
110         uint32_t fifo_lo; 
111         uint32_t last_lo;
112         STAILQ_HEAD(, orb_info) orbs;
113         STAILQ_ENTRY(sbp_targ_login) link;
114         uint16_t hold_sec;
115         uint16_t id;
116         uint8_t flags; 
117         uint8_t spd; 
118         struct callout hold_callout;
119 };
120
121 struct sbp_targ_lstate {
122         uint16_t lun;
123         struct sbp_targ_softc *sc;
124         struct cam_path *path;
125         struct ccb_hdr_slist accept_tios;
126         struct ccb_hdr_slist immed_notifies;
127         struct crom_chunk model;
128         uint32_t flags; 
129         STAILQ_HEAD(, sbp_targ_login) logins;
130 };
131
132 struct sbp_targ_softc {
133         struct firewire_dev_comm fd;
134         struct cam_sim *sim;
135         struct cam_path *path;
136         struct fw_bind fwb;
137         int ndevs;
138         int flags;
139         struct crom_chunk unit;
140         struct sbp_targ_lstate *lstate[MAX_LUN];
141         struct sbp_targ_lstate *black_hole;
142         struct sbp_targ_login *logins[MAX_LOGINS];
143         struct mtx mtx;
144 };
145 #define SBP_LOCK(sc) mtx_lock(&(sc)->mtx)
146 #define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
147
148 struct corb4 {
149 #if BYTE_ORDER == BIG_ENDIAN
150         uint32_t n:1,
151                   rq_fmt:2,
152                   :1,
153                   dir:1,
154                   spd:3,
155                   max_payload:4,
156                   page_table_present:1,
157                   page_size:3,
158                   data_size:16;
159 #else
160         uint32_t data_size:16,
161                   page_size:3,
162                   page_table_present:1,
163                   max_payload:4,
164                   spd:3,
165                   dir:1,
166                   :1,
167                   rq_fmt:2,
168                   n:1;
169 #endif
170 };
171
172 struct morb4 {
173 #if BYTE_ORDER == BIG_ENDIAN
174         uint32_t n:1,
175                   rq_fmt:2,
176                   :9,
177                   fun:4,
178                   id:16;
179 #else
180         uint32_t id:16,
181                   fun:4,
182                   :9,
183                   rq_fmt:2,
184                   n:1;
185 #endif
186 };
187
188 struct orb_info {
189         struct sbp_targ_softc *sc;
190         struct fw_device *fwdev;
191         struct sbp_targ_login *login;
192         union ccb *ccb;
193         struct ccb_accept_tio *atio;
194         uint8_t state; 
195 #define ORBI_STATUS_NONE        0
196 #define ORBI_STATUS_FETCH       1
197 #define ORBI_STATUS_ATIO        2
198 #define ORBI_STATUS_CTIO        3
199 #define ORBI_STATUS_STATUS      4
200 #define ORBI_STATUS_POINTER     5
201 #define ORBI_STATUS_ABORTED     7
202         uint8_t refcount; 
203         uint16_t orb_hi;
204         uint32_t orb_lo;
205         uint32_t data_hi;
206         uint32_t data_lo;
207         struct corb4 orb4;
208         STAILQ_ENTRY(orb_info) link;
209         uint32_t orb[8];
210         uint32_t *page_table;
211         struct sbp_status status;
212 };
213
214 static char *orb_fun_name[] = {
215         ORB_FUN_NAMES
216 };
217
218 static void sbp_targ_recv(struct fw_xfer *);
219 static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
220     uint16_t, uint32_t, struct sbp_targ_login *, int);
221 static void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *);
222
223 static void
224 sbp_targ_identify(driver_t *driver, device_t parent)
225 {
226         BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent));
227 }
228
229 static int
230 sbp_targ_probe(device_t dev)
231 {
232         device_t pa;
233
234         pa = device_get_parent(dev);
235         if(device_get_unit(dev) != device_get_unit(pa)){
236                 return(ENXIO);
237         }
238
239         device_set_desc(dev, "SBP-2/SCSI over FireWire target mode");
240         return (0);
241 }
242
243 static void
244 sbp_targ_dealloc_login(struct sbp_targ_login *login)
245 {
246         struct orb_info *orbi, *next;
247
248         if (login == NULL) {
249                 printf("%s: login = NULL\n", __func__);
250                 return;
251         }
252         for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) {
253                 next = STAILQ_NEXT(orbi, link);
254                 free(orbi, M_SBP_TARG);
255         }
256         callout_stop(&login->hold_callout);
257
258         STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link);
259         login->lstate->sc->logins[login->id] = NULL;
260         free((void *)login, M_SBP_TARG);
261 }
262
263 static void
264 sbp_targ_hold_expire(void *arg)
265 {
266         struct sbp_targ_login *login;
267
268         login = (struct sbp_targ_login *)arg;
269
270         if (login->flags & F_HOLD) {
271                 printf("%s: login_id=%d expired\n", __func__, login->id);
272                 sbp_targ_dealloc_login(login);
273         } else {
274                 printf("%s: login_id=%d not hold\n", __func__, login->id);
275         }
276 }
277
278 static void
279 sbp_targ_post_busreset(void *arg)
280 {
281         struct sbp_targ_softc *sc;
282         struct crom_src *src;
283         struct crom_chunk *root;
284         struct crom_chunk *unit;
285         struct sbp_targ_lstate *lstate;
286         struct sbp_targ_login *login;
287         int i;
288
289         sc = (struct sbp_targ_softc *)arg;
290         src = sc->fd.fc->crom_src;
291         root = sc->fd.fc->crom_root;
292
293         unit = &sc->unit;
294
295         if ((sc->flags & F_FREEZED) == 0) {
296                 SBP_LOCK(sc);
297                 sc->flags |= F_FREEZED;
298                 xpt_freeze_simq(sc->sim, /*count*/1);
299                 SBP_UNLOCK(sc);
300         } else {
301                 printf("%s: already freezed\n", __func__);
302         }
303
304         bzero(unit, sizeof(struct crom_chunk));
305
306         crom_add_chunk(src, root, unit, CROM_UDIR);
307         crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10);
308         crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2);
309         crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
310         crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI);
311
312         crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2);
313         crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8);
314
315         for (i = 0; i < MAX_LUN; i ++) {
316                 lstate = sc->lstate[i];
317                 if (lstate == NULL)
318                         continue;
319                 crom_add_entry(unit, CSRKEY_FIRM_VER, 1);
320                 crom_add_entry(unit, CROM_LUN, i);
321                 crom_add_entry(unit, CSRKEY_MODEL, 1);
322                 crom_add_simple_text(src, unit, &lstate->model, "TargetMode");
323         }
324
325         /* Process for reconnection hold time */
326         for (i = 0; i < MAX_LOGINS; i ++) {
327                 login = sc->logins[i];
328                 if (login == NULL)
329                         continue;
330                 sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
331                 if (login->flags & F_LOGIN) {
332                         login->flags |= F_HOLD;
333                         callout_reset(&login->hold_callout,
334                             hz * login->hold_sec, 
335                             sbp_targ_hold_expire, (void *)login);
336                 }
337         }
338 }
339
340 static void
341 sbp_targ_post_explore(void *arg)
342 {
343         struct sbp_targ_softc *sc;
344
345         sc = (struct sbp_targ_softc *)arg;
346         SBP_LOCK(sc);
347         sc->flags &= ~F_FREEZED;
348         xpt_release_simq(sc->sim, /*run queue*/TRUE);
349         SBP_UNLOCK(sc);
350         return;
351 }
352
353 static cam_status
354 sbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb,
355     struct sbp_targ_lstate **lstate, int notfound_failure)
356 {
357         u_int lun;
358
359         /* XXX 0 is the only vaild target_id */
360         if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD &&
361             ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
362                 *lstate = sc->black_hole;
363                 return (CAM_REQ_CMP);
364         }
365
366         if (ccb->ccb_h.target_id != 0)
367                 return (CAM_TID_INVALID);
368
369         lun = ccb->ccb_h.target_lun;
370         if (lun >= MAX_LUN)
371                 return (CAM_LUN_INVALID);
372         
373         *lstate = sc->lstate[lun];
374
375         if (notfound_failure != 0 && *lstate == NULL)
376                 return (CAM_PATH_INVALID);
377
378         return (CAM_REQ_CMP);
379 }
380
381 static void
382 sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb)
383 {
384         struct ccb_en_lun *cel = &ccb->cel;
385         struct sbp_targ_lstate *lstate;
386         cam_status status;
387
388         status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
389         if (status != CAM_REQ_CMP) {
390                 ccb->ccb_h.status = status;
391                 return;
392         }
393
394         if (cel->enable != 0) {
395                 if (lstate != NULL) {
396                         xpt_print_path(ccb->ccb_h.path);
397                         printf("Lun already enabled\n");
398                         ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
399                         return;
400                 }
401                 if (cel->grp6_len != 0 || cel->grp7_len != 0) {
402                         ccb->ccb_h.status = CAM_REQ_INVALID;
403                         printf("Non-zero Group Codes\n");
404                         return;
405                 }
406                 lstate = (struct sbp_targ_lstate *)
407                     malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO);
408                 if (lstate == NULL) {
409                         xpt_print_path(ccb->ccb_h.path);
410                         printf("Couldn't allocate lstate\n");
411                         ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
412                         return;
413                 }
414                 if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
415                         sc->black_hole = lstate;
416                 else
417                         sc->lstate[ccb->ccb_h.target_lun] = lstate;
418                 memset(lstate, 0, sizeof(*lstate));
419                 lstate->sc = sc;
420                 status = xpt_create_path(&lstate->path, /*periph*/NULL,
421                                          xpt_path_path_id(ccb->ccb_h.path),
422                                          xpt_path_target_id(ccb->ccb_h.path),
423                                          xpt_path_lun_id(ccb->ccb_h.path));
424                 if (status != CAM_REQ_CMP) {
425                         free(lstate, M_SBP_TARG);
426                         xpt_print_path(ccb->ccb_h.path);
427                         printf("Couldn't allocate path\n");
428                         ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
429                         return;
430                 }
431                 SLIST_INIT(&lstate->accept_tios);
432                 SLIST_INIT(&lstate->immed_notifies);
433                 STAILQ_INIT(&lstate->logins);
434
435                 ccb->ccb_h.status = CAM_REQ_CMP;
436                 xpt_print_path(ccb->ccb_h.path);
437                 printf("Lun now enabled for target mode\n");
438                 /* bus reset */
439                 sc->fd.fc->ibr(sc->fd.fc);
440         } else {
441                 struct sbp_targ_login *login, *next;
442
443                 if (lstate == NULL) {
444                         ccb->ccb_h.status = CAM_LUN_INVALID;
445                         return;
446                 }
447                 ccb->ccb_h.status = CAM_REQ_CMP;
448
449                 if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
450                         printf("ATIOs pending\n");
451                         ccb->ccb_h.status = CAM_REQ_INVALID;
452                 }
453
454                 if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
455                         printf("INOTs pending\n");
456                         ccb->ccb_h.status = CAM_REQ_INVALID;
457                 }
458
459                 if (ccb->ccb_h.status != CAM_REQ_CMP) {
460                         return;
461                 }
462
463                 xpt_print_path(ccb->ccb_h.path);
464                 printf("Target mode disabled\n");
465                 xpt_free_path(lstate->path);
466
467                 for (login = STAILQ_FIRST(&lstate->logins); login != NULL;
468                     login = next) {
469                         next = STAILQ_NEXT(login, link);
470                         sbp_targ_dealloc_login(login);
471                 }
472
473                 if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
474                         sc->black_hole = NULL;
475                 else
476                         sc->lstate[ccb->ccb_h.target_lun] = NULL;
477                 free(lstate, M_SBP_TARG);
478
479                 /* bus reset */
480                 sc->fd.fc->ibr(sc->fd.fc);
481         }
482 }
483
484 static void
485 sbp_targ_send_lstate_events(struct sbp_targ_softc *sc,
486     struct sbp_targ_lstate *lstate)
487 {
488 #if 0
489         struct ccb_hdr *ccbh;
490         struct ccb_immed_notify *inot;
491
492         printf("%s: not implemented yet\n", __func__);
493 #endif
494 }
495
496
497 static __inline void
498 sbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi)
499 {
500         STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
501 }
502
503 static __inline void
504 sbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi)
505 {
506         SBP_LOCK(orbi->sc);
507         STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
508         SBP_UNLOCK(orbi->sc);
509 }
510
511 /*
512  * tag_id/init_id encoding
513  *
514  * tag_id and init_id has only 32bit for each.
515  * scsi_target can handle very limited number(up to 15) of init_id.
516  * we have to encode 48bit orb and 64bit EUI64 into these
517  * variables.
518  *
519  * tag_id represents lower 32bit of ORB address.
520  * init_id represents login_id.
521  *
522  */
523
524 static struct orb_info *
525 sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate,
526     u_int tag_id, u_int init_id)
527 {
528         struct sbp_targ_login *login;
529         struct orb_info *orbi;
530
531         login = lstate->sc->logins[init_id];
532         if (login == NULL) {
533                 printf("%s: no such login\n", __func__);
534                 return (NULL);
535         }
536         STAILQ_FOREACH(orbi, &login->orbs, link)
537                 if (orbi->orb_lo == tag_id)
538                         goto found;
539         printf("%s: orb not found tag_id=0x%08x init_id=%d\n",
540                                  __func__, tag_id, init_id);
541         return (NULL);
542 found:
543         return (orbi);
544 }
545
546 static void
547 sbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi)
548 {
549         struct orb_info *norbi;
550
551         SBP_LOCK(sc);
552         for (; orbi != NULL; orbi = norbi) {
553                 printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb);
554                 norbi = STAILQ_NEXT(orbi, link);
555                 if (orbi->state != ORBI_STATUS_ABORTED) {
556                         if (orbi->ccb != NULL) {
557                                 orbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
558                                 xpt_done(orbi->ccb);
559                                 orbi->ccb = NULL;
560                         }
561 #if 0
562                         if (orbi->state <= ORBI_STATUS_ATIO) {
563                                 sbp_targ_remove_orb_info_locked(orbi->login, orbi);
564                                 free(orbi, M_SBP_TARG);
565                         } else
566 #endif
567                                 orbi->state = ORBI_STATUS_ABORTED;
568                 }
569         }
570         SBP_UNLOCK(sc);
571 }
572
573 static void
574 sbp_targ_free_orbi(struct fw_xfer *xfer)
575 {
576         struct orb_info *orbi;
577
578         orbi = (struct orb_info *)xfer->sc;
579         if (xfer->resp != 0) {
580                 /* XXX */
581                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
582         }
583         free(orbi, M_SBP_TARG);
584         fw_xfer_free(xfer);
585 }
586
587 static void
588 sbp_targ_status_FIFO(struct orb_info *orbi,
589     uint32_t fifo_hi, uint32_t fifo_lo, int dequeue)
590 {
591         struct fw_xfer *xfer;
592
593         if (dequeue)
594                 sbp_targ_remove_orb_info(orbi->login, orbi);
595
596         xfer = fwmem_write_block(orbi->fwdev, (void *)orbi,
597             /*spd*/2, fifo_hi, fifo_lo,
598             sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status,
599             sbp_targ_free_orbi);
600
601         if (xfer == NULL) {
602                 /* XXX */
603                 printf("%s: xfer == NULL\n", __func__);
604         }
605 }
606
607 static void
608 sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
609 {
610         struct sbp_status *sbp_status;
611 #if     0
612         struct orb_info *norbi;
613 #endif
614
615         sbp_status = &orbi->status;
616
617         orbi->state = ORBI_STATUS_STATUS;
618
619         sbp_status->resp = 0; /* XXX */
620         sbp_status->status = 0; /* XXX */
621         sbp_status->dead = 0; /* XXX */
622
623         switch (ccb->csio.scsi_status) {
624         case SCSI_STATUS_OK:
625                 if (debug)
626                         printf("%s: STATUS_OK\n", __func__);
627                 sbp_status->len = 1;
628                 break;
629         case SCSI_STATUS_CHECK_COND:
630         case SCSI_STATUS_BUSY:
631         case SCSI_STATUS_CMD_TERMINATED:
632         {
633                 struct sbp_cmd_status *sbp_cmd_status;
634                 struct scsi_sense_data *sense;
635
636                 if (debug)
637                         printf("%s: STATUS %d\n", __func__,
638                             ccb->csio.scsi_status);
639                 sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0];
640                 sbp_cmd_status->status = ccb->csio.scsi_status;
641                 sense = &ccb->csio.sense_data;
642
643 #if 0           /* XXX What we should do? */
644 #if 0
645                 sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
646 #else
647                 norbi = STAILQ_NEXT(orbi, link);
648                 while (norbi) {
649                         printf("%s: status=%d\n", __func__, norbi->state);
650                         if (norbi->ccb != NULL) {
651                                 norbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
652                                 xpt_done(norbi->ccb);
653                                 norbi->ccb = NULL;
654                         }
655                         sbp_targ_remove_orb_info_locked(orbi->login, norbi);
656                         norbi = STAILQ_NEXT(norbi, link);
657                         free(norbi, M_SBP_TARG);
658                 }
659 #endif
660 #endif
661
662                 if ((sense->error_code & SSD_ERRCODE) == SSD_CURRENT_ERROR)
663                         sbp_cmd_status->sfmt = SBP_SFMT_CURR;
664                 else
665                         sbp_cmd_status->sfmt = SBP_SFMT_DEFER;
666
667                 sbp_cmd_status->valid = (sense->error_code & SSD_ERRCODE_VALID)
668                     ? 1 : 0;
669                 sbp_cmd_status->s_key = sense->flags & SSD_KEY;
670                 sbp_cmd_status->mark = (sense->flags & SSD_FILEMARK)? 1 : 0;
671                 sbp_cmd_status->eom = (sense->flags & SSD_EOM) ? 1 : 0;
672                 sbp_cmd_status->ill_len = (sense->flags & SSD_ILI) ? 1 : 0;
673
674                 bcopy(&sense->info[0], &sbp_cmd_status->info, 4);
675
676                 if (sense->extra_len <= 6)
677                         /* add_sense_code(_qual), info, cmd_spec_info */
678                         sbp_status->len = 4;
679                 else
680                         /* fru, sense_key_spec */
681                         sbp_status->len = 5;
682                         
683                 bcopy(&sense->cmd_spec_info[0], &sbp_cmd_status->cdb, 4);
684
685                 sbp_cmd_status->s_code = sense->add_sense_code;
686                 sbp_cmd_status->s_qlfr = sense->add_sense_code_qual;
687                 sbp_cmd_status->fru = sense->fru;
688
689                 bcopy(&sense->sense_key_spec[0],
690                     &sbp_cmd_status->s_keydep[0], 3);
691
692                 break;
693         }
694         default:
695                 printf("%s: unknown scsi status 0x%x\n", __func__,
696                     sbp_status->status);
697         }
698
699         if (orbi->page_table != NULL)
700                 free(orbi->page_table, M_SBP_TARG);
701
702         sbp_targ_status_FIFO(orbi,
703             orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
704 }
705
706 static void
707 sbp_targ_cam_done(struct fw_xfer *xfer)
708 {
709         struct orb_info *orbi;
710         union ccb *ccb;
711
712         orbi = (struct orb_info *)xfer->sc;
713
714         if (debug > 1)
715                 printf("%s: resp=%d refcount=%d\n", __func__,
716                         xfer->resp, orbi->refcount);
717
718         if (xfer->resp != 0) {
719                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
720                 orbi->status.resp = SBP_TRANS_FAIL;
721                 orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/;
722                 orbi->status.dead = 1;
723                 sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
724         }
725
726         orbi->refcount --;
727
728         ccb = orbi->ccb;
729         if (orbi->refcount == 0) {
730                 orbi->ccb = NULL;
731                 if (orbi->state == ORBI_STATUS_ABORTED) {
732                         if (debug)
733                                 printf("%s: orbi aborted\n", __func__);
734                         sbp_targ_remove_orb_info(orbi->login, orbi);
735                         if (orbi->page_table != NULL)
736                                 free(orbi->page_table, M_SBP_TARG);
737                         free(orbi, M_SBP_TARG);
738                 } else if (orbi->status.resp == 0) {
739                         if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
740                                 sbp_targ_send_status(orbi, ccb);
741                         ccb->ccb_h.status = CAM_REQ_CMP;
742                         SBP_LOCK(orbi->sc);
743                         xpt_done(ccb);
744                         SBP_UNLOCK(orbi->sc);
745                 } else {
746                         orbi->status.len = 1;
747                         sbp_targ_status_FIFO(orbi,
748                             orbi->login->fifo_hi, orbi->login->fifo_lo,
749                             /*dequeue*/1);
750                         ccb->ccb_h.status = CAM_REQ_ABORTED;
751                         SBP_LOCK(orbi->sc);
752                         xpt_done(ccb);
753                         SBP_UNLOCK(orbi->sc);
754                 }
755         }
756
757         fw_xfer_free(xfer);
758 }
759
760 static cam_status
761 sbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb)
762 {
763         union ccb *accb;
764         struct sbp_targ_lstate *lstate;
765         struct ccb_hdr_slist *list;
766         struct ccb_hdr *curelm;
767         int found;
768         cam_status status;
769
770         status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
771         if (status != CAM_REQ_CMP)
772                 return (status);
773
774         accb = ccb->cab.abort_ccb;
775
776         if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
777                 list = &lstate->accept_tios;
778         else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY)
779                 list = &lstate->immed_notifies;
780         else
781                 return (CAM_UA_ABORT);
782
783         curelm = SLIST_FIRST(list);
784         found = 0;
785         if (curelm == &accb->ccb_h) {
786                 found = 1;
787                 SLIST_REMOVE_HEAD(list, sim_links.sle);
788         } else {
789                 while(curelm != NULL) {
790                         struct ccb_hdr *nextelm;
791
792                         nextelm = SLIST_NEXT(curelm, sim_links.sle);
793                         if (nextelm == &accb->ccb_h) {
794                                 found = 1;
795                                 SLIST_NEXT(curelm, sim_links.sle) =
796                                     SLIST_NEXT(nextelm, sim_links.sle);
797                                 break;
798                         }
799                         curelm = nextelm;
800                 }
801         }
802         if (found) {
803                 accb->ccb_h.status = CAM_REQ_ABORTED;
804                 xpt_done(accb);
805                 return (CAM_REQ_CMP);
806         }
807         printf("%s: not found\n", __func__);
808         return (CAM_PATH_INVALID);
809 }
810
811 static void
812 sbp_targ_xfer_buf(struct orb_info *orbi, u_int offset,
813     uint16_t dst_hi, uint32_t dst_lo, u_int size,
814     void (*hand)(struct fw_xfer *))
815 {
816         struct fw_xfer *xfer;
817         u_int len, ccb_dir, off = 0;
818         char *ptr;
819
820         if (debug > 1)
821                 printf("%s: offset=%d size=%d\n", __func__, offset, size);
822         ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK;
823         ptr = (char *)orbi->ccb->csio.data_ptr + offset;
824
825         while (size > 0) {
826                 /* XXX assume dst_lo + off doesn't overflow */
827                 len = MIN(size, 2048 /* XXX */);
828                 size -= len;
829                 orbi->refcount ++;
830                 if (ccb_dir == CAM_DIR_OUT)
831                         xfer = fwmem_read_block(orbi->fwdev,
832                            (void *)orbi, /*spd*/2,
833                             dst_hi, dst_lo + off, len,
834                             ptr + off, hand);
835                 else
836                         xfer = fwmem_write_block(orbi->fwdev,
837                            (void *)orbi, /*spd*/2,
838                             dst_hi, dst_lo + off, len,
839                             ptr + off, hand);
840                 if (xfer == NULL) {
841                         printf("%s: xfer == NULL", __func__);
842                         /* XXX what should we do?? */
843                         orbi->refcount --;
844                 }
845                 off += len;
846         }
847 }
848
849 static void
850 sbp_targ_pt_done(struct fw_xfer *xfer)
851 {
852         struct orb_info *orbi;
853         union ccb *ccb;
854         u_int i, offset, res, len;
855         uint32_t t1, t2, *p;
856
857         orbi = (struct orb_info *)xfer->sc;
858         ccb = orbi->ccb;
859         if (orbi->state == ORBI_STATUS_ABORTED) {
860                 if (debug)
861                         printf("%s: orbi aborted\n", __func__);
862                 sbp_targ_remove_orb_info(orbi->login, orbi);
863                 free(orbi->page_table, M_SBP_TARG);
864                 free(orbi, M_SBP_TARG);
865                 fw_xfer_free(xfer);
866                 return;
867         }
868         if (xfer->resp != 0) {
869                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
870                 orbi->status.resp = SBP_TRANS_FAIL;
871                 orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/;
872                 orbi->status.dead = 1;
873                 orbi->status.len = 1;
874                 sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
875
876                 sbp_targ_status_FIFO(orbi,
877                     orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
878                 free(orbi->page_table, M_SBP_TARG);
879                 fw_xfer_free(xfer);
880                 return;
881         }
882         res = ccb->csio.dxfer_len;
883         offset = 0;
884         if (debug)
885                 printf("%s: dxfer_len=%d\n", __func__, res);
886         orbi->refcount ++;
887         for (p = orbi->page_table, i = orbi->orb4.data_size; i > 0; i --) {
888                 t1 = ntohl(*p++);
889                 t2 = ntohl(*p++);
890                 if (debug > 1)
891                         printf("page_table: %04x:%08x %d\n", 
892                             t1 & 0xffff, t2, t1>>16);
893                 len = MIN(t1 >> 16, res);
894                 res -= len;
895                 sbp_targ_xfer_buf(orbi, offset, t1 & 0xffff, t2, len,
896                     sbp_targ_cam_done);
897                 offset += len;
898                 if (res == 0)
899                         break;
900         }
901         orbi->refcount --;
902         if (orbi->refcount == 0)
903                 printf("%s: refcount == 0\n", __func__);
904         if (res !=0)
905                 /* XXX handle res != 0 case */
906                 printf("%s: page table is too small(%d)\n", __func__, res);
907
908         fw_xfer_free(xfer);
909         return;
910 }
911
912 static void
913 sbp_targ_fetch_pt(struct orb_info *orbi)
914 {
915         struct fw_xfer *xfer;
916
917         if (debug)
918                 printf("%s: page_table_size=%d\n",
919                     __func__, orbi->orb4.data_size);
920         orbi->page_table = malloc(orbi->orb4.data_size*8, M_SBP_TARG, M_NOWAIT);
921         if (orbi->page_table == NULL)
922                 goto error;
923         xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/2,
924                     orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*8,
925                             (void *)orbi->page_table, sbp_targ_pt_done);
926         if (xfer != NULL)
927                 return;
928 error:
929         orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
930         xpt_done(orbi->ccb);
931         return;
932 }
933
934 static void
935 sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
936 {
937         struct sbp_targ_softc *sc;
938         struct sbp_targ_lstate *lstate;
939         cam_status status;
940         u_int ccb_dir;
941
942         sc =  (struct sbp_targ_softc *)cam_sim_softc(sim);
943
944         status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE);
945
946         switch (ccb->ccb_h.func_code) {
947         case XPT_CONT_TARGET_IO:
948         {
949                 struct orb_info *orbi;
950
951                 if (debug)
952                         printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n",
953                                          __func__, ccb->csio.tag_id);
954
955                 if (status != CAM_REQ_CMP) {
956                         ccb->ccb_h.status = status;
957                         xpt_done(ccb);
958                         break;
959                 }
960                 /* XXX transfer from/to initiator */
961                 orbi = sbp_targ_get_orb_info(lstate,
962                     ccb->csio.tag_id, ccb->csio.init_id);
963                 if (orbi == NULL) {
964                         ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */
965                         xpt_done(ccb);
966                         break;
967                 }
968                 if (orbi->state == ORBI_STATUS_ABORTED) {
969                         if (debug)
970                                 printf("%s: ctio aborted\n", __func__);
971                         sbp_targ_remove_orb_info_locked(orbi->login, orbi);
972                         free(orbi, M_SBP_TARG);
973                         ccb->ccb_h.status = CAM_REQ_ABORTED;
974                         xpt_done(ccb);
975                         break;
976                 }
977                 orbi->state = ORBI_STATUS_CTIO;
978
979                 orbi->ccb = ccb;
980                 ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
981
982                 /* XXX */
983                 if (ccb->csio.dxfer_len == 0)
984                         ccb_dir = CAM_DIR_NONE;
985
986                 /* Sanity check */
987                 if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0)
988                         printf("%s: direction mismatch\n", __func__);
989
990                 /* check page table */
991                 if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) {
992                         if (debug)
993                                 printf("%s: page_table_present\n",
994                                     __func__);
995                         if (orbi->orb4.page_size != 0) {
996                                 printf("%s: unsupported pagesize %d != 0\n",
997                                     __func__, orbi->orb4.page_size);
998                                 ccb->ccb_h.status = CAM_REQ_INVALID;
999                                 xpt_done(ccb);
1000                                 break;
1001                         }
1002                         sbp_targ_fetch_pt(orbi);
1003                         break;
1004                 }
1005
1006                 /* Sanity check */
1007                 if (ccb_dir != CAM_DIR_NONE &&
1008                     orbi->orb4.data_size != ccb->csio.dxfer_len)
1009                         printf("%s: data_size(%d) != dxfer_len(%d)\n",
1010                             __func__, orbi->orb4.data_size,
1011                             ccb->csio.dxfer_len);
1012
1013                 if (ccb_dir != CAM_DIR_NONE)
1014                         sbp_targ_xfer_buf(orbi, 0, orbi->data_hi,
1015                             orbi->data_lo,
1016                             MIN(orbi->orb4.data_size, ccb->csio.dxfer_len),
1017                             sbp_targ_cam_done);
1018
1019                 if (ccb_dir == CAM_DIR_NONE) {
1020                         if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1021                                 /* XXX */
1022                                 SBP_UNLOCK(sc);
1023                                 sbp_targ_send_status(orbi, ccb);
1024                                 SBP_LOCK(sc);
1025                         }
1026                         ccb->ccb_h.status = CAM_REQ_CMP;
1027                         xpt_done(ccb);
1028                 }
1029                 break;
1030         }
1031         case XPT_ACCEPT_TARGET_IO:      /* Add Accept Target IO Resource */
1032                 if (status != CAM_REQ_CMP) {
1033                         ccb->ccb_h.status = status;
1034                         xpt_done(ccb);
1035                         break;
1036                 }
1037                 SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
1038                     sim_links.sle);
1039                 ccb->ccb_h.status = CAM_REQ_INPROG;
1040                 if ((lstate->flags & F_ATIO_STARVED) != 0) {
1041                         struct sbp_targ_login *login;
1042
1043                         if (debug)
1044                                 printf("%s: new atio arrived\n", __func__);
1045                         lstate->flags &= ~F_ATIO_STARVED;
1046                         STAILQ_FOREACH(login, &lstate->logins, link)
1047                                 if ((login->flags & F_ATIO_STARVED) != 0) {
1048                                         login->flags &= ~F_ATIO_STARVED;
1049                                         sbp_targ_fetch_orb(lstate->sc,
1050                                             login->fwdev,
1051                                             login->last_hi, login->last_lo,
1052                                             login, FETCH_CMD);
1053                                 }
1054                 }
1055                 break;
1056         case XPT_NOTIFY_ACK:            /* recycle notify ack */
1057         case XPT_IMMED_NOTIFY:          /* Add Immediate Notify Resource */
1058                 if (status != CAM_REQ_CMP) {
1059                         ccb->ccb_h.status = status;
1060                         xpt_done(ccb);
1061                         break;
1062                 }
1063                 SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
1064                     sim_links.sle);
1065                 ccb->ccb_h.status = CAM_REQ_INPROG;
1066                 sbp_targ_send_lstate_events(sc, lstate);
1067                 break;
1068         case XPT_EN_LUN:
1069                 sbp_targ_en_lun(sc, ccb);
1070                 xpt_done(ccb);
1071                 break;
1072         case XPT_PATH_INQ:
1073         {
1074                 struct ccb_pathinq *cpi = &ccb->cpi;
1075
1076                 cpi->version_num = 1; /* XXX??? */
1077                 cpi->hba_inquiry = PI_TAG_ABLE;
1078                 cpi->target_sprt = PIT_PROCESSOR
1079                                  | PIT_DISCONNECT
1080                                  | PIT_TERM_IO;
1081                 cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE;
1082                 cpi->hba_eng_cnt = 0;
1083                 cpi->max_target = 7; /* XXX */
1084                 cpi->max_lun = MAX_LUN - 1;
1085                 cpi->initiator_id = 7; /* XXX */
1086                 cpi->bus_id = sim->bus_id;
1087                 cpi->base_transfer_speed = 400 * 1000 / 8;
1088                 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1089                 strncpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN);
1090                 strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
1091                 cpi->unit_number = sim->unit_number;
1092
1093                 cpi->ccb_h.status = CAM_REQ_CMP;
1094                 xpt_done(ccb);
1095                 break;
1096         }
1097         case XPT_ABORT:
1098         {
1099                 union ccb *accb = ccb->cab.abort_ccb;
1100
1101                 switch (accb->ccb_h.func_code) {
1102                 case XPT_ACCEPT_TARGET_IO:
1103                 case XPT_IMMED_NOTIFY:
1104                         ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb);
1105                         break;
1106                 case XPT_CONT_TARGET_IO:
1107                         /* XXX */
1108                         ccb->ccb_h.status = CAM_UA_ABORT;
1109                         break;
1110                 default:
1111                         printf("%s: aborting unknown function %d\n", 
1112                                 __func__, accb->ccb_h.func_code);
1113                         ccb->ccb_h.status = CAM_REQ_INVALID;
1114                         break;
1115                 }
1116                 xpt_done(ccb);
1117                 break;
1118         }
1119         default:
1120                 printf("%s: unknown function %d\n",
1121                     __func__, ccb->ccb_h.func_code);
1122                 ccb->ccb_h.status = CAM_REQ_INVALID;
1123                 xpt_done(ccb);
1124                 break;
1125         }
1126         return;
1127 }
1128
1129 static void
1130 sbp_targ_action(struct cam_sim *sim, union ccb *ccb)
1131 {
1132         int s;
1133
1134         s = splfw();
1135         sbp_targ_action1(sim, ccb);
1136         splx(s);
1137 }
1138
1139 static void
1140 sbp_targ_poll(struct cam_sim *sim)
1141 {
1142         /* XXX */
1143         return;
1144 }
1145
1146 static void
1147 sbp_targ_cmd_handler(struct fw_xfer *xfer)
1148 {
1149         struct fw_pkt *fp;
1150         uint32_t *orb;
1151         struct corb4 *orb4;
1152         struct orb_info *orbi;
1153         struct ccb_accept_tio *atio;
1154         u_char *bytes;
1155         int i;
1156
1157         orbi = (struct orb_info *)xfer->sc;
1158         if (xfer->resp != 0) {
1159                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1160                 orbi->status.resp = SBP_TRANS_FAIL;
1161                 orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1162                 orbi->status.dead = 1;
1163                 orbi->status.len = 1;
1164                 sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1165
1166                 sbp_targ_status_FIFO(orbi,
1167                     orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
1168                 fw_xfer_free(xfer);
1169                 return;
1170         }
1171         fp = &xfer->recv.hdr;
1172
1173         atio = orbi->atio;
1174
1175         if (orbi->state == ORBI_STATUS_ABORTED) {
1176                 printf("%s: aborted\n", __func__);
1177                 sbp_targ_remove_orb_info(orbi->login, orbi);
1178                 free(orbi, M_SBP_TARG);
1179                 atio->ccb_h.status = CAM_REQ_ABORTED;
1180                 SBP_LOCK(orbi->sc);
1181                 xpt_done((union ccb*)atio);
1182                 SBP_UNLOCK(orbi->sc);
1183                 goto done0;
1184         }
1185         orbi->state = ORBI_STATUS_ATIO;
1186
1187         orb = orbi->orb;
1188         /* swap payload except SCSI command */
1189         for (i = 0; i < 5; i ++)
1190                 orb[i] = ntohl(orb[i]);
1191
1192         orb4 = (struct corb4 *)&orb[4];
1193         if (orb4->rq_fmt != 0) {
1194                 /* XXX */
1195                 printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt);
1196         }
1197
1198         atio->ccb_h.target_id = 0; /* XXX */
1199         atio->ccb_h.target_lun = orbi->login->lstate->lun;
1200         atio->sense_len = 0;
1201         atio->tag_action = 1; /* XXX */
1202         atio->tag_id = orbi->orb_lo;
1203         atio->init_id = orbi->login->id;
1204
1205         atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
1206         bytes = (u_char *)&orb[5];
1207         if (debug)
1208                 printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
1209                     __func__, (void *)atio,
1210                     bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
1211                     bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
1212         switch (bytes[0] >> 5) {
1213         case 0:
1214                 atio->cdb_len = 6;
1215                 break;
1216         case 1:
1217         case 2:
1218                 atio->cdb_len = 10;
1219                 break;
1220         case 4:
1221                 atio->cdb_len = 16;
1222                 break;
1223         case 5:
1224                 atio->cdb_len = 12;
1225                 break;
1226         case 3:
1227         default:
1228                 /* Only copy the opcode. */
1229                 atio->cdb_len = 1;
1230                 printf("Reserved or VU command code type encountered\n");
1231                 break;
1232         }
1233
1234         memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len);
1235
1236         atio->ccb_h.status |= CAM_CDB_RECVD;
1237
1238         /* next ORB */
1239         if ((orb[0] & (1<<31)) == 0) {
1240                 if (debug)
1241                         printf("%s: fetch next orb\n", __func__);
1242                 orbi->status.src = SRC_NEXT_EXISTS;
1243                 sbp_targ_fetch_orb(orbi->sc, orbi->fwdev,
1244                     orb[0], orb[1], orbi->login, FETCH_CMD);
1245         } else {
1246                 orbi->status.src = SRC_NO_NEXT;
1247                 orbi->login->flags &= ~F_LINK_ACTIVE;
1248         }
1249
1250         orbi->data_hi = orb[2];
1251         orbi->data_lo = orb[3];
1252         orbi->orb4 = *orb4;
1253
1254         SBP_LOCK(orbi->sc);
1255         xpt_done((union ccb*)atio);
1256         SBP_UNLOCK(orbi->sc);
1257 done0:
1258         fw_xfer_free(xfer);
1259         return;
1260 }
1261
1262 static struct sbp_targ_login *
1263 sbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun)
1264 {
1265         struct sbp_targ_lstate *lstate;
1266         struct sbp_targ_login *login;
1267         int i;
1268
1269         lstate = sc->lstate[lun];
1270         
1271         STAILQ_FOREACH(login, &lstate->logins, link)
1272                 if (login->fwdev == fwdev)
1273                         return (login);
1274
1275         for (i = 0; i < MAX_LOGINS; i ++)
1276                 if (sc->logins[i] == NULL)
1277                         goto found;
1278
1279         printf("%s: increase MAX_LOGIN\n", __func__);
1280         return (NULL);
1281
1282 found:
1283         login = (struct sbp_targ_login *)malloc(
1284             sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO);
1285
1286         if (login == NULL) {
1287                 printf("%s: malloc failed\n", __func__);
1288                 return (NULL);
1289         }
1290
1291         login->id = i;
1292         login->fwdev = fwdev;
1293         login->lstate = lstate;
1294         login->last_hi = 0xffff;
1295         login->last_lo = 0xffffffff;
1296         login->hold_sec = 1;
1297         STAILQ_INIT(&login->orbs);
1298         CALLOUT_INIT(&login->hold_callout);
1299         sc->logins[i] = login;
1300         return (login);
1301 }
1302
1303 static void
1304 sbp_targ_mgm_handler(struct fw_xfer *xfer)
1305 {
1306         struct sbp_targ_lstate *lstate;
1307         struct sbp_targ_login *login;
1308         struct fw_pkt *fp;
1309         uint32_t *orb;
1310         struct morb4 *orb4;
1311         struct orb_info *orbi;
1312         int i;
1313
1314         orbi = (struct orb_info *)xfer->sc;
1315         if (xfer->resp != 0) {
1316                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1317                 orbi->status.resp = SBP_TRANS_FAIL;
1318                 orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
1319                 orbi->status.dead = 1;
1320                 orbi->status.len = 1;
1321                 sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
1322
1323                 sbp_targ_status_FIFO(orbi,
1324                     orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0);
1325                 fw_xfer_free(xfer);
1326                 return;
1327         }
1328         fp = &xfer->recv.hdr;
1329
1330         orb = orbi->orb;
1331         /* swap payload */
1332         for (i = 0; i < 8; i ++) {
1333                 orb[i] = ntohl(orb[i]);
1334         }
1335         orb4 = (struct morb4 *)&orb[4];
1336         if (debug)
1337                 printf("%s: %s\n", __func__, orb_fun_name[orb4->fun]);
1338
1339         orbi->status.src = SRC_NO_NEXT;
1340
1341         switch (orb4->fun << 16) {
1342         case ORB_FUN_LGI:
1343         {
1344                 int exclusive = 0, lun;
1345
1346                 if (orb[4] & ORB_EXV)
1347                         exclusive = 1;
1348
1349                 lun = orb4->id;
1350                 lstate = orbi->sc->lstate[lun];
1351
1352                 if (lun >= MAX_LUN || lstate == NULL ||
1353                     (exclusive && 
1354                     STAILQ_FIRST(&lstate->logins) != NULL &&
1355                     STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev)
1356                     ) {
1357                         /* error */
1358                         orbi->status.dead = 1;
1359                         orbi->status.status = STATUS_ACCESS_DENY;
1360                         orbi->status.len = 1;
1361                         break;
1362                 }
1363
1364                 /* allocate login */
1365                 login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun);
1366                 if (login == NULL) {
1367                         printf("%s: sbp_targ_get_login failed\n",
1368                             __func__);
1369                         orbi->status.dead = 1;
1370                         orbi->status.status = STATUS_RES_UNAVAIL;
1371                         orbi->status.len = 1;
1372                         break;
1373                 }
1374                 printf("%s: login id=%d\n", __func__, login->id);
1375
1376                 login->fifo_hi = orb[6];
1377                 login->fifo_lo = orb[7];
1378                 login->loginres.len = htons(sizeof(uint32_t) * 4);
1379                 login->loginres.id = htons(login->id);
1380                 login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI);
1381                 login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id));
1382                 login->loginres.recon_hold = htons(login->hold_sec);
1383
1384                 STAILQ_INSERT_TAIL(&lstate->logins, login, link);
1385                 fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3],
1386                     sizeof(struct sbp_login_res), (void *)&login->loginres,
1387                     fw_asy_callback_free);
1388                 /* XXX return status after loginres is successfully written */
1389                 break;
1390         }
1391         case ORB_FUN_RCN:
1392                 login = orbi->sc->logins[orb4->id];
1393                 if (login != NULL && login->fwdev == orbi->fwdev) {
1394                         login->flags &= ~F_HOLD;
1395                         callout_stop(&login->hold_callout);
1396                         printf("%s: reconnected id=%d\n",
1397                             __func__, login->id);
1398                 } else {
1399                         orbi->status.dead = 1;
1400                         orbi->status.status = STATUS_ACCESS_DENY;
1401                         printf("%s: reconnection faild id=%d\n",
1402                             __func__, orb4->id);
1403                 }
1404                 break;
1405         case ORB_FUN_LGO:
1406                 login = orbi->sc->logins[orb4->id];
1407                 if (login->fwdev != orbi->fwdev) {
1408                         printf("%s: wrong initiator\n", __func__);
1409                         break;
1410                 }
1411                 sbp_targ_dealloc_login(login);
1412                 break;
1413         default:
1414                 printf("%s: %s not implemented yet\n",
1415                     __func__, orb_fun_name[orb4->fun]);
1416                 break;
1417         }
1418         orbi->status.len = 1;
1419         sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0);
1420         fw_xfer_free(xfer);
1421         return;
1422 }
1423
1424 static void
1425 sbp_targ_pointer_handler(struct fw_xfer *xfer)
1426 {
1427         struct orb_info *orbi;
1428         uint32_t orb0, orb1;
1429
1430         orbi = (struct orb_info *)xfer->sc;
1431         if (xfer->resp != 0) {
1432                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
1433                 goto done;
1434         }
1435
1436         orb0 = ntohl(orbi->orb[0]);
1437         orb1 = ntohl(orbi->orb[1]);
1438         if ((orb0 & (1 << 31)) != 0) {
1439                 printf("%s: invalid pointer\n", __func__);
1440                 goto done;
1441         }
1442         sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev,
1443             (uint16_t)orb0, orb1, orbi->login, FETCH_CMD);
1444 done:
1445         free(orbi, M_SBP_TARG);
1446         fw_xfer_free(xfer);
1447         return;
1448 }
1449
1450 static void
1451 sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
1452     uint16_t orb_hi, uint32_t orb_lo, struct sbp_targ_login *login,
1453     int mode)
1454 {
1455         struct orb_info *orbi;
1456
1457         if (debug)
1458                 printf("%s: fetch orb %04x:%08x\n", __func__, orb_hi, orb_lo);
1459         orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO);
1460         if (orbi == NULL) {
1461                 printf("%s: malloc failed\n", __func__);
1462                 return;
1463         }
1464         orbi->sc = sc;
1465         orbi->fwdev = fwdev;
1466         orbi->login = login;
1467         orbi->orb_hi = orb_hi;
1468         orbi->orb_lo = orb_lo;
1469         orbi->status.orb_hi = htons(orb_hi);
1470         orbi->status.orb_lo = htonl(orb_lo);
1471
1472         switch (mode) {
1473         case FETCH_MGM:
1474                 fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1475                     sizeof(uint32_t) * 8, &orbi->orb[0],
1476                     sbp_targ_mgm_handler);
1477                 break;
1478         case FETCH_CMD:
1479                 orbi->state = ORBI_STATUS_FETCH;
1480                 login->last_hi = orb_hi;
1481                 login->last_lo = orb_lo;
1482                 login->flags |= F_LINK_ACTIVE;
1483                 /* dequeue */
1484                 SBP_LOCK(sc);
1485                 orbi->atio = (struct ccb_accept_tio *)
1486                     SLIST_FIRST(&login->lstate->accept_tios);
1487                 if (orbi->atio == NULL) {
1488                         SBP_UNLOCK(sc);
1489                         printf("%s: no free atio\n", __func__);
1490                         login->lstate->flags |= F_ATIO_STARVED;
1491                         login->flags |= F_ATIO_STARVED;
1492 #if 0
1493                         /* XXX ?? */
1494                         login->fwdev = fwdev;
1495 #endif
1496                         break;
1497                 }
1498                 SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle);
1499                 STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
1500                 SBP_UNLOCK(sc);
1501                 fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1502                     sizeof(uint32_t) * 8, &orbi->orb[0],
1503                     sbp_targ_cmd_handler);
1504                 break;
1505         case FETCH_POINTER:
1506                 orbi->state = ORBI_STATUS_POINTER;
1507                 login->flags |= F_LINK_ACTIVE;
1508                 fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
1509                     sizeof(uint32_t) * 2, &orbi->orb[0],
1510                     sbp_targ_pointer_handler);
1511                 break;
1512         default:
1513                 printf("%s: invalid mode %d\n", __func__, mode);
1514         }
1515 }
1516
1517 static void
1518 sbp_targ_resp_callback(struct fw_xfer *xfer)
1519 {
1520         struct sbp_targ_softc *sc;
1521         int s;
1522
1523         if (debug)
1524                 printf("%s: xfer=%p\n", __func__, xfer);
1525         sc = (struct sbp_targ_softc *)xfer->sc;
1526         fw_xfer_unload(xfer);
1527         xfer->recv.pay_len = SBP_TARG_RECV_LEN;
1528         xfer->hand = sbp_targ_recv;
1529         s = splfw();
1530         STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
1531         splx(s);
1532 }
1533
1534 static int
1535 sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id,
1536     int reg)
1537 {
1538         struct sbp_targ_login *login;
1539         struct sbp_targ_softc *sc;
1540         int rtcode = 0;
1541
1542         if (login_id < 0 || login_id >= MAX_LOGINS)
1543                 return(RESP_ADDRESS_ERROR);
1544
1545         sc = (struct sbp_targ_softc *)xfer->sc;
1546         login = sc->logins[login_id];
1547         if (login == NULL)
1548                 return(RESP_ADDRESS_ERROR);
1549
1550         if (login->fwdev != fwdev) {
1551                 /* XXX */
1552                 return(RESP_ADDRESS_ERROR);
1553         }
1554
1555         switch (reg) {
1556         case 0x08:      /* ORB_POINTER */
1557                 if (debug)
1558                         printf("%s: ORB_POINTER(%d)\n", __func__, login_id);
1559                 if ((login->flags & F_LINK_ACTIVE) != 0) {
1560                         if (debug)
1561                                 printf("link active (ORB_POINTER)\n");
1562                         break;
1563                 }
1564                 sbp_targ_fetch_orb(sc, fwdev,
1565                     ntohl(xfer->recv.payload[0]),
1566                     ntohl(xfer->recv.payload[1]),
1567                     login, FETCH_CMD);
1568                 break;
1569         case 0x04:      /* AGENT_RESET */
1570                 if (debug)
1571                         printf("%s: AGENT RESET(%d)\n", __func__, login_id);
1572                 login->last_hi = 0xffff;
1573                 login->last_lo = 0xffffffff;
1574                 sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
1575                 break;
1576         case 0x10:      /* DOORBELL */
1577                 if (debug)
1578                         printf("%s: DOORBELL(%d)\n", __func__, login_id);
1579                 if (login->last_hi == 0xffff &&
1580                     login->last_lo == 0xffffffff) {
1581                         printf("%s: no previous pointer(DOORBELL)\n",
1582                             __func__);
1583                         break;
1584                 }
1585                 if ((login->flags & F_LINK_ACTIVE) != 0) {
1586                         if (debug)
1587                                 printf("link active (DOORBELL)\n");
1588                         break;
1589                 }
1590                 sbp_targ_fetch_orb(sc, fwdev,
1591                     login->last_hi, login->last_lo,
1592                     login, FETCH_POINTER);
1593                 break;
1594         case 0x00:      /* AGENT_STATE */
1595                 printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id);
1596                 break;
1597         case 0x14:      /* UNSOLICITED_STATE_ENABLE */
1598                 printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n",
1599                                                          __func__, login_id);
1600                 break;
1601         default:
1602                 printf("%s: invalid register %d(%d)\n",
1603                                                  __func__, reg, login_id);
1604                 rtcode = RESP_ADDRESS_ERROR;
1605         }
1606
1607         return (rtcode);
1608 }
1609
1610 static int
1611 sbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev)
1612 {
1613         struct sbp_targ_softc *sc;
1614         struct fw_pkt *fp;
1615
1616         sc = (struct sbp_targ_softc *)xfer->sc;
1617
1618         fp = &xfer->recv.hdr;
1619         if (fp->mode.wreqb.tcode != FWTCODE_WREQB){
1620                 printf("%s: tcode = %d\n", __func__, fp->mode.wreqb.tcode);
1621                 return(RESP_TYPE_ERROR);
1622         }
1623
1624         sbp_targ_fetch_orb(sc, fwdev,
1625             ntohl(xfer->recv.payload[0]),
1626             ntohl(xfer->recv.payload[1]),
1627             NULL, FETCH_MGM);
1628         
1629         return(0);
1630 }
1631
1632 static void
1633 sbp_targ_recv(struct fw_xfer *xfer)
1634 {
1635         struct fw_pkt *fp, *sfp;
1636         struct fw_device *fwdev;
1637         uint32_t lo;
1638         int s, rtcode;
1639         struct sbp_targ_softc *sc;
1640
1641         s = splfw();
1642         sc = (struct sbp_targ_softc *)xfer->sc;
1643         fp = &xfer->recv.hdr;
1644         fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f);
1645         if (fwdev == NULL) {
1646                 printf("%s: cannot resolve nodeid=%d\n",
1647                     __func__, fp->mode.wreqb.src & 0x3f);
1648                 rtcode = RESP_TYPE_ERROR; /* XXX */
1649                 goto done;
1650         }
1651         lo = fp->mode.wreqb.dest_lo;
1652
1653         if (lo == SBP_TARG_BIND_LO(-1))
1654                 rtcode = sbp_targ_mgm(xfer, fwdev);
1655         else if (lo >= SBP_TARG_BIND_LO(0))
1656                 rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo),
1657                     lo % 0x20);
1658         else
1659                 rtcode = RESP_ADDRESS_ERROR;
1660
1661 done:
1662         if (rtcode != 0)
1663                 printf("%s: rtcode = %d\n", __func__, rtcode);
1664         sfp = &xfer->send.hdr;
1665         xfer->send.spd = 2; /* XXX */
1666         xfer->hand = sbp_targ_resp_callback;
1667         sfp->mode.wres.dst = fp->mode.wreqb.src;
1668         sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;
1669         sfp->mode.wres.tcode = FWTCODE_WRES;
1670         sfp->mode.wres.rtcode = rtcode;
1671         sfp->mode.wres.pri = 0;
1672
1673         fw_asyreq(xfer->fc, -1, xfer);
1674         splx(s);
1675 }
1676
1677 static int
1678 sbp_targ_attach(device_t dev)
1679 {
1680         struct sbp_targ_softc *sc;
1681         struct cam_devq *devq;
1682         struct firewire_comm *fc;
1683
1684         sc = (struct sbp_targ_softc *) device_get_softc(dev);
1685         bzero((void *)sc, sizeof(struct sbp_targ_softc));
1686
1687         mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF);
1688         sc->fd.fc = fc = device_get_ivars(dev);
1689         sc->fd.dev = dev;
1690         sc->fd.post_explore = (void *) sbp_targ_post_explore;
1691         sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
1692
1693         devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS);
1694         if (devq == NULL)
1695                 return (ENXIO);
1696
1697         sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
1698             "sbp_targ", sc, device_get_unit(dev), &sc->mtx,
1699             /*untagged*/ 1, /*tagged*/ 1, devq);
1700         if (sc->sim == NULL) {
1701                 cam_simq_free(devq);
1702                 return (ENXIO);
1703         }
1704
1705         SBP_LOCK(sc);
1706         if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS)
1707                 goto fail;
1708
1709         if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim),
1710             CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1711                 xpt_bus_deregister(cam_sim_path(sc->sim));
1712                 goto fail;
1713         }
1714         SBP_UNLOCK(sc);
1715
1716         sc->fwb.start = SBP_TARG_BIND_START;
1717         sc->fwb.end = SBP_TARG_BIND_END;
1718
1719         /* pre-allocate xfer */
1720         STAILQ_INIT(&sc->fwb.xferlist);
1721         fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG,
1722             /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */,
1723             fc, (void *)sc, sbp_targ_recv);
1724         fw_bindadd(fc, &sc->fwb);
1725         return 0;
1726
1727 fail:
1728         SBP_UNLOCK(sc);
1729         cam_sim_free(sc->sim, /*free_devq*/TRUE);
1730         return (ENXIO);
1731 }
1732
1733 static int
1734 sbp_targ_detach(device_t dev)
1735 {
1736         struct sbp_targ_softc *sc;
1737         struct sbp_targ_lstate *lstate;
1738         int i;
1739
1740         sc = (struct sbp_targ_softc *)device_get_softc(dev);
1741         sc->fd.post_busreset = NULL;
1742
1743         SBP_LOCK(sc);
1744         xpt_free_path(sc->path);
1745         xpt_bus_deregister(cam_sim_path(sc->sim));
1746         SBP_UNLOCK(sc);
1747         cam_sim_free(sc->sim, /*free_devq*/TRUE); 
1748
1749         for (i = 0; i < MAX_LUN; i ++) {
1750                 lstate = sc->lstate[i];
1751                 if (lstate != NULL) {
1752                         xpt_free_path(lstate->path);
1753                         free(lstate, M_SBP_TARG);
1754                 }
1755         }
1756         if (sc->black_hole != NULL) {
1757                 xpt_free_path(sc->black_hole->path);
1758                 free(sc->black_hole, M_SBP_TARG);
1759         }
1760                         
1761         fw_bindremove(sc->fd.fc, &sc->fwb);
1762         fw_xferlist_remove(&sc->fwb.xferlist);
1763
1764         mtx_destroy(&sc->mtx);
1765
1766         return 0;
1767 }
1768
1769 static devclass_t sbp_targ_devclass;
1770
1771 static device_method_t sbp_targ_methods[] = {
1772         /* device interface */
1773         DEVMETHOD(device_identify,      sbp_targ_identify),
1774         DEVMETHOD(device_probe,         sbp_targ_probe),
1775         DEVMETHOD(device_attach,        sbp_targ_attach),
1776         DEVMETHOD(device_detach,        sbp_targ_detach),
1777         { 0, 0 }
1778 };
1779
1780 static driver_t sbp_targ_driver = {
1781         "sbp_targ",
1782         sbp_targ_methods,
1783         sizeof(struct sbp_targ_softc),
1784 };
1785
1786 DRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, sbp_targ_devclass, 0, 0);
1787 MODULE_VERSION(sbp_targ, 1);
1788 MODULE_DEPEND(sbp_targ, firewire, 1, 1, 1);
1789 MODULE_DEPEND(sbp_targ, cam, 1, 1, 1);