root/drivers/scsi/mac_scsi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mac_scsi_setup
  2. mac_pdma_recv
  3. mac_pdma_send
  4. write_ctrl_reg
  5. macscsi_pread
  6. macscsi_pwrite
  7. macscsi_dma_xfer_len
  8. macscsi_dma_residual
  9. mac_scsi_probe
  10. mac_scsi_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Generic Macintosh NCR5380 driver
   4  *
   5  * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
   6  *
   7  * Copyright 2019 Finn Thain
   8  *
   9  * derived in part from:
  10  */
  11 /*
  12  * Generic Generic NCR5380 driver
  13  *
  14  * Copyright 1995, Russell King
  15  */
  16 
  17 #include <linux/delay.h>
  18 #include <linux/types.h>
  19 #include <linux/module.h>
  20 #include <linux/ioport.h>
  21 #include <linux/init.h>
  22 #include <linux/blkdev.h>
  23 #include <linux/interrupt.h>
  24 #include <linux/platform_device.h>
  25 
  26 #include <asm/hwtest.h>
  27 #include <asm/io.h>
  28 #include <asm/macintosh.h>
  29 #include <asm/macints.h>
  30 #include <asm/setup.h>
  31 
  32 #include <scsi/scsi_host.h>
  33 
  34 /* Definitions for the core NCR5380 driver. */
  35 
  36 #define NCR5380_implementation_fields   int pdma_residual
  37 
  38 #define NCR5380_read(reg)           in_8(hostdata->io + ((reg) << 4))
  39 #define NCR5380_write(reg, value)   out_8(hostdata->io + ((reg) << 4), value)
  40 
  41 #define NCR5380_dma_xfer_len            macscsi_dma_xfer_len
  42 #define NCR5380_dma_recv_setup          macscsi_pread
  43 #define NCR5380_dma_send_setup          macscsi_pwrite
  44 #define NCR5380_dma_residual            macscsi_dma_residual
  45 
  46 #define NCR5380_intr                    macscsi_intr
  47 #define NCR5380_queue_command           macscsi_queue_command
  48 #define NCR5380_abort                   macscsi_abort
  49 #define NCR5380_host_reset              macscsi_host_reset
  50 #define NCR5380_info                    macscsi_info
  51 
  52 #include "NCR5380.h"
  53 
  54 static int setup_can_queue = -1;
  55 module_param(setup_can_queue, int, 0);
  56 static int setup_cmd_per_lun = -1;
  57 module_param(setup_cmd_per_lun, int, 0);
  58 static int setup_sg_tablesize = -1;
  59 module_param(setup_sg_tablesize, int, 0);
  60 static int setup_use_pdma = 512;
  61 module_param(setup_use_pdma, int, 0);
  62 static int setup_hostid = -1;
  63 module_param(setup_hostid, int, 0);
  64 static int setup_toshiba_delay = -1;
  65 module_param(setup_toshiba_delay, int, 0);
  66 
  67 #ifndef MODULE
  68 static int __init mac_scsi_setup(char *str)
  69 {
  70         int ints[8];
  71 
  72         (void)get_options(str, ARRAY_SIZE(ints), ints);
  73 
  74         if (ints[0] < 1) {
  75                 pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n");
  76                 return 0;
  77         }
  78         if (ints[0] >= 1)
  79                 setup_can_queue = ints[1];
  80         if (ints[0] >= 2)
  81                 setup_cmd_per_lun = ints[2];
  82         if (ints[0] >= 3)
  83                 setup_sg_tablesize = ints[3];
  84         if (ints[0] >= 4)
  85                 setup_hostid = ints[4];
  86         /* ints[5] (use_tagged_queuing) is ignored */
  87         if (ints[0] >= 6)
  88                 setup_use_pdma = ints[6];
  89         if (ints[0] >= 7)
  90                 setup_toshiba_delay = ints[7];
  91         return 1;
  92 }
  93 
  94 __setup("mac5380=", mac_scsi_setup);
  95 #endif /* !MODULE */
  96 
  97 /*
  98  * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to
  99  * specify the number of bytes between the delays expected from a SCSI target.
 100  * This allows the operating system to "prevent bus errors when a target fails
 101  * to deliver the next byte within the processor bus error timeout period."
 102  * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets
 103  * so bus errors are unavoidable.
 104  *
 105  * If a MOVE.B instruction faults, we assume that zero bytes were transferred
 106  * and simply retry. That assumption probably depends on target behaviour but
 107  * seems to hold up okay. The NOP provides synchronization: without it the
 108  * fault can sometimes occur after the program counter has moved past the
 109  * offending instruction. Post-increment addressing can't be used.
 110  */
 111 
 112 #define MOVE_BYTE(operands) \
 113         asm volatile ( \
 114                 "1:     moveb " operands "     \n" \
 115                 "11:    nop                    \n" \
 116                 "       addq #1,%0             \n" \
 117                 "       subq #1,%1             \n" \
 118                 "40:                           \n" \
 119                 "                              \n" \
 120                 ".section .fixup,\"ax\"        \n" \
 121                 ".even                         \n" \
 122                 "90:    movel #1, %2           \n" \
 123                 "       jra 40b                \n" \
 124                 ".previous                     \n" \
 125                 "                              \n" \
 126                 ".section __ex_table,\"a\"     \n" \
 127                 ".align  4                     \n" \
 128                 ".long   1b,90b                \n" \
 129                 ".long  11b,90b                \n" \
 130                 ".previous                     \n" \
 131                 : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
 132 
 133 /*
 134  * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because
 135  * the residual byte count would be uncertain. In that situation the MOVE_WORD
 136  * macro clears n in the fixup section to abort the transfer.
 137  */
 138 
 139 #define MOVE_WORD(operands) \
 140         asm volatile ( \
 141                 "1:     movew " operands "     \n" \
 142                 "11:    nop                    \n" \
 143                 "       subq #2,%1             \n" \
 144                 "40:                           \n" \
 145                 "                              \n" \
 146                 ".section .fixup,\"ax\"        \n" \
 147                 ".even                         \n" \
 148                 "90:    movel #0, %1           \n" \
 149                 "       movel #2, %2           \n" \
 150                 "       jra 40b                \n" \
 151                 ".previous                     \n" \
 152                 "                              \n" \
 153                 ".section __ex_table,\"a\"     \n" \
 154                 ".align  4                     \n" \
 155                 ".long   1b,90b                \n" \
 156                 ".long  11b,90b                \n" \
 157                 ".previous                     \n" \
 158                 : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
 159 
 160 #define MOVE_16_WORDS(operands) \
 161         asm volatile ( \
 162                 "1:     movew " operands "     \n" \
 163                 "2:     movew " operands "     \n" \
 164                 "3:     movew " operands "     \n" \
 165                 "4:     movew " operands "     \n" \
 166                 "5:     movew " operands "     \n" \
 167                 "6:     movew " operands "     \n" \
 168                 "7:     movew " operands "     \n" \
 169                 "8:     movew " operands "     \n" \
 170                 "9:     movew " operands "     \n" \
 171                 "10:    movew " operands "     \n" \
 172                 "11:    movew " operands "     \n" \
 173                 "12:    movew " operands "     \n" \
 174                 "13:    movew " operands "     \n" \
 175                 "14:    movew " operands "     \n" \
 176                 "15:    movew " operands "     \n" \
 177                 "16:    movew " operands "     \n" \
 178                 "17:    nop                    \n" \
 179                 "       subl  #32,%1           \n" \
 180                 "40:                           \n" \
 181                 "                              \n" \
 182                 ".section .fixup,\"ax\"        \n" \
 183                 ".even                         \n" \
 184                 "90:    movel #0, %1           \n" \
 185                 "       movel #2, %2           \n" \
 186                 "       jra 40b                \n" \
 187                 ".previous                     \n" \
 188                 "                              \n" \
 189                 ".section __ex_table,\"a\"     \n" \
 190                 ".align  4                     \n" \
 191                 ".long   1b,90b                \n" \
 192                 ".long   2b,90b                \n" \
 193                 ".long   3b,90b                \n" \
 194                 ".long   4b,90b                \n" \
 195                 ".long   5b,90b                \n" \
 196                 ".long   6b,90b                \n" \
 197                 ".long   7b,90b                \n" \
 198                 ".long   8b,90b                \n" \
 199                 ".long   9b,90b                \n" \
 200                 ".long  10b,90b                \n" \
 201                 ".long  11b,90b                \n" \
 202                 ".long  12b,90b                \n" \
 203                 ".long  13b,90b                \n" \
 204                 ".long  14b,90b                \n" \
 205                 ".long  15b,90b                \n" \
 206                 ".long  16b,90b                \n" \
 207                 ".long  17b,90b                \n" \
 208                 ".previous                     \n" \
 209                 : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
 210 
 211 #define MAC_PDMA_DELAY          32
 212 
 213 static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n)
 214 {
 215         unsigned char *addr = start;
 216         int result = 0;
 217 
 218         if (n >= 1) {
 219                 MOVE_BYTE("%3@,%0@");
 220                 if (result)
 221                         goto out;
 222         }
 223         if (n >= 1 && ((unsigned long)addr & 1)) {
 224                 MOVE_BYTE("%3@,%0@");
 225                 if (result)
 226                         goto out;
 227         }
 228         while (n >= 32)
 229                 MOVE_16_WORDS("%3@,%0@+");
 230         while (n >= 2)
 231                 MOVE_WORD("%3@,%0@+");
 232         if (result)
 233                 return start - addr; /* Negated to indicate uncertain length */
 234         if (n == 1)
 235                 MOVE_BYTE("%3@,%0@");
 236 out:
 237         return addr - start;
 238 }
 239 
 240 static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n)
 241 {
 242         unsigned char *addr = start;
 243         int result = 0;
 244 
 245         if (n >= 1) {
 246                 MOVE_BYTE("%0@,%3@");
 247                 if (result)
 248                         goto out;
 249         }
 250         if (n >= 1 && ((unsigned long)addr & 1)) {
 251                 MOVE_BYTE("%0@,%3@");
 252                 if (result)
 253                         goto out;
 254         }
 255         while (n >= 32)
 256                 MOVE_16_WORDS("%0@+,%3@");
 257         while (n >= 2)
 258                 MOVE_WORD("%0@+,%3@");
 259         if (result)
 260                 return start - addr; /* Negated to indicate uncertain length */
 261         if (n == 1)
 262                 MOVE_BYTE("%0@,%3@");
 263 out:
 264         return addr - start;
 265 }
 266 
 267 /* The "SCSI DMA" chip on the IIfx implements this register. */
 268 #define CTRL_REG                0x8
 269 #define CTRL_INTERRUPTS_ENABLE  BIT(1)
 270 #define CTRL_HANDSHAKE_MODE     BIT(3)
 271 
 272 static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value)
 273 {
 274         out_be32(hostdata->io + (CTRL_REG << 4), value);
 275 }
 276 
 277 static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
 278                                 unsigned char *dst, int len)
 279 {
 280         u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
 281         unsigned char *d = dst;
 282         int result = 0;
 283 
 284         hostdata->pdma_residual = len;
 285 
 286         while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
 287                                       BASR_DRQ | BASR_PHASE_MATCH,
 288                                       BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
 289                 int bytes;
 290 
 291                 if (macintosh_config->ident == MAC_MODEL_IIFX)
 292                         write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
 293                                                  CTRL_INTERRUPTS_ENABLE);
 294 
 295                 bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512));
 296 
 297                 if (bytes > 0) {
 298                         d += bytes;
 299                         hostdata->pdma_residual -= bytes;
 300                 }
 301 
 302                 if (hostdata->pdma_residual == 0)
 303                         goto out;
 304 
 305                 if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
 306                                            BUS_AND_STATUS_REG, BASR_ACK,
 307                                            BASR_ACK, HZ / 64) < 0)
 308                         scmd_printk(KERN_DEBUG, hostdata->connected,
 309                                     "%s: !REQ and !ACK\n", __func__);
 310                 if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
 311                         goto out;
 312 
 313                 if (bytes == 0)
 314                         udelay(MAC_PDMA_DELAY);
 315 
 316                 if (bytes >= 0)
 317                         continue;
 318 
 319                 dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
 320                          "%s: bus error (%d/%d)\n", __func__, d - dst, len);
 321                 NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
 322                 result = -1;
 323                 goto out;
 324         }
 325 
 326         scmd_printk(KERN_ERR, hostdata->connected,
 327                     "%s: phase mismatch or !DRQ\n", __func__);
 328         NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
 329         result = -1;
 330 out:
 331         if (macintosh_config->ident == MAC_MODEL_IIFX)
 332                 write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
 333         return result;
 334 }
 335 
 336 static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
 337                                  unsigned char *src, int len)
 338 {
 339         unsigned char *s = src;
 340         u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
 341         int result = 0;
 342 
 343         hostdata->pdma_residual = len;
 344 
 345         while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
 346                                       BASR_DRQ | BASR_PHASE_MATCH,
 347                                       BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
 348                 int bytes;
 349 
 350                 if (macintosh_config->ident == MAC_MODEL_IIFX)
 351                         write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
 352                                                  CTRL_INTERRUPTS_ENABLE);
 353 
 354                 bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512));
 355 
 356                 if (bytes > 0) {
 357                         s += bytes;
 358                         hostdata->pdma_residual -= bytes;
 359                 }
 360 
 361                 if (hostdata->pdma_residual == 0) {
 362                         if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
 363                                                   TCR_LAST_BYTE_SENT,
 364                                                   TCR_LAST_BYTE_SENT,
 365                                                   HZ / 64) < 0) {
 366                                 scmd_printk(KERN_ERR, hostdata->connected,
 367                                             "%s: Last Byte Sent timeout\n", __func__);
 368                                 result = -1;
 369                         }
 370                         goto out;
 371                 }
 372 
 373                 if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
 374                                            BUS_AND_STATUS_REG, BASR_ACK,
 375                                            BASR_ACK, HZ / 64) < 0)
 376                         scmd_printk(KERN_DEBUG, hostdata->connected,
 377                                     "%s: !REQ and !ACK\n", __func__);
 378                 if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
 379                         goto out;
 380 
 381                 if (bytes == 0)
 382                         udelay(MAC_PDMA_DELAY);
 383 
 384                 if (bytes >= 0)
 385                         continue;
 386 
 387                 dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
 388                          "%s: bus error (%d/%d)\n", __func__, s - src, len);
 389                 NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
 390                 result = -1;
 391                 goto out;
 392         }
 393 
 394         scmd_printk(KERN_ERR, hostdata->connected,
 395                     "%s: phase mismatch or !DRQ\n", __func__);
 396         NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
 397         result = -1;
 398 out:
 399         if (macintosh_config->ident == MAC_MODEL_IIFX)
 400                 write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
 401         return result;
 402 }
 403 
 404 static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
 405                                 struct scsi_cmnd *cmd)
 406 {
 407         if (hostdata->flags & FLAG_NO_PSEUDO_DMA ||
 408             cmd->SCp.this_residual < setup_use_pdma)
 409                 return 0;
 410 
 411         return cmd->SCp.this_residual;
 412 }
 413 
 414 static int macscsi_dma_residual(struct NCR5380_hostdata *hostdata)
 415 {
 416         return hostdata->pdma_residual;
 417 }
 418 
 419 #include "NCR5380.c"
 420 
 421 #define DRV_MODULE_NAME         "mac_scsi"
 422 #define PFX                     DRV_MODULE_NAME ": "
 423 
 424 static struct scsi_host_template mac_scsi_template = {
 425         .module                 = THIS_MODULE,
 426         .proc_name              = DRV_MODULE_NAME,
 427         .name                   = "Macintosh NCR5380 SCSI",
 428         .info                   = macscsi_info,
 429         .queuecommand           = macscsi_queue_command,
 430         .eh_abort_handler       = macscsi_abort,
 431         .eh_host_reset_handler  = macscsi_host_reset,
 432         .can_queue              = 16,
 433         .this_id                = 7,
 434         .sg_tablesize           = 1,
 435         .cmd_per_lun            = 2,
 436         .dma_boundary           = PAGE_SIZE - 1,
 437         .cmd_size               = NCR5380_CMD_SIZE,
 438         .max_sectors            = 128,
 439 };
 440 
 441 static int __init mac_scsi_probe(struct platform_device *pdev)
 442 {
 443         struct Scsi_Host *instance;
 444         struct NCR5380_hostdata *hostdata;
 445         int error;
 446         int host_flags = 0;
 447         struct resource *irq, *pio_mem, *pdma_mem = NULL;
 448 
 449         pio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 450         if (!pio_mem)
 451                 return -ENODEV;
 452 
 453         pdma_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 454 
 455         irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 456 
 457         if (!hwreg_present((unsigned char *)pio_mem->start +
 458                            (STATUS_REG << 4))) {
 459                 pr_info(PFX "no device detected at %pap\n", &pio_mem->start);
 460                 return -ENODEV;
 461         }
 462 
 463         if (setup_can_queue > 0)
 464                 mac_scsi_template.can_queue = setup_can_queue;
 465         if (setup_cmd_per_lun > 0)
 466                 mac_scsi_template.cmd_per_lun = setup_cmd_per_lun;
 467         if (setup_sg_tablesize > 0)
 468                 mac_scsi_template.sg_tablesize = setup_sg_tablesize;
 469         if (setup_hostid >= 0)
 470                 mac_scsi_template.this_id = setup_hostid & 7;
 471 
 472         instance = scsi_host_alloc(&mac_scsi_template,
 473                                    sizeof(struct NCR5380_hostdata));
 474         if (!instance)
 475                 return -ENOMEM;
 476 
 477         if (irq)
 478                 instance->irq = irq->start;
 479         else
 480                 instance->irq = NO_IRQ;
 481 
 482         hostdata = shost_priv(instance);
 483         hostdata->base = pio_mem->start;
 484         hostdata->io = (u8 __iomem *)pio_mem->start;
 485 
 486         if (pdma_mem && setup_use_pdma)
 487                 hostdata->pdma_io = (u8 __iomem *)pdma_mem->start;
 488         else
 489                 host_flags |= FLAG_NO_PSEUDO_DMA;
 490 
 491         host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
 492 
 493         error = NCR5380_init(instance, host_flags | FLAG_LATE_DMA_SETUP);
 494         if (error)
 495                 goto fail_init;
 496 
 497         if (instance->irq != NO_IRQ) {
 498                 error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,
 499                                     "NCR5380", instance);
 500                 if (error)
 501                         goto fail_irq;
 502         }
 503 
 504         NCR5380_maybe_reset_bus(instance);
 505 
 506         error = scsi_add_host(instance, NULL);
 507         if (error)
 508                 goto fail_host;
 509 
 510         platform_set_drvdata(pdev, instance);
 511 
 512         scsi_scan_host(instance);
 513         return 0;
 514 
 515 fail_host:
 516         if (instance->irq != NO_IRQ)
 517                 free_irq(instance->irq, instance);
 518 fail_irq:
 519         NCR5380_exit(instance);
 520 fail_init:
 521         scsi_host_put(instance);
 522         return error;
 523 }
 524 
 525 static int __exit mac_scsi_remove(struct platform_device *pdev)
 526 {
 527         struct Scsi_Host *instance = platform_get_drvdata(pdev);
 528 
 529         scsi_remove_host(instance);
 530         if (instance->irq != NO_IRQ)
 531                 free_irq(instance->irq, instance);
 532         NCR5380_exit(instance);
 533         scsi_host_put(instance);
 534         return 0;
 535 }
 536 
 537 static struct platform_driver mac_scsi_driver = {
 538         .remove = __exit_p(mac_scsi_remove),
 539         .driver = {
 540                 .name   = DRV_MODULE_NAME,
 541         },
 542 };
 543 
 544 module_platform_driver_probe(mac_scsi_driver, mac_scsi_probe);
 545 
 546 MODULE_ALIAS("platform:" DRV_MODULE_NAME);
 547 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */