1114902Sscottl/*- 2119418Sobrien * Written by: David Jeffery 3114902Sscottl * Copyright (c) 2002 Adaptec Inc. 4114902Sscottl * All rights reserved. 5114902Sscottl * 6114902Sscottl * Redistribution and use in source and binary forms, with or without 7114902Sscottl * modification, are permitted provided that the following conditions 8114902Sscottl * are met: 9114902Sscottl * 1. Redistributions of source code must retain the above copyright 10114902Sscottl * notice, this list of conditions and the following disclaimer. 11114902Sscottl * 2. Redistributions in binary form must reproduce the above copyright 12114902Sscottl * notice, this list of conditions and the following disclaimer in the 13114902Sscottl * documentation and/or other materials provided with the distribution. 14114902Sscottl * 15114902Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16114902Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17114902Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18114902Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19114902Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20114902Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21114902Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22114902Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23114902Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24114902Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25114902Sscottl * SUCH DAMAGE. 26114902Sscottl */ 27114902Sscottl 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD$"); 30114902Sscottl 31152919Sscottl#include <dev/ips/ipsreg.h> 32114902Sscottl#include <dev/ips/ips.h> 33114902Sscottl 34114902Sscottl/* 35114902Sscottl * This is an interrupt callback. It is called from 36114902Sscottl * interrupt context when the adapter has completed the 37114902Sscottl * command. This very generic callback simply stores 38114902Sscottl * the command's return value in command->arg and wake's 39114902Sscottl * up anyone waiting on the command. 40114902Sscottl */ 41114902Sscottlstatic void ips_wakeup_callback(ips_command_t *command) 42114902Sscottl{ 43114902Sscottl bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap, 44114902Sscottl BUS_DMASYNC_POSTWRITE); 45140923Sscottl sema_post(&command->sc->cmd_sema); 46114902Sscottl} 47114902Sscottl/* Below are a series of functions for sending an IO request 48114902Sscottl * to the adapter. The flow order is: start, send, callback, finish. 49114902Sscottl * The caller must have already assembled an iorequest struct to hold 50114902Sscottl * the details of the IO request. */ 51114902Sscottlstatic void ips_io_request_finish(ips_command_t *command) 52114902Sscottl{ 53114902Sscottl 54114902Sscottl struct bio *iobuf = command->arg; 55114902Sscottl if(ips_read_request(iobuf)) { 56114902Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 57114902Sscottl BUS_DMASYNC_POSTREAD); 58114902Sscottl } else { 59114902Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 60114902Sscottl BUS_DMASYNC_POSTWRITE); 61114902Sscottl } 62114902Sscottl bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 63150535Sscottl if(COMMAND_ERROR(command)){ 64114902Sscottl iobuf->bio_flags |=BIO_ERROR; 65114902Sscottl iobuf->bio_error = EIO; 66150611Sglebius printf("ips: io error, status= 0x%x\n", command->status.value); 67114902Sscottl } 68114902Sscottl ips_insert_free_cmd(command->sc, command); 69114902Sscottl ipsd_finish(iobuf); 70114902Sscottl} 71114902Sscottl 72114902Sscottlstatic void ips_io_request_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 73114902Sscottl{ 74114902Sscottl ips_softc_t *sc; 75114902Sscottl ips_command_t *command = cmdptr; 76114902Sscottl ips_sg_element_t *sg_list; 77114902Sscottl ips_io_cmd *command_struct; 78114902Sscottl struct bio *iobuf = command->arg; 79114902Sscottl int i, length = 0; 80114902Sscottl u_int8_t cmdtype; 81114902Sscottl 82114902Sscottl sc = command->sc; 83114902Sscottl if(error){ 84114902Sscottl printf("ips: error = %d in ips_sg_request_callback\n", error); 85114902Sscottl bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 86114902Sscottl iobuf->bio_flags |= BIO_ERROR; 87114902Sscottl iobuf->bio_error = ENOMEM; 88114902Sscottl ips_insert_free_cmd(sc, command); 89114902Sscottl ipsd_finish(iobuf); 90114902Sscottl return; 91114902Sscottl } 92114902Sscottl command_struct = (ips_io_cmd *)command->command_buffer; 93114902Sscottl command_struct->id = command->id; 94116931Speter command_struct->drivenum = (uintptr_t)iobuf->bio_driver1; 95114902Sscottl if(segnum != 1){ 96114902Sscottl if(ips_read_request(iobuf)) 97114902Sscottl cmdtype = IPS_SG_READ_CMD; 98114902Sscottl else 99114902Sscottl cmdtype = IPS_SG_WRITE_CMD; 100114902Sscottl command_struct->segnum = segnum; 101114902Sscottl sg_list = (ips_sg_element_t *)((u_int8_t *) 102114902Sscottl command->command_buffer + IPS_COMMAND_LEN); 103114902Sscottl for(i = 0; i < segnum; i++){ 104114902Sscottl sg_list[i].addr = segments[i].ds_addr; 105114902Sscottl sg_list[i].len = segments[i].ds_len; 106114902Sscottl length += segments[i].ds_len; 107114902Sscottl } 108114902Sscottl command_struct->buffaddr = 109114902Sscottl (u_int32_t)command->command_phys_addr + IPS_COMMAND_LEN; 110114902Sscottl } else { 111114902Sscottl if(ips_read_request(iobuf)) 112114902Sscottl cmdtype = IPS_READ_CMD; 113114902Sscottl else 114114902Sscottl cmdtype = IPS_WRITE_CMD; 115114902Sscottl command_struct->buffaddr = segments[0].ds_addr; 116114902Sscottl length = segments[0].ds_len; 117114902Sscottl } 118114902Sscottl command_struct->command = cmdtype; 119114902Sscottl command_struct->lba = iobuf->bio_pblkno; 120114902Sscottl length = (length + IPS_BLKSIZE - 1)/IPS_BLKSIZE; 121114902Sscottl command_struct->length = length; 122114902Sscottl bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 123114902Sscottl BUS_DMASYNC_PREWRITE); 124114902Sscottl if(ips_read_request(iobuf)) { 125114902Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 126114902Sscottl BUS_DMASYNC_PREREAD); 127114902Sscottl } else { 128114902Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 129114902Sscottl BUS_DMASYNC_PREWRITE); 130114902Sscottl } 131121211Sphk PRINTF(10, "ips test: command id: %d segments: %d " 132114902Sscottl "pblkno: %lld length: %d, ds_len: %d\n", command->id, segnum, 133121211Sphk iobuf->bio_pblkno, 134114902Sscottl length, segments[0].ds_len); 135114902Sscottl 136114902Sscottl sc->ips_issue_cmd(command); 137114902Sscottl return; 138114902Sscottl} 139114902Sscottl 140140923Sscottlstatic int ips_send_io_request(ips_command_t *command, struct bio *iobuf) 141114902Sscottl{ 142114902Sscottl command->callback = ips_io_request_finish; 143140923Sscottl command->arg = iobuf; 144114902Sscottl PRINTF(10, "ips test: : bcount %ld\n", iobuf->bio_bcount); 145114902Sscottl bus_dmamap_load(command->data_dmatag, command->data_dmamap, 146114902Sscottl iobuf->bio_data, iobuf->bio_bcount, 147114902Sscottl ips_io_request_callback, command, 0); 148114902Sscottl return 0; 149114902Sscottl} 150114902Sscottl 151126364Sscottlvoid ips_start_io_request(ips_softc_t *sc) 152114902Sscottl{ 153126364Sscottl struct bio *iobuf; 154140923Sscottl ips_command_t *command; 155126364Sscottl 156126364Sscottl iobuf = bioq_first(&sc->queue); 157140923Sscottl if(!iobuf) 158114902Sscottl return; 159126364Sscottl 160140923Sscottl if (ips_get_free_cmd(sc, &command, 0)) 161126364Sscottl return; 162126364Sscottl 163126364Sscottl bioq_remove(&sc->queue, iobuf); 164140923Sscottl ips_send_io_request(command, iobuf); 165114902Sscottl return; 166114902Sscottl} 167114902Sscottl 168114902Sscottl/* Below are a series of functions for sending an adapter info request 169114902Sscottl * to the adapter. The flow order is: get, send, callback. It uses 170114902Sscottl * the generic finish callback at the top of this file. 171114902Sscottl * This can be used to get configuration/status info from the card */ 172114902Sscottlstatic void ips_adapter_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 173114902Sscottl{ 174114902Sscottl ips_softc_t *sc; 175114902Sscottl ips_command_t *command = cmdptr; 176114902Sscottl ips_adapter_info_cmd *command_struct; 177114902Sscottl sc = command->sc; 178114902Sscottl if(error){ 179150535Sscottl ips_set_error(command, error); 180114902Sscottl printf("ips: error = %d in ips_get_adapter_info\n", error); 181114902Sscottl return; 182114902Sscottl } 183114902Sscottl command_struct = (ips_adapter_info_cmd *)command->command_buffer; 184114902Sscottl command_struct->command = IPS_ADAPTER_INFO_CMD; 185114902Sscottl command_struct->id = command->id; 186114902Sscottl command_struct->buffaddr = segments[0].ds_addr; 187114902Sscottl 188114902Sscottl bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 189114902Sscottl BUS_DMASYNC_PREWRITE); 190114902Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 191114902Sscottl BUS_DMASYNC_PREREAD); 192114902Sscottl sc->ips_issue_cmd(command); 193150535Sscottl if (sema_timedwait(&sc->cmd_sema, 30*hz) != 0) { 194150535Sscottl ips_set_error(command, ETIMEDOUT); 195150535Sscottl return; 196150535Sscottl } 197150535Sscottl 198150535Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 199150535Sscottl BUS_DMASYNC_POSTREAD); 200150535Sscottl memcpy(&(sc->adapter_info), command->data_buffer, IPS_ADAPTER_INFO_LEN); 201114902Sscottl} 202114902Sscottl 203114902Sscottl 204114902Sscottl 205114902Sscottlstatic int ips_send_adapter_info_cmd(ips_command_t *command) 206114902Sscottl{ 207114902Sscottl int error = 0; 208114902Sscottl ips_softc_t *sc = command->sc; 209114902Sscottl 210114902Sscottl if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 211114902Sscottl /* alignemnt */ 1, 212114902Sscottl /* boundary */ 0, 213114902Sscottl /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 214114902Sscottl /* highaddr */ BUS_SPACE_MAXADDR, 215114902Sscottl /* filter */ NULL, 216114902Sscottl /* filterarg */ NULL, 217114902Sscottl /* maxsize */ IPS_ADAPTER_INFO_LEN, 218114902Sscottl /* numsegs */ 1, 219114902Sscottl /* maxsegsize*/ IPS_ADAPTER_INFO_LEN, 220114902Sscottl /* flags */ 0, 221140923Sscottl /* lockfunc */ NULL, 222140923Sscottl /* lockarg */ NULL, 223114902Sscottl &command->data_dmatag) != 0) { 224114902Sscottl printf("ips: can't alloc dma tag for adapter status\n"); 225114902Sscottl error = ENOMEM; 226114902Sscottl goto exit; 227114902Sscottl } 228114902Sscottl if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, 229114902Sscottl BUS_DMA_NOWAIT, &command->data_dmamap)){ 230114902Sscottl error = ENOMEM; 231114902Sscottl goto exit; 232114902Sscottl } 233114902Sscottl command->callback = ips_wakeup_callback; 234150535Sscottl error = bus_dmamap_load(command->data_dmatag, command->data_dmamap, 235150535Sscottl command->data_buffer,IPS_ADAPTER_INFO_LEN, 236150535Sscottl ips_adapter_info_callback, command, 237150535Sscottl BUS_DMA_NOWAIT); 238114902Sscottl 239150535Sscottl if (error == 0) 240150535Sscottl bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 241114902Sscottl 242114902Sscottlexit: 243114902Sscottl /* I suppose I should clean up my memory allocations */ 244114902Sscottl bus_dmamem_free(command->data_dmatag, command->data_buffer, 245114902Sscottl command->data_dmamap); 246114902Sscottl bus_dma_tag_destroy(command->data_dmatag); 247114902Sscottl ips_insert_free_cmd(sc, command); 248114902Sscottl return error; 249114902Sscottl} 250114902Sscottl 251114902Sscottlint ips_get_adapter_info(ips_softc_t *sc) 252114902Sscottl{ 253140923Sscottl ips_command_t *command; 254114902Sscottl int error = 0; 255140923Sscottl 256140923Sscottl if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) > 0){ 257114902Sscottl device_printf(sc->dev, "unable to get adapter configuration\n"); 258114902Sscottl return ENXIO; 259114902Sscottl } 260140923Sscottl ips_send_adapter_info_cmd(command); 261150535Sscottl if (COMMAND_ERROR(command)){ 262114902Sscottl error = ENXIO; 263114902Sscottl } 264114902Sscottl return error; 265114902Sscottl} 266114902Sscottl 267114902Sscottl/* Below are a series of functions for sending a drive info request 268114902Sscottl * to the adapter. The flow order is: get, send, callback. It uses 269114902Sscottl * the generic finish callback at the top of this file. 270114902Sscottl * This can be used to get drive status info from the card */ 271114902Sscottlstatic void ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 272114902Sscottl{ 273114902Sscottl ips_softc_t *sc; 274114902Sscottl ips_command_t *command = cmdptr; 275114902Sscottl ips_drive_cmd *command_struct; 276150535Sscottl ips_drive_info_t *driveinfo; 277150535Sscottl 278114902Sscottl sc = command->sc; 279114902Sscottl if(error){ 280150535Sscottl ips_set_error(command, error); 281114902Sscottl printf("ips: error = %d in ips_get_drive_info\n", error); 282114902Sscottl return; 283114902Sscottl } 284114902Sscottl command_struct = (ips_drive_cmd *)command->command_buffer; 285114902Sscottl command_struct->command = IPS_DRIVE_INFO_CMD; 286114902Sscottl command_struct->id = command->id; 287114902Sscottl command_struct->buffaddr = segments[0].ds_addr; 288114902Sscottl 289114902Sscottl bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 290114902Sscottl BUS_DMASYNC_PREWRITE); 291114902Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 292114902Sscottl BUS_DMASYNC_PREREAD); 293114902Sscottl sc->ips_issue_cmd(command); 294150535Sscottl if (sema_timedwait(&sc->cmd_sema, 10*hz) != 0) { 295150535Sscottl ips_set_error(command, ETIMEDOUT); 296150535Sscottl return; 297150535Sscottl } 298150535Sscottl 299150535Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 300150535Sscottl BUS_DMASYNC_POSTREAD); 301150535Sscottl driveinfo = command->data_buffer; 302150535Sscottl memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8); 303150535Sscottl sc->drivecount = driveinfo->drivecount; 304150535Sscottl device_printf(sc->dev, "logical drives: %d\n",sc->drivecount); 305114902Sscottl} 306114902Sscottl 307114902Sscottlstatic int ips_send_drive_info_cmd(ips_command_t *command) 308114902Sscottl{ 309114902Sscottl int error = 0; 310114902Sscottl ips_softc_t *sc = command->sc; 311114902Sscottl 312114902Sscottl if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 313114902Sscottl /* alignemnt */ 1, 314114902Sscottl /* boundary */ 0, 315114902Sscottl /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 316114902Sscottl /* highaddr */ BUS_SPACE_MAXADDR, 317114902Sscottl /* filter */ NULL, 318114902Sscottl /* filterarg */ NULL, 319114902Sscottl /* maxsize */ IPS_DRIVE_INFO_LEN, 320114902Sscottl /* numsegs */ 1, 321114902Sscottl /* maxsegsize*/ IPS_DRIVE_INFO_LEN, 322114902Sscottl /* flags */ 0, 323140923Sscottl /* lockfunc */ NULL, 324140923Sscottl /* lockarg */ NULL, 325114902Sscottl &command->data_dmatag) != 0) { 326114902Sscottl printf("ips: can't alloc dma tag for drive status\n"); 327114902Sscottl error = ENOMEM; 328114902Sscottl goto exit; 329114902Sscottl } 330114902Sscottl if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, 331114902Sscottl BUS_DMA_NOWAIT, &command->data_dmamap)){ 332114902Sscottl error = ENOMEM; 333114902Sscottl goto exit; 334114902Sscottl } 335114902Sscottl command->callback = ips_wakeup_callback; 336150535Sscottl error = bus_dmamap_load(command->data_dmatag, command->data_dmamap, 337150535Sscottl command->data_buffer,IPS_DRIVE_INFO_LEN, 338150535Sscottl ips_drive_info_callback, command, 339150535Sscottl BUS_DMA_NOWAIT); 340150535Sscottl if (error == 0) 341150535Sscottl bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 342114902Sscottl 343114902Sscottlexit: 344114902Sscottl /* I suppose I should clean up my memory allocations */ 345114902Sscottl bus_dmamem_free(command->data_dmatag, command->data_buffer, 346114902Sscottl command->data_dmamap); 347114902Sscottl bus_dma_tag_destroy(command->data_dmatag); 348114902Sscottl ips_insert_free_cmd(sc, command); 349114902Sscottl return error; 350114902Sscottl 351114902Sscottl} 352114902Sscottlint ips_get_drive_info(ips_softc_t *sc) 353114902Sscottl{ 354114902Sscottl int error = 0; 355140923Sscottl ips_command_t *command; 356140923Sscottl 357140923Sscottl if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) > 0){ 358114902Sscottl device_printf(sc->dev, "unable to get drive configuration\n"); 359114902Sscottl return ENXIO; 360114902Sscottl } 361140923Sscottl ips_send_drive_info_cmd(command); 362150535Sscottl if(COMMAND_ERROR(command)){ 363114902Sscottl error = ENXIO; 364114902Sscottl } 365114902Sscottl return error; 366114902Sscottl} 367114902Sscottl 368114902Sscottl/* Below is a pair of functions for making sure data is safely 369114902Sscottl * on disk by flushing the adapter's cache. */ 370114902Sscottlstatic int ips_send_flush_cache_cmd(ips_command_t *command) 371114902Sscottl{ 372114902Sscottl ips_softc_t *sc = command->sc; 373114902Sscottl ips_generic_cmd *command_struct; 374114902Sscottl 375114902Sscottl PRINTF(10,"ips test: got a command, building flush command\n"); 376114902Sscottl command->callback = ips_wakeup_callback; 377114902Sscottl command_struct = (ips_generic_cmd *)command->command_buffer; 378114902Sscottl command_struct->command = IPS_CACHE_FLUSH_CMD; 379114902Sscottl command_struct->id = command->id; 380114902Sscottl bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 381114902Sscottl BUS_DMASYNC_PREWRITE); 382114902Sscottl sc->ips_issue_cmd(command); 383150535Sscottl if (COMMAND_ERROR(command) == 0) 384140923Sscottl sema_wait(&sc->cmd_sema); 385114902Sscottl ips_insert_free_cmd(sc, command); 386114902Sscottl return 0; 387114902Sscottl} 388114902Sscottl 389114902Sscottlint ips_flush_cache(ips_softc_t *sc) 390114902Sscottl{ 391140923Sscottl ips_command_t *command; 392140923Sscottl 393114902Sscottl device_printf(sc->dev, "flushing cache\n"); 394140923Sscottl if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){ 395114902Sscottl device_printf(sc->dev, "ERROR: unable to get a command! can't flush cache!\n"); 396114902Sscottl } 397140923Sscottl ips_send_flush_cache_cmd(command); 398150535Sscottl if(COMMAND_ERROR(command)){ 399114902Sscottl device_printf(sc->dev, "ERROR: cache flush command failed!\n"); 400114902Sscottl } 401114902Sscottl return 0; 402114902Sscottl} 403114902Sscottl 404122999Smbr/* Simplified localtime to provide timevalues for ffdc. 405122999Smbr * Taken from libc/stdtime/localtime.c 406122999Smbr */ 407122999Smbrvoid static ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime) 408122999Smbr{ 409122999Smbr long days, rem, y; 410122999Smbr int yleap, *ip, month; 411122999Smbr int year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR }; 412122999Smbr int mon_lengths[2][IPS_MONSPERYEAR] = { 413122999Smbr { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 414122999Smbr { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 415122999Smbr }; 416122999Smbr 417122999Smbr days = sctime / IPS_SECSPERDAY; 418122999Smbr rem = sctime % IPS_SECSPERDAY; 419122999Smbr 420122999Smbr command->hour = rem / IPS_SECSPERHOUR; 421122999Smbr rem = rem % IPS_SECSPERHOUR; 422122999Smbr 423122999Smbr command->minute = rem / IPS_SECSPERMIN; 424122999Smbr command->second = rem % IPS_SECSPERMIN; 425122999Smbr 426122999Smbr y = IPS_EPOCH_YEAR; 427122999Smbr while (days < 0 || days >= (long) year_lengths[yleap = ips_isleap(y)]) { 428122999Smbr long newy; 429122999Smbr 430122999Smbr newy = y + days / IPS_DAYSPERNYEAR; 431122999Smbr if (days < 0) 432122999Smbr --newy; 433122999Smbr days -= (newy - y) * IPS_DAYSPERNYEAR + 434122999Smbr IPS_LEAPS_THRU_END_OF(newy - 1) - 435122999Smbr IPS_LEAPS_THRU_END_OF(y - 1); 436122999Smbr y = newy; 437122999Smbr } 438122999Smbr command->yearH = y / 100; 439122999Smbr command->yearL = y % 100; 440122999Smbr ip = mon_lengths[yleap]; 441122999Smbr for(month = 0; days >= (long) ip[month]; ++month) 442122999Smbr days = days - (long) ip[month]; 443122999Smbr command->month = month + 1; 444122999Smbr command->day = days + 1; 445122999Smbr} 446122999Smbr 447122999Smbrstatic int ips_send_ffdc_reset_cmd(ips_command_t *command) 448122999Smbr{ 449122999Smbr ips_softc_t *sc = command->sc; 450122999Smbr ips_adapter_ffdc_cmd *command_struct; 451122999Smbr 452122999Smbr PRINTF(10,"ips test: got a command, building ffdc reset command\n"); 453122999Smbr command->callback = ips_wakeup_callback; 454122999Smbr command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer; 455122999Smbr command_struct->command = IPS_FFDC_CMD; 456122999Smbr command_struct->id = command->id; 457122999Smbr command_struct->reset_count = sc->ffdc_resetcount; 458124040Smbr command_struct->reset_type = 0x0; 459122999Smbr ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec); 460122999Smbr 461122999Smbr bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 462122999Smbr BUS_DMASYNC_PREWRITE); 463122999Smbr sc->ips_issue_cmd(command); 464150535Sscottl if (COMMAND_ERROR(command) == 0) 465140923Sscottl sema_wait(&sc->cmd_sema); 466122999Smbr ips_insert_free_cmd(sc, command); 467122999Smbr return 0; 468122999Smbr} 469122999Smbr 470122999Smbrint ips_ffdc_reset(ips_softc_t *sc) 471122999Smbr{ 472140923Sscottl ips_command_t *command; 473140923Sscottl 474140923Sscottl if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){ 475122999Smbr device_printf(sc->dev, "ERROR: unable to get a command! can't send ffdc reset!\n"); 476122999Smbr } 477140923Sscottl ips_send_ffdc_reset_cmd(command); 478150535Sscottl if(COMMAND_ERROR(command)){ 479122999Smbr device_printf(sc->dev, "ERROR: ffdc reset command failed!\n"); 480122999Smbr } 481122999Smbr return 0; 482122999Smbr} 483122999Smbr 484114902Sscottlstatic void ips_write_nvram(ips_command_t *command){ 485114902Sscottl ips_softc_t *sc = command->sc; 486114902Sscottl ips_rw_nvram_cmd *command_struct; 487114902Sscottl ips_nvram_page5 *nvram; 488114902Sscottl 489114902Sscottl /*FIXME check for error */ 490114902Sscottl command->callback = ips_wakeup_callback; 491114902Sscottl command_struct = (ips_rw_nvram_cmd *)command->command_buffer; 492114902Sscottl command_struct->command = IPS_RW_NVRAM_CMD; 493114902Sscottl command_struct->id = command->id; 494114902Sscottl command_struct->pagenum = 5; 495114902Sscottl command_struct->rw = 1; /*write*/ 496114902Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 497114902Sscottl BUS_DMASYNC_POSTREAD); 498114902Sscottl nvram = command->data_buffer; 499122999Smbr /* retrieve adapter info and save in sc */ 500122999Smbr sc->adapter_type = nvram->adapter_type; 501122999Smbr 502114902Sscottl strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4); 503114902Sscottl strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4); 504114902Sscottl nvram->operating_system = IPS_OS_FREEBSD; 505114902Sscottl bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 506114902Sscottl BUS_DMASYNC_PREWRITE); 507114902Sscottl sc->ips_issue_cmd(command); 508114902Sscottl} 509114902Sscottl 510114902Sscottlstatic void ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 511114902Sscottl{ 512114902Sscottl ips_softc_t *sc; 513114902Sscottl ips_command_t *command = cmdptr; 514114902Sscottl ips_rw_nvram_cmd *command_struct; 515114902Sscottl sc = command->sc; 516114902Sscottl if(error){ 517150535Sscottl ips_set_error(command, error); 518114902Sscottl printf("ips: error = %d in ips_read_nvram_callback\n", error); 519114902Sscottl return; 520114902Sscottl } 521114902Sscottl command_struct = (ips_rw_nvram_cmd *)command->command_buffer; 522114902Sscottl command_struct->command = IPS_RW_NVRAM_CMD; 523114902Sscottl command_struct->id = command->id; 524114902Sscottl command_struct->pagenum = 5; 525114902Sscottl command_struct->rw = 0; 526114902Sscottl command_struct->buffaddr = segments[0].ds_addr; 527114902Sscottl 528114902Sscottl bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 529114902Sscottl BUS_DMASYNC_PREWRITE); 530114902Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 531114902Sscottl BUS_DMASYNC_PREREAD); 532114902Sscottl sc->ips_issue_cmd(command); 533150535Sscottl if (sema_timedwait(&sc->cmd_sema, 30*hz) != 0) { 534150535Sscottl ips_set_error(command, ETIMEDOUT); 535150535Sscottl return; 536150535Sscottl } 537150535Sscottl bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 538150535Sscottl BUS_DMASYNC_POSTWRITE); 539114902Sscottl} 540114902Sscottl 541140923Sscottlstatic int ips_read_nvram(ips_command_t *command) 542140923Sscottl{ 543114902Sscottl int error = 0; 544114902Sscottl ips_softc_t *sc = command->sc; 545114902Sscottl 546114902Sscottl if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 547114902Sscottl /* alignemnt */ 1, 548114902Sscottl /* boundary */ 0, 549114902Sscottl /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 550114902Sscottl /* highaddr */ BUS_SPACE_MAXADDR, 551114902Sscottl /* filter */ NULL, 552114902Sscottl /* filterarg */ NULL, 553114902Sscottl /* maxsize */ IPS_NVRAM_PAGE_SIZE, 554114902Sscottl /* numsegs */ 1, 555114902Sscottl /* maxsegsize*/ IPS_NVRAM_PAGE_SIZE, 556114902Sscottl /* flags */ 0, 557140923Sscottl /* lockfunc */ NULL, 558140923Sscottl /* lockarg */ NULL, 559114902Sscottl &command->data_dmatag) != 0) { 560114902Sscottl printf("ips: can't alloc dma tag for nvram\n"); 561114902Sscottl error = ENOMEM; 562114902Sscottl goto exit; 563114902Sscottl } 564114902Sscottl if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, 565114902Sscottl BUS_DMA_NOWAIT, &command->data_dmamap)){ 566114902Sscottl error = ENOMEM; 567114902Sscottl goto exit; 568114902Sscottl } 569114902Sscottl command->callback = ips_write_nvram; 570150535Sscottl error = bus_dmamap_load(command->data_dmatag, command->data_dmamap, 571150535Sscottl command->data_buffer,IPS_NVRAM_PAGE_SIZE, 572150535Sscottl ips_read_nvram_callback, command, 573150535Sscottl BUS_DMA_NOWAIT); 574150535Sscottl if (error == 0) 575150535Sscottl bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 576114902Sscottl 577114902Sscottlexit: 578114902Sscottl bus_dmamem_free(command->data_dmatag, command->data_buffer, 579114902Sscottl command->data_dmamap); 580114902Sscottl bus_dma_tag_destroy(command->data_dmatag); 581114902Sscottl ips_insert_free_cmd(sc, command); 582114902Sscottl return error; 583114902Sscottl} 584114902Sscottl 585114902Sscottlint ips_update_nvram(ips_softc_t *sc) 586114902Sscottl{ 587140923Sscottl ips_command_t *command; 588140923Sscottl 589140923Sscottl if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){ 590114902Sscottl device_printf(sc->dev, "ERROR: unable to get a command! can't update nvram\n"); 591114902Sscottl return 1; 592114902Sscottl } 593140923Sscottl ips_read_nvram(command); 594150535Sscottl if(COMMAND_ERROR(command)){ 595114902Sscottl device_printf(sc->dev, "ERROR: nvram update command failed!\n"); 596114902Sscottl } 597114902Sscottl return 0; 598114902Sscottl 599114902Sscottl 600114902Sscottl} 601114902Sscottl 602114902Sscottl 603114902Sscottlstatic int ips_send_config_sync_cmd(ips_command_t *command) 604114902Sscottl{ 605114902Sscottl ips_softc_t *sc = command->sc; 606114902Sscottl ips_generic_cmd *command_struct; 607114902Sscottl 608114902Sscottl PRINTF(10,"ips test: got a command, building flush command\n"); 609114902Sscottl command->callback = ips_wakeup_callback; 610114902Sscottl command_struct = (ips_generic_cmd *)command->command_buffer; 611114902Sscottl command_struct->command = IPS_CONFIG_SYNC_CMD; 612114902Sscottl command_struct->id = command->id; 613114902Sscottl command_struct->reserve2 = IPS_POCL; 614114902Sscottl bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 615114902Sscottl BUS_DMASYNC_PREWRITE); 616114902Sscottl sc->ips_issue_cmd(command); 617150535Sscottl if (COMMAND_ERROR(command) == 0) 618140923Sscottl sema_wait(&sc->cmd_sema); 619114902Sscottl ips_insert_free_cmd(sc, command); 620114902Sscottl return 0; 621114902Sscottl} 622114902Sscottl 623114902Sscottlstatic int ips_send_error_table_cmd(ips_command_t *command) 624114902Sscottl{ 625114902Sscottl ips_softc_t *sc = command->sc; 626114902Sscottl ips_generic_cmd *command_struct; 627114902Sscottl 628114902Sscottl PRINTF(10,"ips test: got a command, building errortable command\n"); 629114902Sscottl command->callback = ips_wakeup_callback; 630114902Sscottl command_struct = (ips_generic_cmd *)command->command_buffer; 631114902Sscottl command_struct->command = IPS_ERROR_TABLE_CMD; 632114902Sscottl command_struct->id = command->id; 633114902Sscottl command_struct->reserve2 = IPS_CSL; 634114902Sscottl bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 635114902Sscottl BUS_DMASYNC_PREWRITE); 636114902Sscottl sc->ips_issue_cmd(command); 637150535Sscottl if (COMMAND_ERROR(command) == 0) 638140923Sscottl sema_wait(&sc->cmd_sema); 639114902Sscottl ips_insert_free_cmd(sc, command); 640114902Sscottl return 0; 641114902Sscottl} 642114902Sscottl 643114902Sscottl 644114902Sscottlint ips_clear_adapter(ips_softc_t *sc) 645114902Sscottl{ 646140923Sscottl ips_command_t *command; 647140923Sscottl 648114902Sscottl device_printf(sc->dev, "syncing config\n"); 649140923Sscottl if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){ 650114902Sscottl device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n"); 651114902Sscottl return 1; 652114902Sscottl } 653140923Sscottl ips_send_config_sync_cmd(command); 654150535Sscottl if(COMMAND_ERROR(command)){ 655114902Sscottl device_printf(sc->dev, "ERROR: cache sync command failed!\n"); 656114902Sscottl return 1; 657114902Sscottl } 658114902Sscottl 659114902Sscottl device_printf(sc->dev, "clearing error table\n"); 660140923Sscottl if(ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG)){ 661114902Sscottl device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n"); 662114902Sscottl return 1; 663114902Sscottl } 664140923Sscottl ips_send_error_table_cmd(command); 665150535Sscottl if(COMMAND_ERROR(command)){ 666114902Sscottl device_printf(sc->dev, "ERROR: etable command failed!\n"); 667114902Sscottl return 1; 668114902Sscottl } 669114902Sscottl 670114902Sscottl return 0; 671114902Sscottl} 672