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  * 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: releng/8.4/sys/dev/firewire/sbp_targ.c 170872 2007-06-17 05:55:54Z scottl $
   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);

Cache object: 38928a47da02328e432392cb8fef790a


[ 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.