12aedd662SScott Long /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4aad970f1SDavid E. O'Brien * Written by: David Jeffery
52aedd662SScott Long * Copyright (c) 2002 Adaptec Inc.
62aedd662SScott Long * All rights reserved.
72aedd662SScott Long *
82aedd662SScott Long * Redistribution and use in source and binary forms, with or without
92aedd662SScott Long * modification, are permitted provided that the following conditions
102aedd662SScott Long * are met:
112aedd662SScott Long * 1. Redistributions of source code must retain the above copyright
122aedd662SScott Long * notice, this list of conditions and the following disclaimer.
132aedd662SScott Long * 2. Redistributions in binary form must reproduce the above copyright
142aedd662SScott Long * notice, this list of conditions and the following disclaimer in the
152aedd662SScott Long * documentation and/or other materials provided with the distribution.
162aedd662SScott Long *
172aedd662SScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
182aedd662SScott Long * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
192aedd662SScott Long * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
202aedd662SScott Long * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
212aedd662SScott Long * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
222aedd662SScott Long * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
232aedd662SScott Long * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
242aedd662SScott Long * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
252aedd662SScott Long * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
262aedd662SScott Long * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
272aedd662SScott Long * SUCH DAMAGE.
282aedd662SScott Long */
292aedd662SScott Long
30aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
31f94dfeb4SScott Long #include <dev/ips/ipsreg.h>
322aedd662SScott Long #include <dev/ips/ips.h>
332aedd662SScott Long
342aedd662SScott Long /*
352aedd662SScott Long * This is an interrupt callback. It is called from
362aedd662SScott Long * interrupt context when the adapter has completed the
372aedd662SScott Long * command. This very generic callback simply stores
382aedd662SScott Long * the command's return value in command->arg and wake's
392aedd662SScott Long * up anyone waiting on the command.
402aedd662SScott Long */
ips_wakeup_callback(ips_command_t * command)412aedd662SScott Long static void ips_wakeup_callback(ips_command_t *command)
422aedd662SScott Long {
432aedd662SScott Long bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap,
442aedd662SScott Long BUS_DMASYNC_POSTWRITE);
4503a908f2SScott Long sema_post(&command->sc->cmd_sema);
462aedd662SScott Long }
472aedd662SScott Long /* Below are a series of functions for sending an IO request
482aedd662SScott Long * to the adapter. The flow order is: start, send, callback, finish.
492aedd662SScott Long * The caller must have already assembled an iorequest struct to hold
502aedd662SScott Long * the details of the IO request. */
ips_io_request_finish(ips_command_t * command)512aedd662SScott Long static void ips_io_request_finish(ips_command_t *command)
522aedd662SScott Long {
532aedd662SScott Long
542aedd662SScott Long struct bio *iobuf = command->arg;
552aedd662SScott Long if(ips_read_request(iobuf)) {
562aedd662SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
572aedd662SScott Long BUS_DMASYNC_POSTREAD);
582aedd662SScott Long } else {
592aedd662SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
602aedd662SScott Long BUS_DMASYNC_POSTWRITE);
612aedd662SScott Long }
622aedd662SScott Long bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
632eea7051SScott Long if(COMMAND_ERROR(command)){
642aedd662SScott Long iobuf->bio_flags |=BIO_ERROR;
652aedd662SScott Long iobuf->bio_error = EIO;
665cd88eb0SGleb Smirnoff printf("ips: io error, status= 0x%x\n", command->status.value);
672aedd662SScott Long }
682aedd662SScott Long ips_insert_free_cmd(command->sc, command);
692aedd662SScott Long ipsd_finish(iobuf);
702aedd662SScott Long }
712aedd662SScott Long
ips_io_request_callback(void * cmdptr,bus_dma_segment_t * segments,int segnum,int error)722aedd662SScott Long static void ips_io_request_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
732aedd662SScott Long {
742aedd662SScott Long ips_softc_t *sc;
752aedd662SScott Long ips_command_t *command = cmdptr;
762aedd662SScott Long ips_sg_element_t *sg_list;
772aedd662SScott Long ips_io_cmd *command_struct;
782aedd662SScott Long struct bio *iobuf = command->arg;
792aedd662SScott Long int i, length = 0;
802aedd662SScott Long u_int8_t cmdtype;
812aedd662SScott Long
822aedd662SScott Long sc = command->sc;
832aedd662SScott Long if(error){
842aedd662SScott Long printf("ips: error = %d in ips_sg_request_callback\n", error);
852aedd662SScott Long bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
862aedd662SScott Long iobuf->bio_flags |= BIO_ERROR;
872aedd662SScott Long iobuf->bio_error = ENOMEM;
882aedd662SScott Long ips_insert_free_cmd(sc, command);
892aedd662SScott Long ipsd_finish(iobuf);
902aedd662SScott Long return;
912aedd662SScott Long }
922aedd662SScott Long command_struct = (ips_io_cmd *)command->command_buffer;
932aedd662SScott Long command_struct->id = command->id;
94f472527cSPeter Wemm command_struct->drivenum = (uintptr_t)iobuf->bio_driver1;
952aedd662SScott Long if(segnum != 1){
962aedd662SScott Long if(ips_read_request(iobuf))
972aedd662SScott Long cmdtype = IPS_SG_READ_CMD;
982aedd662SScott Long else
992aedd662SScott Long cmdtype = IPS_SG_WRITE_CMD;
1002aedd662SScott Long command_struct->segnum = segnum;
1012aedd662SScott Long sg_list = (ips_sg_element_t *)((u_int8_t *)
1022aedd662SScott Long command->command_buffer + IPS_COMMAND_LEN);
1032aedd662SScott Long for(i = 0; i < segnum; i++){
1042aedd662SScott Long sg_list[i].addr = segments[i].ds_addr;
1052aedd662SScott Long sg_list[i].len = segments[i].ds_len;
1062aedd662SScott Long length += segments[i].ds_len;
1072aedd662SScott Long }
1082aedd662SScott Long command_struct->buffaddr =
1092aedd662SScott Long (u_int32_t)command->command_phys_addr + IPS_COMMAND_LEN;
1102aedd662SScott Long } else {
1112aedd662SScott Long if(ips_read_request(iobuf))
1122aedd662SScott Long cmdtype = IPS_READ_CMD;
1132aedd662SScott Long else
1142aedd662SScott Long cmdtype = IPS_WRITE_CMD;
1152aedd662SScott Long command_struct->buffaddr = segments[0].ds_addr;
1162aedd662SScott Long length = segments[0].ds_len;
1172aedd662SScott Long }
1182aedd662SScott Long command_struct->command = cmdtype;
1192aedd662SScott Long command_struct->lba = iobuf->bio_pblkno;
1202aedd662SScott Long length = (length + IPS_BLKSIZE - 1)/IPS_BLKSIZE;
1212aedd662SScott Long command_struct->length = length;
1222aedd662SScott Long bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
1232aedd662SScott Long BUS_DMASYNC_PREWRITE);
1242aedd662SScott Long if(ips_read_request(iobuf)) {
1252aedd662SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
1262aedd662SScott Long BUS_DMASYNC_PREREAD);
1272aedd662SScott Long } else {
1282aedd662SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
1292aedd662SScott Long BUS_DMASYNC_PREWRITE);
1302aedd662SScott Long }
1310eac610fSPoul-Henning Kamp PRINTF(10, "ips test: command id: %d segments: %d "
1322aedd662SScott Long "pblkno: %lld length: %d, ds_len: %d\n", command->id, segnum,
1330eac610fSPoul-Henning Kamp iobuf->bio_pblkno,
1342aedd662SScott Long length, segments[0].ds_len);
1352aedd662SScott Long
1362aedd662SScott Long sc->ips_issue_cmd(command);
1372aedd662SScott Long return;
1382aedd662SScott Long }
1392aedd662SScott Long
ips_send_io_request(ips_command_t * command,struct bio * iobuf)14003a908f2SScott Long static int ips_send_io_request(ips_command_t *command, struct bio *iobuf)
1412aedd662SScott Long {
1422aedd662SScott Long command->callback = ips_io_request_finish;
14303a908f2SScott Long command->arg = iobuf;
1442aedd662SScott Long PRINTF(10, "ips test: : bcount %ld\n", iobuf->bio_bcount);
1452aedd662SScott Long bus_dmamap_load(command->data_dmatag, command->data_dmamap,
1462aedd662SScott Long iobuf->bio_data, iobuf->bio_bcount,
1472aedd662SScott Long ips_io_request_callback, command, 0);
1482aedd662SScott Long return 0;
1492aedd662SScott Long }
1502aedd662SScott Long
ips_start_io_request(ips_softc_t * sc)151b234a120SScott Long void ips_start_io_request(ips_softc_t *sc)
1522aedd662SScott Long {
153b234a120SScott Long struct bio *iobuf;
15403a908f2SScott Long ips_command_t *command;
155b234a120SScott Long
156b234a120SScott Long iobuf = bioq_first(&sc->queue);
15703a908f2SScott Long if(!iobuf)
1582aedd662SScott Long return;
159b234a120SScott Long
16003a908f2SScott Long if (ips_get_free_cmd(sc, &command, 0))
161b234a120SScott Long return;
162b234a120SScott Long
163b234a120SScott Long bioq_remove(&sc->queue, iobuf);
16403a908f2SScott Long ips_send_io_request(command, iobuf);
1652aedd662SScott Long return;
1662aedd662SScott Long }
1672aedd662SScott Long
1682aedd662SScott Long /* Below are a series of functions for sending an adapter info request
1692aedd662SScott Long * to the adapter. The flow order is: get, send, callback. It uses
1702aedd662SScott Long * the generic finish callback at the top of this file.
1712aedd662SScott Long * This can be used to get configuration/status info from the card */
ips_adapter_info_callback(void * cmdptr,bus_dma_segment_t * segments,int segnum,int error)1722aedd662SScott Long static void ips_adapter_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
1732aedd662SScott Long {
1742aedd662SScott Long ips_softc_t *sc;
1752aedd662SScott Long ips_command_t *command = cmdptr;
1762aedd662SScott Long ips_adapter_info_cmd *command_struct;
1772aedd662SScott Long sc = command->sc;
1782aedd662SScott Long if(error){
1792eea7051SScott Long ips_set_error(command, error);
1802aedd662SScott Long printf("ips: error = %d in ips_get_adapter_info\n", error);
1812aedd662SScott Long return;
1822aedd662SScott Long }
1832aedd662SScott Long command_struct = (ips_adapter_info_cmd *)command->command_buffer;
1842aedd662SScott Long command_struct->command = IPS_ADAPTER_INFO_CMD;
1852aedd662SScott Long command_struct->id = command->id;
1862aedd662SScott Long command_struct->buffaddr = segments[0].ds_addr;
1872aedd662SScott Long
1882aedd662SScott Long bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
1892aedd662SScott Long BUS_DMASYNC_PREWRITE);
1902aedd662SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
1912aedd662SScott Long BUS_DMASYNC_PREREAD);
1922aedd662SScott Long sc->ips_issue_cmd(command);
1932eea7051SScott Long if (sema_timedwait(&sc->cmd_sema, 30*hz) != 0) {
1942eea7051SScott Long ips_set_error(command, ETIMEDOUT);
1952eea7051SScott Long return;
1962eea7051SScott Long }
1972eea7051SScott Long
1982eea7051SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
1992eea7051SScott Long BUS_DMASYNC_POSTREAD);
2002eea7051SScott Long memcpy(&(sc->adapter_info), command->data_buffer, IPS_ADAPTER_INFO_LEN);
2012aedd662SScott Long }
2022aedd662SScott Long
2032aedd662SScott Long
2042aedd662SScott Long
ips_send_adapter_info_cmd(ips_command_t * command)2052aedd662SScott Long static int ips_send_adapter_info_cmd(ips_command_t *command)
2062aedd662SScott Long {
2072aedd662SScott Long int error = 0;
2082aedd662SScott Long ips_softc_t *sc = command->sc;
2092aedd662SScott Long
2102aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag,
2112aedd662SScott Long /* alignemnt */ 1,
2122aedd662SScott Long /* boundary */ 0,
2132aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
2142aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR,
2152aedd662SScott Long /* filter */ NULL,
2162aedd662SScott Long /* filterarg */ NULL,
2172aedd662SScott Long /* maxsize */ IPS_ADAPTER_INFO_LEN,
2182aedd662SScott Long /* numsegs */ 1,
2192aedd662SScott Long /* maxsegsize*/ IPS_ADAPTER_INFO_LEN,
2202aedd662SScott Long /* flags */ 0,
22103a908f2SScott Long /* lockfunc */ NULL,
22203a908f2SScott Long /* lockarg */ NULL,
2232aedd662SScott Long &command->data_dmatag) != 0) {
2242aedd662SScott Long printf("ips: can't alloc dma tag for adapter status\n");
2252aedd662SScott Long error = ENOMEM;
2262aedd662SScott Long goto exit;
2272aedd662SScott Long }
2282aedd662SScott Long if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
2292aedd662SScott Long BUS_DMA_NOWAIT, &command->data_dmamap)){
2302aedd662SScott Long error = ENOMEM;
2312aedd662SScott Long goto exit;
2322aedd662SScott Long }
2332aedd662SScott Long command->callback = ips_wakeup_callback;
2342eea7051SScott Long error = bus_dmamap_load(command->data_dmatag, command->data_dmamap,
2352aedd662SScott Long command->data_buffer,IPS_ADAPTER_INFO_LEN,
2362eea7051SScott Long ips_adapter_info_callback, command,
2372eea7051SScott Long BUS_DMA_NOWAIT);
2382aedd662SScott Long
2392eea7051SScott Long if (error == 0)
2402aedd662SScott Long bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
2412aedd662SScott Long
2422aedd662SScott Long exit:
2432aedd662SScott Long /* I suppose I should clean up my memory allocations */
2442aedd662SScott Long bus_dmamem_free(command->data_dmatag, command->data_buffer,
2452aedd662SScott Long command->data_dmamap);
2462aedd662SScott Long bus_dma_tag_destroy(command->data_dmatag);
2472aedd662SScott Long ips_insert_free_cmd(sc, command);
2482aedd662SScott Long return error;
2492aedd662SScott Long }
2502aedd662SScott Long
ips_get_adapter_info(ips_softc_t * sc)2512aedd662SScott Long int ips_get_adapter_info(ips_softc_t *sc)
2522aedd662SScott Long {
25303a908f2SScott Long ips_command_t *command;
2542aedd662SScott Long int error = 0;
25503a908f2SScott Long
25603a908f2SScott Long if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) > 0){
2572aedd662SScott Long device_printf(sc->dev, "unable to get adapter configuration\n");
2582aedd662SScott Long return ENXIO;
2592aedd662SScott Long }
26003a908f2SScott Long ips_send_adapter_info_cmd(command);
2612eea7051SScott Long if (COMMAND_ERROR(command)){
2622aedd662SScott Long error = ENXIO;
2632aedd662SScott Long }
2642aedd662SScott Long return error;
2652aedd662SScott Long }
2662aedd662SScott Long
2672aedd662SScott Long /* Below are a series of functions for sending a drive info request
2682aedd662SScott Long * to the adapter. The flow order is: get, send, callback. It uses
2692aedd662SScott Long * the generic finish callback at the top of this file.
2702aedd662SScott Long * This can be used to get drive status info from the card */
ips_drive_info_callback(void * cmdptr,bus_dma_segment_t * segments,int segnum,int error)2712aedd662SScott Long static void ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
2722aedd662SScott Long {
2732aedd662SScott Long ips_softc_t *sc;
2742aedd662SScott Long ips_command_t *command = cmdptr;
2752aedd662SScott Long ips_drive_cmd *command_struct;
2762eea7051SScott Long ips_drive_info_t *driveinfo;
2772eea7051SScott Long
2782aedd662SScott Long sc = command->sc;
2792aedd662SScott Long if(error){
2802eea7051SScott Long ips_set_error(command, error);
2812aedd662SScott Long printf("ips: error = %d in ips_get_drive_info\n", error);
2822aedd662SScott Long return;
2832aedd662SScott Long }
2842aedd662SScott Long command_struct = (ips_drive_cmd *)command->command_buffer;
2852aedd662SScott Long command_struct->command = IPS_DRIVE_INFO_CMD;
2862aedd662SScott Long command_struct->id = command->id;
2872aedd662SScott Long command_struct->buffaddr = segments[0].ds_addr;
2882aedd662SScott Long
2892aedd662SScott Long bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
2902aedd662SScott Long BUS_DMASYNC_PREWRITE);
2912aedd662SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
2922aedd662SScott Long BUS_DMASYNC_PREREAD);
2932aedd662SScott Long sc->ips_issue_cmd(command);
2942eea7051SScott Long if (sema_timedwait(&sc->cmd_sema, 10*hz) != 0) {
2952eea7051SScott Long ips_set_error(command, ETIMEDOUT);
2962eea7051SScott Long return;
2972eea7051SScott Long }
2982eea7051SScott Long
2992eea7051SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
3002eea7051SScott Long BUS_DMASYNC_POSTREAD);
3012eea7051SScott Long driveinfo = command->data_buffer;
3022eea7051SScott Long memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8);
3032eea7051SScott Long sc->drivecount = driveinfo->drivecount;
3042eea7051SScott Long device_printf(sc->dev, "logical drives: %d\n",sc->drivecount);
3052aedd662SScott Long }
3062aedd662SScott Long
ips_send_drive_info_cmd(ips_command_t * command)3072aedd662SScott Long static int ips_send_drive_info_cmd(ips_command_t *command)
3082aedd662SScott Long {
3092aedd662SScott Long int error = 0;
3102aedd662SScott Long ips_softc_t *sc = command->sc;
3112aedd662SScott Long
3122aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag,
3132aedd662SScott Long /* alignemnt */ 1,
3142aedd662SScott Long /* boundary */ 0,
3152aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
3162aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR,
3172aedd662SScott Long /* filter */ NULL,
3182aedd662SScott Long /* filterarg */ NULL,
3192aedd662SScott Long /* maxsize */ IPS_DRIVE_INFO_LEN,
3202aedd662SScott Long /* numsegs */ 1,
3212aedd662SScott Long /* maxsegsize*/ IPS_DRIVE_INFO_LEN,
3222aedd662SScott Long /* flags */ 0,
32303a908f2SScott Long /* lockfunc */ NULL,
32403a908f2SScott Long /* lockarg */ NULL,
3252aedd662SScott Long &command->data_dmatag) != 0) {
3262aedd662SScott Long printf("ips: can't alloc dma tag for drive status\n");
3272aedd662SScott Long error = ENOMEM;
3282aedd662SScott Long goto exit;
3292aedd662SScott Long }
3302aedd662SScott Long if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
3312aedd662SScott Long BUS_DMA_NOWAIT, &command->data_dmamap)){
3322aedd662SScott Long error = ENOMEM;
3332aedd662SScott Long goto exit;
3342aedd662SScott Long }
3352aedd662SScott Long command->callback = ips_wakeup_callback;
3362eea7051SScott Long error = bus_dmamap_load(command->data_dmatag, command->data_dmamap,
3372aedd662SScott Long command->data_buffer,IPS_DRIVE_INFO_LEN,
3382eea7051SScott Long ips_drive_info_callback, command,
3392eea7051SScott Long BUS_DMA_NOWAIT);
3402eea7051SScott Long if (error == 0)
3412aedd662SScott Long bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
3422aedd662SScott Long
3432aedd662SScott Long exit:
3442aedd662SScott Long /* I suppose I should clean up my memory allocations */
3452aedd662SScott Long bus_dmamem_free(command->data_dmatag, command->data_buffer,
3462aedd662SScott Long command->data_dmamap);
3472aedd662SScott Long bus_dma_tag_destroy(command->data_dmatag);
3482aedd662SScott Long ips_insert_free_cmd(sc, command);
3492aedd662SScott Long return error;
3502aedd662SScott Long
3512aedd662SScott Long }
ips_get_drive_info(ips_softc_t * sc)3522aedd662SScott Long int ips_get_drive_info(ips_softc_t *sc)
3532aedd662SScott Long {
3542aedd662SScott Long int error = 0;
35503a908f2SScott Long ips_command_t *command;
35603a908f2SScott Long
35703a908f2SScott Long if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) > 0){
3582aedd662SScott Long device_printf(sc->dev, "unable to get drive configuration\n");
3592aedd662SScott Long return ENXIO;
3602aedd662SScott Long }
36103a908f2SScott Long ips_send_drive_info_cmd(command);
3622eea7051SScott Long if(COMMAND_ERROR(command)){
3632aedd662SScott Long error = ENXIO;
3642aedd662SScott Long }
3652aedd662SScott Long return error;
3662aedd662SScott Long }
3672aedd662SScott Long
3682aedd662SScott Long /* Below is a pair of functions for making sure data is safely
3692aedd662SScott Long * on disk by flushing the adapter's cache. */
ips_send_flush_cache_cmd(ips_command_t * command)3702aedd662SScott Long static int ips_send_flush_cache_cmd(ips_command_t *command)
3712aedd662SScott Long {
3722aedd662SScott Long ips_softc_t *sc = command->sc;
3732aedd662SScott Long ips_generic_cmd *command_struct;
3742aedd662SScott Long
3752aedd662SScott Long PRINTF(10,"ips test: got a command, building flush command\n");
3762aedd662SScott Long command->callback = ips_wakeup_callback;
3772aedd662SScott Long command_struct = (ips_generic_cmd *)command->command_buffer;
3782aedd662SScott Long command_struct->command = IPS_CACHE_FLUSH_CMD;
3792aedd662SScott Long command_struct->id = command->id;
3802aedd662SScott Long bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
3812aedd662SScott Long BUS_DMASYNC_PREWRITE);
3822aedd662SScott Long sc->ips_issue_cmd(command);
3832eea7051SScott Long if (COMMAND_ERROR(command) == 0)
38403a908f2SScott Long sema_wait(&sc->cmd_sema);
3852aedd662SScott Long ips_insert_free_cmd(sc, command);
3862aedd662SScott Long return 0;
3872aedd662SScott Long }
3882aedd662SScott Long
ips_flush_cache(ips_softc_t * sc)3892aedd662SScott Long int ips_flush_cache(ips_softc_t *sc)
3902aedd662SScott Long {
39103a908f2SScott Long ips_command_t *command;
39203a908f2SScott Long
3932aedd662SScott Long device_printf(sc->dev, "flushing cache\n");
39403a908f2SScott Long if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){
3952aedd662SScott Long device_printf(sc->dev, "ERROR: unable to get a command! can't flush cache!\n");
3962aedd662SScott Long }
39703a908f2SScott Long ips_send_flush_cache_cmd(command);
3982eea7051SScott Long if(COMMAND_ERROR(command)){
3992aedd662SScott Long device_printf(sc->dev, "ERROR: cache flush command failed!\n");
4002aedd662SScott Long }
4012aedd662SScott Long return 0;
4022aedd662SScott Long }
4032aedd662SScott Long
4047633e7f1SMartin Blapp /* Simplified localtime to provide timevalues for ffdc.
4057633e7f1SMartin Blapp * Taken from libc/stdtime/localtime.c
4067633e7f1SMartin Blapp */
ips_ffdc_settime(ips_adapter_ffdc_cmd * command,time_t sctime)4077633e7f1SMartin Blapp void static ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime)
4087633e7f1SMartin Blapp {
4097633e7f1SMartin Blapp long days, rem, y;
4107633e7f1SMartin Blapp int yleap, *ip, month;
4117633e7f1SMartin Blapp int year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR };
4127633e7f1SMartin Blapp int mon_lengths[2][IPS_MONSPERYEAR] = {
4137633e7f1SMartin Blapp { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
4147633e7f1SMartin Blapp { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
4157633e7f1SMartin Blapp };
4167633e7f1SMartin Blapp
4177633e7f1SMartin Blapp days = sctime / IPS_SECSPERDAY;
4187633e7f1SMartin Blapp rem = sctime % IPS_SECSPERDAY;
4197633e7f1SMartin Blapp
4207633e7f1SMartin Blapp command->hour = rem / IPS_SECSPERHOUR;
4217633e7f1SMartin Blapp rem = rem % IPS_SECSPERHOUR;
4227633e7f1SMartin Blapp
4237633e7f1SMartin Blapp command->minute = rem / IPS_SECSPERMIN;
4247633e7f1SMartin Blapp command->second = rem % IPS_SECSPERMIN;
4257633e7f1SMartin Blapp
4267633e7f1SMartin Blapp y = IPS_EPOCH_YEAR;
4277633e7f1SMartin Blapp while (days < 0 || days >= (long) year_lengths[yleap = ips_isleap(y)]) {
4287633e7f1SMartin Blapp long newy;
4297633e7f1SMartin Blapp
4307633e7f1SMartin Blapp newy = y + days / IPS_DAYSPERNYEAR;
4317633e7f1SMartin Blapp if (days < 0)
4327633e7f1SMartin Blapp --newy;
4337633e7f1SMartin Blapp days -= (newy - y) * IPS_DAYSPERNYEAR +
4347633e7f1SMartin Blapp IPS_LEAPS_THRU_END_OF(newy - 1) -
4357633e7f1SMartin Blapp IPS_LEAPS_THRU_END_OF(y - 1);
4367633e7f1SMartin Blapp y = newy;
4377633e7f1SMartin Blapp }
4387633e7f1SMartin Blapp command->yearH = y / 100;
4397633e7f1SMartin Blapp command->yearL = y % 100;
4407633e7f1SMartin Blapp ip = mon_lengths[yleap];
4417633e7f1SMartin Blapp for(month = 0; days >= (long) ip[month]; ++month)
4427633e7f1SMartin Blapp days = days - (long) ip[month];
4437633e7f1SMartin Blapp command->month = month + 1;
4447633e7f1SMartin Blapp command->day = days + 1;
4457633e7f1SMartin Blapp }
4467633e7f1SMartin Blapp
ips_send_ffdc_reset_cmd(ips_command_t * command)4477633e7f1SMartin Blapp static int ips_send_ffdc_reset_cmd(ips_command_t *command)
4487633e7f1SMartin Blapp {
4497633e7f1SMartin Blapp ips_softc_t *sc = command->sc;
4507633e7f1SMartin Blapp ips_adapter_ffdc_cmd *command_struct;
4517633e7f1SMartin Blapp
4527633e7f1SMartin Blapp PRINTF(10,"ips test: got a command, building ffdc reset command\n");
4537633e7f1SMartin Blapp command->callback = ips_wakeup_callback;
4547633e7f1SMartin Blapp command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer;
4557633e7f1SMartin Blapp command_struct->command = IPS_FFDC_CMD;
4567633e7f1SMartin Blapp command_struct->id = command->id;
4577633e7f1SMartin Blapp command_struct->reset_count = sc->ffdc_resetcount;
458aa8689efSMartin Blapp command_struct->reset_type = 0x0;
4597633e7f1SMartin Blapp ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec);
4607633e7f1SMartin Blapp
4617633e7f1SMartin Blapp bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
4627633e7f1SMartin Blapp BUS_DMASYNC_PREWRITE);
4637633e7f1SMartin Blapp sc->ips_issue_cmd(command);
4642eea7051SScott Long if (COMMAND_ERROR(command) == 0)
46503a908f2SScott Long sema_wait(&sc->cmd_sema);
4667633e7f1SMartin Blapp ips_insert_free_cmd(sc, command);
4677633e7f1SMartin Blapp return 0;
4687633e7f1SMartin Blapp }
4697633e7f1SMartin Blapp
ips_ffdc_reset(ips_softc_t * sc)4707633e7f1SMartin Blapp int ips_ffdc_reset(ips_softc_t *sc)
4717633e7f1SMartin Blapp {
47203a908f2SScott Long ips_command_t *command;
47303a908f2SScott Long
47403a908f2SScott Long if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){
4757633e7f1SMartin Blapp device_printf(sc->dev, "ERROR: unable to get a command! can't send ffdc reset!\n");
4767633e7f1SMartin Blapp }
47703a908f2SScott Long ips_send_ffdc_reset_cmd(command);
4782eea7051SScott Long if(COMMAND_ERROR(command)){
4797633e7f1SMartin Blapp device_printf(sc->dev, "ERROR: ffdc reset command failed!\n");
4807633e7f1SMartin Blapp }
4817633e7f1SMartin Blapp return 0;
4827633e7f1SMartin Blapp }
4837633e7f1SMartin Blapp
ips_write_nvram(ips_command_t * command)4842aedd662SScott Long static void ips_write_nvram(ips_command_t *command){
4852aedd662SScott Long ips_softc_t *sc = command->sc;
4862aedd662SScott Long ips_rw_nvram_cmd *command_struct;
4872aedd662SScott Long ips_nvram_page5 *nvram;
4882aedd662SScott Long
4892aedd662SScott Long /*FIXME check for error */
4902aedd662SScott Long command->callback = ips_wakeup_callback;
4912aedd662SScott Long command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
4922aedd662SScott Long command_struct->command = IPS_RW_NVRAM_CMD;
4932aedd662SScott Long command_struct->id = command->id;
4942aedd662SScott Long command_struct->pagenum = 5;
4952aedd662SScott Long command_struct->rw = 1; /*write*/
4962aedd662SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
4972aedd662SScott Long BUS_DMASYNC_POSTREAD);
4982aedd662SScott Long nvram = command->data_buffer;
4997633e7f1SMartin Blapp /* retrieve adapter info and save in sc */
5007633e7f1SMartin Blapp sc->adapter_type = nvram->adapter_type;
5017633e7f1SMartin Blapp
5022aedd662SScott Long strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4);
5032aedd662SScott Long strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4);
5042aedd662SScott Long nvram->operating_system = IPS_OS_FREEBSD;
5052aedd662SScott Long bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
5062aedd662SScott Long BUS_DMASYNC_PREWRITE);
5072aedd662SScott Long sc->ips_issue_cmd(command);
5082aedd662SScott Long }
5092aedd662SScott Long
ips_read_nvram_callback(void * cmdptr,bus_dma_segment_t * segments,int segnum,int error)5102aedd662SScott Long static void ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
5112aedd662SScott Long {
5122aedd662SScott Long ips_softc_t *sc;
5132aedd662SScott Long ips_command_t *command = cmdptr;
5142aedd662SScott Long ips_rw_nvram_cmd *command_struct;
5152aedd662SScott Long sc = command->sc;
5162aedd662SScott Long if(error){
5172eea7051SScott Long ips_set_error(command, error);
5182aedd662SScott Long printf("ips: error = %d in ips_read_nvram_callback\n", error);
5192aedd662SScott Long return;
5202aedd662SScott Long }
5212aedd662SScott Long command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
5222aedd662SScott Long command_struct->command = IPS_RW_NVRAM_CMD;
5232aedd662SScott Long command_struct->id = command->id;
5242aedd662SScott Long command_struct->pagenum = 5;
5252aedd662SScott Long command_struct->rw = 0;
5262aedd662SScott Long command_struct->buffaddr = segments[0].ds_addr;
5272aedd662SScott Long
5282aedd662SScott Long bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
5292aedd662SScott Long BUS_DMASYNC_PREWRITE);
5302aedd662SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
5312aedd662SScott Long BUS_DMASYNC_PREREAD);
5322aedd662SScott Long sc->ips_issue_cmd(command);
5332eea7051SScott Long if (sema_timedwait(&sc->cmd_sema, 30*hz) != 0) {
5342eea7051SScott Long ips_set_error(command, ETIMEDOUT);
5352eea7051SScott Long return;
5362eea7051SScott Long }
5372eea7051SScott Long bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
5382eea7051SScott Long BUS_DMASYNC_POSTWRITE);
5392aedd662SScott Long }
5402aedd662SScott Long
ips_read_nvram(ips_command_t * command)54103a908f2SScott Long static int ips_read_nvram(ips_command_t *command)
54203a908f2SScott Long {
5432aedd662SScott Long int error = 0;
5442aedd662SScott Long ips_softc_t *sc = command->sc;
5452aedd662SScott Long
5462aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag,
5472aedd662SScott Long /* alignemnt */ 1,
5482aedd662SScott Long /* boundary */ 0,
5492aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
5502aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR,
5512aedd662SScott Long /* filter */ NULL,
5522aedd662SScott Long /* filterarg */ NULL,
5532aedd662SScott Long /* maxsize */ IPS_NVRAM_PAGE_SIZE,
5542aedd662SScott Long /* numsegs */ 1,
5552aedd662SScott Long /* maxsegsize*/ IPS_NVRAM_PAGE_SIZE,
5562aedd662SScott Long /* flags */ 0,
55703a908f2SScott Long /* lockfunc */ NULL,
55803a908f2SScott Long /* lockarg */ NULL,
5592aedd662SScott Long &command->data_dmatag) != 0) {
5602aedd662SScott Long printf("ips: can't alloc dma tag for nvram\n");
5612aedd662SScott Long error = ENOMEM;
5622aedd662SScott Long goto exit;
5632aedd662SScott Long }
5642aedd662SScott Long if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
5652aedd662SScott Long BUS_DMA_NOWAIT, &command->data_dmamap)){
5662aedd662SScott Long error = ENOMEM;
5672aedd662SScott Long goto exit;
5682aedd662SScott Long }
5692aedd662SScott Long command->callback = ips_write_nvram;
5702eea7051SScott Long error = bus_dmamap_load(command->data_dmatag, command->data_dmamap,
5712aedd662SScott Long command->data_buffer,IPS_NVRAM_PAGE_SIZE,
5722eea7051SScott Long ips_read_nvram_callback, command,
5732eea7051SScott Long BUS_DMA_NOWAIT);
5742eea7051SScott Long if (error == 0)
5752aedd662SScott Long bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
5762aedd662SScott Long
5772aedd662SScott Long exit:
5782aedd662SScott Long bus_dmamem_free(command->data_dmatag, command->data_buffer,
5792aedd662SScott Long command->data_dmamap);
5802aedd662SScott Long bus_dma_tag_destroy(command->data_dmatag);
5812aedd662SScott Long ips_insert_free_cmd(sc, command);
5822aedd662SScott Long return error;
5832aedd662SScott Long }
5842aedd662SScott Long
ips_update_nvram(ips_softc_t * sc)5852aedd662SScott Long int ips_update_nvram(ips_softc_t *sc)
5862aedd662SScott Long {
58703a908f2SScott Long ips_command_t *command;
58803a908f2SScott Long
58903a908f2SScott Long if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){
5902aedd662SScott Long device_printf(sc->dev, "ERROR: unable to get a command! can't update nvram\n");
5912aedd662SScott Long return 1;
5922aedd662SScott Long }
59303a908f2SScott Long ips_read_nvram(command);
5942eea7051SScott Long if(COMMAND_ERROR(command)){
5952aedd662SScott Long device_printf(sc->dev, "ERROR: nvram update command failed!\n");
5962aedd662SScott Long }
5972aedd662SScott Long return 0;
5982aedd662SScott Long
5992aedd662SScott Long
6002aedd662SScott Long }
6012aedd662SScott Long
6022aedd662SScott Long
ips_send_config_sync_cmd(ips_command_t * command)6032aedd662SScott Long static int ips_send_config_sync_cmd(ips_command_t *command)
6042aedd662SScott Long {
6052aedd662SScott Long ips_softc_t *sc = command->sc;
6062aedd662SScott Long ips_generic_cmd *command_struct;
6072aedd662SScott Long
6082aedd662SScott Long PRINTF(10,"ips test: got a command, building flush command\n");
6092aedd662SScott Long command->callback = ips_wakeup_callback;
6102aedd662SScott Long command_struct = (ips_generic_cmd *)command->command_buffer;
6112aedd662SScott Long command_struct->command = IPS_CONFIG_SYNC_CMD;
6122aedd662SScott Long command_struct->id = command->id;
6132aedd662SScott Long command_struct->reserve2 = IPS_POCL;
6142aedd662SScott Long bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
6152aedd662SScott Long BUS_DMASYNC_PREWRITE);
6162aedd662SScott Long sc->ips_issue_cmd(command);
6172eea7051SScott Long if (COMMAND_ERROR(command) == 0)
61803a908f2SScott Long sema_wait(&sc->cmd_sema);
6192aedd662SScott Long ips_insert_free_cmd(sc, command);
6202aedd662SScott Long return 0;
6212aedd662SScott Long }
6222aedd662SScott Long
ips_send_error_table_cmd(ips_command_t * command)6232aedd662SScott Long static int ips_send_error_table_cmd(ips_command_t *command)
6242aedd662SScott Long {
6252aedd662SScott Long ips_softc_t *sc = command->sc;
6262aedd662SScott Long ips_generic_cmd *command_struct;
6272aedd662SScott Long
6282aedd662SScott Long PRINTF(10,"ips test: got a command, building errortable command\n");
6292aedd662SScott Long command->callback = ips_wakeup_callback;
6302aedd662SScott Long command_struct = (ips_generic_cmd *)command->command_buffer;
6312aedd662SScott Long command_struct->command = IPS_ERROR_TABLE_CMD;
6322aedd662SScott Long command_struct->id = command->id;
6332aedd662SScott Long command_struct->reserve2 = IPS_CSL;
6342aedd662SScott Long bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
6352aedd662SScott Long BUS_DMASYNC_PREWRITE);
6362aedd662SScott Long sc->ips_issue_cmd(command);
6372eea7051SScott Long if (COMMAND_ERROR(command) == 0)
63803a908f2SScott Long sema_wait(&sc->cmd_sema);
6392aedd662SScott Long ips_insert_free_cmd(sc, command);
6402aedd662SScott Long return 0;
6412aedd662SScott Long }
6422aedd662SScott Long
6432aedd662SScott Long
ips_clear_adapter(ips_softc_t * sc)6442aedd662SScott Long int ips_clear_adapter(ips_softc_t *sc)
6452aedd662SScott Long {
64603a908f2SScott Long ips_command_t *command;
64703a908f2SScott Long
6482aedd662SScott Long device_printf(sc->dev, "syncing config\n");
64903a908f2SScott Long if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){
6502aedd662SScott Long device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n");
6512aedd662SScott Long return 1;
6522aedd662SScott Long }
65303a908f2SScott Long ips_send_config_sync_cmd(command);
6542eea7051SScott Long if(COMMAND_ERROR(command)){
6552aedd662SScott Long device_printf(sc->dev, "ERROR: cache sync command failed!\n");
6562aedd662SScott Long return 1;
6572aedd662SScott Long }
6582aedd662SScott Long
6592aedd662SScott Long device_printf(sc->dev, "clearing error table\n");
66003a908f2SScott Long if(ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){
6612aedd662SScott Long device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n");
6622aedd662SScott Long return 1;
6632aedd662SScott Long }
66403a908f2SScott Long ips_send_error_table_cmd(command);
6652eea7051SScott Long if(COMMAND_ERROR(command)){
6662aedd662SScott Long device_printf(sc->dev, "ERROR: etable command failed!\n");
6672aedd662SScott Long return 1;
6682aedd662SScott Long }
6692aedd662SScott Long
6702aedd662SScott Long return 0;
6712aedd662SScott Long }
672