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 /* maxsize */ IPS_ADAPTER_INFO_LEN, 299 /* numsegs */ 1, 300 /* maxsegsize*/ IPS_ADAPTER_INFO_LEN, 301 /* flags */ 0, 302 &command->data_dmatag) != 0) { 303 kprintf("ips: can't alloc dma tag for adapter status\n"); 304 error = ENOMEM; 305 goto exit; 306 } 307 if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, 308 BUS_DMA_NOWAIT, &command->data_dmamap)) { 309 error = ENOMEM; 310 goto exit; 311 } 312 command->callback = ips_wakeup_callback; 313 bus_dmamap_load(command->data_dmatag, command->data_dmamap, 314 command->data_buffer, IPS_ADAPTER_INFO_LEN, 315 ips_adapter_info_callback, command, BUS_DMA_NOWAIT); 316 if ((command->status.value == IPS_ERROR_STATUS) || 317 ips_timed_wait(command, "ips", 30 * hz) != 0) 318 error = ETIMEDOUT; 319 if (error == 0) { 320 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 321 BUS_DMASYNC_POSTREAD); 322 memcpy(&(sc->adapter_info), command->data_buffer, 323 IPS_ADAPTER_INFO_LEN); 324 } 325 bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 326 exit: 327 /* I suppose I should clean up my memory allocations */ 328 bus_dmamem_free(command->data_dmatag, command->data_buffer, 329 command->data_dmamap); 330 bus_dma_tag_destroy(command->data_dmatag); 331 ips_insert_free_cmd(sc, command); 332 return error; 333 } 334 335 int 336 ips_get_adapter_info(ips_softc_t *sc) 337 { 338 ips_command_t *command; 339 int error = 0; 340 341 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) { 342 device_printf(sc->dev, "unable to get adapter configuration\n"); 343 return ENXIO; 344 } 345 ips_send_adapter_info_cmd(command); 346 if (COMMAND_ERROR(&command->status)) 347 error = ENXIO; 348 return error; 349 } 350 351 /* 352 * Below are a series of functions for sending a drive info request 353 * to the adapter. The flow order is: get, send, callback. It uses 354 * the generic finish callback at the top of this file. 355 * This can be used to get drive status info from the card 356 */ 357 static void 358 ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum, 359 int error) 360 { 361 ips_softc_t *sc; 362 ips_command_t *command = cmdptr; 363 ips_drive_cmd *command_struct; 364 365 sc = command->sc; 366 if (error) { 367 368 command->status.value = IPS_ERROR_STATUS; 369 ips_insert_free_cmd(sc, command); 370 kprintf("ips: error = %d in ips_get_drive_info\n", error); 371 return; 372 } 373 command_struct = (ips_drive_cmd *)command->command_buffer; 374 command_struct->command = IPS_DRIVE_INFO_CMD; 375 command_struct->id = command->id; 376 command_struct->buffaddr = segments[0].ds_addr; 377 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 378 BUS_DMASYNC_PREWRITE); 379 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 380 BUS_DMASYNC_PREREAD); 381 sc->ips_issue_cmd(command); 382 } 383 384 static int 385 ips_send_drive_info_cmd(ips_command_t *command) 386 { 387 int error = 0; 388 ips_softc_t *sc = command->sc; 389 ips_drive_info_t *driveinfo; 390 391 if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 392 /* alignemnt */ 1, 393 /* boundary */ 0, 394 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 395 /* highaddr */ BUS_SPACE_MAXADDR, 396 /* maxsize */ IPS_DRIVE_INFO_LEN, 397 /* numsegs */ 1, 398 /* maxsegsize*/ IPS_DRIVE_INFO_LEN, 399 /* flags */ 0, 400 &command->data_dmatag) != 0) { 401 kprintf("ips: can't alloc dma tag for drive status\n"); 402 error = ENOMEM; 403 goto exit; 404 } 405 if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, 406 BUS_DMA_NOWAIT, &command->data_dmamap)) { 407 error = ENOMEM; 408 goto exit; 409 } 410 command->callback = ips_wakeup_callback; 411 bus_dmamap_load(command->data_dmatag, command->data_dmamap, 412 command->data_buffer,IPS_DRIVE_INFO_LEN, 413 ips_drive_info_callback, command, BUS_DMA_NOWAIT); 414 if ((command->status.value == IPS_ERROR_STATUS) || 415 ips_timed_wait(command, "ips", 10 * hz) != 0) 416 error = ETIMEDOUT; 417 418 if (error == 0) { 419 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 420 BUS_DMASYNC_POSTREAD); 421 driveinfo = command->data_buffer; 422 memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8); 423 sc->drivecount = driveinfo->drivecount; 424 device_printf(sc->dev, "logical drives: %d\n", sc->drivecount); 425 } 426 bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 427 exit: 428 /* I suppose I should clean up my memory allocations */ 429 bus_dmamem_free(command->data_dmatag, command->data_buffer, 430 command->data_dmamap); 431 bus_dma_tag_destroy(command->data_dmatag); 432 ips_insert_free_cmd(sc, command); 433 return error; 434 } 435 436 int 437 ips_get_drive_info(ips_softc_t *sc) 438 { 439 int error = 0; 440 ips_command_t *command; 441 442 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) { 443 device_printf(sc->dev, "unable to get drive configuration\n"); 444 return ENXIO; 445 } 446 ips_send_drive_info_cmd(command); 447 if (COMMAND_ERROR(&command->status)) 448 error = ENXIO; 449 return error; 450 } 451 452 /* 453 * Below is a pair of functions for making sure data is safely 454 * on disk by flushing the adapter's cache. 455 */ 456 static int 457 ips_send_flush_cache_cmd(ips_command_t *command) 458 { 459 ips_softc_t *sc = command->sc; 460 ips_generic_cmd *command_struct; 461 462 PRINTF(10,"ips test: got a command, building flush command\n"); 463 command->callback = ips_wakeup_callback; 464 command_struct = (ips_generic_cmd *)command->command_buffer; 465 command_struct->command = IPS_CACHE_FLUSH_CMD; 466 command_struct->id = command->id; 467 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 468 BUS_DMASYNC_PREWRITE); 469 sc->ips_issue_cmd(command); 470 if (command->status.value != IPS_ERROR_STATUS) 471 ips_timed_wait(command, "flush2", 0); 472 ips_insert_free_cmd(sc, command); 473 return 0; 474 } 475 476 int 477 ips_flush_cache(ips_softc_t *sc) 478 { 479 ips_command_t *command; 480 481 device_printf(sc->dev, "flushing cache\n"); 482 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) { 483 device_printf(sc->dev, "ERROR: unable to get a command! " 484 "can't flush cache!\n"); 485 return(1); 486 } 487 ips_send_flush_cache_cmd(command); 488 if (COMMAND_ERROR(&command->status)) { 489 device_printf(sc->dev, "ERROR: cache flush command failed!\n"); 490 return(1); 491 } 492 return 0; 493 } 494 495 /* 496 * Simplified localtime to provide timevalues for ffdc. 497 * Taken from libc/stdtime/localtime.c 498 */ 499 static void 500 ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime) 501 { 502 long days, rem, y; 503 int yleap, *ip, month; 504 int year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR }; 505 int mon_lengths[2][IPS_MONSPERYEAR] = { 506 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 507 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 508 }; 509 510 days = sctime / IPS_SECSPERDAY; 511 rem = sctime % IPS_SECSPERDAY; 512 513 command->hour = rem / IPS_SECSPERHOUR; 514 rem = rem % IPS_SECSPERHOUR; 515 516 command->minute = rem / IPS_SECSPERMIN; 517 command->second = rem % IPS_SECSPERMIN; 518 519 y = IPS_EPOCH_YEAR; 520 while (days < 0 || days >= (long)year_lengths[yleap = ips_isleap(y)]) { 521 long newy; 522 523 newy = y + days / IPS_DAYSPERNYEAR; 524 if (days < 0) 525 --newy; 526 days -= (newy - y) * IPS_DAYSPERNYEAR + 527 IPS_LEAPS_THRU_END_OF(newy - 1) - 528 IPS_LEAPS_THRU_END_OF(y - 1); 529 y = newy; 530 } 531 command->yearH = y / 100; 532 command->yearL = y % 100; 533 ip = mon_lengths[yleap]; 534 for (month = 0; days >= (long)ip[month]; ++month) 535 days = days - (long)ip[month]; 536 command->month = month + 1; 537 command->day = days + 1; 538 } 539 540 static int 541 ips_send_ffdc_reset_cmd(ips_command_t *command) 542 { 543 ips_softc_t *sc = command->sc; 544 ips_adapter_ffdc_cmd *command_struct; 545 546 PRINTF(10, "ips test: got a command, building ffdc reset command\n"); 547 command->callback = ips_wakeup_callback; 548 command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer; 549 command_struct->command = IPS_FFDC_CMD; 550 command_struct->id = command->id; 551 command_struct->reset_count = sc->ffdc_resetcount; 552 command_struct->reset_type = 0x0; 553 ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec); 554 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 555 BUS_DMASYNC_PREWRITE); 556 sc->ips_issue_cmd(command); 557 if (command->status.value != IPS_ERROR_STATUS) 558 ips_timed_wait(command, "ffdc", 0); 559 ips_insert_free_cmd(sc, command); 560 return 0; 561 } 562 563 int 564 ips_ffdc_reset(ips_softc_t *sc) 565 { 566 ips_command_t *command; 567 568 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) { 569 device_printf(sc->dev, "ERROR: unable to get a command! " 570 "can't send ffdc reset!\n"); 571 return 1; 572 } 573 ips_send_ffdc_reset_cmd(command); 574 if (COMMAND_ERROR(&command->status)) { 575 /* 576 * apparently some cards may report error status for 577 * an ffdc reset command, even though it works correctly 578 * afterwards. just complain about that and proceed here. 579 */ 580 device_printf(sc->dev, 581 "ERROR: ffdc reset command failed(0x%04x)!\n", 582 command->status.value); 583 } 584 return 0; 585 } 586 587 static void 588 ips_write_nvram(ips_command_t *command) 589 { 590 ips_softc_t *sc = command->sc; 591 ips_rw_nvram_cmd *command_struct; 592 ips_nvram_page5 *nvram; 593 594 /*FIXME check for error */ 595 command->callback = ips_wakeup_callback; 596 command_struct = (ips_rw_nvram_cmd *)command->command_buffer; 597 command_struct->command = IPS_RW_NVRAM_CMD; 598 command_struct->id = command->id; 599 command_struct->pagenum = 5; 600 command_struct->rw = 1; /* write */ 601 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 602 BUS_DMASYNC_POSTREAD); 603 nvram = command->data_buffer; 604 /* retrieve adapter info and save in sc */ 605 sc->adapter_type = nvram->adapter_type; 606 strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4); 607 strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4); 608 nvram->operating_system = IPS_OS_FREEBSD; 609 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 610 BUS_DMASYNC_PREWRITE); 611 sc->ips_issue_cmd(command); 612 } 613 614 static void 615 ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum, 616 int error) 617 { 618 ips_softc_t *sc; 619 ips_command_t *command = cmdptr; 620 ips_rw_nvram_cmd *command_struct; 621 622 sc = command->sc; 623 if (error) { 624 command->status.value = IPS_ERROR_STATUS; 625 ips_insert_free_cmd(sc, command); 626 kprintf("ips: error = %d in ips_read_nvram_callback\n", error); 627 return; 628 } 629 command_struct = (ips_rw_nvram_cmd *)command->command_buffer; 630 command_struct->command = IPS_RW_NVRAM_CMD; 631 command_struct->id = command->id; 632 command_struct->pagenum = 5; 633 command_struct->rw = 0; 634 command_struct->buffaddr = segments[0].ds_addr; 635 636 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 637 BUS_DMASYNC_PREWRITE); 638 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 639 BUS_DMASYNC_PREREAD); 640 sc->ips_issue_cmd(command); 641 } 642 643 static int 644 ips_read_nvram(ips_command_t *command) 645 { 646 int error = 0; 647 ips_softc_t *sc = command->sc; 648 649 if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 650 /* alignemnt */ 1, 651 /* boundary */ 0, 652 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 653 /* highaddr */ BUS_SPACE_MAXADDR, 654 /* maxsize */ IPS_NVRAM_PAGE_SIZE, 655 /* numsegs */ 1, 656 /* maxsegsize*/ IPS_NVRAM_PAGE_SIZE, 657 /* flags */ 0, 658 &command->data_dmatag) != 0) { 659 kprintf("ips: can't alloc dma tag for nvram\n"); 660 error = ENOMEM; 661 goto exit; 662 } 663 if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer, 664 BUS_DMA_NOWAIT, &command->data_dmamap)) { 665 error = ENOMEM; 666 goto exit; 667 } 668 command->callback = ips_write_nvram; 669 bus_dmamap_load(command->data_dmatag, command->data_dmamap, 670 command->data_buffer, IPS_NVRAM_PAGE_SIZE, ips_read_nvram_callback, 671 command, BUS_DMA_NOWAIT); 672 if ((command->status.value == IPS_ERROR_STATUS) || 673 ips_timed_wait(command, "ips", 0) != 0) 674 error = ETIMEDOUT; 675 if (error == 0) { 676 bus_dmamap_sync(command->data_dmatag, command->data_dmamap, 677 BUS_DMASYNC_POSTWRITE); 678 } 679 bus_dmamap_unload(command->data_dmatag, command->data_dmamap); 680 exit: 681 bus_dmamem_free(command->data_dmatag, command->data_buffer, 682 command->data_dmamap); 683 bus_dma_tag_destroy(command->data_dmatag); 684 ips_insert_free_cmd(sc, command); 685 return error; 686 } 687 688 int 689 ips_update_nvram(ips_softc_t *sc) 690 { 691 ips_command_t *command; 692 693 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) { 694 device_printf(sc->dev, "ERROR: unable to get a command! " 695 "can't update nvram\n"); 696 return 1; 697 } 698 ips_read_nvram(command); 699 if (COMMAND_ERROR(&command->status)) { 700 device_printf(sc->dev, "ERROR: nvram update command failed!\n"); 701 return 1; 702 } 703 return 0; 704 } 705 706 static int 707 ips_send_config_sync_cmd(ips_command_t *command) 708 { 709 ips_softc_t *sc = command->sc; 710 ips_generic_cmd *command_struct; 711 712 PRINTF(10, "ips test: got a command, building flush command\n"); 713 command->callback = ips_wakeup_callback; 714 command_struct = (ips_generic_cmd *)command->command_buffer; 715 command_struct->command = IPS_CONFIG_SYNC_CMD; 716 command_struct->id = command->id; 717 command_struct->reserve2 = IPS_POCL; 718 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 719 BUS_DMASYNC_PREWRITE); 720 sc->ips_issue_cmd(command); 721 if (command->status.value != IPS_ERROR_STATUS) 722 ips_timed_wait(command, "ipssyn", 0); 723 ips_insert_free_cmd(sc, command); 724 return 0; 725 } 726 727 static int 728 ips_send_error_table_cmd(ips_command_t *command) 729 { 730 ips_softc_t *sc = command->sc; 731 ips_generic_cmd *command_struct; 732 733 PRINTF(10, "ips test: got a command, building errortable command\n"); 734 command->callback = ips_wakeup_callback; 735 command_struct = (ips_generic_cmd *)command->command_buffer; 736 command_struct->command = IPS_ERROR_TABLE_CMD; 737 command_struct->id = command->id; 738 command_struct->reserve2 = IPS_CSL; 739 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, 740 BUS_DMASYNC_PREWRITE); 741 sc->ips_issue_cmd(command); 742 if (command->status.value != IPS_ERROR_STATUS) 743 ips_timed_wait(command, "ipsetc", 0); 744 ips_insert_free_cmd(sc, command); 745 return 0; 746 } 747 748 int 749 ips_clear_adapter(ips_softc_t *sc) 750 { 751 ips_command_t *command; 752 753 device_printf(sc->dev, "syncing config\n"); 754 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) { 755 device_printf(sc->dev, "ERROR: unable to get a command! " 756 "can't sync cache!\n"); 757 return 1; 758 } 759 ips_send_config_sync_cmd(command); 760 if (COMMAND_ERROR(&command->status)) { 761 device_printf(sc->dev, "ERROR: cache sync command failed!\n"); 762 return 1; 763 } 764 device_printf(sc->dev, "clearing error table\n"); 765 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) { 766 device_printf(sc->dev, "ERROR: unable to get a command! " 767 "can't sync cache!\n"); 768 return 1; 769 } 770 ips_send_error_table_cmd(command); 771 if (COMMAND_ERROR(&command->status)) { 772 device_printf(sc->dev, "ERROR: etable command failed!\n"); 773 return 1; 774 } 775 return 0; 776 } 777