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