rx.c revision 5a0e3ad6af8660be21ca98a971cd00f331318c05
1/* 2 * Adaptec AAC series RAID controller driver 3 * (c) Copyright 2001 Red Hat Inc. 4 * 5 * based on the old aacraid driver that is.. 6 * Adaptec aacraid device driver for Linux. 7 * 8 * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2, or (at your option) 13 * any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; see the file COPYING. If not, write to 22 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 23 * 24 * Module Name: 25 * rx.c 26 * 27 * Abstract: Hardware miniport for Drawbridge specific hardware functions. 28 * 29 */ 30 31#include <linux/kernel.h> 32#include <linux/init.h> 33#include <linux/types.h> 34#include <linux/pci.h> 35#include <linux/spinlock.h> 36#include <linux/blkdev.h> 37#include <linux/delay.h> 38#include <linux/completion.h> 39#include <linux/time.h> 40#include <linux/interrupt.h> 41 42#include <scsi/scsi_host.h> 43 44#include "aacraid.h" 45 46static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id) 47{ 48 struct aac_dev *dev = dev_id; 49 unsigned long bellbits; 50 u8 intstat = rx_readb(dev, MUnit.OISR); 51 52 /* 53 * Read mask and invert because drawbridge is reversed. 54 * This allows us to only service interrupts that have 55 * been enabled. 56 * Check to see if this is our interrupt. If it isn't just return 57 */ 58 if (likely(intstat & ~(dev->OIMR))) { 59 bellbits = rx_readl(dev, OutboundDoorbellReg); 60 if (unlikely(bellbits & DoorBellPrintfReady)) { 61 aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5])); 62 rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); 63 rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); 64 } 65 else if (unlikely(bellbits & DoorBellAdapterNormCmdReady)) { 66 rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); 67 aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); 68 } 69 else if (likely(bellbits & DoorBellAdapterNormRespReady)) { 70 rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); 71 aac_response_normal(&dev->queues->queue[HostNormRespQueue]); 72 } 73 else if (unlikely(bellbits & DoorBellAdapterNormCmdNotFull)) { 74 rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); 75 } 76 else if (unlikely(bellbits & DoorBellAdapterNormRespNotFull)) { 77 rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); 78 rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); 79 } 80 return IRQ_HANDLED; 81 } 82 return IRQ_NONE; 83} 84 85static irqreturn_t aac_rx_intr_message(int irq, void *dev_id) 86{ 87 struct aac_dev *dev = dev_id; 88 u32 Index = rx_readl(dev, MUnit.OutboundQueue); 89 if (unlikely(Index == 0xFFFFFFFFL)) 90 Index = rx_readl(dev, MUnit.OutboundQueue); 91 if (likely(Index != 0xFFFFFFFFL)) { 92 do { 93 if (unlikely(aac_intr_normal(dev, Index))) { 94 rx_writel(dev, MUnit.OutboundQueue, Index); 95 rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady); 96 } 97 Index = rx_readl(dev, MUnit.OutboundQueue); 98 } while (Index != 0xFFFFFFFFL); 99 return IRQ_HANDLED; 100 } 101 return IRQ_NONE; 102} 103 104/** 105 * aac_rx_disable_interrupt - Disable interrupts 106 * @dev: Adapter 107 */ 108 109static void aac_rx_disable_interrupt(struct aac_dev *dev) 110{ 111 rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); 112} 113 114/** 115 * aac_rx_enable_interrupt_producer - Enable interrupts 116 * @dev: Adapter 117 */ 118 119static void aac_rx_enable_interrupt_producer(struct aac_dev *dev) 120{ 121 rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); 122} 123 124/** 125 * aac_rx_enable_interrupt_message - Enable interrupts 126 * @dev: Adapter 127 */ 128 129static void aac_rx_enable_interrupt_message(struct aac_dev *dev) 130{ 131 rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); 132} 133 134/** 135 * rx_sync_cmd - send a command and wait 136 * @dev: Adapter 137 * @command: Command to execute 138 * @p1: first parameter 139 * @ret: adapter status 140 * 141 * This routine will send a synchronous command to the adapter and wait 142 * for its completion. 143 */ 144 145static int rx_sync_cmd(struct aac_dev *dev, u32 command, 146 u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, 147 u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) 148{ 149 unsigned long start; 150 int ok; 151 /* 152 * Write the command into Mailbox 0 153 */ 154 writel(command, &dev->IndexRegs->Mailbox[0]); 155 /* 156 * Write the parameters into Mailboxes 1 - 6 157 */ 158 writel(p1, &dev->IndexRegs->Mailbox[1]); 159 writel(p2, &dev->IndexRegs->Mailbox[2]); 160 writel(p3, &dev->IndexRegs->Mailbox[3]); 161 writel(p4, &dev->IndexRegs->Mailbox[4]); 162 /* 163 * Clear the synch command doorbell to start on a clean slate. 164 */ 165 rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); 166 /* 167 * Disable doorbell interrupts 168 */ 169 rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); 170 /* 171 * Force the completion of the mask register write before issuing 172 * the interrupt. 173 */ 174 rx_readb (dev, MUnit.OIMR); 175 /* 176 * Signal that there is a new synch command 177 */ 178 rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0); 179 180 ok = 0; 181 start = jiffies; 182 183 /* 184 * Wait up to 30 seconds 185 */ 186 while (time_before(jiffies, start+30*HZ)) 187 { 188 udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ 189 /* 190 * Mon960 will set doorbell0 bit when it has completed the command. 191 */ 192 if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) { 193 /* 194 * Clear the doorbell. 195 */ 196 rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); 197 ok = 1; 198 break; 199 } 200 /* 201 * Yield the processor in case we are slow 202 */ 203 msleep(1); 204 } 205 if (unlikely(ok != 1)) { 206 /* 207 * Restore interrupt mask even though we timed out 208 */ 209 aac_adapter_enable_int(dev); 210 return -ETIMEDOUT; 211 } 212 /* 213 * Pull the synch status from Mailbox 0. 214 */ 215 if (status) 216 *status = readl(&dev->IndexRegs->Mailbox[0]); 217 if (r1) 218 *r1 = readl(&dev->IndexRegs->Mailbox[1]); 219 if (r2) 220 *r2 = readl(&dev->IndexRegs->Mailbox[2]); 221 if (r3) 222 *r3 = readl(&dev->IndexRegs->Mailbox[3]); 223 if (r4) 224 *r4 = readl(&dev->IndexRegs->Mailbox[4]); 225 /* 226 * Clear the synch command doorbell. 227 */ 228 rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); 229 /* 230 * Restore interrupt mask 231 */ 232 aac_adapter_enable_int(dev); 233 return 0; 234 235} 236 237/** 238 * aac_rx_interrupt_adapter - interrupt adapter 239 * @dev: Adapter 240 * 241 * Send an interrupt to the i960 and breakpoint it. 242 */ 243 244static void aac_rx_interrupt_adapter(struct aac_dev *dev) 245{ 246 rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 247} 248 249/** 250 * aac_rx_notify_adapter - send an event to the adapter 251 * @dev: Adapter 252 * @event: Event to send 253 * 254 * Notify the i960 that something it probably cares about has 255 * happened. 256 */ 257 258static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event) 259{ 260 switch (event) { 261 262 case AdapNormCmdQue: 263 rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1); 264 break; 265 case HostNormRespNotFull: 266 rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4); 267 break; 268 case AdapNormRespQue: 269 rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2); 270 break; 271 case HostNormCmdNotFull: 272 rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3); 273 break; 274 case HostShutdown: 275 break; 276 case FastIo: 277 rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6); 278 break; 279 case AdapPrintfDone: 280 rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5); 281 break; 282 default: 283 BUG(); 284 break; 285 } 286} 287 288/** 289 * aac_rx_start_adapter - activate adapter 290 * @dev: Adapter 291 * 292 * Start up processing on an i960 based AAC adapter 293 */ 294 295static void aac_rx_start_adapter(struct aac_dev *dev) 296{ 297 struct aac_init *init; 298 299 init = dev->init; 300 init->HostElapsedSeconds = cpu_to_le32(get_seconds()); 301 // We can only use a 32 bit address here 302 rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, 303 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 304} 305 306/** 307 * aac_rx_check_health 308 * @dev: device to check if healthy 309 * 310 * Will attempt to determine if the specified adapter is alive and 311 * capable of handling requests, returning 0 if alive. 312 */ 313static int aac_rx_check_health(struct aac_dev *dev) 314{ 315 u32 status = rx_readl(dev, MUnit.OMRx[0]); 316 317 /* 318 * Check to see if the board failed any self tests. 319 */ 320 if (unlikely(status & SELF_TEST_FAILED)) 321 return -1; 322 /* 323 * Check to see if the board panic'd. 324 */ 325 if (unlikely(status & KERNEL_PANIC)) { 326 char * buffer; 327 struct POSTSTATUS { 328 __le32 Post_Command; 329 __le32 Post_Address; 330 } * post; 331 dma_addr_t paddr, baddr; 332 int ret; 333 334 if (likely((status & 0xFF000000L) == 0xBC000000L)) 335 return (status >> 16) & 0xFF; 336 buffer = pci_alloc_consistent(dev->pdev, 512, &baddr); 337 ret = -2; 338 if (unlikely(buffer == NULL)) 339 return ret; 340 post = pci_alloc_consistent(dev->pdev, 341 sizeof(struct POSTSTATUS), &paddr); 342 if (unlikely(post == NULL)) { 343 pci_free_consistent(dev->pdev, 512, buffer, baddr); 344 return ret; 345 } 346 memset(buffer, 0, 512); 347 post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS); 348 post->Post_Address = cpu_to_le32(baddr); 349 rx_writel(dev, MUnit.IMRx[0], paddr); 350 rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0, 351 NULL, NULL, NULL, NULL, NULL); 352 pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS), 353 post, paddr); 354 if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) { 355 ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10); 356 ret <<= 4; 357 ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10); 358 } 359 pci_free_consistent(dev->pdev, 512, buffer, baddr); 360 return ret; 361 } 362 /* 363 * Wait for the adapter to be up and running. 364 */ 365 if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) 366 return -3; 367 /* 368 * Everything is OK 369 */ 370 return 0; 371} 372 373/** 374 * aac_rx_deliver_producer 375 * @fib: fib to issue 376 * 377 * Will send a fib, returning 0 if successful. 378 */ 379int aac_rx_deliver_producer(struct fib * fib) 380{ 381 struct aac_dev *dev = fib->dev; 382 struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; 383 unsigned long qflags; 384 u32 Index; 385 unsigned long nointr = 0; 386 387 spin_lock_irqsave(q->lock, qflags); 388 aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib_va, 1, fib, &nointr); 389 390 q->numpending++; 391 *(q->headers.producer) = cpu_to_le32(Index + 1); 392 spin_unlock_irqrestore(q->lock, qflags); 393 if (!(nointr & aac_config.irq_mod)) 394 aac_adapter_notify(dev, AdapNormCmdQueue); 395 396 return 0; 397} 398 399/** 400 * aac_rx_deliver_message 401 * @fib: fib to issue 402 * 403 * Will send a fib, returning 0 if successful. 404 */ 405static int aac_rx_deliver_message(struct fib * fib) 406{ 407 struct aac_dev *dev = fib->dev; 408 struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; 409 unsigned long qflags; 410 u32 Index; 411 u64 addr; 412 volatile void __iomem *device; 413 414 unsigned long count = 10000000L; /* 50 seconds */ 415 spin_lock_irqsave(q->lock, qflags); 416 q->numpending++; 417 spin_unlock_irqrestore(q->lock, qflags); 418 for(;;) { 419 Index = rx_readl(dev, MUnit.InboundQueue); 420 if (unlikely(Index == 0xFFFFFFFFL)) 421 Index = rx_readl(dev, MUnit.InboundQueue); 422 if (likely(Index != 0xFFFFFFFFL)) 423 break; 424 if (--count == 0) { 425 spin_lock_irqsave(q->lock, qflags); 426 q->numpending--; 427 spin_unlock_irqrestore(q->lock, qflags); 428 return -ETIMEDOUT; 429 } 430 udelay(5); 431 } 432 device = dev->base + Index; 433 addr = fib->hw_fib_pa; 434 writel((u32)(addr & 0xffffffff), device); 435 device += sizeof(u32); 436 writel((u32)(addr >> 32), device); 437 device += sizeof(u32); 438 writel(le16_to_cpu(fib->hw_fib_va->header.Size), device); 439 rx_writel(dev, MUnit.InboundQueue, Index); 440 return 0; 441} 442 443/** 444 * aac_rx_ioremap 445 * @size: mapping resize request 446 * 447 */ 448static int aac_rx_ioremap(struct aac_dev * dev, u32 size) 449{ 450 if (!size) { 451 iounmap(dev->regs.rx); 452 return 0; 453 } 454 dev->base = dev->regs.rx = ioremap(dev->scsi_host_ptr->base, size); 455 if (dev->base == NULL) 456 return -1; 457 dev->IndexRegs = &dev->regs.rx->IndexRegs; 458 return 0; 459} 460 461static int aac_rx_restart_adapter(struct aac_dev *dev, int bled) 462{ 463 u32 var; 464 465 if (!(dev->supplement_adapter_info.SupportedOptions2 & 466 AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) { 467 if (bled) 468 printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", 469 dev->name, dev->id, bled); 470 else { 471 bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, 472 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); 473 if (!bled && (var != 0x00000001) && (var != 0x3803000F)) 474 bled = -EINVAL; 475 } 476 if (bled && (bled != -ETIMEDOUT)) 477 bled = aac_adapter_sync_cmd(dev, IOP_RESET, 478 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); 479 480 if (bled && (bled != -ETIMEDOUT)) 481 return -EINVAL; 482 } 483 if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */ 484 rx_writel(dev, MUnit.reserved2, 3); 485 msleep(5000); /* Delay 5 seconds */ 486 var = 0x00000001; 487 } 488 if (var != 0x00000001) 489 return -EINVAL; 490 if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) 491 return -ENODEV; 492 if (startup_timeout < 300) 493 startup_timeout = 300; 494 return 0; 495} 496 497/** 498 * aac_rx_select_comm - Select communications method 499 * @dev: Adapter 500 * @comm: communications method 501 */ 502 503int aac_rx_select_comm(struct aac_dev *dev, int comm) 504{ 505 switch (comm) { 506 case AAC_COMM_PRODUCER: 507 dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_producer; 508 dev->a_ops.adapter_intr = aac_rx_intr_producer; 509 dev->a_ops.adapter_deliver = aac_rx_deliver_producer; 510 break; 511 case AAC_COMM_MESSAGE: 512 dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_message; 513 dev->a_ops.adapter_intr = aac_rx_intr_message; 514 dev->a_ops.adapter_deliver = aac_rx_deliver_message; 515 break; 516 default: 517 return 1; 518 } 519 return 0; 520} 521 522/** 523 * aac_rx_init - initialize an i960 based AAC card 524 * @dev: device to configure 525 * 526 * Allocate and set up resources for the i960 based AAC variants. The 527 * device_interface in the commregion will be allocated and linked 528 * to the comm region. 529 */ 530 531int _aac_rx_init(struct aac_dev *dev) 532{ 533 unsigned long start; 534 unsigned long status; 535 int restart = 0; 536 int instance = dev->id; 537 const char * name = dev->name; 538 539 if (aac_adapter_ioremap(dev, dev->base_size)) { 540 printk(KERN_WARNING "%s: unable to map adapter.\n", name); 541 goto error_iounmap; 542 } 543 544 /* Failure to reset here is an option ... */ 545 dev->a_ops.adapter_sync_cmd = rx_sync_cmd; 546 dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt; 547 dev->OIMR = status = rx_readb (dev, MUnit.OIMR); 548 if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) && 549 !aac_rx_restart_adapter(dev, 0)) 550 /* Make sure the Hardware FIFO is empty */ 551 while ((++restart < 512) && 552 (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL)); 553 /* 554 * Check to see if the board panic'd while booting. 555 */ 556 status = rx_readl(dev, MUnit.OMRx[0]); 557 if (status & KERNEL_PANIC) { 558 if (aac_rx_restart_adapter(dev, aac_rx_check_health(dev))) 559 goto error_iounmap; 560 ++restart; 561 } 562 /* 563 * Check to see if the board failed any self tests. 564 */ 565 status = rx_readl(dev, MUnit.OMRx[0]); 566 if (status & SELF_TEST_FAILED) { 567 printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); 568 goto error_iounmap; 569 } 570 /* 571 * Check to see if the monitor panic'd while booting. 572 */ 573 if (status & MONITOR_PANIC) { 574 printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); 575 goto error_iounmap; 576 } 577 start = jiffies; 578 /* 579 * Wait for the adapter to be up and running. Wait up to 3 minutes 580 */ 581 while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING)) 582 { 583 if ((restart && 584 (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || 585 time_after(jiffies, start+HZ*startup_timeout)) { 586 printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 587 dev->name, instance, status); 588 goto error_iounmap; 589 } 590 if (!restart && 591 ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || 592 time_after(jiffies, start + HZ * 593 ((startup_timeout > 60) 594 ? (startup_timeout - 60) 595 : (startup_timeout / 2))))) { 596 if (likely(!aac_rx_restart_adapter(dev, aac_rx_check_health(dev)))) 597 start = jiffies; 598 ++restart; 599 } 600 msleep(1); 601 } 602 if (restart && aac_commit) 603 aac_commit = 1; 604 /* 605 * Fill in the common function dispatch table. 606 */ 607 dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; 608 dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; 609 dev->a_ops.adapter_notify = aac_rx_notify_adapter; 610 dev->a_ops.adapter_sync_cmd = rx_sync_cmd; 611 dev->a_ops.adapter_check_health = aac_rx_check_health; 612 dev->a_ops.adapter_restart = aac_rx_restart_adapter; 613 614 /* 615 * First clear out all interrupts. Then enable the one's that we 616 * can handle. 617 */ 618 aac_adapter_comm(dev, AAC_COMM_PRODUCER); 619 aac_adapter_disable_int(dev); 620 rx_writel(dev, MUnit.ODR, 0xffffffff); 621 aac_adapter_enable_int(dev); 622 623 if (aac_init_adapter(dev) == NULL) 624 goto error_iounmap; 625 aac_adapter_comm(dev, dev->comm_interface); 626 dev->msi = aac_msi && !pci_enable_msi(dev->pdev); 627 if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, 628 IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) { 629 if (dev->msi) 630 pci_disable_msi(dev->pdev); 631 printk(KERN_ERR "%s%d: Interrupt unavailable.\n", 632 name, instance); 633 goto error_iounmap; 634 } 635 aac_adapter_enable_int(dev); 636 /* 637 * Tell the adapter that all is configured, and it can 638 * start accepting requests 639 */ 640 aac_rx_start_adapter(dev); 641 642 return 0; 643 644error_iounmap: 645 646 return -1; 647} 648 649int aac_rx_init(struct aac_dev *dev) 650{ 651 /* 652 * Fill in the function dispatch table. 653 */ 654 dev->a_ops.adapter_ioremap = aac_rx_ioremap; 655 dev->a_ops.adapter_comm = aac_rx_select_comm; 656 657 return _aac_rx_init(dev); 658} 659