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/ips/ips_commands.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  * Written by: David Jeffery
    3  * Copyright (c) 2002 Adaptec Inc.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   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  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * $FreeBSD: src/sys/dev/ips/ips_commands.c,v 1.10 2004/05/30 04:01:29 scottl Exp $
   28  */
   29 
   30 #include <sys/devicestat.h>
   31 #include <sys/sysctl.h>
   32 #include <dev/raid/ips/ips.h>
   33 #include <dev/raid/ips/ips_disk.h>
   34 
   35 static int ips_debug_ignore_flush_cmd;
   36 TUNABLE_INT("debug.ips.ignore_flush_cmd", &ips_debug_ignore_flush_cmd);
   37 SYSCTL_NODE(_debug, OID_AUTO, ips, CTLFLAG_RD, 0, "");
   38 SYSCTL_INT(_debug_ips, OID_AUTO, ignore_flush_cmd, CTLFLAG_RW,
   39            &ips_debug_ignore_flush_cmd, 0,
   40            "Do not issue IPS_CACHE_FLUSH_CMD on BUF_CMD_FLUSH");
   41 
   42 int
   43 ips_timed_wait(ips_command_t *command, const char *id, int timo)
   44 {
   45         int error = 0;
   46 
   47         while (command->completed == 0) {
   48                 crit_enter();
   49                 if (command->completed == 0)
   50                         error = tsleep(&command->completed, 0, id, timo);
   51                 crit_exit();
   52                 if (error == EWOULDBLOCK) {
   53                         error = ETIMEDOUT;
   54                         break;
   55                 }
   56         }
   57         return(error);
   58 }
   59 
   60 /*
   61  * This is an interrupt callback.  It is called from
   62  * interrupt context when the adapter has completed the
   63  * command, and wakes up anyone waiting on the command.
   64  */
   65 static void
   66 ips_wakeup_callback(ips_command_t *command)
   67 {
   68         bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap,
   69                         BUS_DMASYNC_POSTWRITE);
   70         command->completed = 1;
   71         wakeup(&command->completed);
   72 }
   73 
   74 /*
   75  * Below are a series of functions for sending an IO request
   76  * to the adapter.  The flow order is: start, send, callback, finish.
   77  * The caller must have already assembled an iorequest struct to hold
   78  * the details of the IO request.
   79  */
   80 static void
   81 ips_io_request_finish(ips_command_t *command)
   82 {
   83         struct bio *bio = command->arg;
   84 
   85         if (ips_read_request(bio)) {
   86                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
   87                                 BUS_DMASYNC_POSTREAD);
   88         } else {
   89                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
   90                                 BUS_DMASYNC_POSTWRITE);
   91         }
   92         bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
   93         if (COMMAND_ERROR(&command->status)) {
   94                 bio->bio_buf->b_flags |=B_ERROR;
   95                 bio->bio_buf->b_error = EIO;
   96         }
   97         ips_insert_free_cmd(command->sc, command);
   98         ipsd_finish(bio);
   99 }
  100 
  101 static void
  102 ips_io_request_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
  103                         int error)
  104 {
  105         ips_softc_t *sc;
  106         ips_command_t *command = cmdptr;
  107         ips_sg_element_t *sg_list;
  108         ips_io_cmd *command_struct;
  109         struct bio *bio = command->arg;
  110         struct buf *bp = bio->bio_buf;
  111         ipsdisk_softc_t *dsc;
  112         int i, length = 0;
  113         u_int8_t cmdtype;
  114 
  115         sc = command->sc;
  116         if (error) {
  117                 kprintf("ips: error = %d in ips_sg_request_callback\n", error);
  118                 bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
  119                 bp->b_flags |= B_ERROR;
  120                 bp->b_error = ENOMEM;
  121                 ips_insert_free_cmd(sc, command);
  122                 ipsd_finish(bio);
  123                 return;
  124         }
  125         dsc = bio->bio_driver_info;
  126         command_struct = (ips_io_cmd *)command->command_buffer;
  127         command_struct->id = command->id;
  128         command_struct->drivenum = dsc->sc->drives[dsc->disk_number].drivenum;
  129 
  130         if (segnum != 1) {
  131                 if (ips_read_request(bio))
  132                         cmdtype = IPS_SG_READ_CMD;
  133                 else
  134                         cmdtype = IPS_SG_WRITE_CMD;
  135                 command_struct->segnum = segnum;
  136                 sg_list = (ips_sg_element_t *)((u_int8_t *)
  137                            command->command_buffer + IPS_COMMAND_LEN);
  138                 for (i = 0; i < segnum; i++) {
  139                         sg_list[i].addr = segments[i].ds_addr;
  140                         sg_list[i].len = segments[i].ds_len;
  141                         length += segments[i].ds_len;
  142                 }
  143                 command_struct->buffaddr =
  144                     (u_int32_t)command->command_phys_addr + IPS_COMMAND_LEN;
  145         } else {
  146                 if (ips_read_request(bio))
  147                         cmdtype = IPS_READ_CMD;
  148                 else
  149                         cmdtype = IPS_WRITE_CMD;
  150                 command_struct->buffaddr = segments[0].ds_addr;
  151                 length = segments[0].ds_len;
  152         }
  153         command_struct->command = cmdtype;
  154         command_struct->lba = bio->bio_offset / IPS_BLKSIZE;
  155         length = (length + IPS_BLKSIZE - 1)/IPS_BLKSIZE;
  156         command_struct->length = length;
  157         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
  158                         BUS_DMASYNC_PREWRITE);
  159         if (ips_read_request(bio)) {
  160                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
  161                                 BUS_DMASYNC_PREREAD);
  162         } else {
  163                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
  164                                 BUS_DMASYNC_PREWRITE);
  165         }
  166         PRINTF(10, "ips test: command id: %d segments: %d "
  167                 "pblkno: %lld length: %d, ds_len: %d\n", command->id, segnum,
  168                 bio->bio_offset / IPS_BLKSIZE,
  169                 length, segments[0].ds_len);
  170 
  171         sc->ips_issue_cmd(command);
  172         return;
  173 }
  174 
  175 static void
  176 ips_flush_request_finish(ips_command_t *command)
  177 {
  178         ips_generic_cmd *gencmd = command->command_buffer;
  179         struct bio *bio = command->arg;
  180 
  181         if (COMMAND_ERROR(&command->status)) {
  182                 device_printf(command->sc->dev,
  183                               "cmd=0x%x,st=0x%x,est=0x%x\n",
  184                               gencmd->command,
  185                               command->status.fields.basic_status,
  186                               command->status.fields.extended_status);
  187 
  188                 bio->bio_buf->b_flags |= B_ERROR;
  189                 bio->bio_buf->b_error = EIO;
  190         }
  191         ips_insert_free_cmd(command->sc, command);
  192         ipsd_finish(bio);
  193 }
  194 
  195 static int
  196 ips_send_flush_request(ips_command_t *command, struct bio *bio)
  197 {
  198         command->arg = bio;
  199         ips_generic_cmd *flush_cmd;
  200         ips_softc_t *sc = command->sc;
  201 
  202         if (!ips_debug_ignore_flush_cmd) {
  203                 ips_insert_free_cmd(sc, command);
  204                 ipsd_finish(bio);
  205                 return 0;
  206         }
  207 
  208         command->callback = ips_flush_request_finish;
  209         flush_cmd = command->command_buffer;
  210         flush_cmd->command      = IPS_CACHE_FLUSH_CMD;
  211         flush_cmd->id           = command->id;
  212         flush_cmd->drivenum     = 0;
  213         flush_cmd->buffaddr     = 0;
  214         flush_cmd->lba          = 0;
  215         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
  216                         BUS_DMASYNC_PREWRITE);
  217 
  218         sc->ips_issue_cmd(command);
  219         return 0;
  220 }
  221 
  222 
  223 static int
  224 ips_send_io_request(ips_command_t *command, struct bio *bio)
  225 {
  226         struct buf *bp = bio->bio_buf;
  227 
  228         command->callback = ips_io_request_finish;
  229         command->arg = bio;
  230         PRINTF(10, "ips test: : bcount %ld\n", bp->b_bcount);
  231         bus_dmamap_load(command->data_dmatag, command->data_dmamap,
  232                         bp->b_data, bp->b_bcount,
  233                         ips_io_request_callback, command, 0);
  234         return 0;
  235 }
  236 
  237 void
  238 ips_start_io_request(ips_softc_t *sc)
  239 {
  240         ips_command_t *command;
  241         struct bio *bio;
  242 
  243         bio = bioq_first(&sc->bio_queue);
  244         if (bio == NULL)
  245                 return;
  246         if (ips_get_free_cmd(sc, &command, 0) != 0)
  247                 return;
  248         bioq_remove(&sc->bio_queue, bio);
  249         if (bio->bio_buf->b_cmd == BUF_CMD_FLUSH)
  250                 ips_send_flush_request(command, bio);
  251         else
  252                 ips_send_io_request(command, bio);
  253 }
  254 
  255 /*
  256  * Below are a series of functions for sending an adapter info request
  257  * to the adapter.  The flow order is: get, send, callback. It uses
  258  * the generic finish callback at the top of this file.
  259  * This can be used to get configuration/status info from the card
  260  */
  261 static void
  262 ips_adapter_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum,
  263                           int error)
  264 {
  265         ips_softc_t *sc;
  266         ips_command_t *command = cmdptr;
  267         ips_adapter_info_cmd *command_struct;
  268         sc = command->sc;
  269         if (error) {
  270                 command->status.value = IPS_ERROR_STATUS; /* a lovely error value */
  271                 ips_insert_free_cmd(sc, command);
  272                 kprintf("ips: error = %d in ips_get_adapter_info\n", error);
  273                 return;
  274         }
  275         command_struct = (ips_adapter_info_cmd *)command->command_buffer;
  276         command_struct->command = IPS_ADAPTER_INFO_CMD;
  277         command_struct->id = command->id;
  278         command_struct->buffaddr = segments[0].ds_addr;
  279 
  280         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
  281                         BUS_DMASYNC_PREWRITE);
  282         bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
  283                         BUS_DMASYNC_PREREAD);
  284         sc->ips_issue_cmd(command);
  285 }
  286 
  287 static int
  288 ips_send_adapter_info_cmd(ips_command_t *command)
  289 {
  290         ips_softc_t *sc = command->sc;
  291         int error = 0;
  292 
  293         if (bus_dma_tag_create( /* parent    */ sc->adapter_dmatag,
  294                                 /* alignemnt */ 1,
  295                                 /* boundary  */ 0,
  296                                 /* lowaddr   */ BUS_SPACE_MAXADDR_32BIT,
  297                                 /* highaddr  */ BUS_SPACE_MAXADDR,
  298                                 /* filter    */ NULL,
  299                                 /* filterarg */ NULL,
  300                                 /* maxsize   */ IPS_ADAPTER_INFO_LEN,
  301                                 /* numsegs   */ 1,
  302                                 /* maxsegsize*/ IPS_ADAPTER_INFO_LEN,
  303                                 /* flags     */ 0,
  304                                 &command->data_dmatag) != 0) {
  305                 kprintf("ips: can't alloc dma tag for adapter status\n");
  306                 error = ENOMEM;
  307                 goto exit;
  308         }
  309         if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
  310            BUS_DMA_NOWAIT, &command->data_dmamap)) {
  311                 error = ENOMEM;
  312                 goto exit;
  313         }
  314         command->callback = ips_wakeup_callback;
  315         bus_dmamap_load(command->data_dmatag, command->data_dmamap,
  316             command->data_buffer, IPS_ADAPTER_INFO_LEN,
  317             ips_adapter_info_callback, command, BUS_DMA_NOWAIT);
  318         if ((command->status.value == IPS_ERROR_STATUS) ||
  319             ips_timed_wait(command, "ips", 30 * hz) != 0)
  320                 error = ETIMEDOUT;
  321         if (error == 0) {
  322                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
  323                     BUS_DMASYNC_POSTREAD);
  324                 memcpy(&(sc->adapter_info), command->data_buffer,
  325                         IPS_ADAPTER_INFO_LEN);
  326         }
  327         bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
  328 exit:
  329         /* I suppose I should clean up my memory allocations */
  330         bus_dmamem_free(command->data_dmatag, command->data_buffer,
  331             command->data_dmamap);
  332         bus_dma_tag_destroy(command->data_dmatag);
  333         ips_insert_free_cmd(sc, command);
  334         return error;
  335 }
  336 
  337 int
  338 ips_get_adapter_info(ips_softc_t *sc)
  339 {
  340         ips_command_t *command;
  341         int error = 0;
  342 
  343         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
  344                 device_printf(sc->dev, "unable to get adapter configuration\n");
  345                 return ENXIO;
  346         }
  347         ips_send_adapter_info_cmd(command);
  348         if (COMMAND_ERROR(&command->status))
  349                 error = ENXIO;
  350         return error;
  351 }
  352 
  353 /*
  354  * Below are a series of functions for sending a drive info request
  355  * to the adapter.  The flow order is: get, send, callback. It uses
  356  * the generic finish callback at the top of this file.
  357  * This can be used to get drive status info from the card
  358  */
  359 static void
  360 ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
  361                         int error)
  362 {
  363         ips_softc_t *sc;
  364         ips_command_t *command = cmdptr;
  365         ips_drive_cmd *command_struct;
  366 
  367         sc = command->sc;
  368         if (error) {
  369 
  370                 command->status.value = IPS_ERROR_STATUS;
  371                 ips_insert_free_cmd(sc, command);
  372                 kprintf("ips: error = %d in ips_get_drive_info\n", error);
  373                 return;
  374         }
  375         command_struct = (ips_drive_cmd *)command->command_buffer;
  376         command_struct->command = IPS_DRIVE_INFO_CMD;
  377         command_struct->id = command->id;
  378         command_struct->buffaddr = segments[0].ds_addr;
  379         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
  380             BUS_DMASYNC_PREWRITE);
  381         bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
  382             BUS_DMASYNC_PREREAD);
  383         sc->ips_issue_cmd(command);
  384 }
  385 
  386 static int
  387 ips_send_drive_info_cmd(ips_command_t *command)
  388 {
  389         int error = 0;
  390         ips_softc_t *sc = command->sc;
  391         ips_drive_info_t *driveinfo;
  392 
  393         if (bus_dma_tag_create( /* parent    */ sc->adapter_dmatag,
  394                                 /* alignemnt */ 1,
  395                                 /* boundary  */ 0,
  396                                 /* lowaddr   */ BUS_SPACE_MAXADDR_32BIT,
  397                                 /* highaddr  */ BUS_SPACE_MAXADDR,
  398                                 /* filter    */ NULL,
  399                                 /* filterarg */ NULL,
  400                                 /* maxsize   */ IPS_DRIVE_INFO_LEN,
  401                                 /* numsegs   */ 1,
  402                                 /* maxsegsize*/ IPS_DRIVE_INFO_LEN,
  403                                 /* flags     */ 0,
  404                                 &command->data_dmatag) != 0) {
  405                 kprintf("ips: can't alloc dma tag for drive status\n");
  406                 error = ENOMEM;
  407                 goto exit;
  408         }
  409         if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
  410             BUS_DMA_NOWAIT, &command->data_dmamap)) {
  411                 error = ENOMEM;
  412                 goto exit;
  413         }
  414         command->callback = ips_wakeup_callback;
  415         bus_dmamap_load(command->data_dmatag, command->data_dmamap,
  416             command->data_buffer,IPS_DRIVE_INFO_LEN,
  417             ips_drive_info_callback, command, BUS_DMA_NOWAIT);
  418         if ((command->status.value == IPS_ERROR_STATUS) ||
  419             ips_timed_wait(command, "ips", 10 * hz) != 0)
  420                 error = ETIMEDOUT;
  421 
  422         if (error == 0) {
  423                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
  424                     BUS_DMASYNC_POSTREAD);
  425                 driveinfo = command->data_buffer;
  426                 memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8);
  427                 sc->drivecount = driveinfo->drivecount;
  428                 device_printf(sc->dev, "logical drives: %d\n", sc->drivecount);
  429         }
  430         bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
  431 exit:
  432         /* I suppose I should clean up my memory allocations */
  433         bus_dmamem_free(command->data_dmatag, command->data_buffer,
  434                         command->data_dmamap);
  435         bus_dma_tag_destroy(command->data_dmatag);
  436         ips_insert_free_cmd(sc, command);
  437         return error;
  438 }
  439 
  440 int
  441 ips_get_drive_info(ips_softc_t *sc)
  442 {
  443         int error = 0;
  444         ips_command_t *command;
  445 
  446         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
  447                 device_printf(sc->dev, "unable to get drive configuration\n");
  448                 return ENXIO;
  449         }
  450         ips_send_drive_info_cmd(command);
  451         if (COMMAND_ERROR(&command->status))
  452                 error = ENXIO;
  453         return error;
  454 }
  455 
  456 /*
  457  * Below is a pair of functions for making sure data is safely
  458  * on disk by flushing the adapter's cache.
  459  */
  460 static int
  461 ips_send_flush_cache_cmd(ips_command_t *command)
  462 {
  463         ips_softc_t *sc = command->sc;
  464         ips_generic_cmd *command_struct;
  465 
  466         PRINTF(10,"ips test: got a command, building flush command\n");
  467         command->callback = ips_wakeup_callback;
  468         command_struct = (ips_generic_cmd *)command->command_buffer;
  469         command_struct->command = IPS_CACHE_FLUSH_CMD;
  470         command_struct->id = command->id;
  471         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
  472             BUS_DMASYNC_PREWRITE);
  473         sc->ips_issue_cmd(command);
  474         if (command->status.value != IPS_ERROR_STATUS)
  475                 ips_timed_wait(command, "flush2", 0);
  476         ips_insert_free_cmd(sc, command);
  477         return 0;
  478 }
  479 
  480 int
  481 ips_flush_cache(ips_softc_t *sc)
  482 {
  483         ips_command_t *command;
  484 
  485         device_printf(sc->dev, "flushing cache\n");
  486         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
  487                 device_printf(sc->dev, "ERROR: unable to get a command! "
  488                     "can't flush cache!\n");
  489                 return(1);
  490         }
  491         ips_send_flush_cache_cmd(command);
  492         if (COMMAND_ERROR(&command->status)) {
  493                 device_printf(sc->dev, "ERROR: cache flush command failed!\n");
  494                 return(1);
  495         }
  496         return 0;
  497 }
  498 
  499 /*
  500  * Simplified localtime to provide timevalues for ffdc.
  501  * Taken from libc/stdtime/localtime.c
  502  */
  503 static void
  504 ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime)
  505 {
  506         long    days, rem, y;
  507         int     yleap, *ip, month;
  508         int     year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR };
  509         int     mon_lengths[2][IPS_MONSPERYEAR] = {
  510                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  511                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  512         };
  513 
  514         days = sctime / IPS_SECSPERDAY;
  515         rem  = sctime % IPS_SECSPERDAY;
  516 
  517         command->hour = rem / IPS_SECSPERHOUR;
  518         rem           = rem % IPS_SECSPERHOUR;
  519 
  520         command->minute = rem / IPS_SECSPERMIN;
  521         command->second = rem % IPS_SECSPERMIN;
  522 
  523         y = IPS_EPOCH_YEAR;
  524         while (days < 0 || days >= (long)year_lengths[yleap = ips_isleap(y)]) {
  525                 long    newy;
  526 
  527                 newy = y + days / IPS_DAYSPERNYEAR;
  528                 if (days < 0)
  529                         --newy;
  530                 days -= (newy - y) * IPS_DAYSPERNYEAR +
  531                     IPS_LEAPS_THRU_END_OF(newy - 1) -
  532                     IPS_LEAPS_THRU_END_OF(y - 1);
  533                 y = newy;
  534         }
  535         command->yearH = y / 100;
  536         command->yearL = y % 100;
  537         ip = mon_lengths[yleap];
  538         for (month = 0; days >= (long)ip[month]; ++month)
  539                 days = days - (long)ip[month];
  540         command->month = month + 1;
  541         command->day = days + 1;
  542 }
  543 
  544 static int
  545 ips_send_ffdc_reset_cmd(ips_command_t *command)
  546 {
  547         ips_softc_t *sc = command->sc;
  548         ips_adapter_ffdc_cmd *command_struct;
  549 
  550         PRINTF(10, "ips test: got a command, building ffdc reset command\n");
  551         command->callback = ips_wakeup_callback;
  552         command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer;
  553         command_struct->command = IPS_FFDC_CMD;
  554         command_struct->id = command->id;
  555         command_struct->reset_count = sc->ffdc_resetcount;
  556         command_struct->reset_type  = 0x0;
  557         ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec);
  558         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
  559             BUS_DMASYNC_PREWRITE);
  560         sc->ips_issue_cmd(command);
  561         if (command->status.value != IPS_ERROR_STATUS)
  562                 ips_timed_wait(command, "ffdc", 0);
  563         ips_insert_free_cmd(sc, command);
  564         return 0;
  565 }
  566 
  567 int
  568 ips_ffdc_reset(ips_softc_t *sc)
  569 {
  570         ips_command_t *command;
  571 
  572         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
  573                 device_printf(sc->dev, "ERROR: unable to get a command! "
  574                     "can't send ffdc reset!\n");
  575                 return 1;
  576         }
  577         ips_send_ffdc_reset_cmd(command);
  578         if (COMMAND_ERROR(&command->status)) {
  579                 /*
  580                  * apparently some cards may report error status for
  581                  * an ffdc reset command, even though it works correctly
  582                  * afterwards.  just complain about that and proceed here.
  583                  */
  584                 device_printf(sc->dev,
  585                               "ERROR: ffdc reset command failed(0x%04x)!\n",
  586                               command->status.value);
  587         }
  588         return 0;
  589 }
  590 
  591 static void
  592 ips_write_nvram(ips_command_t *command)
  593 {
  594         ips_softc_t *sc = command->sc;
  595         ips_rw_nvram_cmd *command_struct;
  596         ips_nvram_page5 *nvram;
  597 
  598         /*FIXME check for error */
  599         command->callback = ips_wakeup_callback;
  600         command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
  601         command_struct->command = IPS_RW_NVRAM_CMD;
  602         command_struct->id = command->id;
  603         command_struct->pagenum = 5;
  604         command_struct->rw      = 1;    /* write */
  605         bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
  606             BUS_DMASYNC_POSTREAD);
  607         nvram = command->data_buffer;
  608         /* retrieve adapter info and save in sc */
  609         sc->adapter_type = nvram->adapter_type;
  610         strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4);
  611         strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4);
  612         nvram->operating_system = IPS_OS_FREEBSD;
  613         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
  614             BUS_DMASYNC_PREWRITE);
  615         sc->ips_issue_cmd(command);
  616 }
  617 
  618 static void
  619 ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
  620                         int error)
  621 {
  622         ips_softc_t *sc;
  623         ips_command_t *command = cmdptr;
  624         ips_rw_nvram_cmd *command_struct;
  625 
  626         sc = command->sc;
  627         if (error) {
  628                 command->status.value = IPS_ERROR_STATUS;
  629                 ips_insert_free_cmd(sc, command);
  630                 kprintf("ips: error = %d in ips_read_nvram_callback\n", error);
  631                 return;
  632         }
  633         command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
  634         command_struct->command = IPS_RW_NVRAM_CMD;
  635         command_struct->id = command->id;
  636         command_struct->pagenum = 5;
  637         command_struct->rw = 0;
  638         command_struct->buffaddr = segments[0].ds_addr;
  639 
  640         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
  641             BUS_DMASYNC_PREWRITE);
  642         bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
  643             BUS_DMASYNC_PREREAD);
  644         sc->ips_issue_cmd(command);
  645 }
  646 
  647 static int
  648 ips_read_nvram(ips_command_t *command)
  649 {
  650         int error = 0;
  651         ips_softc_t *sc = command->sc;
  652 
  653         if (bus_dma_tag_create( /* parent    */ sc->adapter_dmatag,
  654                                 /* alignemnt */ 1,
  655                                 /* boundary  */ 0,
  656                                 /* lowaddr   */ BUS_SPACE_MAXADDR_32BIT,
  657                                 /* highaddr  */ BUS_SPACE_MAXADDR,
  658                                 /* filter    */ NULL,
  659                                 /* filterarg */ NULL,
  660                                 /* maxsize   */ IPS_NVRAM_PAGE_SIZE,
  661                                 /* numsegs   */ 1,
  662                                 /* maxsegsize*/ IPS_NVRAM_PAGE_SIZE,
  663                                 /* flags     */ 0,
  664                                 &command->data_dmatag) != 0) {
  665                 kprintf("ips: can't alloc dma tag for nvram\n");
  666                 error = ENOMEM;
  667                 goto exit;
  668         }
  669         if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
  670             BUS_DMA_NOWAIT, &command->data_dmamap)) {
  671                 error = ENOMEM;
  672                 goto exit;
  673         }
  674         command->callback = ips_write_nvram;
  675         bus_dmamap_load(command->data_dmatag, command->data_dmamap,
  676             command->data_buffer, IPS_NVRAM_PAGE_SIZE, ips_read_nvram_callback,
  677             command, BUS_DMA_NOWAIT);
  678         if ((command->status.value == IPS_ERROR_STATUS) ||
  679             ips_timed_wait(command, "ips", 0) != 0)
  680                 error = ETIMEDOUT;
  681         if (error == 0) {
  682                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
  683                                 BUS_DMASYNC_POSTWRITE);
  684         }
  685         bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
  686 exit:
  687         bus_dmamem_free(command->data_dmatag, command->data_buffer,
  688                         command->data_dmamap);
  689         bus_dma_tag_destroy(command->data_dmatag);
  690         ips_insert_free_cmd(sc, command);
  691         return error;
  692 }
  693 
  694 int
  695 ips_update_nvram(ips_softc_t *sc)
  696 {
  697         ips_command_t *command;
  698 
  699         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
  700                 device_printf(sc->dev, "ERROR: unable to get a command! "
  701                     "can't update nvram\n");
  702                 return 1;
  703         }
  704         ips_read_nvram(command);
  705         if (COMMAND_ERROR(&command->status)) {
  706                 device_printf(sc->dev, "ERROR: nvram update command failed!\n");
  707                 return 1;
  708         }
  709         return 0;
  710 }
  711 
  712 static int
  713 ips_send_config_sync_cmd(ips_command_t *command)
  714 {
  715         ips_softc_t *sc = command->sc;
  716         ips_generic_cmd *command_struct;
  717 
  718         PRINTF(10, "ips test: got a command, building flush command\n");
  719         command->callback = ips_wakeup_callback;
  720         command_struct = (ips_generic_cmd *)command->command_buffer;
  721         command_struct->command = IPS_CONFIG_SYNC_CMD;
  722         command_struct->id = command->id;
  723         command_struct->reserve2 = IPS_POCL;
  724         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
  725             BUS_DMASYNC_PREWRITE);
  726         sc->ips_issue_cmd(command);
  727         if (command->status.value != IPS_ERROR_STATUS)
  728                 ips_timed_wait(command, "ipssyn", 0);
  729         ips_insert_free_cmd(sc, command);
  730         return 0;
  731 }
  732 
  733 static int
  734 ips_send_error_table_cmd(ips_command_t *command)
  735 {
  736         ips_softc_t *sc = command->sc;
  737         ips_generic_cmd *command_struct;
  738 
  739         PRINTF(10, "ips test: got a command, building errortable command\n");
  740         command->callback = ips_wakeup_callback;
  741         command_struct = (ips_generic_cmd *)command->command_buffer;
  742         command_struct->command = IPS_ERROR_TABLE_CMD;
  743         command_struct->id = command->id;
  744         command_struct->reserve2 = IPS_CSL;
  745         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
  746             BUS_DMASYNC_PREWRITE);
  747         sc->ips_issue_cmd(command);
  748         if (command->status.value != IPS_ERROR_STATUS)
  749                 ips_timed_wait(command, "ipsetc", 0);
  750         ips_insert_free_cmd(sc, command);
  751         return 0;
  752 }
  753 
  754 int
  755 ips_clear_adapter(ips_softc_t *sc)
  756 {
  757         ips_command_t *command;
  758 
  759         device_printf(sc->dev, "syncing config\n");
  760         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
  761                 device_printf(sc->dev, "ERROR: unable to get a command! "
  762                     "can't sync cache!\n");
  763                 return 1;
  764         }
  765         ips_send_config_sync_cmd(command);
  766         if (COMMAND_ERROR(&command->status)) {
  767                 device_printf(sc->dev, "ERROR: cache sync command failed!\n");
  768                 return 1;
  769         }
  770         device_printf(sc->dev, "clearing error table\n");
  771         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
  772                 device_printf(sc->dev, "ERROR: unable to get a command! "
  773                     "can't sync cache!\n");
  774                 return 1;
  775         }
  776         ips_send_error_table_cmd(command);
  777         if (COMMAND_ERROR(&command->status)) {
  778                 device_printf(sc->dev, "ERROR: etable command failed!\n");
  779                 return 1;
  780         }
  781         return 0;
  782 }

Cache object: 562e1474e942fb36e9991482af798f8b


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