ips_commands.c revision 124040
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 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: head/sys/dev/ips/ips_commands.c 124040 2004-01-01 10:22:10Z mbr $"); 30 31#include <dev/ips/ips.h> 32 33/* 34 * This is an interrupt callback. It is called from 35 * interrupt context when the adapter has completed the 36 * command. This very generic callback simply stores 37 * the command's return value in command->arg and wake's 38 * up anyone waiting on the command. 39 */ 40static void ips_wakeup_callback(ips_command_t *command) 41{ 42 ips_cmd_status_t *status; 43 status = command->arg; 44 status->value = command->status.value; 45 bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap, 46 BUS_DMASYNC_POSTWRITE); 47 mtx_lock(&command->sc->cmd_mtx); 48 wakeup(status); 49 mtx_unlock(&command->sc->cmd_mtx); 50} 51/* Below are a series of functions for sending an IO request 52 * to the adapter. The flow order is: start, send, callback, finish. 53 * The caller must have already assembled an iorequest struct to hold 54 * the details of the IO request. */ 55static void ips_io_request_finish(ips_command_t *command) 56{ 57 58 struct bio *iobuf = command->arg; 59 if(ips_read_request(iobuf)) { 60 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 61 BUS_DMASYNC_POSTREAD); 62 } else { 63 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 64 BUS_DMASYNC_POSTWRITE); 65 } 66 bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 67 bus_dmamap_destroy(command->data_dmatag, command->data_dmamap); 68 if(COMMAND_ERROR(&command->status)){ 69 iobuf->bio_flags |=BIO_ERROR; 70 iobuf->bio_error = EIO; 71 } 72 ips_insert_free_cmd(command->sc, command); 73 ipsd_finish(iobuf); 74} 75 76static void ips_io_request_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 77{ 78 ips_softc_t *sc; 79 ips_command_t *command = cmdptr; 80 ips_sg_element_t *sg_list; 81 ips_io_cmd *command_struct; 82 struct bio *iobuf = command->arg; 83 int i, length = 0; 84 u_int8_t cmdtype; 85 86 sc = command->sc; 87 if(error){ 88 printf("ips: error = %d in ips_sg_request_callback\n", error); 89 bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 90 bus_dmamap_destroy(command->data_dmatag, command->data_dmamap); 91 iobuf->bio_flags |= BIO_ERROR; 92 iobuf->bio_error = ENOMEM; 93 ips_insert_free_cmd(sc, command); 94 ipsd_finish(iobuf); 95 return; 96 } 97 command_struct = (ips_io_cmd *)command->command_buffer; 98 command_struct->id = command->id; 99 command_struct->drivenum = (uintptr_t)iobuf->bio_driver1; 100 if(segnum != 1){ 101 if(ips_read_request(iobuf)) 102 cmdtype = IPS_SG_READ_CMD; 103 else 104 cmdtype = IPS_SG_WRITE_CMD; 105 command_struct->segnum = segnum; 106 sg_list = (ips_sg_element_t *)((u_int8_t *) 107 command->command_buffer + IPS_COMMAND_LEN); 108 for(i = 0; i < segnum; i++){ 109 sg_list[i].addr = segments[i].ds_addr; 110 sg_list[i].len = segments[i].ds_len; 111 length += segments[i].ds_len; 112 } 113 command_struct->buffaddr = 114 (u_int32_t)command->command_phys_addr + IPS_COMMAND_LEN; 115 } else { 116 if(ips_read_request(iobuf)) 117 cmdtype = IPS_READ_CMD; 118 else 119 cmdtype = IPS_WRITE_CMD; 120 command_struct->buffaddr = segments[0].ds_addr; 121 length = segments[0].ds_len; 122 } 123 command_struct->command = cmdtype; 124 command_struct->lba = iobuf->bio_pblkno; 125 length = (length + IPS_BLKSIZE - 1)/IPS_BLKSIZE; 126 command_struct->length = length; 127 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 128 BUS_DMASYNC_PREWRITE); 129 if(ips_read_request(iobuf)) { 130 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 131 BUS_DMASYNC_PREREAD); 132 } else { 133 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 134 BUS_DMASYNC_PREWRITE); 135 } 136 PRINTF(10, "ips test: command id: %d segments: %d " 137 "pblkno: %lld length: %d, ds_len: %d\n", command->id, segnum, 138 iobuf->bio_pblkno, 139 length, segments[0].ds_len); 140 141 sc->ips_issue_cmd(command); 142 return; 143} 144 145static int ips_send_io_request(ips_command_t *command) 146{ 147 ips_softc_t *sc = command->sc; 148 struct bio *iobuf = command->arg; 149 command->data_dmatag = sc->sg_dmatag; 150 if(bus_dmamap_create(command->data_dmatag, 0, &command->data_dmamap)){ 151 device_printf(sc->dev, "dmamap failed\n"); 152 iobuf->bio_flags |= BIO_ERROR; 153 iobuf->bio_error = ENOMEM; 154 ips_insert_free_cmd(sc, command); 155 ipsd_finish(iobuf); 156 return 0; 157 } 158 command->callback = ips_io_request_finish; 159 PRINTF(10, "ips test: : bcount %ld\n", iobuf->bio_bcount); 160 bus_dmamap_load(command->data_dmatag, command->data_dmamap, 161 iobuf->bio_data, iobuf->bio_bcount, 162 ips_io_request_callback, command, 0); 163 return 0; 164} 165 166void ips_start_io_request(ips_softc_t *sc, struct bio *iobuf) 167{ 168 if(ips_get_free_cmd(sc, ips_send_io_request, iobuf, 0)){ 169 device_printf(sc->dev, "no mem for command slots!\n"); 170 iobuf->bio_flags |= BIO_ERROR; 171 iobuf->bio_error = ENOMEM; 172 ipsd_finish(iobuf); 173 return; 174 } 175 return; 176} 177 178/* Below are a series of functions for sending an adapter info request 179 * to the adapter. The flow order is: get, send, callback. It uses 180 * the generic finish callback at the top of this file. 181 * This can be used to get configuration/status info from the card */ 182static void ips_adapter_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 183{ 184 ips_softc_t *sc; 185 ips_command_t *command = cmdptr; 186 ips_adapter_info_cmd *command_struct; 187 sc = command->sc; 188 if(error){ 189 ips_cmd_status_t * status = command->arg; 190 status->value = IPS_ERROR_STATUS; /* a lovely error value */ 191 ips_insert_free_cmd(sc, command); 192 printf("ips: error = %d in ips_get_adapter_info\n", error); 193 return; 194 } 195 command_struct = (ips_adapter_info_cmd *)command->command_buffer; 196 command_struct->command = IPS_ADAPTER_INFO_CMD; 197 command_struct->id = command->id; 198 command_struct->buffaddr = segments[0].ds_addr; 199 200 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 201 BUS_DMASYNC_PREWRITE); 202 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 203 BUS_DMASYNC_PREREAD); 204 sc->ips_issue_cmd(command); 205} 206 207 208 209static int ips_send_adapter_info_cmd(ips_command_t *command) 210{ 211 int error = 0; 212 ips_softc_t *sc = command->sc; 213 ips_cmd_status_t *status = command->arg; 214 215 if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 216 /* alignemnt */ 1, 217 /* boundary */ 0, 218 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 219 /* highaddr */ BUS_SPACE_MAXADDR, 220 /* filter */ NULL, 221 /* filterarg */ NULL, 222 /* maxsize */ IPS_ADAPTER_INFO_LEN, 223 /* numsegs */ 1, 224 /* maxsegsize*/ IPS_ADAPTER_INFO_LEN, 225 /* flags */ 0, 226 /* lockfunc */ busdma_lock_mutex, 227 /* lockarg */ &Giant, 228 &command->data_dmatag) != 0) { 229 printf("ips: can't alloc dma tag for adapter status\n"); 230 error = ENOMEM; 231 goto exit; 232 } 233 if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, 234 BUS_DMA_NOWAIT, &command->data_dmamap)){ 235 error = ENOMEM; 236 goto exit; 237 } 238 command->callback = ips_wakeup_callback; 239 mtx_lock(&sc->cmd_mtx); 240 bus_dmamap_load(command->data_dmatag, command->data_dmamap, 241 command->data_buffer,IPS_ADAPTER_INFO_LEN, 242 ips_adapter_info_callback, command, BUS_DMA_NOWAIT); 243 244 if ((status->value == IPS_ERROR_STATUS) || 245 (msleep(status, &sc->cmd_mtx, 0, "ips", 30*hz) == EWOULDBLOCK)) 246 error = ETIMEDOUT; 247 mtx_unlock(&sc->cmd_mtx); 248 249 if (error == 0) { 250 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 251 BUS_DMASYNC_POSTREAD); 252 memcpy(&(sc->adapter_info), command->data_buffer, 253 IPS_ADAPTER_INFO_LEN); 254 } 255 bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 256 257exit: 258 /* I suppose I should clean up my memory allocations */ 259 bus_dmamem_free(command->data_dmatag, command->data_buffer, 260 command->data_dmamap); 261 bus_dma_tag_destroy(command->data_dmatag); 262 ips_insert_free_cmd(sc, command); 263 return error; 264} 265 266int ips_get_adapter_info(ips_softc_t *sc) 267{ 268 int error = 0; 269 ips_cmd_status_t *status; 270 status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO); 271 if(!status) 272 return ENOMEM; 273 if(ips_get_free_cmd(sc, ips_send_adapter_info_cmd, status, 274 IPS_NOWAIT_FLAG) > 0){ 275 device_printf(sc->dev, "unable to get adapter configuration\n"); 276 free(status, M_DEVBUF); 277 return ENXIO; 278 } 279 if (COMMAND_ERROR(status)){ 280 error = ENXIO; 281 } 282 free(status, M_DEVBUF); 283 return error; 284} 285 286/* Below are a series of functions for sending a drive info request 287 * to the adapter. The flow order is: get, send, callback. It uses 288 * the generic finish callback at the top of this file. 289 * This can be used to get drive status info from the card */ 290static void ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 291{ 292 ips_softc_t *sc; 293 ips_command_t *command = cmdptr; 294 ips_drive_cmd *command_struct; 295 sc = command->sc; 296 if(error){ 297 ips_cmd_status_t * status = command->arg; 298 status->value = IPS_ERROR_STATUS; 299 ips_insert_free_cmd(sc, command); 300 printf("ips: error = %d in ips_get_drive_info\n", error); 301 return; 302 } 303 command_struct = (ips_drive_cmd *)command->command_buffer; 304 command_struct->command = IPS_DRIVE_INFO_CMD; 305 command_struct->id = command->id; 306 command_struct->buffaddr = segments[0].ds_addr; 307 308 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 309 BUS_DMASYNC_PREWRITE); 310 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 311 BUS_DMASYNC_PREREAD); 312 sc->ips_issue_cmd(command); 313} 314 315static int ips_send_drive_info_cmd(ips_command_t *command) 316{ 317 int error = 0; 318 ips_softc_t *sc = command->sc; 319 ips_cmd_status_t *status = command->arg; 320 ips_drive_info_t *driveinfo; 321 322 if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 323 /* alignemnt */ 1, 324 /* boundary */ 0, 325 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 326 /* highaddr */ BUS_SPACE_MAXADDR, 327 /* filter */ NULL, 328 /* filterarg */ NULL, 329 /* maxsize */ IPS_DRIVE_INFO_LEN, 330 /* numsegs */ 1, 331 /* maxsegsize*/ IPS_DRIVE_INFO_LEN, 332 /* flags */ 0, 333 /* lockfunc */ busdma_lock_mutex, 334 /* lockarg */ &Giant, 335 &command->data_dmatag) != 0) { 336 printf("ips: can't alloc dma tag for drive status\n"); 337 error = ENOMEM; 338 goto exit; 339 } 340 if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, 341 BUS_DMA_NOWAIT, &command->data_dmamap)){ 342 error = ENOMEM; 343 goto exit; 344 } 345 command->callback = ips_wakeup_callback; 346 mtx_lock(&sc->cmd_mtx); 347 bus_dmamap_load(command->data_dmatag, command->data_dmamap, 348 command->data_buffer,IPS_DRIVE_INFO_LEN, 349 ips_drive_info_callback, command, BUS_DMA_NOWAIT); 350 if ((status->value == IPS_ERROR_STATUS) || 351 (msleep(status, &sc->cmd_mtx, 0, "ips", 10*hz) == EWOULDBLOCK)) 352 error = ETIMEDOUT; 353 mtx_unlock(&sc->cmd_mtx); 354 355 if (error == 0) { 356 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 357 BUS_DMASYNC_POSTREAD); 358 driveinfo = command->data_buffer; 359 memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8); 360 sc->drivecount = driveinfo->drivecount; 361 device_printf(sc->dev, "logical drives: %d\n",sc->drivecount); 362 } 363 bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 364 365exit: 366 /* I suppose I should clean up my memory allocations */ 367 bus_dmamem_free(command->data_dmatag, command->data_buffer, 368 command->data_dmamap); 369 bus_dma_tag_destroy(command->data_dmatag); 370 ips_insert_free_cmd(sc, command); 371 return error; 372 373} 374int ips_get_drive_info(ips_softc_t *sc) 375{ 376 int error = 0; 377 ips_cmd_status_t *status; 378 status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO); 379 if(!status) 380 return ENOMEM; 381 if(ips_get_free_cmd(sc, ips_send_drive_info_cmd, status, 382 IPS_NOWAIT_FLAG) > 0){ 383 free(status, M_DEVBUF); 384 device_printf(sc->dev, "unable to get drive configuration\n"); 385 return ENXIO; 386 } 387 if(COMMAND_ERROR(status)){ 388 error = ENXIO; 389 } 390 free(status, M_DEVBUF); 391 return error; 392} 393 394/* Below is a pair of functions for making sure data is safely 395 * on disk by flushing the adapter's cache. */ 396static int ips_send_flush_cache_cmd(ips_command_t *command) 397{ 398 ips_softc_t *sc = command->sc; 399 ips_cmd_status_t *status = command->arg; 400 ips_generic_cmd *command_struct; 401 402 PRINTF(10,"ips test: got a command, building flush command\n"); 403 command->callback = ips_wakeup_callback; 404 command_struct = (ips_generic_cmd *)command->command_buffer; 405 command_struct->command = IPS_CACHE_FLUSH_CMD; 406 command_struct->id = command->id; 407 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 408 BUS_DMASYNC_PREWRITE); 409 mtx_lock(&sc->cmd_mtx); 410 sc->ips_issue_cmd(command); 411 if (status->value != IPS_ERROR_STATUS) 412 msleep(status, &sc->cmd_mtx, 0, "flush2", 0); 413 mtx_unlock(&sc->cmd_mtx); 414 ips_insert_free_cmd(sc, command); 415 return 0; 416} 417 418int ips_flush_cache(ips_softc_t *sc) 419{ 420 ips_cmd_status_t *status; 421 status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO); 422 if(!status) 423 return ENOMEM; 424 device_printf(sc->dev, "flushing cache\n"); 425 if(ips_get_free_cmd(sc, ips_send_flush_cache_cmd, status, 426 IPS_NOWAIT_FLAG)){ 427 free(status, M_DEVBUF); 428 device_printf(sc->dev, "ERROR: unable to get a command! can't flush cache!\n"); 429 } 430 if(COMMAND_ERROR(status)){ 431 device_printf(sc->dev, "ERROR: cache flush command failed!\n"); 432 } 433 free(status, M_DEVBUF); 434 return 0; 435} 436 437/* Simplified localtime to provide timevalues for ffdc. 438 * Taken from libc/stdtime/localtime.c 439 */ 440void static ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime) 441{ 442 long days, rem, y; 443 int yleap, *ip, month; 444 int year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR }; 445 int mon_lengths[2][IPS_MONSPERYEAR] = { 446 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 447 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 448 }; 449 450 days = sctime / IPS_SECSPERDAY; 451 rem = sctime % IPS_SECSPERDAY; 452 453 command->hour = rem / IPS_SECSPERHOUR; 454 rem = rem % IPS_SECSPERHOUR; 455 456 command->minute = rem / IPS_SECSPERMIN; 457 command->second = rem % IPS_SECSPERMIN; 458 459 y = IPS_EPOCH_YEAR; 460 while (days < 0 || days >= (long) year_lengths[yleap = ips_isleap(y)]) { 461 long newy; 462 463 newy = y + days / IPS_DAYSPERNYEAR; 464 if (days < 0) 465 --newy; 466 days -= (newy - y) * IPS_DAYSPERNYEAR + 467 IPS_LEAPS_THRU_END_OF(newy - 1) - 468 IPS_LEAPS_THRU_END_OF(y - 1); 469 y = newy; 470 } 471 command->yearH = y / 100; 472 command->yearL = y % 100; 473 ip = mon_lengths[yleap]; 474 for(month = 0; days >= (long) ip[month]; ++month) 475 days = days - (long) ip[month]; 476 command->month = month + 1; 477 command->day = days + 1; 478} 479 480static int ips_send_ffdc_reset_cmd(ips_command_t *command) 481{ 482 ips_softc_t *sc = command->sc; 483 ips_cmd_status_t *status = command->arg; 484 ips_adapter_ffdc_cmd *command_struct; 485 486 PRINTF(10,"ips test: got a command, building ffdc reset command\n"); 487 command->callback = ips_wakeup_callback; 488 command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer; 489 command_struct->command = IPS_FFDC_CMD; 490 command_struct->id = command->id; 491 command_struct->reset_count = sc->ffdc_resetcount; 492 command_struct->reset_type = 0x0; 493 ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec); 494 495 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 496 BUS_DMASYNC_PREWRITE); 497 mtx_lock(&sc->cmd_mtx); 498 sc->ips_issue_cmd(command); 499 if (status->value != IPS_ERROR_STATUS) 500 msleep(status, &sc->cmd_mtx, 0, "ffdc", 0); 501 mtx_unlock(&sc->cmd_mtx); 502 ips_insert_free_cmd(sc, command); 503 return 0; 504} 505 506int ips_ffdc_reset(ips_softc_t *sc) 507{ 508 ips_cmd_status_t *status; 509 status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO); 510 if(!status) 511 return ENOMEM; 512 if(ips_get_free_cmd(sc, ips_send_ffdc_reset_cmd, status, 513 IPS_NOWAIT_FLAG)){ 514 free(status, M_DEVBUF); 515 device_printf(sc->dev, "ERROR: unable to get a command! can't send ffdc reset!\n"); 516 } 517 if(COMMAND_ERROR(status)){ 518 device_printf(sc->dev, "ERROR: ffdc reset command failed!\n"); 519 } 520 free(status, M_DEVBUF); 521 return 0; 522} 523 524static void ips_write_nvram(ips_command_t *command){ 525 ips_softc_t *sc = command->sc; 526 ips_rw_nvram_cmd *command_struct; 527 ips_nvram_page5 *nvram; 528 529 /*FIXME check for error */ 530 command->callback = ips_wakeup_callback; 531 command_struct = (ips_rw_nvram_cmd *)command->command_buffer; 532 command_struct->command = IPS_RW_NVRAM_CMD; 533 command_struct->id = command->id; 534 command_struct->pagenum = 5; 535 command_struct->rw = 1; /*write*/ 536 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 537 BUS_DMASYNC_POSTREAD); 538 nvram = command->data_buffer; 539 /* retrieve adapter info and save in sc */ 540 sc->adapter_type = nvram->adapter_type; 541 542 strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4); 543 strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4); 544 nvram->operating_system = IPS_OS_FREEBSD; 545 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 546 BUS_DMASYNC_PREWRITE); 547 sc->ips_issue_cmd(command); 548} 549 550static void ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 551{ 552 ips_softc_t *sc; 553 ips_command_t *command = cmdptr; 554 ips_rw_nvram_cmd *command_struct; 555 sc = command->sc; 556 if(error){ 557 ips_cmd_status_t * status = command->arg; 558 status->value = IPS_ERROR_STATUS; 559 ips_insert_free_cmd(sc, command); 560 printf("ips: error = %d in ips_read_nvram_callback\n", error); 561 return; 562 } 563 command_struct = (ips_rw_nvram_cmd *)command->command_buffer; 564 command_struct->command = IPS_RW_NVRAM_CMD; 565 command_struct->id = command->id; 566 command_struct->pagenum = 5; 567 command_struct->rw = 0; 568 command_struct->buffaddr = segments[0].ds_addr; 569 570 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 571 BUS_DMASYNC_PREWRITE); 572 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 573 BUS_DMASYNC_PREREAD); 574 sc->ips_issue_cmd(command); 575} 576 577static int ips_read_nvram(ips_command_t *command){ 578 int error = 0; 579 ips_softc_t *sc = command->sc; 580 ips_cmd_status_t *status = command->arg; 581 582 if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 583 /* alignemnt */ 1, 584 /* boundary */ 0, 585 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 586 /* highaddr */ BUS_SPACE_MAXADDR, 587 /* filter */ NULL, 588 /* filterarg */ NULL, 589 /* maxsize */ IPS_NVRAM_PAGE_SIZE, 590 /* numsegs */ 1, 591 /* maxsegsize*/ IPS_NVRAM_PAGE_SIZE, 592 /* flags */ 0, 593 /* lockfunc */ busdma_lock_mutex, 594 /* lockarg */ &Giant, 595 &command->data_dmatag) != 0) { 596 printf("ips: can't alloc dma tag for nvram\n"); 597 error = ENOMEM; 598 goto exit; 599 } 600 if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, 601 BUS_DMA_NOWAIT, &command->data_dmamap)){ 602 error = ENOMEM; 603 goto exit; 604 } 605 command->callback = ips_write_nvram; 606 mtx_lock(&sc->cmd_mtx); 607 bus_dmamap_load(command->data_dmatag, command->data_dmamap, 608 command->data_buffer,IPS_NVRAM_PAGE_SIZE, 609 ips_read_nvram_callback, command, BUS_DMA_NOWAIT); 610 if ((status->value == IPS_ERROR_STATUS) || 611 (msleep(status, &sc->cmd_mtx, 0, "ips", 0) == EWOULDBLOCK)) 612 error = ETIMEDOUT; 613 mtx_unlock(&sc->cmd_mtx); 614 615 if (error == 0) { 616 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 617 BUS_DMASYNC_POSTWRITE); 618 } 619 bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 620 621exit: 622 bus_dmamem_free(command->data_dmatag, command->data_buffer, 623 command->data_dmamap); 624 bus_dma_tag_destroy(command->data_dmatag); 625 ips_insert_free_cmd(sc, command); 626 return error; 627} 628 629int ips_update_nvram(ips_softc_t *sc) 630{ 631 ips_cmd_status_t *status; 632 status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO); 633 if(!status) 634 return ENOMEM; 635 if(ips_get_free_cmd(sc, ips_read_nvram, status, IPS_NOWAIT_FLAG)){ 636 free(status, M_DEVBUF); 637 device_printf(sc->dev, "ERROR: unable to get a command! can't update nvram\n"); 638 return 1; 639 } 640 if(COMMAND_ERROR(status)){ 641 device_printf(sc->dev, "ERROR: nvram update command failed!\n"); 642 } 643 free(status, M_DEVBUF); 644 return 0; 645 646 647} 648 649 650static int ips_send_config_sync_cmd(ips_command_t *command) 651{ 652 ips_softc_t *sc = command->sc; 653 ips_cmd_status_t *status = command->arg; 654 ips_generic_cmd *command_struct; 655 656 PRINTF(10,"ips test: got a command, building flush command\n"); 657 command->callback = ips_wakeup_callback; 658 command_struct = (ips_generic_cmd *)command->command_buffer; 659 command_struct->command = IPS_CONFIG_SYNC_CMD; 660 command_struct->id = command->id; 661 command_struct->reserve2 = IPS_POCL; 662 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 663 BUS_DMASYNC_PREWRITE); 664 mtx_lock(&sc->cmd_mtx); 665 sc->ips_issue_cmd(command); 666 if (status->value != IPS_ERROR_STATUS) 667 msleep(status, &sc->cmd_mtx, 0, "ipssyn", 0); 668 mtx_unlock(&sc->cmd_mtx); 669 ips_insert_free_cmd(sc, command); 670 return 0; 671} 672 673static int ips_send_error_table_cmd(ips_command_t *command) 674{ 675 ips_softc_t *sc = command->sc; 676 ips_cmd_status_t *status = command->arg; 677 ips_generic_cmd *command_struct; 678 679 PRINTF(10,"ips test: got a command, building errortable command\n"); 680 command->callback = ips_wakeup_callback; 681 command_struct = (ips_generic_cmd *)command->command_buffer; 682 command_struct->command = IPS_ERROR_TABLE_CMD; 683 command_struct->id = command->id; 684 command_struct->reserve2 = IPS_CSL; 685 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 686 BUS_DMASYNC_PREWRITE); 687 mtx_lock(&sc->cmd_mtx); 688 sc->ips_issue_cmd(command); 689 if (status->value != IPS_ERROR_STATUS) 690 msleep(status, &sc->cmd_mtx, 0, "ipsetc", 0); 691 mtx_unlock(&sc->cmd_mtx); 692 ips_insert_free_cmd(sc, command); 693 return 0; 694} 695 696 697int ips_clear_adapter(ips_softc_t *sc) 698{ 699 ips_cmd_status_t *status; 700 status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO); 701 if(!status) 702 return ENOMEM; 703 device_printf(sc->dev, "syncing config\n"); 704 if(ips_get_free_cmd(sc, ips_send_config_sync_cmd, status, 705 IPS_NOWAIT_FLAG)){ 706 free(status, M_DEVBUF); 707 device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n"); 708 return 1; 709 } 710 if(COMMAND_ERROR(status)){ 711 free(status, M_DEVBUF); 712 device_printf(sc->dev, "ERROR: cache sync command failed!\n"); 713 return 1; 714 } 715 716 device_printf(sc->dev, "clearing error table\n"); 717 if(ips_get_free_cmd(sc, ips_send_error_table_cmd, status, 718 IPS_NOWAIT_FLAG)){ 719 free(status, M_DEVBUF); 720 device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n"); 721 return 1; 722 } 723 if(COMMAND_ERROR(status)){ 724 device_printf(sc->dev, "ERROR: etable command failed!\n"); 725 free(status, M_DEVBUF); 726 return 1; 727 } 728 729 free(status, M_DEVBUF); 730 return 0; 731} 732