diff options
| -rw-r--r-- | Documentation/scsi/g_NCR5380.txt | 46 | ||||
| -rw-r--r-- | drivers/scsi/NCR5380.c | 77 | ||||
| -rw-r--r-- | drivers/scsi/NCR5380.h | 11 | ||||
| -rw-r--r-- | drivers/scsi/aacraid/linit.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/g_NCR5380.c | 153 | ||||
| -rw-r--r-- | drivers/scsi/g_NCR5380.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/ibmvscsi/ibmvscsi.c | 7 | ||||
| -rw-r--r-- | drivers/scsi/ibmvscsi/ibmvscsi.h | 1 | ||||
| -rw-r--r-- | drivers/scsi/ufs/ufs-qcom.c | 44 | ||||
| -rw-r--r-- | drivers/scsi/ufs/ufs-qcom.h | 1 | ||||
| -rw-r--r-- | drivers/scsi/ufs/ufs_quirks.h | 30 | ||||
| -rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 55 | ||||
| -rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 12 | ||||
| -rw-r--r-- | drivers/scsi/ufs/ufshci.h | 7 |
14 files changed, 283 insertions, 165 deletions
diff --git a/Documentation/scsi/g_NCR5380.txt b/Documentation/scsi/g_NCR5380.txt index e2c187947e58..37b1967a00a9 100644 --- a/Documentation/scsi/g_NCR5380.txt +++ b/Documentation/scsi/g_NCR5380.txt | |||
| @@ -6,17 +6,15 @@ NCR53c400 extensions (c) 1994,1995,1996 Kevin Lentin | |||
| 6 | This file documents the NCR53c400 extensions by Kevin Lentin and some | 6 | This file documents the NCR53c400 extensions by Kevin Lentin and some |
| 7 | enhancements to the NCR5380 core. | 7 | enhancements to the NCR5380 core. |
| 8 | 8 | ||
| 9 | This driver supports both NCR5380 and NCR53c400 cards in port or memory | 9 | This driver supports NCR5380 and NCR53c400 and compatible cards in port or |
| 10 | mapped modes. Currently this driver can only support one of those mapping | 10 | memory mapped modes. |
| 11 | modes at a time but it does support both of these chips at the same time. | ||
| 12 | The next release of this driver will support port & memory mapped cards at | ||
| 13 | the same time. It should be able to handle multiple different cards in the | ||
| 14 | same machine. | ||
| 15 | 11 | ||
| 16 | The drivers/scsi/Makefile has an override in it for the most common | 12 | Use of an interrupt is recommended, if supported by the board, as this will |
| 17 | NCR53c400 card, the Trantor T130B in its default configuration: | 13 | allow targets to disconnect and thereby improve SCSI bus utilization. |
| 18 | Port: 0x350 | 14 | |
| 19 | IRQ : 5 | 15 | If the irq parameter is 254 or is omitted entirely, the driver will probe |
| 16 | for the correct IRQ line automatically. If the irq parameter is 0 or 255 | ||
| 17 | then no IRQ will be used. | ||
| 20 | 18 | ||
| 21 | The NCR53c400 does not support DMA but it does have Pseudo-DMA which is | 19 | The NCR53c400 does not support DMA but it does have Pseudo-DMA which is |
| 22 | supported by the driver. | 20 | supported by the driver. |
| @@ -47,22 +45,24 @@ These old-style parameters can support only one card: | |||
| 47 | dtc_3181e=1 to set up for a Domex Technology Corp 3181E board | 45 | dtc_3181e=1 to set up for a Domex Technology Corp 3181E board |
| 48 | hp_c2502=1 to set up for a Hewlett Packard C2502 board | 46 | hp_c2502=1 to set up for a Hewlett Packard C2502 board |
| 49 | 47 | ||
| 50 | e.g. | 48 | E.g. Trantor T130B in its default configuration: |
| 51 | OLD: modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1 | 49 | modprobe g_NCR5380 irq=5 base=0x350 card=1 |
| 52 | NEW: modprobe g_NCR5380 irq=5 base=0x350 card=0 | 50 | or alternatively, using the old syntax, |
| 53 | for a port mapped NCR5380 board or | 51 | modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_53c400=1 |
| 54 | |||
| 55 | OLD: modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 | ||
| 56 | NEW: modprobe g_NCR5380 irq=255 base=0xc8000 card=1 | ||
| 57 | for a memory mapped NCR53C400 board with interrupts disabled or | ||
| 58 | 52 | ||
| 59 | NEW: modprobe g_NCR5380 irq=0,7 base=0x240,0x300 card=3,4 | 53 | E.g. a port mapped NCR5380 board, driver to probe for IRQ: |
| 60 | for two cards: DTC3181 (in non-PnP mode) at 0x240 with no IRQ | 54 | modprobe g_NCR5380 base=0x350 card=0 |
| 61 | and HP C2502 at 0x300 with IRQ 7 | 55 | or alternatively, |
| 56 | modprobe g_NCR5380 ncr_addr=0x350 ncr_5380=1 | ||
| 62 | 57 | ||
| 63 | (255 should be specified for no or DMA interrupt, 254 to autoprobe for an | 58 | E.g. a memory mapped NCR53C400 board with no IRQ: |
| 64 | IRQ line if overridden on the command line.) | 59 | modprobe g_NCR5380 irq=255 base=0xc8000 card=1 |
| 60 | or alternatively, | ||
| 61 | modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 | ||
| 65 | 62 | ||
| 63 | E.g. two cards, DTC3181 (in non-PnP mode) at 0x240 with no IRQ | ||
| 64 | and HP C2502 at 0x300 with IRQ 7: | ||
| 65 | modprobe g_NCR5380 irq=0,7 base=0x240,0x300 card=3,4 | ||
| 66 | 66 | ||
| 67 | Kevin Lentin | 67 | Kevin Lentin |
| 68 | K.Lentin@cs.monash.edu.au | 68 | K.Lentin@cs.monash.edu.au |
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index d849ffa378b1..4f5ca794bb71 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c | |||
| @@ -97,9 +97,6 @@ | |||
| 97 | * and macros and include this file in your driver. | 97 | * and macros and include this file in your driver. |
| 98 | * | 98 | * |
| 99 | * These macros control options : | 99 | * These macros control options : |
| 100 | * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be | ||
| 101 | * defined. | ||
| 102 | * | ||
| 103 | * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically | 100 | * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically |
| 104 | * for commands that return with a CHECK CONDITION status. | 101 | * for commands that return with a CHECK CONDITION status. |
| 105 | * | 102 | * |
| @@ -127,9 +124,7 @@ | |||
| 127 | * NCR5380_dma_residual - residual byte count | 124 | * NCR5380_dma_residual - residual byte count |
| 128 | * | 125 | * |
| 129 | * The generic driver is initialized by calling NCR5380_init(instance), | 126 | * The generic driver is initialized by calling NCR5380_init(instance), |
| 130 | * after setting the appropriate host specific fields and ID. If the | 127 | * after setting the appropriate host specific fields and ID. |
| 131 | * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, | ||
| 132 | * possible) function may be used. | ||
| 133 | */ | 128 | */ |
| 134 | 129 | ||
| 135 | #ifndef NCR5380_io_delay | 130 | #ifndef NCR5380_io_delay |
| @@ -351,76 +346,6 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) | |||
| 351 | } | 346 | } |
| 352 | #endif | 347 | #endif |
| 353 | 348 | ||
| 354 | |||
| 355 | static int probe_irq; | ||
| 356 | |||
| 357 | /** | ||
| 358 | * probe_intr - helper for IRQ autoprobe | ||
| 359 | * @irq: interrupt number | ||
| 360 | * @dev_id: unused | ||
| 361 | * @regs: unused | ||
| 362 | * | ||
| 363 | * Set a flag to indicate the IRQ in question was received. This is | ||
| 364 | * used by the IRQ probe code. | ||
| 365 | */ | ||
| 366 | |||
| 367 | static irqreturn_t probe_intr(int irq, void *dev_id) | ||
| 368 | { | ||
| 369 | probe_irq = irq; | ||
| 370 | return IRQ_HANDLED; | ||
| 371 | } | ||
| 372 | |||
| 373 | /** | ||
| 374 | * NCR5380_probe_irq - find the IRQ of an NCR5380 | ||
| 375 | * @instance: NCR5380 controller | ||
| 376 | * @possible: bitmask of ISA IRQ lines | ||
| 377 | * | ||
| 378 | * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ | ||
| 379 | * and then looking to see what interrupt actually turned up. | ||
| 380 | */ | ||
| 381 | |||
| 382 | static int __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance, | ||
| 383 | int possible) | ||
| 384 | { | ||
| 385 | struct NCR5380_hostdata *hostdata = shost_priv(instance); | ||
| 386 | unsigned long timeout; | ||
| 387 | int trying_irqs, i, mask; | ||
| 388 | |||
| 389 | for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1) | ||
| 390 | if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0)) | ||
| 391 | trying_irqs |= mask; | ||
| 392 | |||
| 393 | timeout = jiffies + msecs_to_jiffies(250); | ||
| 394 | probe_irq = NO_IRQ; | ||
| 395 | |||
| 396 | /* | ||
| 397 | * A interrupt is triggered whenever BSY = false, SEL = true | ||
| 398 | * and a bit set in the SELECT_ENABLE_REG is asserted on the | ||
| 399 | * SCSI bus. | ||
| 400 | * | ||
| 401 | * Note that the bus is only driven when the phase control signals | ||
| 402 | * (I/O, C/D, and MSG) match those in the TCR, so we must reset that | ||
| 403 | * to zero. | ||
| 404 | */ | ||
| 405 | |||
| 406 | NCR5380_write(TARGET_COMMAND_REG, 0); | ||
| 407 | NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); | ||
| 408 | NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); | ||
| 409 | NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); | ||
| 410 | |||
| 411 | while (probe_irq == NO_IRQ && time_before(jiffies, timeout)) | ||
| 412 | schedule_timeout_uninterruptible(1); | ||
| 413 | |||
| 414 | NCR5380_write(SELECT_ENABLE_REG, 0); | ||
| 415 | NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); | ||
| 416 | |||
| 417 | for (i = 1, mask = 2; i < 16; ++i, mask <<= 1) | ||
| 418 | if (trying_irqs & mask) | ||
| 419 | free_irq(i, NULL); | ||
| 420 | |||
| 421 | return probe_irq; | ||
| 422 | } | ||
| 423 | |||
| 424 | /** | 349 | /** |
| 425 | * NCR58380_info - report driver and host information | 350 | * NCR58380_info - report driver and host information |
| 426 | * @instance: relevant scsi host instance | 351 | * @instance: relevant scsi host instance |
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 3c6ce5434449..51a3567a6fb2 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h | |||
| @@ -199,16 +199,6 @@ | |||
| 199 | 199 | ||
| 200 | #define PHASE_SR_TO_TCR(phase) ((phase) >> 2) | 200 | #define PHASE_SR_TO_TCR(phase) ((phase) >> 2) |
| 201 | 201 | ||
| 202 | /* | ||
| 203 | * These are "special" values for the irq and dma_channel fields of the | ||
| 204 | * Scsi_Host structure | ||
| 205 | */ | ||
| 206 | |||
| 207 | #define DMA_NONE 255 | ||
| 208 | #define IRQ_AUTO 254 | ||
| 209 | #define DMA_AUTO 254 | ||
| 210 | #define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */ | ||
| 211 | |||
| 212 | #ifndef NO_IRQ | 202 | #ifndef NO_IRQ |
| 213 | #define NO_IRQ 0 | 203 | #define NO_IRQ 0 |
| 214 | #endif | 204 | #endif |
| @@ -290,7 +280,6 @@ static void NCR5380_print(struct Scsi_Host *instance); | |||
| 290 | #define NCR5380_dprint_phase(flg, arg) do {} while (0) | 280 | #define NCR5380_dprint_phase(flg, arg) do {} while (0) |
| 291 | #endif | 281 | #endif |
| 292 | 282 | ||
| 293 | static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible); | ||
| 294 | static int NCR5380_init(struct Scsi_Host *instance, int flags); | 283 | static int NCR5380_init(struct Scsi_Host *instance, int flags); |
| 295 | static int NCR5380_maybe_reset_bus(struct Scsi_Host *); | 284 | static int NCR5380_maybe_reset_bus(struct Scsi_Host *); |
| 296 | static void NCR5380_exit(struct Scsi_Host *instance); | 285 | static void NCR5380_exit(struct Scsi_Host *instance); |
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index e4f3e22fcbd9..3ecbf20ca29f 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c | |||
| @@ -160,7 +160,6 @@ static const struct pci_device_id aac_pci_tbl[] = { | |||
| 160 | { 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Series 6 (Tupelo) */ | 160 | { 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Series 6 (Tupelo) */ |
| 161 | { 0x9005, 0x028c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 63 }, /* Adaptec PMC Series 7 (Denali) */ | 161 | { 0x9005, 0x028c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 63 }, /* Adaptec PMC Series 7 (Denali) */ |
| 162 | { 0x9005, 0x028d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 64 }, /* Adaptec PMC Series 8 */ | 162 | { 0x9005, 0x028d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 64 }, /* Adaptec PMC Series 8 */ |
| 163 | { 0x9005, 0x028f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 65 }, /* Adaptec PMC Series 9 */ | ||
| 164 | { 0,} | 163 | { 0,} |
| 165 | }; | 164 | }; |
| 166 | MODULE_DEVICE_TABLE(pci, aac_pci_tbl); | 165 | MODULE_DEVICE_TABLE(pci, aac_pci_tbl); |
| @@ -239,7 +238,6 @@ static struct aac_driver_ident aac_drivers[] = { | |||
| 239 | { aac_src_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 6 (Tupelo) */ | 238 | { aac_src_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 6 (Tupelo) */ |
| 240 | { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 7 (Denali) */ | 239 | { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 7 (Denali) */ |
| 241 | { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 8 */ | 240 | { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 8 */ |
| 242 | { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC } /* Adaptec PMC Series 9 */ | ||
| 243 | }; | 241 | }; |
| 244 | 242 | ||
| 245 | /** | 243 | /** |
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index de5147a8c959..6f9665d50d84 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c | |||
| @@ -37,7 +37,7 @@ | |||
| 37 | #define MAX_CARDS 8 | 37 | #define MAX_CARDS 8 |
| 38 | 38 | ||
| 39 | /* old-style parameters for compatibility */ | 39 | /* old-style parameters for compatibility */ |
| 40 | static int ncr_irq; | 40 | static int ncr_irq = -1; |
| 41 | static int ncr_addr; | 41 | static int ncr_addr; |
| 42 | static int ncr_5380; | 42 | static int ncr_5380; |
| 43 | static int ncr_53c400; | 43 | static int ncr_53c400; |
| @@ -52,9 +52,9 @@ module_param(ncr_53c400a, int, 0); | |||
| 52 | module_param(dtc_3181e, int, 0); | 52 | module_param(dtc_3181e, int, 0); |
| 53 | module_param(hp_c2502, int, 0); | 53 | module_param(hp_c2502, int, 0); |
| 54 | 54 | ||
| 55 | static int irq[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 55 | static int irq[] = { -1, -1, -1, -1, -1, -1, -1, -1 }; |
| 56 | module_param_array(irq, int, NULL, 0); | 56 | module_param_array(irq, int, NULL, 0); |
| 57 | MODULE_PARM_DESC(irq, "IRQ number(s)"); | 57 | MODULE_PARM_DESC(irq, "IRQ number(s) (0=none, 254=auto [default])"); |
| 58 | 58 | ||
| 59 | static int base[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 59 | static int base[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
| 60 | module_param_array(base, int, NULL, 0); | 60 | module_param_array(base, int, NULL, 0); |
| @@ -67,6 +67,56 @@ MODULE_PARM_DESC(card, "card type (0=NCR5380, 1=NCR53C400, 2=NCR53C400A, 3=DTC31 | |||
| 67 | MODULE_ALIAS("g_NCR5380_mmio"); | 67 | MODULE_ALIAS("g_NCR5380_mmio"); |
| 68 | MODULE_LICENSE("GPL"); | 68 | MODULE_LICENSE("GPL"); |
| 69 | 69 | ||
| 70 | static void g_NCR5380_trigger_irq(struct Scsi_Host *instance) | ||
| 71 | { | ||
| 72 | struct NCR5380_hostdata *hostdata = shost_priv(instance); | ||
| 73 | |||
| 74 | /* | ||
| 75 | * An interrupt is triggered whenever BSY = false, SEL = true | ||
| 76 | * and a bit set in the SELECT_ENABLE_REG is asserted on the | ||
| 77 | * SCSI bus. | ||
| 78 | * | ||
| 79 | * Note that the bus is only driven when the phase control signals | ||
| 80 | * (I/O, C/D, and MSG) match those in the TCR. | ||
| 81 | */ | ||
| 82 | NCR5380_write(TARGET_COMMAND_REG, | ||
| 83 | PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); | ||
| 84 | NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); | ||
| 85 | NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); | ||
| 86 | NCR5380_write(INITIATOR_COMMAND_REG, | ||
| 87 | ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); | ||
| 88 | |||
| 89 | msleep(1); | ||
| 90 | |||
| 91 | NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); | ||
| 92 | NCR5380_write(SELECT_ENABLE_REG, 0); | ||
| 93 | NCR5380_write(TARGET_COMMAND_REG, 0); | ||
| 94 | } | ||
| 95 | |||
| 96 | /** | ||
| 97 | * g_NCR5380_probe_irq - find the IRQ of a NCR5380 or equivalent | ||
| 98 | * @instance: SCSI host instance | ||
| 99 | * | ||
| 100 | * Autoprobe for the IRQ line used by the card by triggering an IRQ | ||
| 101 | * and then looking to see what interrupt actually turned up. | ||
| 102 | */ | ||
| 103 | |||
| 104 | static int g_NCR5380_probe_irq(struct Scsi_Host *instance) | ||
| 105 | { | ||
| 106 | struct NCR5380_hostdata *hostdata = shost_priv(instance); | ||
| 107 | int irq_mask, irq; | ||
| 108 | |||
| 109 | NCR5380_read(RESET_PARITY_INTERRUPT_REG); | ||
| 110 | irq_mask = probe_irq_on(); | ||
| 111 | g_NCR5380_trigger_irq(instance); | ||
| 112 | irq = probe_irq_off(irq_mask); | ||
| 113 | NCR5380_read(RESET_PARITY_INTERRUPT_REG); | ||
| 114 | |||
| 115 | if (irq <= 0) | ||
| 116 | return NO_IRQ; | ||
| 117 | return irq; | ||
| 118 | } | ||
| 119 | |||
| 70 | /* | 120 | /* |
| 71 | * Configure I/O address of 53C400A or DTC436 by writing magic numbers | 121 | * Configure I/O address of 53C400A or DTC436 by writing magic numbers |
| 72 | * to ports 0x779 and 0x379. | 122 | * to ports 0x779 and 0x379. |
| @@ -81,14 +131,33 @@ static void magic_configure(int idx, u8 irq, u8 magic[]) | |||
| 81 | outb(magic[3], 0x379); | 131 | outb(magic[3], 0x379); |
| 82 | outb(magic[4], 0x379); | 132 | outb(magic[4], 0x379); |
| 83 | 133 | ||
| 84 | /* allowed IRQs for HP C2502 */ | 134 | if (irq == 9) |
| 85 | if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7) | 135 | irq = 2; |
| 86 | irq = 0; | 136 | |
| 87 | if (idx >= 0 && idx <= 7) | 137 | if (idx >= 0 && idx <= 7) |
| 88 | cfg = 0x80 | idx | (irq << 4); | 138 | cfg = 0x80 | idx | (irq << 4); |
| 89 | outb(cfg, 0x379); | 139 | outb(cfg, 0x379); |
| 90 | } | 140 | } |
| 91 | 141 | ||
| 142 | static irqreturn_t legacy_empty_irq_handler(int irq, void *dev_id) | ||
| 143 | { | ||
| 144 | return IRQ_HANDLED; | ||
| 145 | } | ||
| 146 | |||
| 147 | static int legacy_find_free_irq(int *irq_table) | ||
| 148 | { | ||
| 149 | while (*irq_table != -1) { | ||
| 150 | if (!request_irq(*irq_table, legacy_empty_irq_handler, | ||
| 151 | IRQF_PROBE_SHARED, "Test IRQ", | ||
| 152 | (void *)irq_table)) { | ||
| 153 | free_irq(*irq_table, (void *) irq_table); | ||
| 154 | return *irq_table; | ||
| 155 | } | ||
| 156 | irq_table++; | ||
| 157 | } | ||
| 158 | return -1; | ||
| 159 | } | ||
| 160 | |||
| 92 | static unsigned int ncr_53c400a_ports[] = { | 161 | static unsigned int ncr_53c400a_ports[] = { |
| 93 | 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 | 162 | 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 |
| 94 | }; | 163 | }; |
| @@ -101,6 +170,9 @@ static u8 ncr_53c400a_magic[] = { /* 53C400A & DTC436 */ | |||
| 101 | static u8 hp_c2502_magic[] = { /* HP C2502 */ | 170 | static u8 hp_c2502_magic[] = { /* HP C2502 */ |
| 102 | 0x0f, 0x22, 0xf0, 0x20, 0x80 | 171 | 0x0f, 0x22, 0xf0, 0x20, 0x80 |
| 103 | }; | 172 | }; |
| 173 | static int hp_c2502_irqs[] = { | ||
| 174 | 9, 5, 7, 3, 4, -1 | ||
| 175 | }; | ||
| 104 | 176 | ||
| 105 | static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, | 177 | static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, |
| 106 | struct device *pdev, int base, int irq, int board) | 178 | struct device *pdev, int base, int irq, int board) |
| @@ -248,6 +320,13 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, | |||
| 248 | } | 320 | } |
| 249 | } | 321 | } |
| 250 | 322 | ||
| 323 | /* Check for vacant slot */ | ||
| 324 | NCR5380_write(MODE_REG, 0); | ||
| 325 | if (NCR5380_read(MODE_REG) != 0) { | ||
| 326 | ret = -ENODEV; | ||
| 327 | goto out_unregister; | ||
| 328 | } | ||
| 329 | |||
| 251 | ret = NCR5380_init(instance, flags | FLAG_LATE_DMA_SETUP); | 330 | ret = NCR5380_init(instance, flags | FLAG_LATE_DMA_SETUP); |
| 252 | if (ret) | 331 | if (ret) |
| 253 | goto out_unregister; | 332 | goto out_unregister; |
| @@ -262,31 +341,59 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, | |||
| 262 | 341 | ||
| 263 | NCR5380_maybe_reset_bus(instance); | 342 | NCR5380_maybe_reset_bus(instance); |
| 264 | 343 | ||
| 265 | if (irq != IRQ_AUTO) | ||
| 266 | instance->irq = irq; | ||
| 267 | else | ||
| 268 | instance->irq = NCR5380_probe_irq(instance, 0xffff); | ||
| 269 | |||
| 270 | /* Compatibility with documented NCR5380 kernel parameters */ | 344 | /* Compatibility with documented NCR5380 kernel parameters */ |
| 271 | if (instance->irq == 255) | 345 | if (irq == 255 || irq == 0) |
| 272 | instance->irq = NO_IRQ; | 346 | irq = NO_IRQ; |
| 347 | else if (irq == -1) | ||
| 348 | irq = IRQ_AUTO; | ||
| 349 | |||
| 350 | if (board == BOARD_HP_C2502) { | ||
| 351 | int *irq_table = hp_c2502_irqs; | ||
| 352 | int board_irq = -1; | ||
| 353 | |||
| 354 | switch (irq) { | ||
| 355 | case NO_IRQ: | ||
| 356 | board_irq = 0; | ||
| 357 | break; | ||
| 358 | case IRQ_AUTO: | ||
| 359 | board_irq = legacy_find_free_irq(irq_table); | ||
| 360 | break; | ||
| 361 | default: | ||
| 362 | while (*irq_table != -1) | ||
| 363 | if (*irq_table++ == irq) | ||
| 364 | board_irq = irq; | ||
| 365 | } | ||
| 366 | |||
| 367 | if (board_irq <= 0) { | ||
| 368 | board_irq = 0; | ||
| 369 | irq = NO_IRQ; | ||
| 370 | } | ||
| 371 | |||
| 372 | magic_configure(port_idx, board_irq, magic); | ||
| 373 | } | ||
| 374 | |||
| 375 | if (irq == IRQ_AUTO) { | ||
| 376 | instance->irq = g_NCR5380_probe_irq(instance); | ||
| 377 | if (instance->irq == NO_IRQ) | ||
| 378 | shost_printk(KERN_INFO, instance, "no irq detected\n"); | ||
| 379 | } else { | ||
| 380 | instance->irq = irq; | ||
| 381 | if (instance->irq == NO_IRQ) | ||
| 382 | shost_printk(KERN_INFO, instance, "no irq provided\n"); | ||
| 383 | } | ||
| 273 | 384 | ||
| 274 | if (instance->irq != NO_IRQ) { | 385 | if (instance->irq != NO_IRQ) { |
| 275 | /* set IRQ for HP C2502 */ | ||
| 276 | if (board == BOARD_HP_C2502) | ||
| 277 | magic_configure(port_idx, instance->irq, magic); | ||
| 278 | if (request_irq(instance->irq, generic_NCR5380_intr, | 386 | if (request_irq(instance->irq, generic_NCR5380_intr, |
| 279 | 0, "NCR5380", instance)) { | 387 | 0, "NCR5380", instance)) { |
| 280 | printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); | ||
| 281 | instance->irq = NO_IRQ; | 388 | instance->irq = NO_IRQ; |
| 389 | shost_printk(KERN_INFO, instance, | ||
| 390 | "irq %d denied\n", instance->irq); | ||
| 391 | } else { | ||
| 392 | shost_printk(KERN_INFO, instance, | ||
| 393 | "irq %d acquired\n", instance->irq); | ||
| 282 | } | 394 | } |
| 283 | } | 395 | } |
| 284 | 396 | ||
| 285 | if (instance->irq == NO_IRQ) { | ||
| 286 | printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); | ||
| 287 | printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); | ||
| 288 | } | ||
| 289 | |||
| 290 | ret = scsi_add_host(instance, pdev); | 397 | ret = scsi_add_host(instance, pdev); |
| 291 | if (ret) | 398 | if (ret) |
| 292 | goto out_free_irq; | 399 | goto out_free_irq; |
| @@ -597,7 +704,7 @@ static int __init generic_NCR5380_init(void) | |||
| 597 | int ret = 0; | 704 | int ret = 0; |
| 598 | 705 | ||
| 599 | /* compatibility with old-style parameters */ | 706 | /* compatibility with old-style parameters */ |
| 600 | if (irq[0] == 0 && base[0] == 0 && card[0] == -1) { | 707 | if (irq[0] == -1 && base[0] == 0 && card[0] == -1) { |
| 601 | irq[0] = ncr_irq; | 708 | irq[0] = ncr_irq; |
| 602 | base[0] = ncr_addr; | 709 | base[0] = ncr_addr; |
| 603 | if (ncr_5380) | 710 | if (ncr_5380) |
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h index 3ce5b65ccb00..81b22d989648 100644 --- a/drivers/scsi/g_NCR5380.h +++ b/drivers/scsi/g_NCR5380.h | |||
| @@ -51,4 +51,6 @@ | |||
| 51 | #define BOARD_DTC3181E 3 | 51 | #define BOARD_DTC3181E 3 |
| 52 | #define BOARD_HP_C2502 4 | 52 | #define BOARD_HP_C2502 4 |
| 53 | 53 | ||
| 54 | #define IRQ_AUTO 254 | ||
| 55 | |||
| 54 | #endif /* GENERIC_NCR5380_H */ | 56 | #endif /* GENERIC_NCR5380_H */ |
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index d9534ee6ef52..50cd01165e35 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c | |||
| @@ -95,6 +95,7 @@ static int fast_fail = 1; | |||
| 95 | static int client_reserve = 1; | 95 | static int client_reserve = 1; |
| 96 | static char partition_name[97] = "UNKNOWN"; | 96 | static char partition_name[97] = "UNKNOWN"; |
| 97 | static unsigned int partition_number = -1; | 97 | static unsigned int partition_number = -1; |
| 98 | static LIST_HEAD(ibmvscsi_head); | ||
| 98 | 99 | ||
| 99 | static struct scsi_transport_template *ibmvscsi_transport_template; | 100 | static struct scsi_transport_template *ibmvscsi_transport_template; |
| 100 | 101 | ||
| @@ -232,6 +233,7 @@ static void ibmvscsi_task(void *data) | |||
| 232 | while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { | 233 | while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { |
| 233 | ibmvscsi_handle_crq(crq, hostdata); | 234 | ibmvscsi_handle_crq(crq, hostdata); |
| 234 | crq->valid = VIOSRP_CRQ_FREE; | 235 | crq->valid = VIOSRP_CRQ_FREE; |
| 236 | wmb(); | ||
| 235 | } | 237 | } |
| 236 | 238 | ||
| 237 | vio_enable_interrupts(vdev); | 239 | vio_enable_interrupts(vdev); |
| @@ -240,6 +242,7 @@ static void ibmvscsi_task(void *data) | |||
| 240 | vio_disable_interrupts(vdev); | 242 | vio_disable_interrupts(vdev); |
| 241 | ibmvscsi_handle_crq(crq, hostdata); | 243 | ibmvscsi_handle_crq(crq, hostdata); |
| 242 | crq->valid = VIOSRP_CRQ_FREE; | 244 | crq->valid = VIOSRP_CRQ_FREE; |
| 245 | wmb(); | ||
| 243 | } else { | 246 | } else { |
| 244 | done = 1; | 247 | done = 1; |
| 245 | } | 248 | } |
| @@ -992,7 +995,7 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct) | |||
| 992 | if (unlikely(rsp->opcode != SRP_RSP)) { | 995 | if (unlikely(rsp->opcode != SRP_RSP)) { |
| 993 | if (printk_ratelimit()) | 996 | if (printk_ratelimit()) |
| 994 | dev_warn(evt_struct->hostdata->dev, | 997 | dev_warn(evt_struct->hostdata->dev, |
| 995 | "bad SRP RSP type %d\n", rsp->opcode); | 998 | "bad SRP RSP type %#02x\n", rsp->opcode); |
| 996 | } | 999 | } |
| 997 | 1000 | ||
| 998 | if (cmnd) { | 1001 | if (cmnd) { |
| @@ -2270,6 +2273,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
| 2270 | } | 2273 | } |
| 2271 | 2274 | ||
| 2272 | dev_set_drvdata(&vdev->dev, hostdata); | 2275 | dev_set_drvdata(&vdev->dev, hostdata); |
| 2276 | list_add_tail(&hostdata->host_list, &ibmvscsi_head); | ||
| 2273 | return 0; | 2277 | return 0; |
| 2274 | 2278 | ||
| 2275 | add_srp_port_failed: | 2279 | add_srp_port_failed: |
| @@ -2291,6 +2295,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
| 2291 | static int ibmvscsi_remove(struct vio_dev *vdev) | 2295 | static int ibmvscsi_remove(struct vio_dev *vdev) |
| 2292 | { | 2296 | { |
| 2293 | struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev); | 2297 | struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev); |
| 2298 | list_del(&hostdata->host_list); | ||
| 2294 | unmap_persist_bufs(hostdata); | 2299 | unmap_persist_bufs(hostdata); |
| 2295 | release_event_pool(&hostdata->pool, hostdata); | 2300 | release_event_pool(&hostdata->pool, hostdata); |
| 2296 | ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, | 2301 | ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, |
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index e0f6c3aeb4ee..3a7875575616 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h | |||
| @@ -90,6 +90,7 @@ struct event_pool { | |||
| 90 | 90 | ||
| 91 | /* all driver data associated with a host adapter */ | 91 | /* all driver data associated with a host adapter */ |
| 92 | struct ibmvscsi_host_data { | 92 | struct ibmvscsi_host_data { |
| 93 | struct list_head host_list; | ||
| 93 | atomic_t request_limit; | 94 | atomic_t request_limit; |
| 94 | int client_migrated; | 95 | int client_migrated; |
| 95 | int reset_crq; | 96 | int reset_crq; |
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index aa43bfea0d00..abe617372661 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "unipro.h" | 23 | #include "unipro.h" |
| 24 | #include "ufs-qcom.h" | 24 | #include "ufs-qcom.h" |
| 25 | #include "ufshci.h" | 25 | #include "ufshci.h" |
| 26 | #include "ufs_quirks.h" | ||
| 26 | #define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ | 27 | #define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ |
| 27 | (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) | 28 | (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) |
| 28 | 29 | ||
| @@ -1031,6 +1032,34 @@ out: | |||
| 1031 | return ret; | 1032 | return ret; |
| 1032 | } | 1033 | } |
| 1033 | 1034 | ||
| 1035 | static int ufs_qcom_quirk_host_pa_saveconfigtime(struct ufs_hba *hba) | ||
| 1036 | { | ||
| 1037 | int err; | ||
| 1038 | u32 pa_vs_config_reg1; | ||
| 1039 | |||
| 1040 | err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), | ||
| 1041 | &pa_vs_config_reg1); | ||
| 1042 | if (err) | ||
| 1043 | goto out; | ||
| 1044 | |||
| 1045 | /* Allow extension of MSB bits of PA_SaveConfigTime attribute */ | ||
| 1046 | err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), | ||
| 1047 | (pa_vs_config_reg1 | (1 << 12))); | ||
| 1048 | |||
| 1049 | out: | ||
| 1050 | return err; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba) | ||
| 1054 | { | ||
| 1055 | int err = 0; | ||
| 1056 | |||
| 1057 | if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME) | ||
| 1058 | err = ufs_qcom_quirk_host_pa_saveconfigtime(hba); | ||
| 1059 | |||
| 1060 | return err; | ||
| 1061 | } | ||
| 1062 | |||
| 1034 | static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) | 1063 | static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) |
| 1035 | { | 1064 | { |
| 1036 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); | 1065 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
| @@ -1194,7 +1223,16 @@ static int ufs_qcom_init(struct ufs_hba *hba) | |||
| 1194 | */ | 1223 | */ |
| 1195 | host->generic_phy = devm_phy_get(dev, "ufsphy"); | 1224 | host->generic_phy = devm_phy_get(dev, "ufsphy"); |
| 1196 | 1225 | ||
| 1197 | if (IS_ERR(host->generic_phy)) { | 1226 | if (host->generic_phy == ERR_PTR(-EPROBE_DEFER)) { |
| 1227 | /* | ||
| 1228 | * UFS driver might be probed before the phy driver does. | ||
| 1229 | * In that case we would like to return EPROBE_DEFER code. | ||
| 1230 | */ | ||
| 1231 | err = -EPROBE_DEFER; | ||
| 1232 | dev_warn(dev, "%s: required phy device. hasn't probed yet. err = %d\n", | ||
| 1233 | __func__, err); | ||
| 1234 | goto out_variant_clear; | ||
| 1235 | } else if (IS_ERR(host->generic_phy)) { | ||
| 1198 | err = PTR_ERR(host->generic_phy); | 1236 | err = PTR_ERR(host->generic_phy); |
| 1199 | dev_err(dev, "%s: PHY get failed %d\n", __func__, err); | 1237 | dev_err(dev, "%s: PHY get failed %d\n", __func__, err); |
| 1200 | goto out_variant_clear; | 1238 | goto out_variant_clear; |
| @@ -1432,7 +1470,8 @@ static void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba, | |||
| 1432 | reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM); | 1470 | reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM); |
| 1433 | print_fn(hba, reg, 64, "UFS_UFS_DBG_RD_PRDT_RAM ", priv); | 1471 | print_fn(hba, reg, 64, "UFS_UFS_DBG_RD_PRDT_RAM ", priv); |
| 1434 | 1472 | ||
| 1435 | ufshcd_writel(hba, (reg & ~UFS_BIT(17)), REG_UFS_CFG1); | 1473 | /* clear bit 17 - UTP_DBG_RAMS_EN */ |
| 1474 | ufshcd_rmwl(hba, UFS_BIT(17), 0, REG_UFS_CFG1); | ||
| 1436 | 1475 | ||
| 1437 | reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM); | 1476 | reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM); |
| 1438 | print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UAWM ", priv); | 1477 | print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UAWM ", priv); |
| @@ -1609,6 +1648,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { | |||
| 1609 | .hce_enable_notify = ufs_qcom_hce_enable_notify, | 1648 | .hce_enable_notify = ufs_qcom_hce_enable_notify, |
| 1610 | .link_startup_notify = ufs_qcom_link_startup_notify, | 1649 | .link_startup_notify = ufs_qcom_link_startup_notify, |
| 1611 | .pwr_change_notify = ufs_qcom_pwr_change_notify, | 1650 | .pwr_change_notify = ufs_qcom_pwr_change_notify, |
| 1651 | .apply_dev_quirks = ufs_qcom_apply_dev_quirks, | ||
| 1612 | .suspend = ufs_qcom_suspend, | 1652 | .suspend = ufs_qcom_suspend, |
| 1613 | .resume = ufs_qcom_resume, | 1653 | .resume = ufs_qcom_resume, |
| 1614 | .dbg_register_dump = ufs_qcom_dump_dbg_regs, | 1654 | .dbg_register_dump = ufs_qcom_dump_dbg_regs, |
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index a19307a57ce2..fe517cd7dac3 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h | |||
| @@ -142,6 +142,7 @@ enum ufs_qcom_phy_init_type { | |||
| 142 | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) | 142 | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) |
| 143 | 143 | ||
| 144 | /* QUniPro Vendor specific attributes */ | 144 | /* QUniPro Vendor specific attributes */ |
| 145 | #define PA_VS_CONFIG_REG1 0x9000 | ||
| 145 | #define DME_VS_CORE_CLK_CTRL 0xD002 | 146 | #define DME_VS_CORE_CLK_CTRL 0xD002 |
| 146 | /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ | 147 | /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ |
| 147 | #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) | 148 | #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) |
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index f7983058f3f7..08b799d4efcc 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h | |||
| @@ -134,29 +134,17 @@ struct ufs_dev_fix { | |||
| 134 | */ | 134 | */ |
| 135 | #define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7) | 135 | #define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7) |
| 136 | 136 | ||
| 137 | /* | ||
| 138 | * The max. value PA_SaveConfigTime is 250 (10us) but this is not enough for | ||
| 139 | * some vendors. | ||
| 140 | * Gear switch from PWM to HS may fail even with this max. PA_SaveConfigTime. | ||
| 141 | * Gear switch can be issued by host controller as an error recovery and any | ||
| 142 | * software delay will not help on this case so we need to increase | ||
| 143 | * PA_SaveConfigTime to >32us as per vendor recommendation. | ||
| 144 | */ | ||
| 145 | #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8) | ||
| 137 | 146 | ||
| 138 | struct ufs_hba; | 147 | struct ufs_hba; |
| 139 | void ufs_advertise_fixup_device(struct ufs_hba *hba); | 148 | void ufs_advertise_fixup_device(struct ufs_hba *hba); |
| 140 | 149 | ||
| 141 | static struct ufs_dev_fix ufs_fixups[] = { | ||
| 142 | /* UFS cards deviations table */ | ||
| 143 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
| 144 | UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), | ||
| 145 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), | ||
| 146 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
| 147 | UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS), | ||
| 148 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
| 149 | UFS_DEVICE_NO_FASTAUTO), | ||
| 150 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
| 151 | UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE), | ||
| 152 | UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL, | ||
| 153 | UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), | ||
| 154 | UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG", | ||
| 155 | UFS_DEVICE_QUIRK_PA_TACTIVATE), | ||
| 156 | UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG", | ||
| 157 | UFS_DEVICE_QUIRK_PA_TACTIVATE), | ||
| 158 | UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), | ||
| 159 | |||
| 160 | END_FIX | ||
| 161 | }; | ||
| 162 | #endif /* UFS_QUIRKS_H_ */ | 150 | #endif /* UFS_QUIRKS_H_ */ |
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index ef8548c3a423..a2c2817fc566 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
| @@ -185,6 +185,30 @@ ufs_get_pm_lvl_to_link_pwr_state(enum ufs_pm_level lvl) | |||
| 185 | return ufs_pm_lvl_states[lvl].link_state; | 185 | return ufs_pm_lvl_states[lvl].link_state; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | static struct ufs_dev_fix ufs_fixups[] = { | ||
| 189 | /* UFS cards deviations table */ | ||
| 190 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
| 191 | UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), | ||
| 192 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), | ||
| 193 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
| 194 | UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS), | ||
| 195 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
| 196 | UFS_DEVICE_NO_FASTAUTO), | ||
| 197 | UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, | ||
| 198 | UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE), | ||
| 199 | UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL, | ||
| 200 | UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), | ||
| 201 | UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG", | ||
| 202 | UFS_DEVICE_QUIRK_PA_TACTIVATE), | ||
| 203 | UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG", | ||
| 204 | UFS_DEVICE_QUIRK_PA_TACTIVATE), | ||
| 205 | UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), | ||
| 206 | UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, | ||
| 207 | UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME), | ||
| 208 | |||
| 209 | END_FIX | ||
| 210 | }; | ||
| 211 | |||
| 188 | static void ufshcd_tmc_handler(struct ufs_hba *hba); | 212 | static void ufshcd_tmc_handler(struct ufs_hba *hba); |
| 189 | static void ufshcd_async_scan(void *data, async_cookie_t cookie); | 213 | static void ufshcd_async_scan(void *data, async_cookie_t cookie); |
| 190 | static int ufshcd_reset_and_restore(struct ufs_hba *hba); | 214 | static int ufshcd_reset_and_restore(struct ufs_hba *hba); |
| @@ -288,10 +312,24 @@ int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, | |||
| 288 | */ | 312 | */ |
| 289 | static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) | 313 | static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) |
| 290 | { | 314 | { |
| 291 | if (hba->ufs_version == UFSHCI_VERSION_10) | 315 | u32 intr_mask = 0; |
| 292 | return INTERRUPT_MASK_ALL_VER_10; | 316 | |
| 293 | else | 317 | switch (hba->ufs_version) { |
| 294 | return INTERRUPT_MASK_ALL_VER_11; | 318 | case UFSHCI_VERSION_10: |
| 319 | intr_mask = INTERRUPT_MASK_ALL_VER_10; | ||
| 320 | break; | ||
| 321 | /* allow fall through */ | ||
| 322 | case UFSHCI_VERSION_11: | ||
| 323 | case UFSHCI_VERSION_20: | ||
| 324 | intr_mask = INTERRUPT_MASK_ALL_VER_11; | ||
| 325 | break; | ||
| 326 | /* allow fall through */ | ||
| 327 | case UFSHCI_VERSION_21: | ||
| 328 | default: | ||
| 329 | intr_mask = INTERRUPT_MASK_ALL_VER_21; | ||
| 330 | } | ||
| 331 | |||
| 332 | return intr_mask; | ||
| 295 | } | 333 | } |
| 296 | 334 | ||
| 297 | /** | 335 | /** |
| @@ -5199,6 +5237,8 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) | |||
| 5199 | 5237 | ||
| 5200 | if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE) | 5238 | if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE) |
| 5201 | ufshcd_quirk_tune_host_pa_tactivate(hba); | 5239 | ufshcd_quirk_tune_host_pa_tactivate(hba); |
| 5240 | |||
| 5241 | ufshcd_vops_apply_dev_quirks(hba); | ||
| 5202 | } | 5242 | } |
| 5203 | 5243 | ||
| 5204 | /** | 5244 | /** |
| @@ -6667,6 +6707,13 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) | |||
| 6667 | /* Get UFS version supported by the controller */ | 6707 | /* Get UFS version supported by the controller */ |
| 6668 | hba->ufs_version = ufshcd_get_ufs_version(hba); | 6708 | hba->ufs_version = ufshcd_get_ufs_version(hba); |
| 6669 | 6709 | ||
| 6710 | if ((hba->ufs_version != UFSHCI_VERSION_10) && | ||
| 6711 | (hba->ufs_version != UFSHCI_VERSION_11) && | ||
| 6712 | (hba->ufs_version != UFSHCI_VERSION_20) && | ||
| 6713 | (hba->ufs_version != UFSHCI_VERSION_21)) | ||
| 6714 | dev_err(hba->dev, "invalid UFS version 0x%x\n", | ||
| 6715 | hba->ufs_version); | ||
| 6716 | |||
| 6670 | /* Get Interrupt bit mask per version */ | 6717 | /* Get Interrupt bit mask per version */ |
| 6671 | hba->intr_mask = ufshcd_get_intr_mask(hba); | 6718 | hba->intr_mask = ufshcd_get_intr_mask(hba); |
| 6672 | 6719 | ||
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 7d9ff22acfea..08cd26ed2382 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h | |||
| @@ -266,7 +266,7 @@ struct ufs_pwr_mode_info { | |||
| 266 | * @setup_task_mgmt: called before any task management request is issued | 266 | * @setup_task_mgmt: called before any task management request is issued |
| 267 | * to set some things | 267 | * to set some things |
| 268 | * @hibern8_notify: called around hibern8 enter/exit | 268 | * @hibern8_notify: called around hibern8 enter/exit |
| 269 | * to configure some things | 269 | * @apply_dev_quirks: called to apply device specific quirks |
| 270 | * @suspend: called during host controller PM callback | 270 | * @suspend: called during host controller PM callback |
| 271 | * @resume: called during host controller PM callback | 271 | * @resume: called during host controller PM callback |
| 272 | * @dbg_register_dump: used to dump controller debug information | 272 | * @dbg_register_dump: used to dump controller debug information |
| @@ -293,7 +293,8 @@ struct ufs_hba_variant_ops { | |||
| 293 | void (*setup_xfer_req)(struct ufs_hba *, int, bool); | 293 | void (*setup_xfer_req)(struct ufs_hba *, int, bool); |
| 294 | void (*setup_task_mgmt)(struct ufs_hba *, int, u8); | 294 | void (*setup_task_mgmt)(struct ufs_hba *, int, u8); |
| 295 | void (*hibern8_notify)(struct ufs_hba *, enum uic_cmd_dme, | 295 | void (*hibern8_notify)(struct ufs_hba *, enum uic_cmd_dme, |
| 296 | enum ufs_notify_change_status); | 296 | enum ufs_notify_change_status); |
| 297 | int (*apply_dev_quirks)(struct ufs_hba *); | ||
| 297 | int (*suspend)(struct ufs_hba *, enum ufs_pm_op); | 298 | int (*suspend)(struct ufs_hba *, enum ufs_pm_op); |
| 298 | int (*resume)(struct ufs_hba *, enum ufs_pm_op); | 299 | int (*resume)(struct ufs_hba *, enum ufs_pm_op); |
| 299 | void (*dbg_register_dump)(struct ufs_hba *hba); | 300 | void (*dbg_register_dump)(struct ufs_hba *hba); |
| @@ -839,6 +840,13 @@ static inline void ufshcd_vops_hibern8_notify(struct ufs_hba *hba, | |||
| 839 | return hba->vops->hibern8_notify(hba, cmd, status); | 840 | return hba->vops->hibern8_notify(hba, cmd, status); |
| 840 | } | 841 | } |
| 841 | 842 | ||
| 843 | static inline int ufshcd_vops_apply_dev_quirks(struct ufs_hba *hba) | ||
| 844 | { | ||
| 845 | if (hba->vops && hba->vops->apply_dev_quirks) | ||
| 846 | return hba->vops->apply_dev_quirks(hba); | ||
| 847 | return 0; | ||
| 848 | } | ||
| 849 | |||
| 842 | static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op) | 850 | static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op) |
| 843 | { | 851 | { |
| 844 | if (hba->vops && hba->vops->suspend) | 852 | if (hba->vops && hba->vops->suspend) |
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 5d978867be57..8c5190e2e1c9 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h | |||
| @@ -72,6 +72,10 @@ enum { | |||
| 72 | REG_UIC_COMMAND_ARG_1 = 0x94, | 72 | REG_UIC_COMMAND_ARG_1 = 0x94, |
| 73 | REG_UIC_COMMAND_ARG_2 = 0x98, | 73 | REG_UIC_COMMAND_ARG_2 = 0x98, |
| 74 | REG_UIC_COMMAND_ARG_3 = 0x9C, | 74 | REG_UIC_COMMAND_ARG_3 = 0x9C, |
| 75 | REG_UFS_CCAP = 0x100, | ||
| 76 | REG_UFS_CRYPTOCAP = 0x104, | ||
| 77 | |||
| 78 | UFSHCI_CRYPTO_REG_SPACE_SIZE = 0x400, | ||
| 75 | }; | 79 | }; |
| 76 | 80 | ||
| 77 | /* Controller capability masks */ | 81 | /* Controller capability masks */ |
| @@ -275,6 +279,9 @@ enum { | |||
| 275 | 279 | ||
| 276 | /* Interrupt disable mask for UFSHCI v1.1 */ | 280 | /* Interrupt disable mask for UFSHCI v1.1 */ |
| 277 | INTERRUPT_MASK_ALL_VER_11 = 0x31FFF, | 281 | INTERRUPT_MASK_ALL_VER_11 = 0x31FFF, |
| 282 | |||
| 283 | /* Interrupt disable mask for UFSHCI v2.1 */ | ||
| 284 | INTERRUPT_MASK_ALL_VER_21 = 0x71FFF, | ||
| 278 | }; | 285 | }; |
| 279 | 286 | ||
| 280 | /* | 287 | /* |
