The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/firewire/sbp_targ.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-4-Clause
    3  *
    4  * Copyright (C) 2003
    5  *      Hidetoshi Shimokawa. All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *
   18  *      This product includes software developed by Hidetoshi Shimokawa.
   19  *
   20  * 4. Neither the name of the author nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  * $FreeBSD$
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/kernel.h>
   41 #include <sys/systm.h>
   42 #include <sys/sysctl.h>
   43 #include <sys/types.h>
   44 #include <sys/conf.h>
   45 #include <sys/malloc.h>
   46 #include <sys/endian.h>
   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 #include <cam/scsi/scsi_message.h>
   65 
   66 #define SBP_TARG_RECV_LEN       8
   67 #define MAX_INITIATORS          8
   68 #define MAX_LUN                 63
   69 #define MAX_LOGINS              63
   70 #define MAX_NODES               63
   71 /*
   72  * management/command block agent registers
   73  *
   74  * BASE 0xffff f001 0000 management port
   75  * BASE 0xffff f001 0020 command port for login id 0
   76  * BASE 0xffff f001 0040 command port for login id 1
   77  *
   78  */
   79 #define SBP_TARG_MGM     0x10000        /* offset from 0xffff f000 000 */
   80 #define SBP_TARG_BIND_HI        0xffff
   81 #define SBP_TARG_BIND_LO(l)     (0xf0000000 + SBP_TARG_MGM + 0x20 * ((l) + 1))
   82 #define SBP_TARG_BIND_START     (((u_int64_t)SBP_TARG_BIND_HI << 32) | \
   83                                     SBP_TARG_BIND_LO(-1))
   84 #define SBP_TARG_BIND_END       (((u_int64_t)SBP_TARG_BIND_HI << 32) | \
   85                                     SBP_TARG_BIND_LO(MAX_LOGINS))
   86 #define SBP_TARG_LOGIN_ID(lo)   (((lo) - SBP_TARG_BIND_LO(0))/0x20)
   87 
   88 #define FETCH_MGM       0
   89 #define FETCH_CMD       1
   90 #define FETCH_POINTER   2
   91 
   92 #define F_LINK_ACTIVE   (1 << 0)
   93 #define F_ATIO_STARVED  (1 << 1)
   94 #define F_LOGIN         (1 << 2)
   95 #define F_HOLD          (1 << 3)
   96 #define F_FREEZED       (1 << 4)
   97 
   98 static MALLOC_DEFINE(M_SBP_TARG, "sbp_targ", "SBP-II/FireWire target mode");
   99 
  100 static int debug = 0;
  101 
  102 SYSCTL_INT(_debug, OID_AUTO, sbp_targ_debug, CTLFLAG_RW, &debug, 0,
  103         "SBP target mode debug flag");
  104 
  105 struct sbp_targ_login {
  106         struct sbp_targ_lstate *lstate;
  107         struct fw_device *fwdev;
  108         struct sbp_login_res loginres;
  109         uint16_t fifo_hi;
  110         uint16_t last_hi;
  111         uint32_t fifo_lo;
  112         uint32_t last_lo;
  113         STAILQ_HEAD(, orb_info) orbs;
  114         STAILQ_ENTRY(sbp_targ_login) link;
  115         uint16_t hold_sec;
  116         uint16_t id;
  117         uint8_t flags;
  118         uint8_t spd;
  119         struct callout hold_callout;
  120 };
  121 
  122 struct sbp_targ_lstate {
  123         uint16_t lun;
  124         struct sbp_targ_softc *sc;
  125         struct cam_path *path;
  126         struct ccb_hdr_slist accept_tios;
  127         struct ccb_hdr_slist immed_notifies;
  128         struct crom_chunk model;
  129         uint32_t flags;
  130         STAILQ_HEAD(, sbp_targ_login) logins;
  131 };
  132 
  133 struct sbp_targ_softc {
  134         struct firewire_dev_comm fd;
  135         struct cam_sim *sim;
  136         struct cam_path *path;
  137         struct fw_bind fwb;
  138         int ndevs;
  139         int flags;
  140         struct crom_chunk unit;
  141         struct sbp_targ_lstate *lstate[MAX_LUN];
  142         struct sbp_targ_lstate *black_hole;
  143         struct sbp_targ_login *logins[MAX_LOGINS];
  144         struct mtx mtx;
  145 };
  146 #define SBP_LOCK(sc) mtx_lock(&(sc)->mtx)
  147 #define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
  148 
  149 struct corb4 {
  150 #if BYTE_ORDER == BIG_ENDIAN
  151         uint32_t n:1,
  152                   rq_fmt:2,
  153                   :1,
  154                   dir:1,
  155                   spd:3,
  156                   max_payload:4,
  157                   page_table_present:1,
  158                   page_size:3,
  159                   data_size:16;
  160 #else
  161         uint32_t data_size:16,
  162                   page_size:3,
  163                   page_table_present:1,
  164                   max_payload:4,
  165                   spd:3,
  166                   dir:1,
  167                   :1,
  168                   rq_fmt:2,
  169                   n:1;
  170 #endif
  171 };
  172 
  173 struct morb4 {
  174 #if BYTE_ORDER == BIG_ENDIAN
  175         uint32_t n:1,
  176                   rq_fmt:2,
  177                   :9,
  178                   fun:4,
  179                   id:16;
  180 #else
  181         uint32_t id:16,
  182                   fun:4,
  183                   :9,
  184                   rq_fmt:2,
  185                   n:1;
  186 #endif
  187 };
  188 
  189  
  190 /*
  191  * Urestricted page table format 
  192  * states that the segment length
  193  * and high base addr are in the first
  194  * 32 bits and the base low is in 
  195  * the second
  196  */
  197 struct unrestricted_page_table_fmt {
  198         uint16_t segment_len;
  199         uint16_t segment_base_high;
  200         uint32_t segment_base_low;
  201 };
  202 
  203 
  204 struct orb_info {
  205         struct sbp_targ_softc *sc;
  206         struct fw_device *fwdev;
  207         struct sbp_targ_login *login;
  208         union ccb *ccb;
  209         struct ccb_accept_tio *atio;
  210         uint8_t state;
  211 #define ORBI_STATUS_NONE        0
  212 #define ORBI_STATUS_FETCH       1
  213 #define ORBI_STATUS_ATIO        2
  214 #define ORBI_STATUS_CTIO        3
  215 #define ORBI_STATUS_STATUS      4
  216 #define ORBI_STATUS_POINTER     5
  217 #define ORBI_STATUS_ABORTED     7
  218         uint8_t refcount;
  219         uint16_t orb_hi;
  220         uint32_t orb_lo;
  221         uint32_t data_hi;
  222         uint32_t data_lo;
  223         struct corb4 orb4;
  224         STAILQ_ENTRY(orb_info) link;
  225         uint32_t orb[8];
  226         struct unrestricted_page_table_fmt *page_table;
  227         struct unrestricted_page_table_fmt *cur_pte;
  228         struct unrestricted_page_table_fmt *last_pte;
  229         uint32_t  last_block_read;
  230         struct sbp_status status;
  231 };
  232 
  233 static char *orb_fun_name[] = {
  234         ORB_FUN_NAMES
  235 };
  236 
  237 static void sbp_targ_recv(struct fw_xfer *);
  238 static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
  239     uint16_t, uint32_t, struct sbp_targ_login *, int);
  240 static void sbp_targ_xfer_pt(struct orb_info *);
  241 static void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *);
  242 
  243 static void
  244 sbp_targ_identify(driver_t *driver, device_t parent)
  245 {
  246         BUS_ADD_CHILD(parent, 0, "sbp_targ", device_get_unit(parent));
  247 }
  248 
  249 static int
  250 sbp_targ_probe(device_t dev)
  251 {
  252         device_t pa;
  253 
  254         pa = device_get_parent(dev);
  255         if (device_get_unit(dev) != device_get_unit(pa)) {
  256                 return (ENXIO);
  257         }
  258 
  259         device_set_desc(dev, "SBP-2/SCSI over FireWire target mode");
  260         return (0);
  261 }
  262 
  263 static void
  264 sbp_targ_dealloc_login(struct sbp_targ_login *login)
  265 {
  266         struct orb_info *orbi, *next;
  267 
  268         if (login == NULL) {
  269                 printf("%s: login = NULL\n", __func__);
  270                 return;
  271         }
  272         for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) {
  273                 next = STAILQ_NEXT(orbi, link);
  274                 if (debug)
  275                         printf("%s: free orbi %p\n", __func__, orbi);
  276                 free(orbi, M_SBP_TARG);
  277                 orbi = NULL;
  278         }
  279         callout_stop(&login->hold_callout);
  280 
  281         STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link);
  282         login->lstate->sc->logins[login->id] = NULL;
  283         if (debug)
  284                 printf("%s: free login %p\n", __func__, login);
  285         free((void *)login, M_SBP_TARG);
  286         login = NULL;
  287 }
  288 
  289 static void
  290 sbp_targ_hold_expire(void *arg)
  291 {
  292         struct sbp_targ_login *login;
  293 
  294         login = (struct sbp_targ_login *)arg;
  295 
  296         if (login->flags & F_HOLD) {
  297                 printf("%s: login_id=%d expired\n", __func__, login->id);
  298                 sbp_targ_dealloc_login(login);
  299         } else {
  300                 printf("%s: login_id=%d not hold\n", __func__, login->id);
  301         }
  302 }
  303 
  304 static void
  305 sbp_targ_post_busreset(void *arg)
  306 {
  307         struct sbp_targ_softc *sc;
  308         struct crom_src *src;
  309         struct crom_chunk *root;
  310         struct crom_chunk *unit;
  311         struct sbp_targ_lstate *lstate;
  312         struct sbp_targ_login *login;
  313         int i;
  314 
  315         sc = (struct sbp_targ_softc *)arg;
  316         src = sc->fd.fc->crom_src;
  317         root = sc->fd.fc->crom_root;
  318 
  319         unit = &sc->unit;
  320 
  321         if ((sc->flags & F_FREEZED) == 0) {
  322                 sc->flags |= F_FREEZED;
  323                 xpt_freeze_simq(sc->sim, /*count*/1);
  324         } else {
  325                 printf("%s: already freezed\n", __func__);
  326         }
  327 
  328         bzero(unit, sizeof(struct crom_chunk));
  329 
  330         crom_add_chunk(src, root, unit, CROM_UDIR);
  331         crom_add_entry(unit, CSRKEY_SPEC, CSRVAL_ANSIT10);
  332         crom_add_entry(unit, CSRKEY_VER, CSRVAL_T10SBP2);
  333         crom_add_entry(unit, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
  334         crom_add_entry(unit, CSRKEY_COM_SET, CSRVAL_SCSI);
  335 
  336         crom_add_entry(unit, CROM_MGM, SBP_TARG_MGM >> 2);
  337         crom_add_entry(unit, CSRKEY_UNIT_CH, (10<<8) | 8);
  338 
  339         for (i = 0; i < MAX_LUN; i++) {
  340                 lstate = sc->lstate[i];
  341                 if (lstate == NULL)
  342                         continue;
  343                 crom_add_entry(unit, CSRKEY_FIRM_VER, 1);
  344                 crom_add_entry(unit, CROM_LUN, i);
  345                 crom_add_entry(unit, CSRKEY_MODEL, 1);
  346                 crom_add_simple_text(src, unit, &lstate->model, "TargetMode");
  347         }
  348 
  349         /* Process for reconnection hold time */
  350         for (i = 0; i < MAX_LOGINS; i++) {
  351                 login = sc->logins[i];
  352                 if (login == NULL)
  353                         continue;
  354                 sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
  355                 if (login->flags & F_LOGIN) {
  356                         login->flags |= F_HOLD;
  357                         callout_reset(&login->hold_callout,
  358                             hz * login->hold_sec,
  359                             sbp_targ_hold_expire, (void *)login);
  360                 }
  361         }
  362 }
  363 
  364 static void
  365 sbp_targ_post_explore(void *arg)
  366 {
  367         struct sbp_targ_softc *sc;
  368 
  369         sc = (struct sbp_targ_softc *)arg;
  370         sc->flags &= ~F_FREEZED;
  371         xpt_release_simq(sc->sim, /*run queue*/TRUE);
  372         return;
  373 }
  374 
  375 static cam_status
  376 sbp_targ_find_devs(struct sbp_targ_softc *sc, union ccb *ccb,
  377     struct sbp_targ_lstate **lstate, int notfound_failure)
  378 {
  379         u_int lun;
  380 
  381         /* XXX 0 is the only vaild target_id */
  382         if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD &&
  383             ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
  384                 *lstate = sc->black_hole;
  385                 if (debug)
  386                         printf("setting black hole for this target id(%d)\n", ccb->ccb_h.target_id);
  387                 return (CAM_REQ_CMP);
  388         }
  389 
  390         lun = ccb->ccb_h.target_lun;
  391         if (lun >= MAX_LUN)
  392                 return (CAM_LUN_INVALID);
  393 
  394         *lstate = sc->lstate[lun];
  395 
  396         if (notfound_failure != 0 && *lstate == NULL) {
  397                 if (debug)
  398                         printf("%s: lstate for lun is invalid, target(%d), lun(%d)\n",
  399                                 __func__, ccb->ccb_h.target_id, lun);
  400                 return (CAM_PATH_INVALID);
  401         } else
  402                 if (debug)
  403                         printf("%s: setting lstate for tgt(%d) lun(%d)\n",
  404                                 __func__,ccb->ccb_h.target_id, lun);
  405 
  406         return (CAM_REQ_CMP);
  407 }
  408 
  409 static void
  410 sbp_targ_en_lun(struct sbp_targ_softc *sc, union ccb *ccb)
  411 {
  412         struct ccb_en_lun *cel = &ccb->cel;
  413         struct sbp_targ_lstate *lstate;
  414         cam_status status;
  415 
  416         status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
  417         if (status != CAM_REQ_CMP) {
  418                 ccb->ccb_h.status = status;
  419                 return;
  420         }
  421 
  422         if (cel->enable != 0) {
  423                 if (lstate != NULL) {
  424                         xpt_print_path(ccb->ccb_h.path);
  425                         printf("Lun already enabled\n");
  426                         ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
  427                         return;
  428                 }
  429                 if (cel->grp6_len != 0 || cel->grp7_len != 0) {
  430                         ccb->ccb_h.status = CAM_REQ_INVALID;
  431                         printf("Non-zero Group Codes\n");
  432                         return;
  433                 }
  434                 lstate = (struct sbp_targ_lstate *)
  435                     malloc(sizeof(*lstate), M_SBP_TARG, M_NOWAIT | M_ZERO);
  436                 if (lstate == NULL) {
  437                         xpt_print_path(ccb->ccb_h.path);
  438                         printf("Couldn't allocate lstate\n");
  439                         ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
  440                         return;
  441                 } else {
  442                         if (debug)
  443                                 printf("%s: malloc'd lstate %p\n",__func__, lstate);
  444                 }       
  445                 if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) {
  446                         sc->black_hole = lstate;
  447                         if (debug)
  448                                 printf("Blackhole set due to target id == %d\n",
  449                                         ccb->ccb_h.target_id);
  450                 } else
  451                         sc->lstate[ccb->ccb_h.target_lun] = lstate;
  452 
  453                 memset(lstate, 0, sizeof(*lstate));
  454                 lstate->sc = sc;
  455                 status = xpt_create_path(&lstate->path, /*periph*/NULL,
  456                                          xpt_path_path_id(ccb->ccb_h.path),
  457                                          xpt_path_target_id(ccb->ccb_h.path),
  458                                          xpt_path_lun_id(ccb->ccb_h.path));
  459                 if (status != CAM_REQ_CMP) {
  460                         free(lstate, M_SBP_TARG);
  461                         lstate = NULL;
  462                         xpt_print_path(ccb->ccb_h.path);
  463                         printf("Couldn't allocate path\n");
  464                         ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
  465                         return;
  466                 }
  467                 SLIST_INIT(&lstate->accept_tios);
  468                 SLIST_INIT(&lstate->immed_notifies);
  469                 STAILQ_INIT(&lstate->logins);
  470 
  471                 ccb->ccb_h.status = CAM_REQ_CMP;
  472                 xpt_print_path(ccb->ccb_h.path);
  473                 printf("Lun now enabled for target mode\n");
  474                 /* bus reset */
  475                 sc->fd.fc->ibr(sc->fd.fc);
  476         } else {
  477                 struct sbp_targ_login *login, *next;
  478 
  479                 if (lstate == NULL) {
  480                         ccb->ccb_h.status = CAM_LUN_INVALID;
  481                         printf("Invalid lstate for this target\n");
  482                         return;
  483                 }
  484                 ccb->ccb_h.status = CAM_REQ_CMP;
  485 
  486                 if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
  487                         printf("ATIOs pending\n");
  488                         ccb->ccb_h.status = CAM_REQ_INVALID;
  489                 }
  490 
  491                 if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
  492                         printf("INOTs pending\n");
  493                         ccb->ccb_h.status = CAM_REQ_INVALID;
  494                 }
  495 
  496                 if (ccb->ccb_h.status != CAM_REQ_CMP) {
  497                         printf("status != CAM_REQ_CMP\n");
  498                         return;
  499                 }
  500 
  501                 xpt_print_path(ccb->ccb_h.path);
  502                 printf("Target mode disabled\n");
  503                 xpt_free_path(lstate->path);
  504 
  505                 for (login = STAILQ_FIRST(&lstate->logins); login != NULL;
  506                     login = next) {
  507                         next = STAILQ_NEXT(login, link);
  508                         sbp_targ_dealloc_login(login);
  509                 }
  510 
  511                 if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
  512                         sc->black_hole = NULL;
  513                 else
  514                         sc->lstate[ccb->ccb_h.target_lun] = NULL;
  515                 if (debug)
  516                         printf("%s: free lstate %p\n", __func__, lstate);
  517                 free(lstate, M_SBP_TARG);
  518                 lstate = NULL;
  519 
  520                 /* bus reset */
  521                 sc->fd.fc->ibr(sc->fd.fc);
  522         }
  523 }
  524 
  525 static void
  526 sbp_targ_send_lstate_events(struct sbp_targ_softc *sc,
  527     struct sbp_targ_lstate *lstate)
  528 {
  529 #if 0
  530         struct ccb_hdr *ccbh;
  531         struct ccb_immediate_notify *inot;
  532 
  533         printf("%s: not implemented yet\n", __func__);
  534 #endif
  535 }
  536 
  537 
  538 static __inline void
  539 sbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi)
  540 {
  541         STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
  542 }
  543 
  544 static __inline void
  545 sbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi)
  546 {
  547         SBP_LOCK(orbi->sc);
  548         STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
  549         SBP_UNLOCK(orbi->sc);
  550 }
  551 
  552 /*
  553  * tag_id/init_id encoding
  554  *
  555  * tag_id and init_id has only 32bit for each.
  556  * scsi_target can handle very limited number(up to 15) of init_id.
  557  * we have to encode 48bit orb and 64bit EUI64 into these
  558  * variables.
  559  *
  560  * tag_id represents lower 32bit of ORB address.
  561  * init_id represents login_id.
  562  *
  563  */
  564 
  565 static struct orb_info *
  566 sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate,
  567     u_int tag_id, u_int init_id)
  568 {
  569         struct sbp_targ_login *login;
  570         struct orb_info *orbi;
  571 
  572         login = lstate->sc->logins[init_id];
  573         if (login == NULL) {
  574                 printf("%s: no such login\n", __func__);
  575                 return (NULL);
  576         }
  577         STAILQ_FOREACH(orbi, &login->orbs, link)
  578                 if (orbi->orb_lo == tag_id)
  579                         goto found;
  580         printf("%s: orb not found tag_id=0x%08x init_id=%d\n",
  581                          __func__, tag_id, init_id);
  582         return (NULL);
  583 found:
  584         return (orbi);
  585 }
  586 
  587 static void
  588 sbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi)
  589 {
  590         struct orb_info *norbi;
  591 
  592         SBP_LOCK(sc);
  593         for (; orbi != NULL; orbi = norbi) {
  594                 printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb);
  595                 norbi = STAILQ_NEXT(orbi, link);
  596                 if (orbi->state != ORBI_STATUS_ABORTED) {
  597                         if (orbi->ccb != NULL) {
  598                                 orbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
  599                                 xpt_done(orbi->ccb);
  600                                 orbi->ccb = NULL;
  601                         }
  602                         if (orbi->state <= ORBI_STATUS_ATIO) {
  603                                 sbp_targ_remove_orb_info_locked(orbi->login, orbi);
  604                                 if (debug)
  605                                         printf("%s: free orbi %p\n", __func__, orbi);
  606                                 free(orbi, M_SBP_TARG);
  607                                 orbi = NULL;
  608                         } else
  609                                 orbi->state = ORBI_STATUS_ABORTED;
  610                 }
  611         }
  612         SBP_UNLOCK(sc);
  613 }
  614 
  615 static void
  616 sbp_targ_free_orbi(struct fw_xfer *xfer)
  617 {
  618         struct orb_info *orbi;
  619 
  620         if (xfer->resp != 0) {
  621                 /* XXX */
  622                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
  623         }
  624         orbi = (struct orb_info *)xfer->sc;
  625         if ( orbi->page_table != NULL ) {
  626                 if (debug)
  627                         printf("%s:  free orbi->page_table %p\n", __func__, orbi->page_table);
  628                 free(orbi->page_table, M_SBP_TARG);
  629                 orbi->page_table = NULL;
  630         }
  631         if (debug)
  632                 printf("%s: free orbi %p\n", __func__, orbi);
  633         free(orbi, M_SBP_TARG);
  634         orbi = NULL;
  635         fw_xfer_free(xfer);
  636 }
  637 
  638 static void
  639 sbp_targ_status_FIFO(struct orb_info *orbi,
  640     uint32_t fifo_hi, uint32_t fifo_lo, int dequeue)
  641 {
  642         struct fw_xfer *xfer;
  643 
  644         if (dequeue)
  645                 sbp_targ_remove_orb_info(orbi->login, orbi);
  646 
  647         xfer = fwmem_write_block(orbi->fwdev, (void *)orbi,
  648             /*spd*/FWSPD_S400, fifo_hi, fifo_lo,
  649             sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status,
  650             sbp_targ_free_orbi);
  651 
  652         if (xfer == NULL) {
  653                 /* XXX */
  654                 printf("%s: xfer == NULL\n", __func__);
  655         }
  656 }
  657 
  658 /*
  659  * Generate the appropriate CAM status for the
  660  * target.
  661  */
  662 static void
  663 sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
  664 {
  665         struct sbp_status *sbp_status;
  666 #if     0
  667         struct orb_info *norbi;
  668 #endif
  669 
  670         sbp_status = &orbi->status;
  671 
  672         orbi->state = ORBI_STATUS_STATUS;
  673 
  674         sbp_status->resp = 0; /* XXX */
  675         sbp_status->status = 0; /* XXX */
  676         sbp_status->dead = 0; /* XXX */
  677 
  678         ccb->ccb_h.status= CAM_REQ_CMP;
  679 
  680         switch (ccb->csio.scsi_status) {
  681         case SCSI_STATUS_OK:
  682                 if (debug)
  683                         printf("%s: STATUS_OK\n", __func__);
  684                 sbp_status->len = 1;
  685                 break;
  686         case SCSI_STATUS_CHECK_COND:
  687                 if (debug)
  688                         printf("%s: STATUS SCSI_STATUS_CHECK_COND\n", __func__);
  689                 goto process_scsi_status;
  690         case SCSI_STATUS_BUSY:
  691                 if (debug)
  692                         printf("%s: STATUS SCSI_STATUS_BUSY\n", __func__);
  693                 goto process_scsi_status;
  694         case SCSI_STATUS_CMD_TERMINATED:
  695 process_scsi_status:
  696         {
  697                 struct sbp_cmd_status *sbp_cmd_status;
  698                 struct scsi_sense_data *sense;
  699                 int error_code, sense_key, asc, ascq;
  700                 uint8_t stream_bits;
  701                 uint8_t sks[3];
  702                 uint64_t info;
  703                 int64_t sinfo;
  704                 int sense_len;
  705 
  706                 sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0];
  707                 sbp_cmd_status->status = ccb->csio.scsi_status;
  708                 sense = &ccb->csio.sense_data;
  709 
  710 #if 0           /* XXX What we should do? */
  711 #if 0
  712                 sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
  713 #else
  714                 norbi = STAILQ_NEXT(orbi, link);
  715                 while (norbi) {
  716                         printf("%s: status=%d\n", __func__, norbi->state);
  717                         if (norbi->ccb != NULL) {
  718                                 norbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
  719                                 xpt_done(norbi->ccb);
  720                                 norbi->ccb = NULL;
  721                         }
  722                         sbp_targ_remove_orb_info_locked(orbi->login, norbi);
  723                         norbi = STAILQ_NEXT(norbi, link);
  724                         free(norbi, M_SBP_TARG);
  725                 }
  726 #endif
  727 #endif
  728 
  729                 sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
  730                 scsi_extract_sense_len(sense, sense_len, &error_code,
  731                     &sense_key, &asc, &ascq, /*show_errors*/ 0);
  732 
  733                 switch (error_code) {
  734                 case SSD_CURRENT_ERROR:
  735                 case SSD_DESC_CURRENT_ERROR:
  736                         sbp_cmd_status->sfmt = SBP_SFMT_CURR;
  737                         break;
  738                 default:
  739                         sbp_cmd_status->sfmt = SBP_SFMT_DEFER;
  740                         break;
  741                 }
  742 
  743                 if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info,
  744                                         &sinfo) == 0) {
  745                         uint32_t info_trunc;
  746                         sbp_cmd_status->valid = 1;
  747                         info_trunc = info;
  748 
  749                         sbp_cmd_status->info = htobe32(info_trunc);
  750                 } else {
  751                         sbp_cmd_status->valid = 0;
  752                 }
  753 
  754                 sbp_cmd_status->s_key = sense_key;
  755 
  756                 if (scsi_get_stream_info(sense, sense_len, NULL,
  757                                          &stream_bits) == 0) {
  758                         sbp_cmd_status->mark =
  759                             (stream_bits & SSD_FILEMARK) ? 1 : 0;
  760                         sbp_cmd_status->eom =
  761                             (stream_bits & SSD_EOM) ? 1 : 0;
  762                         sbp_cmd_status->ill_len =
  763                             (stream_bits & SSD_ILI) ? 1 : 0;
  764                 } else {
  765                         sbp_cmd_status->mark = 0;
  766                         sbp_cmd_status->eom = 0;
  767                         sbp_cmd_status->ill_len = 0;
  768                 }
  769 
  770 
  771                 /* add_sense_code(_qual), info, cmd_spec_info */
  772                 sbp_status->len = 4;
  773 
  774                 if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND,
  775                                         &info, &sinfo) == 0) {
  776                         uint32_t cmdspec_trunc;
  777 
  778                         cmdspec_trunc = info;
  779 
  780                         sbp_cmd_status->cdb = htobe32(cmdspec_trunc);
  781                 }
  782 
  783                 sbp_cmd_status->s_code = asc;
  784                 sbp_cmd_status->s_qlfr = ascq;
  785 
  786                 if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU, &info,
  787                                         &sinfo) == 0) {
  788                         sbp_cmd_status->fru = (uint8_t)info;
  789                         sbp_status->len = 5;
  790                 } else {
  791                         sbp_cmd_status->fru = 0;
  792                 }
  793 
  794                 if (scsi_get_sks(sense, sense_len, sks) == 0) {
  795                         bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks));
  796                         sbp_status->len = 5;
  797                         ccb->ccb_h.status |= CAM_SENT_SENSE;
  798                 }
  799 
  800                 break;
  801         }
  802         default:
  803                 printf("%s: unknown scsi status 0x%x\n", __func__,
  804                     sbp_status->status);
  805         }
  806 
  807 
  808         sbp_targ_status_FIFO(orbi,
  809             orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
  810 }
  811 
  812 /*
  813  * Invoked as a callback handler from fwmem_read/write_block
  814  *
  815  * Process read/write of initiator address space
  816  * completion and pass status onto the backend target.
  817  * If this is a partial read/write for a CCB then
  818  * we decrement the orbi's refcount to indicate
  819  * the status of the read/write is complete
  820  */
  821 static void
  822 sbp_targ_cam_done(struct fw_xfer *xfer)
  823 {
  824         struct orb_info *orbi;
  825         union ccb *ccb;
  826 
  827         orbi = (struct orb_info *)xfer->sc;
  828 
  829         if (debug)
  830                 printf("%s: resp=%d refcount=%d\n", __func__,
  831                         xfer->resp, orbi->refcount);
  832 
  833         if (xfer->resp != 0) {
  834                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
  835                 orbi->status.resp = SBP_TRANS_FAIL;
  836                 orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/;
  837                 orbi->status.dead = 1;
  838                 sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
  839         }
  840 
  841         orbi->refcount--;
  842 
  843         ccb = orbi->ccb;
  844         if (orbi->refcount == 0) {
  845                 orbi->ccb = NULL;
  846                 if (orbi->state == ORBI_STATUS_ABORTED) {
  847                         if (debug)
  848                                 printf("%s: orbi aborted\n", __func__);
  849                         sbp_targ_remove_orb_info(orbi->login, orbi);
  850                         if (orbi->page_table != NULL) {
  851                                 if (debug)
  852                                         printf("%s: free orbi->page_table %p\n",
  853                                                 __func__, orbi->page_table);
  854                                 free(orbi->page_table, M_SBP_TARG);
  855                         }
  856                         if (debug)
  857                                 printf("%s: free orbi %p\n", __func__, orbi);
  858                         free(orbi, M_SBP_TARG);
  859                         orbi = NULL;
  860                 } else if (orbi->status.resp == ORBI_STATUS_NONE) {
  861                         if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
  862                                 if (debug) 
  863                                         printf("%s: CAM_SEND_STATUS set %0x\n", __func__, ccb->ccb_h.flags);
  864                                 sbp_targ_send_status(orbi, ccb);
  865                         } else {
  866                                 if (debug)
  867                                         printf("%s: CAM_SEND_STATUS not set %0x\n", __func__, ccb->ccb_h.flags);
  868                                 ccb->ccb_h.status = CAM_REQ_CMP;
  869                         }
  870                         xpt_done(ccb);
  871                 } else {
  872                         orbi->status.len = 1;
  873                         sbp_targ_status_FIFO(orbi,
  874                             orbi->login->fifo_hi, orbi->login->fifo_lo,
  875                             /*dequeue*/1);
  876                         ccb->ccb_h.status = CAM_REQ_ABORTED;
  877                         xpt_done(ccb);
  878                 }
  879         }
  880 
  881         fw_xfer_free(xfer);
  882 }
  883 
  884 static cam_status
  885 sbp_targ_abort_ccb(struct sbp_targ_softc *sc, union ccb *ccb)
  886 {
  887         union ccb *accb;
  888         struct sbp_targ_lstate *lstate;
  889         struct ccb_hdr_slist *list;
  890         struct ccb_hdr *curelm;
  891         int found;
  892         cam_status status;
  893 
  894         status = sbp_targ_find_devs(sc, ccb, &lstate, 0);
  895         if (status != CAM_REQ_CMP)
  896                 return (status);
  897 
  898         accb = ccb->cab.abort_ccb;
  899 
  900         if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
  901                 list = &lstate->accept_tios;
  902         else if (accb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY)
  903                 list = &lstate->immed_notifies;
  904         else
  905                 return (CAM_UA_ABORT);
  906 
  907         curelm = SLIST_FIRST(list);
  908         found = 0;
  909         if (curelm == &accb->ccb_h) {
  910                 found = 1;
  911                 SLIST_REMOVE_HEAD(list, sim_links.sle);
  912         } else {
  913                 while (curelm != NULL) {
  914                         struct ccb_hdr *nextelm;
  915 
  916                         nextelm = SLIST_NEXT(curelm, sim_links.sle);
  917                         if (nextelm == &accb->ccb_h) {
  918                                 found = 1;
  919                                 SLIST_NEXT(curelm, sim_links.sle) =
  920                                     SLIST_NEXT(nextelm, sim_links.sle);
  921                                 break;
  922                         }
  923                         curelm = nextelm;
  924                 }
  925         }
  926         if (found) {
  927                 accb->ccb_h.status = CAM_REQ_ABORTED;
  928                 xpt_done(accb);
  929                 return (CAM_REQ_CMP);
  930         }
  931         printf("%s: not found\n", __func__);
  932         return (CAM_PATH_INVALID);
  933 }
  934 
  935 /*
  936  * directly execute a read or write to the initiator
  937  * address space and set hand(sbp_targ_cam_done) to 
  938  * process the completion from the SIM to the target.
  939  * set orbi->refcount to inidicate that a read/write
  940  * is inflight to/from the initiator.
  941  */
  942 static void
  943 sbp_targ_xfer_buf(struct orb_info *orbi, u_int offset,
  944     uint16_t dst_hi, uint32_t dst_lo, u_int size,
  945     void (*hand)(struct fw_xfer *))
  946 {
  947         struct fw_xfer *xfer;
  948         u_int len, ccb_dir, off = 0;
  949         char *ptr;
  950 
  951         if (debug > 1)
  952                 printf("%s: offset=%d size=%d\n", __func__, offset, size);
  953         ccb_dir = orbi->ccb->ccb_h.flags & CAM_DIR_MASK;
  954         ptr = (char *)orbi->ccb->csio.data_ptr + offset;
  955 
  956         while (size > 0) {
  957                 /* XXX assume dst_lo + off doesn't overflow */
  958                 len = MIN(size, 2048 /* XXX */);
  959                 size -= len;
  960                 orbi->refcount ++;
  961                 if (ccb_dir == CAM_DIR_OUT) {
  962                         if (debug)
  963                                 printf("%s: CAM_DIR_OUT --> read block in?\n",__func__);
  964                         xfer = fwmem_read_block(orbi->fwdev,
  965                            (void *)orbi, /*spd*/FWSPD_S400,
  966                             dst_hi, dst_lo + off, len,
  967                             ptr + off, hand);
  968                 } else {
  969                         if (debug)
  970                                 printf("%s: CAM_DIR_IN --> write block out?\n",__func__);
  971                         xfer = fwmem_write_block(orbi->fwdev,
  972                            (void *)orbi, /*spd*/FWSPD_S400,
  973                             dst_hi, dst_lo + off, len,
  974                             ptr + off, hand);
  975                 }
  976                 if (xfer == NULL) {
  977                         printf("%s: xfer == NULL", __func__);
  978                         /* XXX what should we do?? */
  979                         orbi->refcount--;
  980                 }
  981                 off += len;
  982         }
  983 }
  984 
  985 static void
  986 sbp_targ_pt_done(struct fw_xfer *xfer)
  987 {
  988         struct orb_info *orbi;
  989         struct unrestricted_page_table_fmt *pt;
  990         uint32_t i;
  991 
  992         orbi = (struct orb_info *)xfer->sc;
  993 
  994         if (orbi->state == ORBI_STATUS_ABORTED) {
  995                 if (debug)
  996                         printf("%s: orbi aborted\n", __func__);
  997                 sbp_targ_remove_orb_info(orbi->login, orbi);
  998                 if (debug) {
  999                         printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
 1000                         printf("%s: free orbi %p\n", __func__, orbi);
 1001                 }
 1002                 free(orbi->page_table, M_SBP_TARG);
 1003                 free(orbi, M_SBP_TARG);
 1004                 orbi = NULL;
 1005                 fw_xfer_free(xfer);
 1006                 return;
 1007         }
 1008         if (xfer->resp != 0) {
 1009                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
 1010                 orbi->status.resp = SBP_TRANS_FAIL;
 1011                 orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/;
 1012                 orbi->status.dead = 1;
 1013                 orbi->status.len = 1;
 1014                 sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
 1015 
 1016                 if (debug)
 1017                         printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
 1018 
 1019                 sbp_targ_status_FIFO(orbi,
 1020                     orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
 1021                 free(orbi->page_table, M_SBP_TARG);
 1022                 orbi->page_table = NULL;
 1023                 fw_xfer_free(xfer);
 1024                 return;
 1025         }
 1026         orbi->refcount++;
 1027 /*
 1028  * Set endianness here so we don't have 
 1029  * to deal with is later
 1030  */
 1031         for (i = 0, pt = orbi->page_table; i < orbi->orb4.data_size; i++, pt++) {
 1032                 pt->segment_len = ntohs(pt->segment_len);
 1033                 if (debug)
 1034                         printf("%s:segment_len = %u\n", __func__,pt->segment_len);
 1035                 pt->segment_base_high = ntohs(pt->segment_base_high);
 1036                 pt->segment_base_low = ntohl(pt->segment_base_low);
 1037         }
 1038 
 1039         sbp_targ_xfer_pt(orbi);
 1040 
 1041         orbi->refcount--;
 1042         if (orbi->refcount == 0)
 1043                 printf("%s: refcount == 0\n", __func__);
 1044 
 1045         fw_xfer_free(xfer);
 1046         return;
 1047 }
 1048 
 1049 static void sbp_targ_xfer_pt(struct orb_info *orbi)
 1050 {
 1051         union ccb *ccb;
 1052         uint32_t res, offset, len;
 1053 
 1054         ccb = orbi->ccb;
 1055         if (debug)
 1056                 printf("%s: dxfer_len=%d\n", __func__, ccb->csio.dxfer_len);
 1057         res = ccb->csio.dxfer_len;
 1058         /*
 1059          * If the page table required multiple CTIO's to 
 1060          * complete, then cur_pte is non NULL 
 1061          * and we need to start from the last position
 1062          * If this is the first pass over a page table
 1063          * then we just start at the beginning of the page
 1064          * table.
 1065          *
 1066          * Parse the unrestricted page table and figure out where we need
 1067          * to shove the data from this read request.
 1068          */
 1069         for (offset = 0, len = 0; (res != 0) && (orbi->cur_pte < orbi->last_pte); offset += len) {
 1070                 len = MIN(orbi->cur_pte->segment_len, res);
 1071                 res -= len;
 1072                 if (debug)
 1073                         printf("%s:page_table: %04x:%08x segment_len(%u) res(%u) len(%u)\n", 
 1074                                 __func__, orbi->cur_pte->segment_base_high,
 1075                                 orbi->cur_pte->segment_base_low,
 1076                                 orbi->cur_pte->segment_len,
 1077                                 res, len);
 1078                 sbp_targ_xfer_buf(orbi, offset, 
 1079                                 orbi->cur_pte->segment_base_high,
 1080                                 orbi->cur_pte->segment_base_low,
 1081                                 len, sbp_targ_cam_done);
 1082                 /*
 1083                  * If we have only written partially to
 1084                  * this page table, then we need to save
 1085                  * our position for the next CTIO.  If we
 1086                  * have completed the page table, then we
 1087                  * are safe to move on to the next entry.
 1088                  */
 1089                 if (len == orbi->cur_pte->segment_len) {
 1090                         orbi->cur_pte++;
 1091                 } else {
 1092                         uint32_t saved_base_low;
 1093 
 1094                         /* Handle transfers that cross a 4GB boundary. */
 1095                         saved_base_low = orbi->cur_pte->segment_base_low;
 1096                         orbi->cur_pte->segment_base_low += len;
 1097                         if (orbi->cur_pte->segment_base_low < saved_base_low)
 1098                                 orbi->cur_pte->segment_base_high++;
 1099 
 1100                         orbi->cur_pte->segment_len -= len;
 1101                 }
 1102         }
 1103         if (debug) {
 1104                 printf("%s: base_low(%08x) page_table_off(%p) last_block(%u)\n",
 1105                         __func__, orbi->cur_pte->segment_base_low, 
 1106                         orbi->cur_pte, orbi->last_block_read);  
 1107         }
 1108         if (res != 0)
 1109                 printf("Warning - short pt encountered.  "
 1110                         "Could not transfer all data.\n");
 1111         return;
 1112 }
 1113 
 1114 /*
 1115  * Create page table in local memory
 1116  * and transfer it from the initiator
 1117  * in order to know where we are supposed
 1118  * to put the data.
 1119  */
 1120 
 1121 static void
 1122 sbp_targ_fetch_pt(struct orb_info *orbi)
 1123 {
 1124         struct fw_xfer *xfer;
 1125 
 1126         /*
 1127          * Pull in page table from initiator
 1128          * and setup for data from our
 1129          * backend device.
 1130          */
 1131         if (orbi->page_table == NULL) {
 1132                 orbi->page_table = malloc(orbi->orb4.data_size*
 1133                                           sizeof(struct unrestricted_page_table_fmt),
 1134                                           M_SBP_TARG, M_NOWAIT|M_ZERO);
 1135                 if (orbi->page_table == NULL)
 1136                         goto error;
 1137                 orbi->cur_pte = orbi->page_table;
 1138                 orbi->last_pte = orbi->page_table + orbi->orb4.data_size;
 1139                 orbi->last_block_read = orbi->orb4.data_size;
 1140                 if (debug && orbi->page_table != NULL) 
 1141                         printf("%s: malloc'd orbi->page_table(%p), orb4.data_size(%u)\n",
 1142                                 __func__, orbi->page_table, orbi->orb4.data_size);
 1143 
 1144                 xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/FWSPD_S400,
 1145                                         orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*
 1146                                         sizeof(struct unrestricted_page_table_fmt),
 1147                                         (void *)orbi->page_table, sbp_targ_pt_done);
 1148 
 1149                 if (xfer != NULL)
 1150                         return;
 1151         } else {
 1152                 /*
 1153                  * This is a CTIO for a page table we have
 1154                  * already malloc'd, so just directly invoke
 1155                  * the xfer function on the orbi.
 1156                  */
 1157                 sbp_targ_xfer_pt(orbi);
 1158                 return;
 1159         }
 1160 error:
 1161         orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
 1162         if (debug)      
 1163                 printf("%s: free orbi->page_table %p due to xfer == NULL\n", __func__, orbi->page_table);
 1164         if (orbi->page_table != NULL) {
 1165                 free(orbi->page_table, M_SBP_TARG);
 1166                 orbi->page_table = NULL;
 1167         }
 1168         xpt_done(orbi->ccb);
 1169         return;
 1170 }
 1171 
 1172 static void
 1173 sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
 1174 {
 1175         struct sbp_targ_softc *sc;
 1176         struct sbp_targ_lstate *lstate;
 1177         cam_status status;
 1178         u_int ccb_dir;
 1179 
 1180         sc =  (struct sbp_targ_softc *)cam_sim_softc(sim);
 1181 
 1182         status = sbp_targ_find_devs(sc, ccb, &lstate, TRUE);
 1183 
 1184         switch (ccb->ccb_h.func_code) {
 1185         case XPT_CONT_TARGET_IO:
 1186         {
 1187                 struct orb_info *orbi;
 1188 
 1189                 if (debug)
 1190                         printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n",
 1191                                          __func__, ccb->csio.tag_id);
 1192 
 1193                 if (status != CAM_REQ_CMP) {
 1194                         ccb->ccb_h.status = status;
 1195                         xpt_done(ccb);
 1196                         break;
 1197                 }
 1198                 /* XXX transfer from/to initiator */
 1199                 orbi = sbp_targ_get_orb_info(lstate,
 1200                     ccb->csio.tag_id, ccb->csio.init_id);
 1201                 if (orbi == NULL) {
 1202                         ccb->ccb_h.status = CAM_REQ_ABORTED; /* XXX */
 1203                         xpt_done(ccb);
 1204                         break;
 1205                 }
 1206                 if (orbi->state == ORBI_STATUS_ABORTED) {
 1207                         if (debug)
 1208                                 printf("%s: ctio aborted\n", __func__);
 1209                         sbp_targ_remove_orb_info_locked(orbi->login, orbi);
 1210                         if (debug)
 1211                                 printf("%s: free orbi %p\n", __func__, orbi);
 1212                         free(orbi, M_SBP_TARG);
 1213                         ccb->ccb_h.status = CAM_REQ_ABORTED;
 1214                         xpt_done(ccb);
 1215                         break;
 1216                 }
 1217                 orbi->state = ORBI_STATUS_CTIO;
 1218 
 1219                 orbi->ccb = ccb;
 1220                 ccb_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
 1221 
 1222                 /* XXX */
 1223                 if (ccb->csio.dxfer_len == 0)
 1224                         ccb_dir = CAM_DIR_NONE;
 1225 
 1226                 /* Sanity check */
 1227                 if (ccb_dir == CAM_DIR_IN && orbi->orb4.dir == 0)
 1228                         printf("%s: direction mismatch\n", __func__);
 1229 
 1230                 /* check page table */
 1231                 if (ccb_dir != CAM_DIR_NONE && orbi->orb4.page_table_present) {
 1232                         if (debug)
 1233                                 printf("%s: page_table_present\n",
 1234                                     __func__);
 1235                         if (orbi->orb4.page_size != 0) {
 1236                                 printf("%s: unsupported pagesize %d != 0\n",
 1237                                     __func__, orbi->orb4.page_size);
 1238                                 ccb->ccb_h.status = CAM_REQ_INVALID;
 1239                                 xpt_done(ccb);
 1240                                 break;
 1241                         }
 1242                         sbp_targ_fetch_pt(orbi);
 1243                         break;
 1244                 }
 1245 
 1246                 /* Sanity check */
 1247                 if (ccb_dir != CAM_DIR_NONE) {
 1248                         sbp_targ_xfer_buf(orbi, 0, orbi->data_hi,
 1249                             orbi->data_lo,
 1250                             MIN(orbi->orb4.data_size, ccb->csio.dxfer_len),
 1251                             sbp_targ_cam_done);
 1252                         if ( orbi->orb4.data_size > ccb->csio.dxfer_len ) {
 1253                                 orbi->data_lo += ccb->csio.dxfer_len;
 1254                                 orbi->orb4.data_size -= ccb->csio.dxfer_len;
 1255                         }
 1256                 }
 1257 
 1258                 if (ccb_dir == CAM_DIR_NONE) {
 1259                         if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
 1260                                 /* XXX */
 1261                                 SBP_UNLOCK(sc);
 1262                                 sbp_targ_send_status(orbi, ccb);
 1263                                 SBP_LOCK(sc);
 1264                         }
 1265                         ccb->ccb_h.status = CAM_REQ_CMP;
 1266                         xpt_done(ccb);
 1267                 }
 1268                 break;
 1269         }
 1270         case XPT_ACCEPT_TARGET_IO:      /* Add Accept Target IO Resource */
 1271                 if (status != CAM_REQ_CMP) {
 1272                         ccb->ccb_h.status = status;
 1273                         xpt_done(ccb);
 1274                         break;
 1275                 }
 1276                 SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
 1277                     sim_links.sle);
 1278                 ccb->ccb_h.status = CAM_REQ_INPROG;
 1279                 if ((lstate->flags & F_ATIO_STARVED) != 0) {
 1280                         struct sbp_targ_login *login;
 1281 
 1282                         if (debug)
 1283                                 printf("%s: new atio arrived\n", __func__);
 1284                         lstate->flags &= ~F_ATIO_STARVED;
 1285                         STAILQ_FOREACH(login, &lstate->logins, link)
 1286                                 if ((login->flags & F_ATIO_STARVED) != 0) {
 1287                                         login->flags &= ~F_ATIO_STARVED;
 1288                                         sbp_targ_fetch_orb(lstate->sc,
 1289                                             login->fwdev,
 1290                                             login->last_hi, login->last_lo,
 1291                                             login, FETCH_CMD);
 1292                                 }
 1293                 }
 1294                 break;
 1295         case XPT_NOTIFY_ACKNOWLEDGE:    /* recycle notify ack */
 1296         case XPT_IMMEDIATE_NOTIFY:      /* Add Immediate Notify Resource */
 1297                 if (status != CAM_REQ_CMP) {
 1298                         ccb->ccb_h.status = status;
 1299                         xpt_done(ccb);
 1300                         break;
 1301                 }
 1302                 SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
 1303                     sim_links.sle);
 1304                 ccb->ccb_h.status = CAM_REQ_INPROG;
 1305                 sbp_targ_send_lstate_events(sc, lstate);
 1306                 break;
 1307         case XPT_EN_LUN:
 1308                 sbp_targ_en_lun(sc, ccb);
 1309                 xpt_done(ccb);
 1310                 break;
 1311         case XPT_PATH_INQ:
 1312         {
 1313                 struct ccb_pathinq *cpi = &ccb->cpi;
 1314 
 1315                 cpi->version_num = 1; /* XXX??? */
 1316                 cpi->hba_inquiry = PI_TAG_ABLE;
 1317                 cpi->target_sprt = PIT_PROCESSOR
 1318                                  | PIT_DISCONNECT
 1319                                  | PIT_TERM_IO;
 1320                 cpi->transport = XPORT_SPI; /* FIXME add XPORT_FW type to cam */
 1321                 cpi->hba_misc = PIM_NOINITIATOR | PIM_NOBUSRESET |
 1322                     PIM_NO_6_BYTE;
 1323                 cpi->hba_eng_cnt = 0;
 1324                 cpi->max_target = 7; /* XXX */
 1325                 cpi->max_lun = MAX_LUN - 1;
 1326                 cpi->initiator_id = 7; /* XXX */
 1327                 cpi->bus_id = sim->bus_id;
 1328                 cpi->base_transfer_speed = 400 * 1000 / 8;
 1329                 strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
 1330                 strlcpy(cpi->hba_vid, "SBP_TARG", HBA_IDLEN);
 1331                 strlcpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
 1332                 cpi->unit_number = sim->unit_number;
 1333 
 1334                 cpi->ccb_h.status = CAM_REQ_CMP;
 1335                 xpt_done(ccb);
 1336                 break;
 1337         }
 1338         case XPT_ABORT:
 1339         {
 1340                 union ccb *accb = ccb->cab.abort_ccb;
 1341 
 1342                 switch (accb->ccb_h.func_code) {
 1343                 case XPT_ACCEPT_TARGET_IO:
 1344                 case XPT_IMMEDIATE_NOTIFY:
 1345                         ccb->ccb_h.status = sbp_targ_abort_ccb(sc, ccb);
 1346                         break;
 1347                 case XPT_CONT_TARGET_IO:
 1348                         /* XXX */
 1349                         ccb->ccb_h.status = CAM_UA_ABORT;
 1350                         break;
 1351                 default:
 1352                         printf("%s: aborting unknown function %d\n",
 1353                                 __func__, accb->ccb_h.func_code);
 1354                         ccb->ccb_h.status = CAM_REQ_INVALID;
 1355                         break;
 1356                 }
 1357                 xpt_done(ccb);
 1358                 break;
 1359         }
 1360 #ifdef CAM_NEW_TRAN_CODE
 1361         case XPT_SET_TRAN_SETTINGS:
 1362                 ccb->ccb_h.status = CAM_REQ_INVALID;
 1363                 xpt_done(ccb);
 1364                 break;
 1365         case XPT_GET_TRAN_SETTINGS:
 1366         {
 1367                 struct ccb_trans_settings *cts = &ccb->cts;
 1368                 struct ccb_trans_settings_scsi *scsi =
 1369                         &cts->proto_specific.scsi;
 1370                 struct ccb_trans_settings_spi *spi =
 1371                         &cts->xport_specific.spi;
 1372 
 1373                 cts->protocol = PROTO_SCSI;
 1374                 cts->protocol_version = SCSI_REV_2;
 1375                 cts->transport = XPORT_FW;     /* should have a FireWire */
 1376                 cts->transport_version = 2;
 1377                 spi->valid = CTS_SPI_VALID_DISC;
 1378                 spi->flags = CTS_SPI_FLAGS_DISC_ENB;
 1379                 scsi->valid = CTS_SCSI_VALID_TQ;
 1380                 scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
 1381 #if 0
 1382                 printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:\n",
 1383                         device_get_nameunit(sc->fd.dev),
 1384                         ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
 1385 #endif
 1386                 cts->ccb_h.status = CAM_REQ_CMP;
 1387                 xpt_done(ccb);
 1388                 break;
 1389         }
 1390 #endif
 1391 
 1392         default:
 1393                 printf("%s: unknown function 0x%x\n",
 1394                     __func__, ccb->ccb_h.func_code);
 1395                 ccb->ccb_h.status = CAM_PROVIDE_FAIL;
 1396                 xpt_done(ccb);
 1397                 break;
 1398         }
 1399         return;
 1400 }
 1401 
 1402 static void
 1403 sbp_targ_action(struct cam_sim *sim, union ccb *ccb)
 1404 {
 1405         int s;
 1406 
 1407         s = splfw();
 1408         sbp_targ_action1(sim, ccb);
 1409         splx(s);
 1410 }
 1411 
 1412 static void
 1413 sbp_targ_poll(struct cam_sim *sim)
 1414 {
 1415         /* XXX */
 1416         return;
 1417 }
 1418 
 1419 static void
 1420 sbp_targ_cmd_handler(struct fw_xfer *xfer)
 1421 {
 1422         uint32_t *orb;
 1423         struct corb4 *orb4;
 1424         struct orb_info *orbi;
 1425         struct ccb_accept_tio *atio;
 1426         u_char *bytes;
 1427         int i;
 1428 
 1429         orbi = (struct orb_info *)xfer->sc;
 1430         if (xfer->resp != 0) {
 1431                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
 1432                 orbi->status.resp = SBP_TRANS_FAIL;
 1433                 orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
 1434                 orbi->status.dead = 1;
 1435                 orbi->status.len = 1;
 1436                 sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
 1437 
 1438                 sbp_targ_status_FIFO(orbi,
 1439                     orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
 1440                 fw_xfer_free(xfer);
 1441                 return;
 1442         }
 1443 
 1444         atio = orbi->atio;
 1445 
 1446         if (orbi->state == ORBI_STATUS_ABORTED) {
 1447                 printf("%s: aborted\n", __func__);
 1448                 sbp_targ_remove_orb_info(orbi->login, orbi);
 1449                 free(orbi, M_SBP_TARG);
 1450                 atio->ccb_h.status = CAM_REQ_ABORTED;
 1451                 xpt_done((union ccb*)atio);
 1452                 goto done0;
 1453         }
 1454         orbi->state = ORBI_STATUS_ATIO;
 1455 
 1456         orb = orbi->orb;
 1457         /* swap payload except SCSI command */
 1458         for (i = 0; i < 5; i++)
 1459                 orb[i] = ntohl(orb[i]);
 1460 
 1461         orb4 = (struct corb4 *)&orb[4];
 1462         if (orb4->rq_fmt != 0) {
 1463                 /* XXX */
 1464                 printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt);
 1465         }
 1466 
 1467         atio->ccb_h.target_id = 0; /* XXX */
 1468         atio->ccb_h.target_lun = orbi->login->lstate->lun;
 1469         atio->sense_len = 0;
 1470         atio->tag_action = MSG_SIMPLE_TASK;
 1471         atio->tag_id = orbi->orb_lo;
 1472         atio->init_id = orbi->login->id;
 1473 
 1474         atio->ccb_h.flags |= CAM_TAG_ACTION_VALID;
 1475         bytes = (u_char *)&orb[5];
 1476         if (debug)
 1477                 printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
 1478                     __func__, (void *)atio,
 1479                     bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
 1480                     bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
 1481         switch (bytes[0] >> 5) {
 1482         case 0:
 1483                 atio->cdb_len = 6;
 1484                 break;
 1485         case 1:
 1486         case 2:
 1487                 atio->cdb_len = 10;
 1488                 break;
 1489         case 4:
 1490                 atio->cdb_len = 16;
 1491                 break;
 1492         case 5:
 1493                 atio->cdb_len = 12;
 1494                 break;
 1495         case 3:
 1496         default:
 1497                 /* Only copy the opcode. */
 1498                 atio->cdb_len = 1;
 1499                 printf("Reserved or VU command code type encountered\n");
 1500                 break;
 1501         }
 1502 
 1503         memcpy(atio->cdb_io.cdb_bytes, bytes, atio->cdb_len);
 1504 
 1505         atio->ccb_h.status |= CAM_CDB_RECVD;
 1506 
 1507         /* next ORB */
 1508         if ((orb[0] & (1<<31)) == 0) {
 1509                 if (debug)
 1510                         printf("%s: fetch next orb\n", __func__);
 1511                 orbi->status.src = SRC_NEXT_EXISTS;
 1512                 sbp_targ_fetch_orb(orbi->sc, orbi->fwdev,
 1513                     orb[0], orb[1], orbi->login, FETCH_CMD);
 1514         } else {
 1515                 orbi->status.src = SRC_NO_NEXT;
 1516                 orbi->login->flags &= ~F_LINK_ACTIVE;
 1517         }
 1518 
 1519         orbi->data_hi = orb[2];
 1520         orbi->data_lo = orb[3];
 1521         orbi->orb4 = *orb4;
 1522 
 1523         xpt_done((union ccb*)atio);
 1524 done0:
 1525         fw_xfer_free(xfer);
 1526         return;
 1527 }
 1528 
 1529 static struct sbp_targ_login *
 1530 sbp_targ_get_login(struct sbp_targ_softc *sc, struct fw_device *fwdev, int lun)
 1531 {
 1532         struct sbp_targ_lstate *lstate;
 1533         struct sbp_targ_login *login;
 1534         int i;
 1535 
 1536         lstate = sc->lstate[lun];
 1537 
 1538         STAILQ_FOREACH(login, &lstate->logins, link)
 1539                 if (login->fwdev == fwdev)
 1540                         return (login);
 1541 
 1542         for (i = 0; i < MAX_LOGINS; i++)
 1543                 if (sc->logins[i] == NULL)
 1544                         goto found;
 1545 
 1546         printf("%s: increase MAX_LOGIN\n", __func__);
 1547         return (NULL);
 1548 
 1549 found:
 1550         login = (struct sbp_targ_login *)malloc(
 1551             sizeof(struct sbp_targ_login), M_SBP_TARG, M_NOWAIT | M_ZERO);
 1552 
 1553         if (login == NULL) {
 1554                 printf("%s: malloc failed\n", __func__);
 1555                 return (NULL);
 1556         }
 1557 
 1558         login->id = i;
 1559         login->fwdev = fwdev;
 1560         login->lstate = lstate;
 1561         login->last_hi = 0xffff;
 1562         login->last_lo = 0xffffffff;
 1563         login->hold_sec = 1;
 1564         STAILQ_INIT(&login->orbs);
 1565         CALLOUT_INIT(&login->hold_callout);
 1566         sc->logins[i] = login;
 1567         return (login);
 1568 }
 1569 
 1570 static void
 1571 sbp_targ_mgm_handler(struct fw_xfer *xfer)
 1572 {
 1573         struct sbp_targ_lstate *lstate;
 1574         struct sbp_targ_login *login;
 1575         uint32_t *orb;
 1576         struct morb4 *orb4;
 1577         struct orb_info *orbi;
 1578         int i;
 1579 
 1580         orbi = (struct orb_info *)xfer->sc;
 1581         if (xfer->resp != 0) {
 1582                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
 1583                 orbi->status.resp = SBP_TRANS_FAIL;
 1584                 orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
 1585                 orbi->status.dead = 1;
 1586                 orbi->status.len = 1;
 1587                 sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
 1588 
 1589                 sbp_targ_status_FIFO(orbi,
 1590                     orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0);
 1591                 fw_xfer_free(xfer);
 1592                 return;
 1593         }
 1594 
 1595         orb = orbi->orb;
 1596         /* swap payload */
 1597         for (i = 0; i < 8; i++) {
 1598                 orb[i] = ntohl(orb[i]);
 1599         }
 1600         orb4 = (struct morb4 *)&orb[4];
 1601         if (debug)
 1602                 printf("%s: %s\n", __func__, orb_fun_name[orb4->fun]);
 1603 
 1604         orbi->status.src = SRC_NO_NEXT;
 1605 
 1606         switch (orb4->fun << 16) {
 1607         case ORB_FUN_LGI:
 1608         {
 1609                 int exclusive = 0, lun;
 1610 
 1611                 if (orb[4] & ORB_EXV)
 1612                         exclusive = 1;
 1613 
 1614                 lun = orb4->id;
 1615                 lstate = orbi->sc->lstate[lun];
 1616 
 1617                 if (lun >= MAX_LUN || lstate == NULL ||
 1618                     (exclusive &&
 1619                     STAILQ_FIRST(&lstate->logins) != NULL &&
 1620                     STAILQ_FIRST(&lstate->logins)->fwdev != orbi->fwdev)
 1621                    ) {
 1622                         /* error */
 1623                         orbi->status.dead = 1;
 1624                         orbi->status.status = STATUS_ACCESS_DENY;
 1625                         orbi->status.len = 1;
 1626                         break;
 1627                 }
 1628 
 1629                 /* allocate login */
 1630                 login = sbp_targ_get_login(orbi->sc, orbi->fwdev, lun);
 1631                 if (login == NULL) {
 1632                         printf("%s: sbp_targ_get_login failed\n",
 1633                             __func__);
 1634                         orbi->status.dead = 1;
 1635                         orbi->status.status = STATUS_RES_UNAVAIL;
 1636                         orbi->status.len = 1;
 1637                         break;
 1638                 }
 1639                 printf("%s: login id=%d\n", __func__, login->id);
 1640 
 1641                 login->fifo_hi = orb[6];
 1642                 login->fifo_lo = orb[7];
 1643                 login->loginres.len = htons(sizeof(uint32_t) * 4);
 1644                 login->loginres.id = htons(login->id);
 1645                 login->loginres.cmd_hi = htons(SBP_TARG_BIND_HI);
 1646                 login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id));
 1647                 login->loginres.recon_hold = htons(login->hold_sec);
 1648 
 1649                 STAILQ_INSERT_TAIL(&lstate->logins, login, link);
 1650                 fwmem_write_block(orbi->fwdev, NULL, /*spd*/FWSPD_S400, orb[2], orb[3],
 1651                     sizeof(struct sbp_login_res), (void *)&login->loginres,
 1652                     fw_asy_callback_free);
 1653                 /* XXX return status after loginres is successfully written */
 1654                 break;
 1655         }
 1656         case ORB_FUN_RCN:
 1657                 login = orbi->sc->logins[orb4->id];
 1658                 if (login != NULL && login->fwdev == orbi->fwdev) {
 1659                         login->flags &= ~F_HOLD;
 1660                         callout_stop(&login->hold_callout);
 1661                         printf("%s: reconnected id=%d\n",
 1662                             __func__, login->id);
 1663                 } else {
 1664                         orbi->status.dead = 1;
 1665                         orbi->status.status = STATUS_ACCESS_DENY;
 1666                         printf("%s: reconnection failed id=%d\n",
 1667                             __func__, orb4->id);
 1668                 }
 1669                 break;
 1670         case ORB_FUN_LGO:
 1671                 login = orbi->sc->logins[orb4->id];
 1672                 if (login->fwdev != orbi->fwdev) {
 1673                         printf("%s: wrong initiator\n", __func__);
 1674                         break;
 1675                 }
 1676                 sbp_targ_dealloc_login(login);
 1677                 break;
 1678         default:
 1679                 printf("%s: %s not implemented yet\n",
 1680                     __func__, orb_fun_name[orb4->fun]);
 1681                 break;
 1682         }
 1683         orbi->status.len = 1;
 1684         sbp_targ_status_FIFO(orbi, orb[6], orb[7], /*dequeue*/0);
 1685         fw_xfer_free(xfer);
 1686         return;
 1687 }
 1688 
 1689 static void
 1690 sbp_targ_pointer_handler(struct fw_xfer *xfer)
 1691 {
 1692         struct orb_info *orbi;
 1693         uint32_t orb0, orb1;
 1694 
 1695         orbi = (struct orb_info *)xfer->sc;
 1696         if (xfer->resp != 0) {
 1697                 printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
 1698                 goto done;
 1699         }
 1700 
 1701         orb0 = ntohl(orbi->orb[0]);
 1702         orb1 = ntohl(orbi->orb[1]);
 1703         if ((orb0 & (1U << 31)) != 0) {
 1704                 printf("%s: invalid pointer\n", __func__);
 1705                 goto done;
 1706         }
 1707         sbp_targ_fetch_orb(orbi->login->lstate->sc, orbi->fwdev,
 1708             (uint16_t)orb0, orb1, orbi->login, FETCH_CMD);
 1709 done:
 1710         free(orbi, M_SBP_TARG);
 1711         fw_xfer_free(xfer);
 1712         return;
 1713 }
 1714 
 1715 static void
 1716 sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev,
 1717     uint16_t orb_hi, uint32_t orb_lo, struct sbp_targ_login *login,
 1718     int mode)
 1719 {
 1720         struct orb_info *orbi;
 1721 
 1722         if (debug)
 1723                 printf("%s: fetch orb %04x:%08x\n", __func__, orb_hi, orb_lo);
 1724         orbi = malloc(sizeof(struct orb_info), M_SBP_TARG, M_NOWAIT | M_ZERO);
 1725         if (orbi == NULL) {
 1726                 printf("%s: malloc failed\n", __func__);
 1727                 return;
 1728         }
 1729         orbi->sc = sc;
 1730         orbi->fwdev = fwdev;
 1731         orbi->login = login;
 1732         orbi->orb_hi = orb_hi;
 1733         orbi->orb_lo = orb_lo;
 1734         orbi->status.orb_hi = htons(orb_hi);
 1735         orbi->status.orb_lo = htonl(orb_lo);
 1736         orbi->page_table = NULL;
 1737 
 1738         switch (mode) {
 1739         case FETCH_MGM:
 1740                 fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
 1741                     sizeof(uint32_t) * 8, &orbi->orb[0],
 1742                     sbp_targ_mgm_handler);
 1743                 break;
 1744         case FETCH_CMD:
 1745                 orbi->state = ORBI_STATUS_FETCH;
 1746                 login->last_hi = orb_hi;
 1747                 login->last_lo = orb_lo;
 1748                 login->flags |= F_LINK_ACTIVE;
 1749                 /* dequeue */
 1750                 SBP_LOCK(sc);
 1751                 orbi->atio = (struct ccb_accept_tio *)
 1752                     SLIST_FIRST(&login->lstate->accept_tios);
 1753                 if (orbi->atio == NULL) {
 1754                         SBP_UNLOCK(sc);
 1755                         printf("%s: no free atio\n", __func__);
 1756                         login->lstate->flags |= F_ATIO_STARVED;
 1757                         login->flags |= F_ATIO_STARVED;
 1758 #if 0
 1759                         /* XXX ?? */
 1760                         login->fwdev = fwdev;
 1761 #endif
 1762                         break;
 1763                 }
 1764                 SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle);
 1765                 STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
 1766                 SBP_UNLOCK(sc);
 1767                 fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
 1768                     sizeof(uint32_t) * 8, &orbi->orb[0],
 1769                     sbp_targ_cmd_handler);
 1770                 break;
 1771         case FETCH_POINTER:
 1772                 orbi->state = ORBI_STATUS_POINTER;
 1773                 login->flags |= F_LINK_ACTIVE;
 1774                 fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
 1775                     sizeof(uint32_t) * 2, &orbi->orb[0],
 1776                     sbp_targ_pointer_handler);
 1777                 break;
 1778         default:
 1779                 printf("%s: invalid mode %d\n", __func__, mode);
 1780         }
 1781 }
 1782 
 1783 static void
 1784 sbp_targ_resp_callback(struct fw_xfer *xfer)
 1785 {
 1786         struct sbp_targ_softc *sc;
 1787         int s;
 1788 
 1789         if (debug)
 1790                 printf("%s: xfer=%p\n", __func__, xfer);
 1791         sc = (struct sbp_targ_softc *)xfer->sc;
 1792         fw_xfer_unload(xfer);
 1793         xfer->recv.pay_len = SBP_TARG_RECV_LEN;
 1794         xfer->hand = sbp_targ_recv;
 1795         s = splfw();
 1796         STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
 1797         splx(s);
 1798 }
 1799 
 1800 static int
 1801 sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id,
 1802     int reg)
 1803 {
 1804         struct sbp_targ_login *login;
 1805         struct sbp_targ_softc *sc;
 1806         int rtcode = 0;
 1807 
 1808         if (login_id < 0 || login_id >= MAX_LOGINS)
 1809                 return (RESP_ADDRESS_ERROR);
 1810 
 1811         sc = (struct sbp_targ_softc *)xfer->sc;
 1812         login = sc->logins[login_id];
 1813         if (login == NULL)
 1814                 return (RESP_ADDRESS_ERROR);
 1815 
 1816         if (login->fwdev != fwdev) {
 1817                 /* XXX */
 1818                 return (RESP_ADDRESS_ERROR);
 1819         }
 1820 
 1821         switch (reg) {
 1822         case 0x08:      /* ORB_POINTER */
 1823                 if (debug)
 1824                         printf("%s: ORB_POINTER(%d)\n", __func__, login_id);
 1825                 if ((login->flags & F_LINK_ACTIVE) != 0) {
 1826                         if (debug)
 1827                                 printf("link active (ORB_POINTER)\n");
 1828                         break;
 1829                 }
 1830                 sbp_targ_fetch_orb(sc, fwdev,
 1831                     ntohl(xfer->recv.payload[0]),
 1832                     ntohl(xfer->recv.payload[1]),
 1833                     login, FETCH_CMD);
 1834                 break;
 1835         case 0x04:      /* AGENT_RESET */
 1836                 if (debug)
 1837                         printf("%s: AGENT RESET(%d)\n", __func__, login_id);
 1838                 login->last_hi = 0xffff;
 1839                 login->last_lo = 0xffffffff;
 1840                 sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
 1841                 break;
 1842         case 0x10:      /* DOORBELL */
 1843                 if (debug)
 1844                         printf("%s: DOORBELL(%d)\n", __func__, login_id);
 1845                 if (login->last_hi == 0xffff &&
 1846                     login->last_lo == 0xffffffff) {
 1847                         printf("%s: no previous pointer(DOORBELL)\n",
 1848                             __func__);
 1849                         break;
 1850                 }
 1851                 if ((login->flags & F_LINK_ACTIVE) != 0) {
 1852                         if (debug)
 1853                                 printf("link active (DOORBELL)\n");
 1854                         break;
 1855                 }
 1856                 sbp_targ_fetch_orb(sc, fwdev,
 1857                     login->last_hi, login->last_lo,
 1858                     login, FETCH_POINTER);
 1859                 break;
 1860         case 0x00:      /* AGENT_STATE */
 1861                 printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id);
 1862                 break;
 1863         case 0x14:      /* UNSOLICITED_STATE_ENABLE */
 1864                 printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n",
 1865                                                          __func__, login_id);
 1866                 break;
 1867         default:
 1868                 printf("%s: invalid register %d(%d)\n",
 1869                                                  __func__, reg, login_id);
 1870                 rtcode = RESP_ADDRESS_ERROR;
 1871         }
 1872 
 1873         return (rtcode);
 1874 }
 1875 
 1876 static int
 1877 sbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev)
 1878 {
 1879         struct sbp_targ_softc *sc;
 1880         struct fw_pkt *fp;
 1881 
 1882         sc = (struct sbp_targ_softc *)xfer->sc;
 1883 
 1884         fp = &xfer->recv.hdr;
 1885         if (fp->mode.wreqb.tcode != FWTCODE_WREQB) {
 1886                 printf("%s: tcode = %d\n", __func__, fp->mode.wreqb.tcode);
 1887                 return (RESP_TYPE_ERROR);
 1888         }
 1889 
 1890         sbp_targ_fetch_orb(sc, fwdev,
 1891             ntohl(xfer->recv.payload[0]),
 1892             ntohl(xfer->recv.payload[1]),
 1893             NULL, FETCH_MGM);
 1894 
 1895         return (0);
 1896 }
 1897 
 1898 static void
 1899 sbp_targ_recv(struct fw_xfer *xfer)
 1900 {
 1901         struct fw_pkt *fp, *sfp;
 1902         struct fw_device *fwdev;
 1903         uint32_t lo;
 1904         int s, rtcode;
 1905         struct sbp_targ_softc *sc;
 1906 
 1907         s = splfw();
 1908         sc = (struct sbp_targ_softc *)xfer->sc;
 1909         fp = &xfer->recv.hdr;
 1910         fwdev = fw_noderesolve_nodeid(sc->fd.fc, fp->mode.wreqb.src & 0x3f);
 1911         if (fwdev == NULL) {
 1912                 printf("%s: cannot resolve nodeid=%d\n",
 1913                     __func__, fp->mode.wreqb.src & 0x3f);
 1914                 rtcode = RESP_TYPE_ERROR; /* XXX */
 1915                 goto done;
 1916         }
 1917         lo = fp->mode.wreqb.dest_lo;
 1918 
 1919         if (lo == SBP_TARG_BIND_LO(-1))
 1920                 rtcode = sbp_targ_mgm(xfer, fwdev);
 1921         else if (lo >= SBP_TARG_BIND_LO(0))
 1922                 rtcode = sbp_targ_cmd(xfer, fwdev, SBP_TARG_LOGIN_ID(lo),
 1923                     lo % 0x20);
 1924         else
 1925                 rtcode = RESP_ADDRESS_ERROR;
 1926 
 1927 done:
 1928         if (rtcode != 0)
 1929                 printf("%s: rtcode = %d\n", __func__, rtcode);
 1930         sfp = &xfer->send.hdr;
 1931         xfer->send.spd = FWSPD_S400;
 1932         xfer->hand = sbp_targ_resp_callback;
 1933         sfp->mode.wres.dst = fp->mode.wreqb.src;
 1934         sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;
 1935         sfp->mode.wres.tcode = FWTCODE_WRES;
 1936         sfp->mode.wres.rtcode = rtcode;
 1937         sfp->mode.wres.pri = 0;
 1938 
 1939         fw_asyreq(xfer->fc, -1, xfer);
 1940         splx(s);
 1941 }
 1942 
 1943 static int
 1944 sbp_targ_attach(device_t dev)
 1945 {
 1946         struct sbp_targ_softc *sc;
 1947         struct cam_devq *devq;
 1948         struct firewire_comm *fc;
 1949 
 1950         sc = (struct sbp_targ_softc *) device_get_softc(dev);
 1951         bzero((void *)sc, sizeof(struct sbp_targ_softc));
 1952 
 1953         mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF);
 1954         sc->fd.fc = fc = device_get_ivars(dev);
 1955         sc->fd.dev = dev;
 1956         sc->fd.post_explore = (void *) sbp_targ_post_explore;
 1957         sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
 1958 
 1959         devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS);
 1960         if (devq == NULL)
 1961                 return (ENXIO);
 1962 
 1963         sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
 1964             "sbp_targ", sc, device_get_unit(dev), &sc->mtx,
 1965             /*untagged*/ 1, /*tagged*/ 1, devq);
 1966         if (sc->sim == NULL) {
 1967                 cam_simq_free(devq);
 1968                 return (ENXIO);
 1969         }
 1970 
 1971         SBP_LOCK(sc);
 1972         if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS)
 1973                 goto fail;
 1974 
 1975         if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim),
 1976             CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
 1977                 xpt_bus_deregister(cam_sim_path(sc->sim));
 1978                 goto fail;
 1979         }
 1980         SBP_UNLOCK(sc);
 1981 
 1982         sc->fwb.start = SBP_TARG_BIND_START;
 1983         sc->fwb.end = SBP_TARG_BIND_END;
 1984 
 1985         /* pre-allocate xfer */
 1986         STAILQ_INIT(&sc->fwb.xferlist);
 1987         fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG,
 1988             /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */,
 1989             fc, (void *)sc, sbp_targ_recv);
 1990         fw_bindadd(fc, &sc->fwb);
 1991         return 0;
 1992 
 1993 fail:
 1994         SBP_UNLOCK(sc);
 1995         cam_sim_free(sc->sim, /*free_devq*/TRUE);
 1996         return (ENXIO);
 1997 }
 1998 
 1999 static int
 2000 sbp_targ_detach(device_t dev)
 2001 {
 2002         struct sbp_targ_softc *sc;
 2003         struct sbp_targ_lstate *lstate;
 2004         int i;
 2005 
 2006         sc = (struct sbp_targ_softc *)device_get_softc(dev);
 2007         sc->fd.post_busreset = NULL;
 2008 
 2009         SBP_LOCK(sc);
 2010         xpt_free_path(sc->path);
 2011         xpt_bus_deregister(cam_sim_path(sc->sim));
 2012         cam_sim_free(sc->sim, /*free_devq*/TRUE);
 2013         SBP_UNLOCK(sc);
 2014 
 2015         for (i = 0; i < MAX_LUN; i++) {
 2016                 lstate = sc->lstate[i];
 2017                 if (lstate != NULL) {
 2018                         xpt_free_path(lstate->path);
 2019                         free(lstate, M_SBP_TARG);
 2020                 }
 2021         }
 2022         if (sc->black_hole != NULL) {
 2023                 xpt_free_path(sc->black_hole->path);
 2024                 free(sc->black_hole, M_SBP_TARG);
 2025         }
 2026 
 2027         fw_bindremove(sc->fd.fc, &sc->fwb);
 2028         fw_xferlist_remove(&sc->fwb.xferlist);
 2029 
 2030         mtx_destroy(&sc->mtx);
 2031 
 2032         return 0;
 2033 }
 2034 
 2035 static device_method_t sbp_targ_methods[] = {
 2036         /* device interface */
 2037         DEVMETHOD(device_identify,      sbp_targ_identify),
 2038         DEVMETHOD(device_probe,         sbp_targ_probe),
 2039         DEVMETHOD(device_attach,        sbp_targ_attach),
 2040         DEVMETHOD(device_detach,        sbp_targ_detach),
 2041         { 0, 0 }
 2042 };
 2043 
 2044 static driver_t sbp_targ_driver = {
 2045         "sbp_targ",
 2046         sbp_targ_methods,
 2047         sizeof(struct sbp_targ_softc),
 2048 };
 2049 
 2050 DRIVER_MODULE(sbp_targ, firewire, sbp_targ_driver, 0, 0);
 2051 MODULE_VERSION(sbp_targ, 1);
 2052 MODULE_DEPEND(sbp_targ, firewire, 1, 1, 1);
 2053 MODULE_DEPEND(sbp_targ, cam, 1, 1, 1);

Cache object: 0a7329a870356586dd5b6a53f7aa9bad


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.