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/pst/pst-iop.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) 2001,2002,2003 Søren Schmidt <sos@FreeBSD.org>
    3  * 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  *    without modification, immediately at the beginning of the file.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/8.1/sys/dev/pst/pst-iop.c 196405 2009-08-20 20:23:28Z jhb $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/module.h>
   36 #include <sys/bus.h>
   37 #include <sys/bio.h>
   38 #include <sys/malloc.h>
   39 #include <sys/lock.h>
   40 #include <sys/mutex.h>
   41 #include <vm/vm.h>
   42 #include <vm/pmap.h>
   43 #include <machine/stdarg.h>
   44 #include <machine/resource.h>
   45 #include <machine/bus.h>
   46 #include <sys/rman.h>
   47 #include <dev/pci/pcivar.h>
   48 #include <dev/pci/pcireg.h>
   49 
   50 #include "dev/pst/pst-iop.h"
   51 
   52 struct iop_request {
   53     struct i2o_single_reply *reply;
   54     u_int32_t mfa;
   55 };
   56 
   57 /* local vars */
   58 MALLOC_DEFINE(M_PSTIOP, "PSTIOP", "Promise SuperTrak IOP driver");
   59 
   60 int
   61 iop_init(struct iop_softc *sc)
   62 {
   63     int mfa, timeout = 10000;
   64 
   65     while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
   66         DELAY(1000);
   67     if (!timeout) {
   68         printf("pstiop: no free mfa\n");
   69         return 0;
   70     }
   71     iop_free_mfa(sc, mfa);
   72 
   73     sc->reg->oqueue_intr_mask = 0xffffffff;
   74 
   75     if (!iop_reset(sc)) {
   76         printf("pstiop: no reset response\n");
   77         return 0;
   78     }
   79 
   80     if (!iop_init_outqueue(sc)) {
   81         printf("pstiop: init outbound queue failed\n");
   82         return 0;
   83     }
   84 
   85     /* register iop_attach to be run when interrupts are enabled */
   86     if (!(sc->iop_delayed_attach = (struct intr_config_hook *)
   87                                    malloc(sizeof(struct intr_config_hook),
   88                                    M_PSTIOP, M_NOWAIT | M_ZERO))) {
   89         printf("pstiop: malloc of delayed attach hook failed\n");
   90         return 0;
   91     }
   92     sc->iop_delayed_attach->ich_func = iop_attach;
   93     sc->iop_delayed_attach->ich_arg = sc;
   94     if (config_intrhook_establish(sc->iop_delayed_attach)) {
   95         printf("pstiop: config_intrhook_establish failed\n");
   96         free(sc->iop_delayed_attach, M_PSTIOP);
   97     }
   98     return 1;
   99 }
  100 
  101 void
  102 iop_attach(void *arg)
  103 {
  104     struct iop_softc *sc;
  105     int i;
  106 
  107     sc = arg;
  108     if (sc->iop_delayed_attach) {
  109         config_intrhook_disestablish(sc->iop_delayed_attach);
  110         free(sc->iop_delayed_attach, M_PSTIOP);
  111         sc->iop_delayed_attach = NULL;
  112     }
  113 
  114     if (!iop_get_lct(sc)) {
  115         printf("pstiop: get LCT failed\n");
  116         return;
  117     }
  118 
  119     /* figure out what devices are here and config as needed */
  120     for (i = 0; sc->lct[i].entry_size == I2O_LCT_ENTRYSIZE; i++) {
  121 #ifdef PSTDEBUG
  122         struct i2o_get_param_reply *reply;
  123 
  124         printf("pstiop: LCT entry %d ", i);
  125         printf("class=%04x ", sc->lct[i].class);
  126         printf("sub=%04x ", sc->lct[i].sub_class);
  127         printf("localtid=%04x ", sc->lct[i].local_tid);
  128         printf("usertid=%04x ", sc->lct[i].user_tid);
  129         printf("parentid=%04x\n", sc->lct[i].parent_tid);
  130 
  131         if ((reply = iop_get_util_params(sc, sc->lct[i].local_tid,
  132                                          I2O_PARAMS_OPERATION_FIELD_GET,
  133                                          I2O_UTIL_DEVICE_IDENTITY_GROUP_NO))) {
  134             struct i2o_device_identity *ident =
  135                 (struct i2o_device_identity *)reply->result;
  136             printf("pstiop: vendor=<%.16s> product=<%.16s>\n",
  137                    ident->vendor, ident->product);
  138             printf("pstiop: description=<%.16s> revision=<%.8s>\n",
  139                    ident->description, ident->revision);
  140             contigfree(reply, PAGE_SIZE, M_PSTIOP);
  141         }
  142 #endif
  143 
  144         if (sc->lct[i].user_tid != I2O_TID_NONE &&
  145             sc->lct[i].user_tid != I2O_TID_HOST)
  146             continue;
  147 
  148         switch (sc->lct[i].class) {
  149         case I2O_CLASS_DDM:
  150             if (sc->lct[i].sub_class == I2O_SUBCLASS_ISM)
  151                 sc->ism = sc->lct[i].local_tid;
  152             break;
  153 
  154         case I2O_CLASS_RANDOM_BLOCK_STORAGE:
  155             pst_add_raid(sc, &sc->lct[i]);
  156             break;
  157         }
  158     }
  159 
  160     /* setup and enable interrupts */
  161     bus_setup_intr(sc->dev, sc->r_irq, INTR_TYPE_BIO|INTR_ENTROPY|INTR_MPSAFE,
  162                    NULL, iop_intr, sc, &sc->handle);
  163     sc->reg->oqueue_intr_mask = 0x0;
  164 }
  165 
  166 void
  167 iop_intr(void *data)
  168 {
  169     struct iop_softc *sc = (struct iop_softc *)data;
  170     struct i2o_single_reply *reply;
  171     u_int32_t mfa;
  172 
  173     /* we might get more than one finished request pr interrupt */
  174     mtx_lock(&sc->mtx);
  175     while (1) {
  176         if ((mfa = sc->reg->oqueue) == 0xffffffff)
  177             if ((mfa = sc->reg->oqueue) == 0xffffffff)
  178                 break;
  179 
  180         reply = (struct i2o_single_reply *)(sc->obase + (mfa - sc->phys_obase));
  181 
  182         /* if this is an event register reply, shout! */
  183         if (reply->function == I2O_UTIL_EVENT_REGISTER) {
  184             struct i2o_util_event_reply_message *event =
  185                 (struct i2o_util_event_reply_message *)reply;
  186 
  187             printf("pstiop: EVENT!! idx=%08x data=%08x\n",
  188                    event->event_mask, event->event_data[0]);
  189             break;
  190         }
  191 
  192         /* if reply is a failurenotice we need to free the original mfa */
  193         if (reply->message_flags & I2O_MESSAGE_FLAGS_FAIL)
  194             iop_free_mfa(sc,((struct i2o_fault_reply *)(reply))->preserved_mfa);
  195 
  196         /* reply->initiator_context points to the service routine */
  197         ((void (*)(struct iop_softc *, u_int32_t, struct i2o_single_reply *))
  198             (reply->initiator_context))(sc, mfa, reply);
  199     }
  200     mtx_unlock(&sc->mtx);
  201 }
  202 
  203 int
  204 iop_reset(struct iop_softc *sc)
  205 {
  206     struct i2o_exec_iop_reset_message *msg;
  207     int mfa, timeout = 5000;
  208     volatile u_int32_t reply = 0;
  209 
  210     mfa = iop_get_mfa(sc);
  211     msg = (struct i2o_exec_iop_reset_message *)(sc->ibase + mfa);
  212     bzero(msg, sizeof(struct i2o_exec_iop_reset_message));
  213     msg->version_offset = 0x1;
  214     msg->message_flags = 0x0;
  215     msg->message_size = sizeof(struct i2o_exec_iop_reset_message) >> 2;
  216     msg->target_address = I2O_TID_IOP;
  217     msg->initiator_address = I2O_TID_HOST;
  218     msg->function = I2O_EXEC_IOP_RESET;
  219     msg->status_word_low_addr = vtophys(&reply);
  220     msg->status_word_high_addr = 0;
  221 
  222     sc->reg->iqueue = mfa;
  223 
  224     while (--timeout && !reply)
  225         DELAY(1000);
  226 
  227     /* wait for iqueue ready */
  228     timeout = 10000;
  229     while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
  230         DELAY(1000);
  231 
  232     iop_free_mfa(sc, mfa);
  233     return reply;
  234 }
  235 
  236 int
  237 iop_init_outqueue(struct iop_softc *sc)
  238 {
  239     struct i2o_exec_init_outqueue_message *msg;
  240     int i, mfa, timeout = 5000;
  241     volatile u_int32_t reply = 0;
  242 
  243     if (!(sc->obase = contigmalloc(I2O_IOP_OUTBOUND_FRAME_COUNT *
  244                                    I2O_IOP_OUTBOUND_FRAME_SIZE,
  245                                    M_PSTIOP, M_NOWAIT,
  246                                    0x00010000, 0xFFFFFFFF,
  247                                    PAGE_SIZE, 0))) {
  248         printf("pstiop: contigmalloc of outqueue buffers failed!\n");
  249         return 0;
  250     }
  251     sc->phys_obase = vtophys(sc->obase);
  252     mfa = iop_get_mfa(sc);
  253     msg = (struct i2o_exec_init_outqueue_message *)(sc->ibase + mfa);
  254     bzero(msg, sizeof(struct i2o_exec_init_outqueue_message));
  255     msg->version_offset = 0x61;
  256     msg->message_flags = 0x0;
  257     msg->message_size = sizeof(struct i2o_exec_init_outqueue_message) >> 2;
  258     msg->target_address = I2O_TID_IOP;
  259     msg->initiator_address = I2O_TID_HOST;
  260     msg->function = I2O_EXEC_OUTBOUND_INIT;
  261     msg->host_pagesize = PAGE_SIZE;
  262     msg->init_code = 0x00; /* SOS XXX should be 0x80 == OS */
  263     msg->queue_framesize = I2O_IOP_OUTBOUND_FRAME_SIZE / sizeof(u_int32_t);
  264     msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
  265     msg->sgl[0].count = sizeof(reply);
  266     msg->sgl[0].phys_addr[0] = vtophys(&reply);
  267     msg->sgl[1].flags = I2O_SGL_END | I2O_SGL_EOB;
  268     msg->sgl[1].count = 1;
  269     msg->sgl[1].phys_addr[0] = 0;
  270 
  271     sc->reg->iqueue = mfa;
  272 
  273     /* wait for init to complete */
  274     while (--timeout && reply != I2O_EXEC_OUTBOUND_INIT_COMPLETE)
  275         DELAY(1000);
  276 
  277     if (!timeout) {
  278         printf("pstiop: timeout waiting for init-complete response\n");
  279         iop_free_mfa(sc, mfa);
  280         return 0;
  281     }
  282 
  283     /* now init our oqueue bufs */
  284     for (i = 0; i < I2O_IOP_OUTBOUND_FRAME_COUNT; i++) {
  285         sc->reg->oqueue = sc->phys_obase + (i * I2O_IOP_OUTBOUND_FRAME_SIZE);
  286         DELAY(1000);
  287     }
  288 
  289     return 1;
  290 }
  291 
  292 int
  293 iop_get_lct(struct iop_softc *sc)
  294 {
  295     struct i2o_exec_get_lct_message *msg;
  296     struct i2o_get_lct_reply *reply;
  297     int mfa;
  298 #define ALLOCSIZE        (PAGE_SIZE + (256 * sizeof(struct i2o_lct_entry)))
  299 
  300     if (!(reply = contigmalloc(ALLOCSIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
  301                                0x00010000, 0xFFFFFFFF, PAGE_SIZE, 0)))
  302         return 0;
  303 
  304     mfa = iop_get_mfa(sc);
  305     msg = (struct i2o_exec_get_lct_message *)(sc->ibase + mfa);
  306     bzero(msg, sizeof(struct i2o_exec_get_lct_message));
  307     msg->version_offset = 0x61;
  308     msg->message_flags = 0x0;
  309     msg->message_size = sizeof(struct i2o_exec_get_lct_message) >> 2;
  310     msg->target_address = I2O_TID_IOP;
  311     msg->initiator_address = I2O_TID_HOST;
  312     msg->function = I2O_EXEC_LCT_NOTIFY;
  313     msg->class = I2O_CLASS_MATCH_ANYCLASS;
  314     msg->last_change_id = 0;
  315 
  316     msg->sgl.flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
  317     msg->sgl.count = ALLOCSIZE;
  318     msg->sgl.phys_addr[0] = vtophys(reply);
  319 
  320     if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg)) {
  321         contigfree(reply, ALLOCSIZE, M_PSTIOP);
  322         return 0;
  323     }
  324     if (!(sc->lct = malloc(reply->table_size * sizeof(struct i2o_lct_entry),
  325                            M_PSTIOP, M_NOWAIT | M_ZERO))) {
  326         contigfree(reply, ALLOCSIZE, M_PSTIOP);
  327         return 0;
  328     }
  329     bcopy(&reply->entry[0], sc->lct,
  330           reply->table_size * sizeof(struct i2o_lct_entry));
  331     sc->lct_count = reply->table_size;
  332     contigfree(reply, ALLOCSIZE, M_PSTIOP);
  333     return 1;
  334 }
  335 
  336 struct i2o_get_param_reply *
  337 iop_get_util_params(struct iop_softc *sc, int target, int operation, int group)
  338 {
  339     struct i2o_util_get_param_message *msg;
  340     struct i2o_get_param_operation *param;
  341     struct i2o_get_param_reply *reply;
  342     int mfa;
  343 
  344     if (!(param = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
  345                                0x00010000, 0xFFFFFFFF, PAGE_SIZE, 0)))
  346         return NULL;
  347 
  348     if (!(reply = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
  349                                0x00010000, 0xFFFFFFFF, PAGE_SIZE, 0)))
  350         return NULL;
  351 
  352     mfa = iop_get_mfa(sc);
  353     msg = (struct i2o_util_get_param_message *)(sc->ibase + mfa);
  354     bzero(msg, sizeof(struct i2o_util_get_param_message));
  355     msg->version_offset = 0x51;
  356     msg->message_flags = 0x0;
  357     msg->message_size = sizeof(struct i2o_util_get_param_message) >> 2;
  358     msg->target_address = target;
  359     msg->initiator_address = I2O_TID_HOST;
  360     msg->function = I2O_UTIL_PARAMS_GET;
  361     msg->operation_flags = 0;
  362 
  363     param->operation_count = 1;
  364     param->operation[0].operation = operation;
  365     param->operation[0].group = group;
  366     param->operation[0].field_count = 0xffff;
  367 
  368     msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_DIR | I2O_SGL_EOB;
  369     msg->sgl[0].count = sizeof(struct i2o_get_param_operation);
  370     msg->sgl[0].phys_addr[0] = vtophys(param);
  371 
  372     msg->sgl[1].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
  373     msg->sgl[1].count = PAGE_SIZE;
  374     msg->sgl[1].phys_addr[0] = vtophys(reply);
  375 
  376     if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg) ||
  377         reply->error_info_size) {
  378         contigfree(reply, PAGE_SIZE, M_PSTIOP);
  379         reply = NULL;
  380     }
  381     contigfree(param, PAGE_SIZE, M_PSTIOP);
  382     return reply;
  383 }
  384 
  385 u_int32_t
  386 iop_get_mfa(struct iop_softc *sc)
  387 {
  388     u_int32_t mfa;
  389     int timeout = 10000;
  390 
  391     while ((mfa = sc->reg->iqueue) == 0xffffffff && timeout) {
  392         DELAY(1000);
  393         timeout--;
  394     }
  395     if (!timeout)
  396         printf("pstiop: no free mfa\n");
  397     return mfa;
  398 }
  399 
  400 void
  401 iop_free_mfa(struct iop_softc *sc, int mfa)
  402 {
  403     struct i2o_basic_message *msg = (struct i2o_basic_message *)(sc->ibase+mfa);
  404 
  405     bzero(msg, sizeof(struct i2o_basic_message));
  406     msg->version = 0x01;
  407     msg->message_flags = 0x0;
  408     msg->message_size = sizeof(struct i2o_basic_message) >> 2;
  409     msg->target_address = I2O_TID_IOP;
  410     msg->initiator_address = I2O_TID_HOST;
  411     msg->function = I2O_UTIL_NOP;
  412     sc->reg->iqueue = mfa;
  413 }
  414 
  415 static void
  416 iop_done(struct iop_softc *sc, u_int32_t mfa, struct i2o_single_reply *reply)
  417 {
  418     struct iop_request *request =
  419         (struct iop_request *)reply->transaction_context;
  420     
  421     request->reply = reply;
  422     request->mfa = mfa;
  423     wakeup(request);
  424 }
  425 
  426 int
  427 iop_queue_wait_msg(struct iop_softc *sc, int mfa, struct i2o_basic_message *msg)
  428 {
  429     struct i2o_single_reply *reply;
  430     struct iop_request request;
  431     u_int32_t out_mfa;
  432     int status, timeout = 10000;
  433 
  434     mtx_lock(&sc->mtx);
  435     if (!(sc->reg->oqueue_intr_mask & 0x08)) {
  436         msg->transaction_context = (u_int32_t)&request;
  437         msg->initiator_context = (u_int32_t)iop_done;
  438         sc->reg->iqueue = mfa;
  439         if (msleep(&request, &sc->mtx, PRIBIO, "pstwt", 10 * hz)) {
  440             printf("pstiop: timeout waiting for message response\n");
  441             iop_free_mfa(sc, mfa);
  442             mtx_unlock(&sc->mtx);
  443             return -1;
  444         }
  445         status = request.reply->status;
  446         sc->reg->oqueue = request.mfa;
  447     }
  448     else {
  449         sc->reg->iqueue = mfa;
  450         while (--timeout && ((out_mfa = sc->reg->oqueue) == 0xffffffff))
  451             DELAY(1000);
  452         if (!timeout) {
  453             printf("pstiop: timeout waiting for message response\n");
  454             iop_free_mfa(sc, mfa);
  455             mtx_unlock(&sc->mtx);
  456             return -1;
  457         }
  458         reply = (struct i2o_single_reply *)(sc->obase+(out_mfa-sc->phys_obase));
  459         status = reply->status;
  460         sc->reg->oqueue = out_mfa;
  461     }
  462     mtx_unlock(&sc->mtx);
  463     return status;
  464 }
  465 
  466 int
  467 iop_create_sgl(struct i2o_basic_message *msg, caddr_t data, int count, int dir)
  468 {
  469     struct i2o_sgl *sgl = (struct i2o_sgl *)((int32_t *)msg + msg->offset);
  470     u_int32_t sgl_count, sgl_phys;
  471     int i = 0;
  472 
  473     if (((uintptr_t)data & 3) || (count & 3)) {
  474         printf("pstiop: non aligned DMA transfer attempted\n");
  475         return 0;
  476     }
  477     if (!count) {
  478         printf("pstiop: zero length DMA transfer attempted\n");
  479         return 0;
  480     }
  481 
  482     sgl_count = min(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK)));
  483     sgl_phys = vtophys(data);
  484     sgl->flags = dir | I2O_SGL_PAGELIST | I2O_SGL_EOB | I2O_SGL_END;
  485     sgl->count = count;
  486     data += sgl_count;
  487     count -= sgl_count;
  488 
  489     while (count) {
  490         sgl->phys_addr[i] = sgl_phys;
  491         sgl_phys = vtophys(data);
  492         data += min(count, PAGE_SIZE);
  493         count -= min(count, PAGE_SIZE);
  494         if (++i >= I2O_SGL_MAX_SEGS) {
  495             printf("pstiop: too many segments in SGL\n");
  496             return 0;
  497         }
  498     }
  499     sgl->phys_addr[i] = sgl_phys;
  500     msg->message_size += i;
  501     return 1;
  502 }

Cache object: 9edfca097f64e6823bacbf014d4b4a07


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