linux/drivers/scsi/mac_scsi.c
<<
>>
Prefs
   1/*
   2 * Generic Macintosh NCR5380 driver
   3 *
   4 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
   5 *
   6 * derived in part from:
   7 */
   8/*
   9 * Generic Generic NCR5380 driver
  10 *
  11 * Copyright 1995, Russell King
  12 */
  13
  14#include <linux/types.h>
  15#include <linux/module.h>
  16#include <linux/ioport.h>
  17#include <linux/init.h>
  18#include <linux/blkdev.h>
  19#include <linux/interrupt.h>
  20#include <linux/platform_device.h>
  21
  22#include <asm/hwtest.h>
  23#include <asm/io.h>
  24#include <asm/macints.h>
  25#include <asm/setup.h>
  26
  27#include <scsi/scsi_host.h>
  28
  29/* Definitions for the core NCR5380 driver. */
  30
  31#define NCR5380_implementation_fields   int pdma_residual
  32
  33#define NCR5380_read(reg)           in_8(hostdata->io + ((reg) << 4))
  34#define NCR5380_write(reg, value)   out_8(hostdata->io + ((reg) << 4), value)
  35
  36#define NCR5380_dma_xfer_len            macscsi_dma_xfer_len
  37#define NCR5380_dma_recv_setup          macscsi_pread
  38#define NCR5380_dma_send_setup          macscsi_pwrite
  39#define NCR5380_dma_residual            macscsi_dma_residual
  40
  41#define NCR5380_intr                    macscsi_intr
  42#define NCR5380_queue_command           macscsi_queue_command
  43#define NCR5380_abort                   macscsi_abort
  44#define NCR5380_host_reset              macscsi_host_reset
  45#define NCR5380_info                    macscsi_info
  46
  47#include "NCR5380.h"
  48
  49static int setup_can_queue = -1;
  50module_param(setup_can_queue, int, 0);
  51static int setup_cmd_per_lun = -1;
  52module_param(setup_cmd_per_lun, int, 0);
  53static int setup_sg_tablesize = -1;
  54module_param(setup_sg_tablesize, int, 0);
  55static int setup_use_pdma = -1;
  56module_param(setup_use_pdma, int, 0);
  57static int setup_hostid = -1;
  58module_param(setup_hostid, int, 0);
  59static int setup_toshiba_delay = -1;
  60module_param(setup_toshiba_delay, int, 0);
  61
  62#ifndef MODULE
  63static int __init mac_scsi_setup(char *str)
  64{
  65        int ints[8];
  66
  67        (void)get_options(str, ARRAY_SIZE(ints), ints);
  68
  69        if (ints[0] < 1) {
  70                pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n");
  71                return 0;
  72        }
  73        if (ints[0] >= 1)
  74                setup_can_queue = ints[1];
  75        if (ints[0] >= 2)
  76                setup_cmd_per_lun = ints[2];
  77        if (ints[0] >= 3)
  78                setup_sg_tablesize = ints[3];
  79        if (ints[0] >= 4)
  80                setup_hostid = ints[4];
  81        /* ints[5] (use_tagged_queuing) is ignored */
  82        if (ints[0] >= 6)
  83                setup_use_pdma = ints[6];
  84        if (ints[0] >= 7)
  85                setup_toshiba_delay = ints[7];
  86        return 1;
  87}
  88
  89__setup("mac5380=", mac_scsi_setup);
  90#endif /* !MODULE */
  91
  92/* Pseudo DMA asm originally by Ove Edlund */
  93
  94#define CP_IO_TO_MEM(s,d,n)                             \
  95__asm__ __volatile__                                    \
  96    ("    cmp.w  #4,%2\n"                               \
  97     "    bls    8f\n"                                  \
  98     "    move.w %1,%%d0\n"                             \
  99     "    neg.b  %%d0\n"                                \
 100     "    and.w  #3,%%d0\n"                             \
 101     "    sub.w  %%d0,%2\n"                             \
 102     "    bra    2f\n"                                  \
 103     " 1: move.b (%0),(%1)+\n"                          \
 104     " 2: dbf    %%d0,1b\n"                             \
 105     "    move.w %2,%%d0\n"                             \
 106     "    lsr.w  #5,%%d0\n"                             \
 107     "    bra    4f\n"                                  \
 108     " 3: move.l (%0),(%1)+\n"                          \
 109     "31: move.l (%0),(%1)+\n"                          \
 110     "32: move.l (%0),(%1)+\n"                          \
 111     "33: move.l (%0),(%1)+\n"                          \
 112     "34: move.l (%0),(%1)+\n"                          \
 113     "35: move.l (%0),(%1)+\n"                          \
 114     "36: move.l (%0),(%1)+\n"                          \
 115     "37: move.l (%0),(%1)+\n"                          \
 116     " 4: dbf    %%d0,3b\n"                             \
 117     "    move.w %2,%%d0\n"                             \
 118     "    lsr.w  #2,%%d0\n"                             \
 119     "    and.w  #7,%%d0\n"                             \
 120     "    bra    6f\n"                                  \
 121     " 5: move.l (%0),(%1)+\n"                          \
 122     " 6: dbf    %%d0,5b\n"                             \
 123     "    and.w  #3,%2\n"                               \
 124     "    bra    8f\n"                                  \
 125     " 7: move.b (%0),(%1)+\n"                          \
 126     " 8: dbf    %2,7b\n"                               \
 127     "    moveq.l #0, %2\n"                             \
 128     " 9: \n"                                           \
 129     ".section .fixup,\"ax\"\n"                         \
 130     "    .even\n"                                      \
 131     "91: moveq.l #1, %2\n"                             \
 132     "    jra 9b\n"                                     \
 133     "94: moveq.l #4, %2\n"                             \
 134     "    jra 9b\n"                                     \
 135     ".previous\n"                                      \
 136     ".section __ex_table,\"a\"\n"                      \
 137     "   .align 4\n"                                    \
 138     "   .long  1b,91b\n"                               \
 139     "   .long  3b,94b\n"                               \
 140     "   .long 31b,94b\n"                               \
 141     "   .long 32b,94b\n"                               \
 142     "   .long 33b,94b\n"                               \
 143     "   .long 34b,94b\n"                               \
 144     "   .long 35b,94b\n"                               \
 145     "   .long 36b,94b\n"                               \
 146     "   .long 37b,94b\n"                               \
 147     "   .long  5b,94b\n"                               \
 148     "   .long  7b,91b\n"                               \
 149     ".previous"                                        \
 150     : "=a"(s), "=a"(d), "=d"(n)                        \
 151     : "0"(s), "1"(d), "2"(n)                           \
 152     : "d0")
 153
 154static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
 155                                unsigned char *dst, int len)
 156{
 157        u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
 158        unsigned char *d = dst;
 159        int n = len;
 160        int transferred;
 161
 162        while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
 163                                      BASR_DRQ | BASR_PHASE_MATCH,
 164                                      BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
 165                CP_IO_TO_MEM(s, d, n);
 166
 167                transferred = d - dst - n;
 168                hostdata->pdma_residual = len - transferred;
 169
 170                /* No bus error. */
 171                if (n == 0)
 172                        return 0;
 173
 174                /* Target changed phase early? */
 175                if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
 176                                           BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0)
 177                        scmd_printk(KERN_ERR, hostdata->connected,
 178                                    "%s: !REQ and !ACK\n", __func__);
 179                if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
 180                        return 0;
 181
 182                dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
 183                         "%s: bus error (%d/%d)\n", __func__, transferred, len);
 184                NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
 185                d = dst + transferred;
 186                n = len - transferred;
 187        }
 188
 189        scmd_printk(KERN_ERR, hostdata->connected,
 190                    "%s: phase mismatch or !DRQ\n", __func__);
 191        NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
 192        return -1;
 193}
 194
 195
 196#define CP_MEM_TO_IO(s,d,n)                             \
 197__asm__ __volatile__                                    \
 198    ("    cmp.w  #4,%2\n"                               \
 199     "    bls    8f\n"                                  \
 200     "    move.w %0,%%d0\n"                             \
 201     "    neg.b  %%d0\n"                                \
 202     "    and.w  #3,%%d0\n"                             \
 203     "    sub.w  %%d0,%2\n"                             \
 204     "    bra    2f\n"                                  \
 205     " 1: move.b (%0)+,(%1)\n"                          \
 206     " 2: dbf    %%d0,1b\n"                             \
 207     "    move.w %2,%%d0\n"                             \
 208     "    lsr.w  #5,%%d0\n"                             \
 209     "    bra    4f\n"                                  \
 210     " 3: move.l (%0)+,(%1)\n"                          \
 211     "31: move.l (%0)+,(%1)\n"                          \
 212     "32: move.l (%0)+,(%1)\n"                          \
 213     "33: move.l (%0)+,(%1)\n"                          \
 214     "34: move.l (%0)+,(%1)\n"                          \
 215     "35: move.l (%0)+,(%1)\n"                          \
 216     "36: move.l (%0)+,(%1)\n"                          \
 217     "37: move.l (%0)+,(%1)\n"                          \
 218     " 4: dbf    %%d0,3b\n"                             \
 219     "    move.w %2,%%d0\n"                             \
 220     "    lsr.w  #2,%%d0\n"                             \
 221     "    and.w  #7,%%d0\n"                             \
 222     "    bra    6f\n"                                  \
 223     " 5: move.l (%0)+,(%1)\n"                          \
 224     " 6: dbf    %%d0,5b\n"                             \
 225     "    and.w  #3,%2\n"                               \
 226     "    bra    8f\n"                                  \
 227     " 7: move.b (%0)+,(%1)\n"                          \
 228     " 8: dbf    %2,7b\n"                               \
 229     "    moveq.l #0, %2\n"                             \
 230     " 9: \n"                                           \
 231     ".section .fixup,\"ax\"\n"                         \
 232     "    .even\n"                                      \
 233     "91: moveq.l #1, %2\n"                             \
 234     "    jra 9b\n"                                     \
 235     "94: moveq.l #4, %2\n"                             \
 236     "    jra 9b\n"                                     \
 237     ".previous\n"                                      \
 238     ".section __ex_table,\"a\"\n"                      \
 239     "   .align 4\n"                                    \
 240     "   .long  1b,91b\n"                               \
 241     "   .long  3b,94b\n"                               \
 242     "   .long 31b,94b\n"                               \
 243     "   .long 32b,94b\n"                               \
 244     "   .long 33b,94b\n"                               \
 245     "   .long 34b,94b\n"                               \
 246     "   .long 35b,94b\n"                               \
 247     "   .long 36b,94b\n"                               \
 248     "   .long 37b,94b\n"                               \
 249     "   .long  5b,94b\n"                               \
 250     "   .long  7b,91b\n"                               \
 251     ".previous"                                        \
 252     : "=a"(s), "=a"(d), "=d"(n)                        \
 253     : "0"(s), "1"(d), "2"(n)                           \
 254     : "d0")
 255
 256static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
 257                                 unsigned char *src, int len)
 258{
 259        unsigned char *s = src;
 260        u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
 261        int n = len;
 262        int transferred;
 263
 264        while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
 265                                      BASR_DRQ | BASR_PHASE_MATCH,
 266                                      BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
 267                CP_MEM_TO_IO(s, d, n);
 268
 269                transferred = s - src - n;
 270                hostdata->pdma_residual = len - transferred;
 271
 272                /* Target changed phase early? */
 273                if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
 274                                           BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0)
 275                        scmd_printk(KERN_ERR, hostdata->connected,
 276                                    "%s: !REQ and !ACK\n", __func__);
 277                if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
 278                        return 0;
 279
 280                /* No bus error. */
 281                if (n == 0) {
 282                        if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
 283                                                  TCR_LAST_BYTE_SENT,
 284                                                  TCR_LAST_BYTE_SENT, HZ / 64) < 0)
 285                                scmd_printk(KERN_ERR, hostdata->connected,
 286                                            "%s: Last Byte Sent timeout\n", __func__);
 287                        return 0;
 288                }
 289
 290                dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
 291                         "%s: bus error (%d/%d)\n", __func__, transferred, len);
 292                NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
 293                s = src + transferred;
 294                n = len - transferred;
 295        }
 296
 297        scmd_printk(KERN_ERR, hostdata->connected,
 298                    "%s: phase mismatch or !DRQ\n", __func__);
 299        NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
 300
 301        return -1;
 302}
 303
 304static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
 305                                struct scsi_cmnd *cmd)
 306{
 307        if (hostdata->flags & FLAG_NO_PSEUDO_DMA ||
 308            cmd->SCp.this_residual < 16)
 309                return 0;
 310
 311        return cmd->SCp.this_residual;
 312}
 313
 314static int macscsi_dma_residual(struct NCR5380_hostdata *hostdata)
 315{
 316        return hostdata->pdma_residual;
 317}
 318
 319#include "NCR5380.c"
 320
 321#define DRV_MODULE_NAME         "mac_scsi"
 322#define PFX                     DRV_MODULE_NAME ": "
 323
 324static struct scsi_host_template mac_scsi_template = {
 325        .module                 = THIS_MODULE,
 326        .proc_name              = DRV_MODULE_NAME,
 327        .name                   = "Macintosh NCR5380 SCSI",
 328        .info                   = macscsi_info,
 329        .queuecommand           = macscsi_queue_command,
 330        .eh_abort_handler       = macscsi_abort,
 331        .eh_host_reset_handler  = macscsi_host_reset,
 332        .can_queue              = 16,
 333        .this_id                = 7,
 334        .sg_tablesize           = 1,
 335        .cmd_per_lun            = 2,
 336        .use_clustering         = DISABLE_CLUSTERING,
 337        .cmd_size               = NCR5380_CMD_SIZE,
 338        .max_sectors            = 128,
 339};
 340
 341static int __init mac_scsi_probe(struct platform_device *pdev)
 342{
 343        struct Scsi_Host *instance;
 344        struct NCR5380_hostdata *hostdata;
 345        int error;
 346        int host_flags = 0;
 347        struct resource *irq, *pio_mem, *pdma_mem = NULL;
 348
 349        pio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 350        if (!pio_mem)
 351                return -ENODEV;
 352
 353        pdma_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 354
 355        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 356
 357        if (!hwreg_present((unsigned char *)pio_mem->start +
 358                           (STATUS_REG << 4))) {
 359                pr_info(PFX "no device detected at %pap\n", &pio_mem->start);
 360                return -ENODEV;
 361        }
 362
 363        if (setup_can_queue > 0)
 364                mac_scsi_template.can_queue = setup_can_queue;
 365        if (setup_cmd_per_lun > 0)
 366                mac_scsi_template.cmd_per_lun = setup_cmd_per_lun;
 367        if (setup_sg_tablesize >= 0)
 368                mac_scsi_template.sg_tablesize = setup_sg_tablesize;
 369        if (setup_hostid >= 0)
 370                mac_scsi_template.this_id = setup_hostid & 7;
 371
 372        instance = scsi_host_alloc(&mac_scsi_template,
 373                                   sizeof(struct NCR5380_hostdata));
 374        if (!instance)
 375                return -ENOMEM;
 376
 377        if (irq)
 378                instance->irq = irq->start;
 379        else
 380                instance->irq = NO_IRQ;
 381
 382        hostdata = shost_priv(instance);
 383        hostdata->base = pio_mem->start;
 384        hostdata->io = (u8 __iomem *)pio_mem->start;
 385
 386        if (pdma_mem && setup_use_pdma)
 387                hostdata->pdma_io = (u8 __iomem *)pdma_mem->start;
 388        else
 389                host_flags |= FLAG_NO_PSEUDO_DMA;
 390
 391        host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
 392
 393        error = NCR5380_init(instance, host_flags | FLAG_LATE_DMA_SETUP);
 394        if (error)
 395                goto fail_init;
 396
 397        if (instance->irq != NO_IRQ) {
 398                error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,
 399                                    "NCR5380", instance);
 400                if (error)
 401                        goto fail_irq;
 402        }
 403
 404        NCR5380_maybe_reset_bus(instance);
 405
 406        error = scsi_add_host(instance, NULL);
 407        if (error)
 408                goto fail_host;
 409
 410        platform_set_drvdata(pdev, instance);
 411
 412        scsi_scan_host(instance);
 413        return 0;
 414
 415fail_host:
 416        if (instance->irq != NO_IRQ)
 417                free_irq(instance->irq, instance);
 418fail_irq:
 419        NCR5380_exit(instance);
 420fail_init:
 421        scsi_host_put(instance);
 422        return error;
 423}
 424
 425static int __exit mac_scsi_remove(struct platform_device *pdev)
 426{
 427        struct Scsi_Host *instance = platform_get_drvdata(pdev);
 428
 429        scsi_remove_host(instance);
 430        if (instance->irq != NO_IRQ)
 431                free_irq(instance->irq, instance);
 432        NCR5380_exit(instance);
 433        scsi_host_put(instance);
 434        return 0;
 435}
 436
 437static struct platform_driver mac_scsi_driver = {
 438        .remove = __exit_p(mac_scsi_remove),
 439        .driver = {
 440                .name   = DRV_MODULE_NAME,
 441        },
 442};
 443
 444module_platform_driver_probe(mac_scsi_driver, mac_scsi_probe);
 445
 446MODULE_ALIAS("platform:" DRV_MODULE_NAME);
 447MODULE_LICENSE("GPL");
 448