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

Cache object: 2576a30e0a0050fa3938b0e6976d4e48


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