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/raid/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 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  * $FreeBSD: src/sys/dev/pst/pst-iop.c,v 1.2.2.1 2002/08/18 12:32:36 sos Exp $
   29  */
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/module.h>
   35 #include <sys/bus.h>
   36 #include <sys/buf.h>
   37 #include <sys/malloc.h>
   38 #include <sys/rman.h>
   39 
   40 #include <vm/vm.h>
   41 #include <vm/pmap.h>
   42 
   43 #include <machine/clock.h>
   44 #include <machine/stdarg.h>
   45 
   46 #include <bus/pci/pcivar.h>
   47 #include <bus/pci/pcireg.h>
   48 
   49 #include "pst-iop.h"
   50 
   51 /* local vars */
   52 MALLOC_DEFINE(M_PSTIOP, "PSTIOP", "Promise SuperTrak IOP driver");
   53 
   54 int
   55 iop_init(struct iop_softc *sc)
   56 {
   57     int mfa, timeout = 10000;
   58 
   59     while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
   60         DELAY(1000);
   61     if (!timeout) {
   62         kprintf("pstiop: no free mfa\n");
   63         return 0;
   64     }
   65     iop_free_mfa(sc, mfa);
   66 
   67     sc->reg->oqueue_intr_mask = 0xffffffff;
   68 
   69     if (!iop_reset(sc)) {
   70         kprintf("pstiop: no reset response\n");
   71         return 0;
   72     }
   73 
   74     if (!iop_init_outqueue(sc)) {
   75         kprintf("pstiop: init outbound queue failed\n");
   76         return 0;
   77     }
   78 
   79     /* register iop_attach to be run when interrupts are enabled */
   80     sc->iop_delayed_attach = kmalloc(sizeof(struct intr_config_hook), 
   81                                    M_PSTIOP, M_INTWAIT | M_ZERO);
   82     sc->iop_delayed_attach->ich_func = (void *)iop_attach;
   83     sc->iop_delayed_attach->ich_arg = (void *)sc;
   84     sc->iop_delayed_attach->ich_desc = "pst";
   85     if (config_intrhook_establish(sc->iop_delayed_attach)) {
   86         kprintf("pstiop: config_intrhook_establish failed\n");
   87         kfree(sc->iop_delayed_attach, M_PSTIOP);
   88     }
   89     return 1;
   90 }
   91 
   92 void
   93 iop_attach(struct iop_softc *sc)
   94 {
   95     int i;
   96 
   97     if (sc->iop_delayed_attach) {
   98         config_intrhook_disestablish(sc->iop_delayed_attach);
   99         kfree(sc->iop_delayed_attach, M_PSTIOP);
  100         sc->iop_delayed_attach = NULL;
  101     }
  102 
  103     if (!iop_get_lct(sc)) {
  104         kprintf("pstiop: get LCT failed\n");
  105         return;
  106     }
  107 
  108     /* figure out what devices are here and config as needed */
  109     for (i = 0; sc->lct[i].entry_size == I2O_LCT_ENTRYSIZE; i++) {
  110 #ifdef PSTDEBUG
  111         struct i2o_get_param_reply *reply;
  112 
  113         kprintf("pstiop: LCT entry %d ", i);
  114         kprintf("class=%04x ", sc->lct[i].class);
  115         kprintf("sub=%04x ", sc->lct[i].sub_class);
  116         kprintf("localtid=%04x ", sc->lct[i].local_tid);
  117         kprintf("usertid=%04x ", sc->lct[i].user_tid);
  118         kprintf("parentid=%04x\n", sc->lct[i].parent_tid);
  119 
  120         if ((reply = iop_get_util_params(sc, sc->lct[i].local_tid,
  121                                          I2O_PARAMS_OPERATION_FIELD_GET,
  122                                          I2O_UTIL_DEVICE_IDENTITY_GROUP_NO))) {
  123             struct i2o_device_identity *ident =
  124                 (struct i2o_device_identity *)reply->result;
  125             kprintf("pstiop: vendor=<%.16s> product=<%.16s>\n",
  126                    ident->vendor, ident->product);
  127             kprintf("pstiop: description=<%.16s> revision=<%.8s>\n",
  128                    ident->description, ident->revision);
  129             contigfree(reply, PAGE_SIZE, M_PSTIOP);
  130         }
  131 #endif
  132 
  133         if (sc->lct[i].user_tid != I2O_TID_NONE &&
  134             sc->lct[i].user_tid != I2O_TID_HOST)
  135             continue;
  136 
  137         switch (sc->lct[i].class) {
  138         case I2O_CLASS_RANDOM_BLOCK_STORAGE:
  139             pst_add_raid(sc, &sc->lct[i]);
  140             break;
  141         }
  142     }
  143     /* setup and enable interrupts */
  144     bus_setup_intr(sc->dev, sc->r_irq, 0, iop_intr, sc, &sc->handle, NULL);
  145     sc->reg->oqueue_intr_mask = 0x0;
  146 }
  147 
  148 void
  149 iop_intr(void *data)
  150 {
  151     struct iop_softc *sc = (struct iop_softc *)data;
  152     struct i2o_single_reply *reply;
  153     u_int32_t mfa;
  154 
  155     /* we might get more than one finished request pr interrupt */
  156     while (1) {
  157         if ((mfa = sc->reg->oqueue) == 0xffffffff)
  158             if ((mfa = sc->reg->oqueue) == 0xffffffff)
  159                 return;
  160 
  161         reply = (struct i2o_single_reply *)(sc->obase + (mfa - sc->phys_obase));
  162 
  163         /* if this is a event register reply, shout! */
  164         if (reply->function == I2O_UTIL_EVENT_REGISTER) {
  165             struct i2o_util_event_reply_message *event = 
  166                 (struct i2o_util_event_reply_message *)reply;
  167 
  168             kprintf("pstiop: EVENT!! idx=%08x data=%08x\n",
  169                    event->event_mask, event->event_data[0]);
  170             return;
  171         }
  172 
  173         /* if reply is a failurenotice we need to free the original mfa */
  174         if (reply->message_flags & I2O_MESSAGE_FLAGS_FAIL)
  175             iop_free_mfa(sc,((struct i2o_fault_reply *)(reply))->preserved_mfa);
  176         
  177         /* reply->initiator_context points to the service routine */
  178         ((void (*)(struct iop_softc *, u_int32_t, struct i2o_single_reply *))
  179             (reply->initiator_context))(sc, mfa, reply);
  180     }
  181 }
  182 
  183 int
  184 iop_reset(struct iop_softc *sc)
  185 {
  186     struct i2o_exec_iop_reset_message *msg;
  187     int mfa, timeout = 5000;
  188     volatile u_int32_t reply = 0;
  189 
  190     mfa = iop_get_mfa(sc);
  191     msg = (struct i2o_exec_iop_reset_message *)(sc->ibase + mfa);
  192     bzero(msg, sizeof(struct i2o_exec_iop_reset_message));
  193     msg->version_offset = 0x1;
  194     msg->message_flags = 0x0;
  195     msg->message_size = sizeof(struct i2o_exec_iop_reset_message) >> 2;
  196     msg->target_address = I2O_TID_IOP;
  197     msg->initiator_address = I2O_TID_HOST;
  198     msg->function = I2O_EXEC_IOP_RESET;
  199     msg->status_word_low_addr = vtophys(&reply);
  200     msg->status_word_high_addr = 0;
  201 
  202     sc->reg->iqueue = mfa;
  203 
  204     while (--timeout && !reply)
  205         DELAY(1000);
  206 
  207     /* wait for iqueue ready */
  208     timeout = 10000;
  209     while ((mfa = sc->reg->iqueue) == 0xffffffff && --timeout)
  210         DELAY(1000);
  211 
  212     iop_free_mfa(sc, mfa);
  213     return reply;
  214 }
  215 
  216 int
  217 iop_init_outqueue(struct iop_softc *sc)
  218 {
  219     struct i2o_exec_init_outqueue_message *msg;
  220     int i, mfa, timeout = 5000;
  221     volatile u_int32_t reply = 0;
  222 
  223     if (!(sc->obase = contigmalloc(I2O_IOP_OUTBOUND_FRAME_COUNT *
  224                                    I2O_IOP_OUTBOUND_FRAME_SIZE,
  225                                    M_PSTIOP, M_NOWAIT,
  226                                    0x00010000, 0xFFFFFFFF,
  227                                    sizeof(u_int32_t), 0))) {
  228         kprintf("pstiop: contigmalloc of outqueue buffers failed!\n");
  229         return 0;
  230     }
  231     sc->phys_obase = vtophys(sc->obase);
  232     mfa = iop_get_mfa(sc);
  233     msg = (struct i2o_exec_init_outqueue_message *)(sc->ibase + mfa);
  234     bzero(msg, sizeof(struct i2o_exec_init_outqueue_message));
  235     msg->version_offset = 0x61;
  236     msg->message_flags = 0x0;
  237     msg->message_size = sizeof(struct i2o_exec_init_outqueue_message) >> 2;
  238     msg->target_address = I2O_TID_IOP;
  239     msg->initiator_address = I2O_TID_HOST;
  240     msg->function = I2O_EXEC_OUTBOUND_INIT;
  241     msg->host_pagesize = PAGE_SIZE;
  242     msg->init_code = 0x00; /* SOS XXX should be 0x80 == OS */
  243     msg->queue_framesize = I2O_IOP_OUTBOUND_FRAME_SIZE / sizeof(u_int32_t);
  244     msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
  245     msg->sgl[0].count = sizeof(reply);
  246     msg->sgl[0].phys_addr[0] = vtophys(&reply);
  247     msg->sgl[1].flags = I2O_SGL_END | I2O_SGL_EOB;
  248     msg->sgl[1].count = 1;
  249     msg->sgl[1].phys_addr[0] = 0;
  250 
  251     sc->reg->iqueue = mfa;
  252 
  253     /* wait for init to complete */
  254     while (--timeout && reply != I2O_EXEC_OUTBOUND_INIT_COMPLETE)
  255         DELAY(1000);
  256     
  257     if (!timeout) {
  258         kprintf("pstiop: timeout waiting for init-complete response\n");
  259         iop_free_mfa(sc, mfa);
  260         return 0;
  261     }
  262 
  263     /* now init our oqueue bufs */
  264     for (i = 0; i < I2O_IOP_OUTBOUND_FRAME_COUNT; i++) {
  265         sc->reg->oqueue = sc->phys_obase + (i * I2O_IOP_OUTBOUND_FRAME_SIZE);
  266         DELAY(1000);
  267     }
  268 
  269     iop_free_mfa(sc, mfa);
  270     return 1;
  271 }
  272 
  273 int
  274 iop_get_lct(struct iop_softc *sc)
  275 {
  276     struct i2o_exec_get_lct_message *msg;
  277     struct i2o_get_lct_reply *reply;
  278     int mfa;
  279 #define ALLOCSIZE        (PAGE_SIZE + (256 * sizeof(struct i2o_lct_entry)))
  280 
  281     if (!(reply = contigmalloc(ALLOCSIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
  282                                0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
  283         return 0;
  284 
  285     mfa = iop_get_mfa(sc);
  286     msg = (struct i2o_exec_get_lct_message *)(sc->ibase + mfa);
  287     bzero(msg, sizeof(struct i2o_exec_get_lct_message));
  288     msg->version_offset = 0x61;
  289     msg->message_flags = 0x0;
  290     msg->message_size = sizeof(struct i2o_exec_get_lct_message) >> 2;
  291     msg->target_address = I2O_TID_IOP;
  292     msg->initiator_address = I2O_TID_HOST;
  293     msg->function = I2O_EXEC_LCT_NOTIFY;
  294     msg->class = I2O_CLASS_MATCH_ANYCLASS;
  295     msg->last_change_id = 0;
  296 
  297     msg->sgl.flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
  298     msg->sgl.count = ALLOCSIZE;
  299     msg->sgl.phys_addr[0] = vtophys(reply);
  300 
  301     if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg)) {
  302         contigfree(reply, ALLOCSIZE, M_PSTIOP);
  303         return 0;
  304     }
  305     sc->lct = kmalloc(reply->table_size * sizeof(struct i2o_lct_entry),
  306                            M_PSTIOP, M_INTWAIT | M_ZERO);
  307     bcopy(&reply->entry[0], sc->lct, 
  308           reply->table_size * sizeof(struct i2o_lct_entry));
  309     sc->lct_count = reply->table_size;
  310     contigfree(reply, ALLOCSIZE, M_PSTIOP);
  311     return 1;
  312 }
  313 
  314 struct i2o_get_param_reply *
  315 iop_get_util_params(struct iop_softc *sc, int target, int operation, int group)
  316 {
  317     struct i2o_util_get_param_message *msg;
  318     struct i2o_get_param_operation *param;
  319     struct i2o_get_param_reply *reply;
  320     int mfa;
  321 
  322     if (!(param = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
  323                                0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
  324         return NULL;
  325 
  326     if (!(reply = contigmalloc(PAGE_SIZE, M_PSTIOP, M_NOWAIT | M_ZERO,
  327                                0x00010000, 0xFFFFFFFF, sizeof(u_int32_t), 0)))
  328     {
  329         contigfree(param, PAGE_SIZE, M_PSTIOP);
  330         return NULL;
  331     }
  332 
  333     mfa = iop_get_mfa(sc);
  334     msg = (struct i2o_util_get_param_message *)(sc->ibase + mfa);
  335     bzero(msg, sizeof(struct i2o_util_get_param_message));
  336     msg->version_offset = 0x51;
  337     msg->message_flags = 0x0;
  338     msg->message_size = sizeof(struct i2o_util_get_param_message) >> 2;
  339     msg->target_address = target;
  340     msg->initiator_address = I2O_TID_HOST;
  341     msg->function = I2O_UTIL_PARAMS_GET;
  342     msg->operation_flags = 0;
  343 
  344     param->operation_count = 1;
  345     param->operation[0].operation = operation;
  346     param->operation[0].group = group;
  347     param->operation[0].field_count = 0xffff;
  348 
  349     msg->sgl[0].flags = I2O_SGL_SIMPLE | I2O_SGL_DIR | I2O_SGL_EOB;
  350     msg->sgl[0].count = sizeof(struct i2o_get_param_operation);
  351     msg->sgl[0].phys_addr[0] = vtophys(param);
  352 
  353     msg->sgl[1].flags = I2O_SGL_SIMPLE | I2O_SGL_END | I2O_SGL_EOB;
  354     msg->sgl[1].count = PAGE_SIZE;
  355     msg->sgl[1].phys_addr[0] = vtophys(reply);
  356 
  357     if (iop_queue_wait_msg(sc, mfa, (struct i2o_basic_message *)msg) ||
  358         reply->error_info_size) {
  359         contigfree(reply, PAGE_SIZE, M_PSTIOP);
  360         reply = NULL;
  361     }
  362     contigfree(param, PAGE_SIZE, M_PSTIOP);
  363     return reply;
  364 }
  365 
  366 u_int32_t
  367 iop_get_mfa(struct iop_softc *sc)
  368 {
  369     u_int32_t mfa;
  370     int timeout = 10000;
  371 
  372     while ((mfa = sc->reg->iqueue) == 0xffffffff && timeout) {
  373         DELAY(1000);
  374         timeout--;
  375     }
  376     if (!timeout)
  377         kprintf("pstiop: no free mfa\n");
  378     return mfa;
  379 }
  380 
  381 void
  382 iop_free_mfa(struct iop_softc *sc, int mfa)
  383 {
  384     struct i2o_basic_message *msg = (struct i2o_basic_message *)(sc->ibase+mfa);
  385 
  386     bzero(msg, sizeof(struct i2o_basic_message));
  387     msg->version = 0x01;
  388     msg->message_flags = 0x0;
  389     msg->message_size = sizeof(struct i2o_basic_message) >> 2;
  390     msg->target_address = I2O_TID_IOP;
  391     msg->initiator_address = I2O_TID_HOST;
  392     msg->function = I2O_UTIL_NOP;
  393     sc->reg->iqueue = mfa;
  394 }
  395 
  396 int
  397 iop_queue_wait_msg(struct iop_softc *sc, int mfa, struct i2o_basic_message *msg)
  398 {
  399     struct i2o_single_reply *reply;
  400     int out_mfa, status, timeout = 10000;
  401 
  402     sc->reg->iqueue = mfa;
  403 
  404     while (--timeout && ((out_mfa = sc->reg->oqueue) == 0xffffffff))
  405         DELAY(1000);
  406     if (!timeout) {
  407         kprintf("pstiop: timeout waiting for message response\n");
  408         iop_free_mfa(sc, mfa);
  409         return -1;
  410     }
  411 
  412     reply = (struct i2o_single_reply *)(sc->obase + (out_mfa - sc->phys_obase));
  413     status = reply->status;
  414     sc->reg->oqueue = out_mfa;
  415     return status;
  416 }
  417 
  418 int
  419 iop_create_sgl(struct i2o_basic_message *msg, caddr_t data, int count, int dir)
  420 {
  421     struct i2o_sgl *sgl = (struct i2o_sgl *)((int32_t *)msg + msg->offset);
  422     u_int32_t sgl_count, sgl_phys;
  423     int i = 0;
  424 
  425     if (((uintptr_t)data & 3) || (count & 3)) {
  426         kprintf("pstiop: non aligned DMA transfer attempted\n");
  427         return 0;
  428     }
  429     if (!count) {
  430         kprintf("pstiop: zero length DMA transfer attempted\n");
  431         return 0;
  432     }
  433     
  434     sgl_count = min(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK)));
  435     sgl_phys = vtophys(data);
  436     sgl->flags = dir | I2O_SGL_PAGELIST | I2O_SGL_EOB | I2O_SGL_END;
  437     sgl->count = count;
  438     data += sgl_count;
  439     count -= sgl_count;
  440 
  441     while (count) {
  442         sgl->phys_addr[i] = sgl_phys;
  443         sgl_phys = vtophys(data);
  444         data += min(count, PAGE_SIZE);
  445         count -= min(count, PAGE_SIZE);
  446         if (++i >= I2O_SGL_MAX_SEGS) {
  447             kprintf("pstiop: too many segments in SGL\n");
  448             return 0;
  449         }
  450     }
  451     sgl->phys_addr[i] = sgl_phys;
  452     msg->message_size += i;
  453     return 1;
  454 }

Cache object: 60f6c4610a90bd208b4091b490a319f5


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