Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.12-rc6 666 lines 16 kB view raw
1/* 2 * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) 3 * 4 * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net) 5 * 6 * VME support added by Sam Creasey 7 * 8 * TODO: modify this driver to support multiple Sun3 SCSI VME boards 9 * 10 * Adapted from mac_scsinew.c: 11 */ 12/* 13 * Generic Macintosh NCR5380 driver 14 * 15 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov> 16 * 17 * derived in part from: 18 */ 19/* 20 * Generic Generic NCR5380 driver 21 * 22 * Copyright 1995, Russell King 23 */ 24 25#include <linux/types.h> 26#include <linux/delay.h> 27#include <linux/module.h> 28#include <linux/ioport.h> 29#include <linux/init.h> 30#include <linux/blkdev.h> 31#include <linux/platform_device.h> 32 33#include <asm/io.h> 34#include <asm/dvma.h> 35 36#include <scsi/scsi_host.h> 37 38/* minimum number of bytes to do dma on */ 39#define DMA_MIN_SIZE 129 40 41/* Definitions for the core NCR5380 driver. */ 42 43#define NCR5380_implementation_fields /* none */ 44 45#define NCR5380_read(reg) in_8(hostdata->io + (reg)) 46#define NCR5380_write(reg, value) out_8(hostdata->io + (reg), value) 47 48#define NCR5380_queue_command sun3scsi_queue_command 49#define NCR5380_bus_reset sun3scsi_bus_reset 50#define NCR5380_abort sun3scsi_abort 51#define NCR5380_info sun3scsi_info 52 53#define NCR5380_dma_xfer_len sun3scsi_dma_xfer_len 54#define NCR5380_dma_recv_setup sun3scsi_dma_count 55#define NCR5380_dma_send_setup sun3scsi_dma_count 56#define NCR5380_dma_residual sun3scsi_dma_residual 57 58#include "NCR5380.h" 59 60/* dma regs start at regbase + 8, directly after the NCR regs */ 61struct sun3_dma_regs { 62 unsigned short dma_addr_hi; /* vme only */ 63 unsigned short dma_addr_lo; /* vme only */ 64 unsigned short dma_count_hi; /* vme only */ 65 unsigned short dma_count_lo; /* vme only */ 66 unsigned short udc_data; /* udc dma data reg (obio only) */ 67 unsigned short udc_addr; /* uda dma addr reg (obio only) */ 68 unsigned short fifo_data; /* fifo data reg, 69 * holds extra byte on odd dma reads 70 */ 71 unsigned short fifo_count; 72 unsigned short csr; /* control/status reg */ 73 unsigned short bpack_hi; /* vme only */ 74 unsigned short bpack_lo; /* vme only */ 75 unsigned short ivect; /* vme only */ 76 unsigned short fifo_count_hi; /* vme only */ 77}; 78 79/* ucd chip specific regs - live in dvma space */ 80struct sun3_udc_regs { 81 unsigned short rsel; /* select regs to load */ 82 unsigned short addr_hi; /* high word of addr */ 83 unsigned short addr_lo; /* low word */ 84 unsigned short count; /* words to be xfer'd */ 85 unsigned short mode_hi; /* high word of channel mode */ 86 unsigned short mode_lo; /* low word of channel mode */ 87}; 88 89/* addresses of the udc registers */ 90#define UDC_MODE 0x38 91#define UDC_CSR 0x2e /* command/status */ 92#define UDC_CHN_HI 0x26 /* chain high word */ 93#define UDC_CHN_LO 0x22 /* chain lo word */ 94#define UDC_CURA_HI 0x1a /* cur reg A high */ 95#define UDC_CURA_LO 0x0a /* cur reg A low */ 96#define UDC_CURB_HI 0x12 /* cur reg B high */ 97#define UDC_CURB_LO 0x02 /* cur reg B low */ 98#define UDC_MODE_HI 0x56 /* mode reg high */ 99#define UDC_MODE_LO 0x52 /* mode reg low */ 100#define UDC_COUNT 0x32 /* words to xfer */ 101 102/* some udc commands */ 103#define UDC_RESET 0 104#define UDC_CHN_START 0xa0 /* start chain */ 105#define UDC_INT_ENABLE 0x32 /* channel 1 int on */ 106 107/* udc mode words */ 108#define UDC_MODE_HIWORD 0x40 109#define UDC_MODE_LSEND 0xc2 110#define UDC_MODE_LRECV 0xd2 111 112/* udc reg selections */ 113#define UDC_RSEL_SEND 0x282 114#define UDC_RSEL_RECV 0x182 115 116/* bits in csr reg */ 117#define CSR_DMA_ACTIVE 0x8000 118#define CSR_DMA_CONFLICT 0x4000 119#define CSR_DMA_BUSERR 0x2000 120 121#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */ 122#define CSR_SDB_INT 0x200 /* sbc interrupt pending */ 123#define CSR_DMA_INT 0x100 /* dma interrupt pending */ 124 125#define CSR_LEFT 0xc0 126#define CSR_LEFT_3 0xc0 127#define CSR_LEFT_2 0x80 128#define CSR_LEFT_1 0x40 129#define CSR_PACK_ENABLE 0x20 130 131#define CSR_DMA_ENABLE 0x10 132 133#define CSR_SEND 0x8 /* 1 = send 0 = recv */ 134#define CSR_FIFO 0x2 /* reset fifo */ 135#define CSR_INTR 0x4 /* interrupt enable */ 136#define CSR_SCSI 0x1 137 138#define VME_DATA24 0x3d00 139 140extern int sun3_map_test(unsigned long, char *); 141 142static int setup_can_queue = -1; 143module_param(setup_can_queue, int, 0); 144static int setup_cmd_per_lun = -1; 145module_param(setup_cmd_per_lun, int, 0); 146static int setup_sg_tablesize = -1; 147module_param(setup_sg_tablesize, int, 0); 148static int setup_hostid = -1; 149module_param(setup_hostid, int, 0); 150 151/* ms to wait after hitting dma regs */ 152#define SUN3_DMA_DELAY 10 153 154/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */ 155#define SUN3_DVMA_BUFSIZE 0xe000 156 157static struct scsi_cmnd *sun3_dma_setup_done; 158static volatile struct sun3_dma_regs *dregs; 159static struct sun3_udc_regs *udc_regs; 160static unsigned char *sun3_dma_orig_addr; 161static unsigned long sun3_dma_orig_count; 162static int sun3_dma_active; 163static unsigned long last_residual; 164 165#ifndef SUN3_SCSI_VME 166/* dma controller register access functions */ 167 168static inline unsigned short sun3_udc_read(unsigned char reg) 169{ 170 unsigned short ret; 171 172 dregs->udc_addr = UDC_CSR; 173 udelay(SUN3_DMA_DELAY); 174 ret = dregs->udc_data; 175 udelay(SUN3_DMA_DELAY); 176 177 return ret; 178} 179 180static inline void sun3_udc_write(unsigned short val, unsigned char reg) 181{ 182 dregs->udc_addr = reg; 183 udelay(SUN3_DMA_DELAY); 184 dregs->udc_data = val; 185 udelay(SUN3_DMA_DELAY); 186} 187#endif 188 189// safe bits for the CSR 190#define CSR_GOOD 0x060f 191 192static irqreturn_t scsi_sun3_intr(int irq, void *dev) 193{ 194 struct Scsi_Host *instance = dev; 195 unsigned short csr = dregs->csr; 196 int handled = 0; 197 198#ifdef SUN3_SCSI_VME 199 dregs->csr &= ~CSR_DMA_ENABLE; 200#endif 201 202 if(csr & ~CSR_GOOD) { 203 if (csr & CSR_DMA_BUSERR) 204 shost_printk(KERN_ERR, instance, "bus error in DMA\n"); 205 if (csr & CSR_DMA_CONFLICT) 206 shost_printk(KERN_ERR, instance, "DMA conflict\n"); 207 handled = 1; 208 } 209 210 if(csr & (CSR_SDB_INT | CSR_DMA_INT)) { 211 NCR5380_intr(irq, dev); 212 handled = 1; 213 } 214 215 return IRQ_RETVAL(handled); 216} 217 218/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */ 219static int sun3scsi_dma_setup(struct NCR5380_hostdata *hostdata, 220 unsigned char *data, int count, int write_flag) 221{ 222 void *addr; 223 224 if(sun3_dma_orig_addr != NULL) 225 dvma_unmap(sun3_dma_orig_addr); 226 227#ifdef SUN3_SCSI_VME 228 addr = (void *)dvma_map_vme((unsigned long) data, count); 229#else 230 addr = (void *)dvma_map((unsigned long) data, count); 231#endif 232 233 sun3_dma_orig_addr = addr; 234 sun3_dma_orig_count = count; 235 236#ifndef SUN3_SCSI_VME 237 dregs->fifo_count = 0; 238 sun3_udc_write(UDC_RESET, UDC_CSR); 239 240 /* reset fifo */ 241 dregs->csr &= ~CSR_FIFO; 242 dregs->csr |= CSR_FIFO; 243#endif 244 245 /* set direction */ 246 if(write_flag) 247 dregs->csr |= CSR_SEND; 248 else 249 dregs->csr &= ~CSR_SEND; 250 251#ifdef SUN3_SCSI_VME 252 dregs->csr |= CSR_PACK_ENABLE; 253 254 dregs->dma_addr_hi = ((unsigned long)addr >> 16); 255 dregs->dma_addr_lo = ((unsigned long)addr & 0xffff); 256 257 dregs->dma_count_hi = 0; 258 dregs->dma_count_lo = 0; 259 dregs->fifo_count_hi = 0; 260 dregs->fifo_count = 0; 261#else 262 /* byte count for fifo */ 263 dregs->fifo_count = count; 264 265 sun3_udc_write(UDC_RESET, UDC_CSR); 266 267 /* reset fifo */ 268 dregs->csr &= ~CSR_FIFO; 269 dregs->csr |= CSR_FIFO; 270 271 if(dregs->fifo_count != count) { 272 shost_printk(KERN_ERR, hostdata->host, 273 "FIFO mismatch %04x not %04x\n", 274 dregs->fifo_count, (unsigned int) count); 275 NCR5380_dprint(NDEBUG_DMA, hostdata->host); 276 } 277 278 /* setup udc */ 279 udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8); 280 udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff); 281 udc_regs->count = count/2; /* count in words */ 282 udc_regs->mode_hi = UDC_MODE_HIWORD; 283 if(write_flag) { 284 if(count & 1) 285 udc_regs->count++; 286 udc_regs->mode_lo = UDC_MODE_LSEND; 287 udc_regs->rsel = UDC_RSEL_SEND; 288 } else { 289 udc_regs->mode_lo = UDC_MODE_LRECV; 290 udc_regs->rsel = UDC_RSEL_RECV; 291 } 292 293 /* announce location of regs block */ 294 sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8), 295 UDC_CHN_HI); 296 297 sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO); 298 299 /* set dma master on */ 300 sun3_udc_write(0xd, UDC_MODE); 301 302 /* interrupt enable */ 303 sun3_udc_write(UDC_INT_ENABLE, UDC_CSR); 304#endif 305 306 return count; 307 308} 309 310static int sun3scsi_dma_count(struct NCR5380_hostdata *hostdata, 311 unsigned char *data, int count) 312{ 313 return count; 314} 315 316static inline int sun3scsi_dma_recv_setup(struct NCR5380_hostdata *hostdata, 317 unsigned char *data, int count) 318{ 319 return sun3scsi_dma_setup(hostdata, data, count, 0); 320} 321 322static inline int sun3scsi_dma_send_setup(struct NCR5380_hostdata *hostdata, 323 unsigned char *data, int count) 324{ 325 return sun3scsi_dma_setup(hostdata, data, count, 1); 326} 327 328static int sun3scsi_dma_residual(struct NCR5380_hostdata *hostdata) 329{ 330 return last_residual; 331} 332 333static int sun3scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, 334 struct scsi_cmnd *cmd) 335{ 336 int wanted_len = cmd->SCp.this_residual; 337 338 if (wanted_len < DMA_MIN_SIZE || blk_rq_is_passthrough(cmd->request)) 339 return 0; 340 341 return wanted_len; 342} 343 344static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data) 345{ 346#ifdef SUN3_SCSI_VME 347 unsigned short csr; 348 349 csr = dregs->csr; 350 351 dregs->dma_count_hi = (sun3_dma_orig_count >> 16); 352 dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff); 353 354 dregs->fifo_count_hi = (sun3_dma_orig_count >> 16); 355 dregs->fifo_count = (sun3_dma_orig_count & 0xffff); 356 357/* if(!(csr & CSR_DMA_ENABLE)) 358 * dregs->csr |= CSR_DMA_ENABLE; 359 */ 360#else 361 sun3_udc_write(UDC_CHN_START, UDC_CSR); 362#endif 363 364 return 0; 365} 366 367/* clean up after our dma is done */ 368static int sun3scsi_dma_finish(int write_flag) 369{ 370 unsigned short __maybe_unused count; 371 unsigned short fifo; 372 int ret = 0; 373 374 sun3_dma_active = 0; 375 376#ifdef SUN3_SCSI_VME 377 dregs->csr &= ~CSR_DMA_ENABLE; 378 379 fifo = dregs->fifo_count; 380 if (write_flag) { 381 if ((fifo > 0) && (fifo < sun3_dma_orig_count)) 382 fifo++; 383 } 384 385 last_residual = fifo; 386 /* empty bytes from the fifo which didn't make it */ 387 if ((!write_flag) && (dregs->csr & CSR_LEFT)) { 388 unsigned char *vaddr; 389 390 vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr); 391 392 vaddr += (sun3_dma_orig_count - fifo); 393 vaddr--; 394 395 switch (dregs->csr & CSR_LEFT) { 396 case CSR_LEFT_3: 397 *vaddr = (dregs->bpack_lo & 0xff00) >> 8; 398 vaddr--; 399 400 case CSR_LEFT_2: 401 *vaddr = (dregs->bpack_hi & 0x00ff); 402 vaddr--; 403 404 case CSR_LEFT_1: 405 *vaddr = (dregs->bpack_hi & 0xff00) >> 8; 406 break; 407 } 408 } 409#else 410 // check to empty the fifo on a read 411 if(!write_flag) { 412 int tmo = 20000; /* .2 sec */ 413 414 while(1) { 415 if(dregs->csr & CSR_FIFO_EMPTY) 416 break; 417 418 if(--tmo <= 0) { 419 printk("sun3scsi: fifo failed to empty!\n"); 420 return 1; 421 } 422 udelay(10); 423 } 424 } 425 426 dregs->udc_addr = 0x32; 427 udelay(SUN3_DMA_DELAY); 428 count = 2 * dregs->udc_data; 429 udelay(SUN3_DMA_DELAY); 430 431 fifo = dregs->fifo_count; 432 last_residual = fifo; 433 434 /* empty bytes from the fifo which didn't make it */ 435 if((!write_flag) && (count - fifo) == 2) { 436 unsigned short data; 437 unsigned char *vaddr; 438 439 data = dregs->fifo_data; 440 vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr); 441 442 vaddr += (sun3_dma_orig_count - fifo); 443 444 vaddr[-2] = (data & 0xff00) >> 8; 445 vaddr[-1] = (data & 0xff); 446 } 447#endif 448 449 dvma_unmap(sun3_dma_orig_addr); 450 sun3_dma_orig_addr = NULL; 451 452#ifdef SUN3_SCSI_VME 453 dregs->dma_addr_hi = 0; 454 dregs->dma_addr_lo = 0; 455 dregs->dma_count_hi = 0; 456 dregs->dma_count_lo = 0; 457 458 dregs->fifo_count = 0; 459 dregs->fifo_count_hi = 0; 460 461 dregs->csr &= ~CSR_SEND; 462/* dregs->csr |= CSR_DMA_ENABLE; */ 463#else 464 sun3_udc_write(UDC_RESET, UDC_CSR); 465 dregs->fifo_count = 0; 466 dregs->csr &= ~CSR_SEND; 467 468 /* reset fifo */ 469 dregs->csr &= ~CSR_FIFO; 470 dregs->csr |= CSR_FIFO; 471#endif 472 473 sun3_dma_setup_done = NULL; 474 475 return ret; 476 477} 478 479#include "NCR5380.c" 480 481#ifdef SUN3_SCSI_VME 482#define SUN3_SCSI_NAME "Sun3 NCR5380 VME SCSI" 483#define DRV_MODULE_NAME "sun3_scsi_vme" 484#else 485#define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI" 486#define DRV_MODULE_NAME "sun3_scsi" 487#endif 488 489#define PFX DRV_MODULE_NAME ": " 490 491static struct scsi_host_template sun3_scsi_template = { 492 .module = THIS_MODULE, 493 .proc_name = DRV_MODULE_NAME, 494 .name = SUN3_SCSI_NAME, 495 .info = sun3scsi_info, 496 .queuecommand = sun3scsi_queue_command, 497 .eh_abort_handler = sun3scsi_abort, 498 .eh_bus_reset_handler = sun3scsi_bus_reset, 499 .can_queue = 16, 500 .this_id = 7, 501 .sg_tablesize = SG_NONE, 502 .cmd_per_lun = 2, 503 .use_clustering = DISABLE_CLUSTERING, 504 .cmd_size = NCR5380_CMD_SIZE, 505}; 506 507static int __init sun3_scsi_probe(struct platform_device *pdev) 508{ 509 struct Scsi_Host *instance; 510 struct NCR5380_hostdata *hostdata; 511 int error; 512 struct resource *irq, *mem; 513 void __iomem *ioaddr; 514 int host_flags = 0; 515#ifdef SUN3_SCSI_VME 516 int i; 517#endif 518 519 if (setup_can_queue > 0) 520 sun3_scsi_template.can_queue = setup_can_queue; 521 if (setup_cmd_per_lun > 0) 522 sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun; 523 if (setup_sg_tablesize >= 0) 524 sun3_scsi_template.sg_tablesize = setup_sg_tablesize; 525 if (setup_hostid >= 0) 526 sun3_scsi_template.this_id = setup_hostid & 7; 527 528#ifdef SUN3_SCSI_VME 529 ioaddr = NULL; 530 for (i = 0; i < 2; i++) { 531 unsigned char x; 532 533 irq = platform_get_resource(pdev, IORESOURCE_IRQ, i); 534 mem = platform_get_resource(pdev, IORESOURCE_MEM, i); 535 if (!irq || !mem) 536 break; 537 538 ioaddr = sun3_ioremap(mem->start, resource_size(mem), 539 SUN3_PAGE_TYPE_VME16); 540 dregs = (struct sun3_dma_regs *)(ioaddr + 8); 541 542 if (sun3_map_test((unsigned long)dregs, &x)) { 543 unsigned short oldcsr; 544 545 oldcsr = dregs->csr; 546 dregs->csr = 0; 547 udelay(SUN3_DMA_DELAY); 548 if (dregs->csr == 0x1400) 549 break; 550 551 dregs->csr = oldcsr; 552 } 553 554 iounmap(ioaddr); 555 ioaddr = NULL; 556 } 557 if (!ioaddr) 558 return -ENODEV; 559#else 560 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 561 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 562 if (!irq || !mem) 563 return -ENODEV; 564 565 ioaddr = ioremap(mem->start, resource_size(mem)); 566 dregs = (struct sun3_dma_regs *)(ioaddr + 8); 567 568 udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs)); 569 if (!udc_regs) { 570 pr_err(PFX "couldn't allocate DVMA memory!\n"); 571 iounmap(ioaddr); 572 return -ENOMEM; 573 } 574#endif 575 576 instance = scsi_host_alloc(&sun3_scsi_template, 577 sizeof(struct NCR5380_hostdata)); 578 if (!instance) { 579 error = -ENOMEM; 580 goto fail_alloc; 581 } 582 583 instance->irq = irq->start; 584 585 hostdata = shost_priv(instance); 586 hostdata->base = mem->start; 587 hostdata->io = ioaddr; 588 589 error = NCR5380_init(instance, host_flags); 590 if (error) 591 goto fail_init; 592 593 error = request_irq(instance->irq, scsi_sun3_intr, 0, 594 "NCR5380", instance); 595 if (error) { 596 pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n", 597 instance->host_no, instance->irq); 598 goto fail_irq; 599 } 600 601 dregs->csr = 0; 602 udelay(SUN3_DMA_DELAY); 603 dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR; 604 udelay(SUN3_DMA_DELAY); 605 dregs->fifo_count = 0; 606#ifdef SUN3_SCSI_VME 607 dregs->fifo_count_hi = 0; 608 dregs->dma_addr_hi = 0; 609 dregs->dma_addr_lo = 0; 610 dregs->dma_count_hi = 0; 611 dregs->dma_count_lo = 0; 612 613 dregs->ivect = VME_DATA24 | (instance->irq & 0xff); 614#endif 615 616 NCR5380_maybe_reset_bus(instance); 617 618 error = scsi_add_host(instance, NULL); 619 if (error) 620 goto fail_host; 621 622 platform_set_drvdata(pdev, instance); 623 624 scsi_scan_host(instance); 625 return 0; 626 627fail_host: 628 free_irq(instance->irq, instance); 629fail_irq: 630 NCR5380_exit(instance); 631fail_init: 632 scsi_host_put(instance); 633fail_alloc: 634 if (udc_regs) 635 dvma_free(udc_regs); 636 iounmap(ioaddr); 637 return error; 638} 639 640static int __exit sun3_scsi_remove(struct platform_device *pdev) 641{ 642 struct Scsi_Host *instance = platform_get_drvdata(pdev); 643 struct NCR5380_hostdata *hostdata = shost_priv(instance); 644 void __iomem *ioaddr = hostdata->io; 645 646 scsi_remove_host(instance); 647 free_irq(instance->irq, instance); 648 NCR5380_exit(instance); 649 scsi_host_put(instance); 650 if (udc_regs) 651 dvma_free(udc_regs); 652 iounmap(ioaddr); 653 return 0; 654} 655 656static struct platform_driver sun3_scsi_driver = { 657 .remove = __exit_p(sun3_scsi_remove), 658 .driver = { 659 .name = DRV_MODULE_NAME, 660 }, 661}; 662 663module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe); 664 665MODULE_ALIAS("platform:" DRV_MODULE_NAME); 666MODULE_LICENSE("GPL");