diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-09-19 11:28:51 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-09-19 11:28:51 +0200 |
commit | a1d1eb2f57501b2e7e2076ce89b3f3a666ddbfdd (patch) | |
tree | 375d5bd69b2fc2610648b649eff32aa6582af4e2 /drivers/scsi | |
parent | Merge tag 'dma-mapping-6.12-2024-09-19' of git://git.infradead.org/users/hch/... (diff) | |
parent | Merge patch series "smartpqi updates" (diff) | |
download | linux-a1d1eb2f57501b2e7e2076ce89b3f3a666ddbfdd.tar.xz linux-a1d1eb2f57501b2e7e2076ce89b3f3a666ddbfdd.zip |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"Updates to the usual drivers (ufs, smartpqi, NCR5380, mac_scsi, lpfc,
mpi3mr).
There are no user visible core changes and a whole series of minor
updates and fixes. The largest core change is probably the
simplification of the workqueue allocation path"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (86 commits)
scsi: smartpqi: update driver version to 2.1.30-031
scsi: smartpqi: fix volume size updates
scsi: smartpqi: fix rare system hang during LUN reset
scsi: smartpqi: add new controller PCI IDs
scsi: smartpqi: add counter for parity write stream requests
scsi: smartpqi: correct stream detection
scsi: smartpqi: Add fw log to kdump
scsi: bnx2fc: Remove some unused fields in struct bnx2fc_rport
scsi: qla2xxx: Remove the unused 'del_list_entry' field in struct fc_port
scsi: ufs: core: Remove ufshcd_urgent_bkops()
scsi: core: Remove obsoleted declaration for scsi_driverbyte_string()
scsi: bnx2i: Remove unused declarations
scsi: core: Simplify an alloc_workqueue() invocation
scsi: ufs: Simplify alloc*_workqueue() invocation
scsi: stex: Simplify an alloc_ordered_workqueue() invocation
scsi: scsi_transport_fc: Simplify alloc_workqueue() invocations
scsi: snic: Simplify alloc_workqueue() invocations
scsi: qedi: Simplify an alloc_workqueue() invocation
scsi: qedf: Simplify alloc_workqueue() invocations
scsi: myrs: Simplify an alloc_ordered_workqueue() invocation
...
Diffstat (limited to 'drivers/scsi')
66 files changed, 929 insertions, 587 deletions
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index cea3a79d538e..0e10502660de 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -157,7 +157,6 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd) } ncmd->status = 0; - ncmd->message = 0; } static inline void advance_sg_buffer(struct NCR5380_cmd *ncmd) @@ -199,7 +198,6 @@ static inline void set_resid_from_SCp(struct scsi_cmnd *cmd) * Polls the chip in a reasonably efficient manner waiting for an * event to occur. After a short quick poll we begin to yield the CPU * (if possible). In irq contexts the time-out is arbitrarily limited. - * Callers may hold locks as long as they are held in irq mode. * * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT. */ @@ -1228,24 +1226,15 @@ out: return ret; } -/* - * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, - * unsigned char *phase, int *count, unsigned char **data) - * - * Purpose : transfers data in given phase using polled I/O - * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of - * bytes to transfer, **data - pointer to data pointer, - * can_sleep - 1 or 0 when sleeping is permitted or not, respectively. - * - * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes are transferred or exit - * is in same phase. - * - * Also, *phase, *count, *data are modified in place. +/** + * NCR5380_transfer_pio() - transfers data in given phase using polled I/O + * @instance: instance of driver + * @phase: pointer to what phase is expected + * @count: pointer to number of bytes to transfer + * @data: pointer to data pointer + * @can_sleep: 1 or 0 when sleeping is permitted or not, respectively * - * XXX Note : handling for bus free may be useful. + * Returns: void. *phase, *count, *data are modified in place. */ /* @@ -1254,9 +1243,9 @@ out: * counts, we will always do a pseudo DMA or DMA transfer. */ -static int NCR5380_transfer_pio(struct Scsi_Host *instance, - unsigned char *phase, int *count, - unsigned char **data, unsigned int can_sleep) +static void NCR5380_transfer_pio(struct Scsi_Host *instance, + unsigned char *phase, int *count, + unsigned char **data, unsigned int can_sleep) { struct NCR5380_hostdata *hostdata = shost_priv(instance); unsigned char p = *phase, tmp; @@ -1277,8 +1266,8 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, * valid */ - if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, - HZ * can_sleep) < 0) + if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ | SR_BSY, + SR_REQ | SR_BSY, HZ * can_sleep) < 0) break; dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n"); @@ -1329,17 +1318,19 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n"); -/* - * We have several special cases to consider during REQ/ACK handshaking : - * 1. We were in MSGOUT phase, and we are on the last byte of the - * message. ATN must be dropped as ACK is dropped. - * - * 2. We are in a MSGIN phase, and we are on the last byte of the - * message. We must exit with ACK asserted, so that the calling - * code may raise ATN before dropping ACK to reject the message. - * - * 3. ACK and ATN are clear and the target may proceed as normal. - */ + /* + * We have several special cases to consider during REQ/ACK + * handshaking: + * + * 1. We were in MSGOUT phase, and we are on the last byte of + * the message. ATN must be dropped as ACK is dropped. + * + * 2. We are in MSGIN phase, and we are on the last byte of the + * message. We must exit with ACK asserted, so that the calling + * code may raise ATN before dropping ACK to reject the message. + * + * 3. ACK and ATN are clear & the target may proceed as normal. + */ if (!(p == PHASE_MSGIN && c == 1)) { if (p == PHASE_MSGOUT && c > 1) NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); @@ -1361,11 +1352,6 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, *phase = tmp & PHASE_MASK; else *phase = PHASE_UNKNOWN; - - if (!c || (*phase == p)) - return 0; - else - return -1; } /** @@ -1485,6 +1471,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char **data) { struct NCR5380_hostdata *hostdata = shost_priv(instance); + struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(hostdata->connected); int c = *count; unsigned char p = *phase; unsigned char *d = *data; @@ -1496,7 +1483,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, return -1; } - NCR5380_to_ncmd(hostdata->connected)->phase = p; + ncmd->phase = p; if (p & SR_IO) { if (hostdata->read_overruns) @@ -1574,79 +1561,80 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, /* The result is zero iff pseudo DMA send/receive was completed. */ hostdata->dma_len = c; -/* - * A note regarding the DMA errata workarounds for early NMOS silicon. - * - * For DMA sends, we want to wait until the last byte has been - * transferred out over the bus before we turn off DMA mode. Alas, there - * seems to be no terribly good way of doing this on a 5380 under all - * conditions. For non-scatter-gather operations, we can wait until REQ - * and ACK both go false, or until a phase mismatch occurs. Gather-sends - * are nastier, since the device will be expecting more data than we - * are prepared to send it, and REQ will remain asserted. On a 53C8[01] we - * could test Last Byte Sent to assure transfer (I imagine this is precisely - * why this signal was added to the newer chips) but on the older 538[01] - * this signal does not exist. The workaround for this lack is a watchdog; - * we bail out of the wait-loop after a modest amount of wait-time if - * the usual exit conditions are not met. Not a terribly clean or - * correct solution :-% - * - * DMA receive is equally tricky due to a nasty characteristic of the NCR5380. - * If the chip is in DMA receive mode, it will respond to a target's - * REQ by latching the SCSI data into the INPUT DATA register and asserting - * ACK, even if it has _already_ been notified by the DMA controller that - * the current DMA transfer has completed! If the NCR5380 is then taken - * out of DMA mode, this already-acknowledged byte is lost. This is - * not a problem for "one DMA transfer per READ command", because - * the situation will never arise... either all of the data is DMA'ed - * properly, or the target switches to MESSAGE IN phase to signal a - * disconnection (either operation bringing the DMA to a clean halt). - * However, in order to handle scatter-receive, we must work around the - * problem. The chosen fix is to DMA fewer bytes, then check for the - * condition before taking the NCR5380 out of DMA mode. One or two extra - * bytes are transferred via PIO as necessary to fill out the original - * request. - */ - - if (hostdata->flags & FLAG_DMA_FIXUP) { - if (p & SR_IO) { - /* - * The workaround was to transfer fewer bytes than we - * intended to with the pseudo-DMA read function, wait for - * the chip to latch the last byte, read it, and then disable - * pseudo-DMA mode. - * - * After REQ is asserted, the NCR5380 asserts DRQ and ACK. - * REQ is deasserted when ACK is asserted, and not reasserted - * until ACK goes false. Since the NCR5380 won't lower ACK - * until DACK is asserted, which won't happen unless we twiddle - * the DMA port or we take the NCR5380 out of DMA mode, we - * can guarantee that we won't handshake another extra - * byte. - */ + /* + * A note regarding the DMA errata workarounds for early NMOS silicon. + * + * For DMA sends, we want to wait until the last byte has been + * transferred out over the bus before we turn off DMA mode. Alas, there + * seems to be no terribly good way of doing this on a 5380 under all + * conditions. For non-scatter-gather operations, we can wait until REQ + * and ACK both go false, or until a phase mismatch occurs. Gather-sends + * are nastier, since the device will be expecting more data than we + * are prepared to send it, and REQ will remain asserted. On a 53C8[01] + * we could test Last Byte Sent to assure transfer (I imagine this is + * precisely why this signal was added to the newer chips) but on the + * older 538[01] this signal does not exist. The workaround for this + * lack is a watchdog; we bail out of the wait-loop after a modest + * amount of wait-time if the usual exit conditions are not met. + * Not a terribly clean or correct solution :-% + * + * DMA receive is equally tricky due to a nasty characteristic of the + * NCR5380. If the chip is in DMA receive mode, it will respond to a + * target's REQ by latching the SCSI data into the INPUT DATA register + * and asserting ACK, even if it has _already_ been notified by the + * DMA controller that the current DMA transfer has completed! If the + * NCR5380 is then taken out of DMA mode, this already-acknowledged + * byte is lost. + * + * This is not a problem for "one DMA transfer per READ + * command", because the situation will never arise... either all of + * the data is DMA'ed properly, or the target switches to MESSAGE IN + * phase to signal a disconnection (either operation bringing the DMA + * to a clean halt). However, in order to handle scatter-receive, we + * must work around the problem. The chosen fix is to DMA fewer bytes, + * then check for the condition before taking the NCR5380 out of DMA + * mode. One or two extra bytes are transferred via PIO as necessary + * to fill out the original request. + */ - if (NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, - BASR_DRQ, BASR_DRQ, 0) < 0) { - result = -1; - shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n"); - } - if (NCR5380_poll_politely(hostdata, STATUS_REG, - SR_REQ, 0, 0) < 0) { - result = -1; - shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n"); - } - d[*count - 1] = NCR5380_read(INPUT_DATA_REG); - } else { - /* - * Wait for the last byte to be sent. If REQ is being asserted for - * the byte we're interested, we'll ACK it and it will go false. - */ - if (NCR5380_poll_politely2(hostdata, - BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ, - BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, 0) < 0) { - result = -1; - shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n"); + if ((hostdata->flags & FLAG_DMA_FIXUP) && + (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) { + /* + * The workaround was to transfer fewer bytes than we + * intended to with the pseudo-DMA receive function, wait for + * the chip to latch the last byte, read it, and then disable + * DMA mode. + * + * After REQ is asserted, the NCR5380 asserts DRQ and ACK. + * REQ is deasserted when ACK is asserted, and not reasserted + * until ACK goes false. Since the NCR5380 won't lower ACK + * until DACK is asserted, which won't happen unless we twiddle + * the DMA port or we take the NCR5380 out of DMA mode, we + * can guarantee that we won't handshake another extra + * byte. + * + * If sending, wait for the last byte to be sent. If REQ is + * being asserted for the byte we're interested, we'll ACK it + * and it will go false. + */ + if (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, + BASR_DRQ, BASR_DRQ, 0)) { + if ((p & SR_IO) && + (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) { + if (!NCR5380_poll_politely(hostdata, STATUS_REG, + SR_REQ, 0, 0)) { + d[c] = NCR5380_read(INPUT_DATA_REG); + --ncmd->this_residual; + } else { + result = -1; + scmd_printk(KERN_ERR, hostdata->connected, + "PDMA fixup: !REQ timeout\n"); + } } + } else if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH) { + result = -1; + scmd_printk(KERN_ERR, hostdata->connected, + "PDMA fixup: DRQ timeout\n"); } } @@ -1666,9 +1654,6 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, * Side effects : SCSI things happen, the disconnected queue will be * modified if a command disconnects, *instance->connected will * change. - * - * XXX Note : we need to watch for bus free or a reset condition here - * to recover from an unexpected bus free condition. */ static void NCR5380_information_transfer(struct Scsi_Host *instance) @@ -1807,9 +1792,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) return; case PHASE_MSGIN: len = 1; + tmp = 0xff; data = &tmp; NCR5380_transfer_pio(instance, &phase, &len, &data, 0); - ncmd->message = tmp; + if (tmp == 0xff) + break; switch (tmp) { case ABORT: @@ -1996,6 +1983,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) break; case PHASE_STATIN: len = 1; + tmp = ncmd->status; data = &tmp; NCR5380_transfer_pio(instance, &phase, &len, &data, 0); ncmd->status = tmp; @@ -2005,9 +1993,20 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) NCR5380_dprint(NDEBUG_ANY, instance); } /* switch(phase) */ } else { + int err; + spin_unlock_irq(&hostdata->lock); - NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, HZ); + err = NCR5380_poll_politely(hostdata, STATUS_REG, + SR_REQ, SR_REQ, HZ); spin_lock_irq(&hostdata->lock); + + if (err < 0 && hostdata->connected && + !(NCR5380_read(STATUS_REG) & SR_BSY)) { + scmd_printk(KERN_ERR, hostdata->connected, + "BSY signal lost\n"); + do_reset(instance); + bus_reset_cleanup(instance); + } } } } diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 8dc2be4212dc..d402d4bffcb2 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -3,10 +3,10 @@ * NCR 5380 defines * * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix consulting and custom programming) - * drew@colorado.edu - * +1 (303) 666-5836 + * Visionary Computing + * (Unix consulting and custom programming) + * drew@colorado.edu + * +1 (303) 666-5836 * * For more information, please consult * @@ -78,7 +78,7 @@ #define ICR_DIFF_ENABLE 0x20 /* wo Set to enable diff. drivers */ #define ICR_ASSERT_ACK 0x10 /* rw ini Set to assert ACK */ #define ICR_ASSERT_BSY 0x08 /* rw Set to assert BSY */ -#define ICR_ASSERT_SEL 0x04 /* rw Set to assert SEL */ +#define ICR_ASSERT_SEL 0x04 /* rw Set to assert SEL */ #define ICR_ASSERT_ATN 0x02 /* rw Set to assert ATN */ #define ICR_ASSERT_DATA 0x01 /* rw SCSI_DATA_REG is asserted */ @@ -135,7 +135,7 @@ #define BASR_IRQ 0x10 /* ro mirror of IRQ pin */ #define BASR_PHASE_MATCH 0x08 /* ro Set when MSG CD IO match TCR */ #define BASR_BUSY_ERROR 0x04 /* ro Unexpected change to inactive state */ -#define BASR_ATN 0x02 /* ro BUS status */ +#define BASR_ATN 0x02 /* ro BUS status */ #define BASR_ACK 0x01 /* ro BUS status */ /* Write any value to this register to start a DMA send */ @@ -170,7 +170,7 @@ #define CSR_BASE CSR_53C80_INTR /* Note : PHASE_* macros are based on the values of the STATUS register */ -#define PHASE_MASK (SR_MSG | SR_CD | SR_IO) +#define PHASE_MASK (SR_MSG | SR_CD | SR_IO) #define PHASE_DATAOUT 0 #define PHASE_DATAIN SR_IO @@ -231,7 +231,6 @@ struct NCR5380_cmd { int this_residual; struct scatterlist *buffer; int status; - int message; int phase; struct list_head list; }; @@ -286,8 +285,9 @@ static const char *NCR5380_info(struct Scsi_Host *instance); static void NCR5380_reselect(struct Scsi_Host *instance); static bool NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *); static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); -static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data, - unsigned int can_sleep); +static void NCR5380_transfer_pio(struct Scsi_Host *instance, + unsigned char *phase, int *count, + unsigned char **data, unsigned int can_sleep); static int NCR5380_poll_politely2(struct NCR5380_hostdata *, unsigned int, u8, u8, unsigned int, u8, u8, unsigned long); diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index b22857c6f3f4..ec3834bda111 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -1267,7 +1267,7 @@ static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3 return ret; command = ContainerRawIo; fibsize = sizeof(struct aac_raw_io) + - ((le32_to_cpu(readcmd->sg.count)-1) * sizeof(struct sgentryraw)); + (le32_to_cpu(readcmd->sg.count) * sizeof(struct sgentryraw)); } BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); @@ -1302,7 +1302,7 @@ static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u if (ret < 0) return ret; fibsize = sizeof(struct aac_read64) + - ((le32_to_cpu(readcmd->sg.count) - 1) * + (le32_to_cpu(readcmd->sg.count) * sizeof (struct sgentry64)); BUG_ON (fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); @@ -1337,7 +1337,7 @@ static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 if (ret < 0) return ret; fibsize = sizeof(struct aac_read) + - ((le32_to_cpu(readcmd->sg.count) - 1) * + (le32_to_cpu(readcmd->sg.count) * sizeof (struct sgentry)); BUG_ON (fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); @@ -1401,7 +1401,7 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u return ret; command = ContainerRawIo; fibsize = sizeof(struct aac_raw_io) + - ((le32_to_cpu(writecmd->sg.count)-1) * sizeof (struct sgentryraw)); + (le32_to_cpu(writecmd->sg.count) * sizeof(struct sgentryraw)); } BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); @@ -1436,7 +1436,7 @@ static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, if (ret < 0) return ret; fibsize = sizeof(struct aac_write64) + - ((le32_to_cpu(writecmd->sg.count) - 1) * + (le32_to_cpu(writecmd->sg.count) * sizeof (struct sgentry64)); BUG_ON (fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); @@ -1473,7 +1473,7 @@ static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3 if (ret < 0) return ret; fibsize = sizeof(struct aac_write) + - ((le32_to_cpu(writecmd->sg.count) - 1) * + (le32_to_cpu(writecmd->sg.count) * sizeof (struct sgentry)); BUG_ON (fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); @@ -1592,9 +1592,9 @@ static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd) /* * Build Scatter/Gather list */ - fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) + + fibsize = sizeof(struct aac_srb) + ((le32_to_cpu(srbcmd->sg.count) & 0xff) * - sizeof (struct sgentry64)); + sizeof(struct sgentry64)); BUG_ON (fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); @@ -1624,7 +1624,7 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd) * Build Scatter/Gather list */ fibsize = sizeof (struct aac_srb) + - (((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * + ((le32_to_cpu(srbcmd->sg.count) & 0xff) * sizeof (struct sgentry)); BUG_ON (fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); @@ -1693,8 +1693,7 @@ static int aac_send_safw_bmic_cmd(struct aac_dev *dev, fibptr->hw_fib_va->header.XferState &= ~cpu_to_le32(FastResponseCapable); - fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + - sizeof(struct sgentry64); + fibsize = sizeof(struct aac_srb) + sizeof(struct sgentry64); /* allocate DMA buffer for response */ addr = dma_map_single(&dev->pdev->dev, xfer_buf, xfer_len, @@ -1833,7 +1832,7 @@ static int aac_get_safw_ciss_luns(struct aac_dev *dev) struct aac_ciss_phys_luns_resp *phys_luns; datasize = sizeof(struct aac_ciss_phys_luns_resp) + - (AAC_MAX_TARGETS - 1) * sizeof(struct _ciss_lun); + AAC_MAX_TARGETS * sizeof(struct _ciss_lun); phys_luns = kmalloc(datasize, GFP_KERNEL); if (phys_luns == NULL) goto out; @@ -2267,7 +2266,7 @@ int aac_get_adapter_info(struct aac_dev* dev) dev->a_ops.adapter_bounds = aac_bounds_32; dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write) + sizeof(struct sgentry)) / + sizeof(struct aac_write)) / sizeof(struct sgentry); if (dev->dac_support) { dev->a_ops.adapter_read = aac_read_block64; @@ -2278,8 +2277,7 @@ int aac_get_adapter_info(struct aac_dev* dev) dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write64) + - sizeof(struct sgentry64)) / + sizeof(struct aac_write64)) / sizeof(struct sgentry64); } else { dev->a_ops.adapter_read = aac_read_block; diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 7d5a155073c6..1d09d3ac6aa4 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -322,7 +322,7 @@ struct aac_ciss_phys_luns_resp { u8 level3[2]; u8 level2[2]; u8 node_ident[16]; /* phys. node identifier */ - } lun[1]; /* List of phys. devices */ + } lun[]; /* List of phys. devices */ }; /* @@ -507,32 +507,27 @@ struct sge_ieee1212 { struct sgmap { __le32 count; - struct sgentry sg[1]; + struct sgentry sg[]; }; struct user_sgmap { u32 count; - struct user_sgentry sg[1]; + struct user_sgentry sg[]; }; struct sgmap64 { __le32 count; - struct sgentry64 sg[1]; + struct sgentry64 sg[]; }; struct user_sgmap64 { u32 count; - struct user_sgentry64 sg[1]; + struct user_sgentry64 sg[]; }; struct sgmapraw { __le32 count; - struct sgentryraw sg[1]; -}; - -struct user_sgmapraw { - u32 count; - struct user_sgentryraw sg[1]; + struct sgentryraw sg[]; }; struct creation_info @@ -873,7 +868,7 @@ union aac_init __le16 element_count; __le16 comp_thresh; __le16 unused; - } rrq[1]; /* up to 64 RRQ addresses */ + } rrq[] __counted_by_le(rr_queue_count); /* up to 64 RRQ addresses */ } r8; }; @@ -2029,8 +2024,8 @@ struct aac_srb_reply }; struct aac_srb_unit { - struct aac_srb srb; struct aac_srb_reply srb_reply; + struct aac_srb srb; }; /* diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index e7cc927ed952..68240d6f27ab 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -523,7 +523,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) goto cleanup; } - if ((fibsize < (sizeof(struct user_aac_srb) - sizeof(struct user_sgentry))) || + if ((fibsize < sizeof(struct user_aac_srb)) || (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)))) { rcode = -EINVAL; goto cleanup; @@ -561,7 +561,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) rcode = -EINVAL; goto cleanup; } - actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + + actual_fibsize = sizeof(struct aac_srb) + ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry)); actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) * (sizeof(struct sgentry64) - sizeof(struct sgentry)); diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 0f64b0244303..28cf18955a08 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -522,8 +522,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) spin_lock_init(&dev->iq_lock); dev->max_fib_size = sizeof(struct hw_fib); dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size - - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write) + sizeof(struct sgentry)) + - sizeof(struct aac_fibhdr) - sizeof(struct aac_write)) / sizeof(struct sgentry); dev->comm_interface = AAC_COMM_PRODUCER; dev->raw_io_interface = dev->raw_io_64 = 0; diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 25cee03d7f97..47287559c768 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -2327,8 +2327,9 @@ static int aac_send_wellness_command(struct aac_dev *dev, char *wellness_str, sg64->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); sg64->sg[0].count = cpu_to_le32(datasize); - ret = aac_fib_send(ScsiPortCommand64, fibptr, sizeof(struct aac_srb), - FsaNormal, 1, 1, NULL, NULL); + ret = aac_fib_send(ScsiPortCommand64, fibptr, + sizeof(struct aac_srb) + sizeof(struct sgentry), + FsaNormal, 1, 1, NULL, NULL); dma_free_coherent(&dev->pdev->dev, datasize, dma_buf, addr); diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index 11ef58204e96..28115ed637e8 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -410,7 +410,7 @@ static void aac_src_start_adapter(struct aac_dev *dev) lower_32_bits(dev->init_pa), upper_32_bits(dev->init_pa), sizeof(struct _r8) + - (AAC_MAX_HRRQ - 1) * sizeof(struct _rrq), + AAC_MAX_HRRQ * sizeof(struct _rrq), 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } else { init->r7.host_elapsed_seconds = diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 06acb5ff609e..76a1e373386e 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -5528,7 +5528,6 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, struct beiscsi_hba *phba = NULL; struct be_eq_obj *pbe_eq; unsigned int s_handle; - char wq_name[20]; int ret, i; ret = beiscsi_enable_pci(pcidev); @@ -5634,9 +5633,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev, phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0; - snprintf(wq_name, sizeof(wq_name), "beiscsi_%02x_wq", - phba->shost->host_no); - phba->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, wq_name); + phba->wq = alloc_workqueue("beiscsi_%02x_wq", WQ_MEM_RECLAIM, 1, + phba->shost->host_no); if (!phba->wq) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : beiscsi_dev_probe-" diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index a9d3d8562d3c..66fb701401de 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -766,9 +766,8 @@ bfad_thread_workq(struct bfad_s *bfad) struct bfad_im_s *im = bfad->im; bfa_trc(bfad, 0); - snprintf(im->drv_workq_name, KOBJ_NAME_LEN, "bfad_wq_%d", - bfad->inst_no); - im->drv_workq = create_singlethread_workqueue(im->drv_workq_name); + im->drv_workq = alloc_ordered_workqueue("bfad_wq_%d", WQ_MEM_RECLAIM, + bfad->inst_no); if (!im->drv_workq) return BFA_STATUS_FAILED; diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h index 4353feedf76a..0884af04bd1f 100644 --- a/drivers/scsi/bfa/bfad_im.h +++ b/drivers/scsi/bfa/bfad_im.h @@ -134,7 +134,6 @@ struct bfad_fcp_binding { struct bfad_im_s { struct bfad_s *bfad; struct workqueue_struct *drv_workq; - char drv_workq_name[KOBJ_NAME_LEN]; struct work_struct aen_im_notify_work; }; diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 7e74f77da14f..6d47a4d8eed6 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -358,18 +358,12 @@ struct bnx2fc_rport { dma_addr_t lcq_dma; u32 lcq_mem_size; - void *ofld_req[4]; - dma_addr_t ofld_req_dma[4]; - void *enbl_req; - dma_addr_t enbl_req_dma; - spinlock_t tgt_lock; spinlock_t cq_lock; atomic_t num_active_ios; u32 flush_in_prog; unsigned long timestamp; unsigned long retry_delay_timestamp; - struct list_head free_task_list; struct bnx2fc_cmd *pending_queue[BNX2FC_SQ_WQES_MAX+1]; struct list_head active_cmd_queue; struct list_head els_queue; diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 1078c20c5ef6..f49783b89d04 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -2363,8 +2363,8 @@ static int _bnx2fc_create(struct net_device *netdev, interface->vlan_id = vlan_id; interface->tm_timeout = BNX2FC_TM_TIMEOUT; - interface->timer_work_queue = - create_singlethread_workqueue("bnx2fc_timer_wq"); + interface->timer_work_queue = alloc_ordered_workqueue( + "%s", WQ_MEM_RECLAIM, "bnx2fc_timer_wq"); if (!interface->timer_work_queue) { printk(KERN_ERR PFX "ulp_init could not create timer_wq\n"); rc = -EINVAL; diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index df7d04afce05..7030efee5c46 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -815,11 +815,6 @@ extern struct bnx2i_hba *get_adapter_list_head(void); struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba, u16 iscsi_cid); -int bnx2i_alloc_ep_pool(void); -void bnx2i_release_ep_pool(void); -struct bnx2i_endpoint *bnx2i_ep_ofld_list_next(struct bnx2i_hba *hba); -struct bnx2i_endpoint *bnx2i_ep_destroy_list_next(struct bnx2i_hba *hba); - struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic); struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic); @@ -869,12 +864,6 @@ extern int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep); -/* Debug related function prototypes */ -extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn); -extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn); -extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn); -extern void bnx2i_print_recv_state(struct bnx2i_conn *conn); - extern int bnx2i_percpu_io_thread(void *arg); extern int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index f8a09e3eba58..6e1b252cea0e 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -822,7 +822,8 @@ static int __init rdac_init(void) /* * Create workqueue to handle mode selects for rdac */ - kmpath_rdacd = create_singlethread_workqueue("kmpath_rdacd"); + kmpath_rdacd = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, "kmpath_rdacd"); if (!kmpath_rdacd) { scsi_unregister_device_handler(&rdac_dh); printk(KERN_ERR "kmpath_rdacd creation failed.\n"); diff --git a/drivers/scsi/elx/efct/efct_lio.c b/drivers/scsi/elx/efct/efct_lio.c index 6a6ec32c46bd..9ac69356b13e 100644 --- a/drivers/scsi/elx/efct/efct_lio.c +++ b/drivers/scsi/elx/efct/efct_lio.c @@ -1114,7 +1114,8 @@ int efct_scsi_tgt_new_device(struct efct *efct) atomic_set(&efct->tgt_efct.watermark_hit, 0); atomic_set(&efct->tgt_efct.initiator_count, 0); - lio_wq = create_singlethread_workqueue("efct_lio_worker"); + lio_wq = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, + "efct_lio_worker"); if (!lio_wq) { efc_log_err(efct, "workqueue create failed\n"); return -EIO; diff --git a/drivers/scsi/elx/libefc/efc_nport.c b/drivers/scsi/elx/libefc/efc_nport.c index 2e83a667901f..1a7437f4328e 100644 --- a/drivers/scsi/elx/libefc/efc_nport.c +++ b/drivers/scsi/elx/libefc/efc_nport.c @@ -705,9 +705,9 @@ efc_nport_vport_del(struct efc *efc, struct efc_domain *domain, spin_lock_irqsave(&efc->lock, flags); list_for_each_entry(nport, &domain->nport_list, list_entry) { if (nport->wwpn == wwpn && nport->wwnn == wwnn) { - kref_put(&nport->ref, nport->release); /* Shutdown this NPORT */ efc_sm_post_event(&nport->sm, EFC_EVT_SHUTDOWN, NULL); + kref_put(&nport->ref, nport->release); break; } } diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h index ed63f7a9ea54..8a133254c4f6 100644 --- a/drivers/scsi/esas2r/esas2r.h +++ b/drivers/scsi/esas2r/esas2r.h @@ -929,7 +929,6 @@ struct esas2r_adapter { struct list_head fw_event_list; spinlock_t fw_event_lock; u8 fw_events_off; /* if '1', then ignore events */ - char fw_event_q_name[ESAS2R_KOBJ_NAME_LEN]; /* * intr_mode stores the interrupt mode currently being used by this * adapter. it is based on the interrupt_mode module parameter, but diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c index c1a5ab662dc8..0cea5f3d1a08 100644 --- a/drivers/scsi/esas2r/esas2r_init.c +++ b/drivers/scsi/esas2r/esas2r_init.c @@ -311,9 +311,8 @@ int esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid, sema_init(&a->nvram_semaphore, 1); esas2r_fw_event_off(a); - snprintf(a->fw_event_q_name, ESAS2R_KOBJ_NAME_LEN, "esas2r/%d", - a->index); - a->fw_event_q = create_singlethread_workqueue(a->fw_event_q_name); + a->fw_event_q = + alloc_ordered_workqueue("esas2r/%d", WQ_MEM_RECLAIM, a->index); init_waitqueue_head(&a->buffered_ioctl_waiter); init_waitqueue_head(&a->nvram_waiter); diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index 7d3b904af9e8..0609ca6b9353 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -45,12 +45,8 @@ MODULE_PARM_DESC(fcf_dev_loss_tmo, */ #define fcoe_ctlr_id(x) \ ((x)->id) -#define fcoe_ctlr_work_q_name(x) \ - ((x)->work_q_name) #define fcoe_ctlr_work_q(x) \ ((x)->work_q) -#define fcoe_ctlr_devloss_work_q_name(x) \ - ((x)->devloss_work_q_name) #define fcoe_ctlr_devloss_work_q(x) \ ((x)->devloss_work_q) #define fcoe_ctlr_mode(x) \ @@ -797,18 +793,14 @@ struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent, ctlr->fcf_dev_loss_tmo = fcoe_fcf_dev_loss_tmo; - snprintf(ctlr->work_q_name, sizeof(ctlr->work_q_name), - "ctlr_wq_%d", ctlr->id); - ctlr->work_q = create_singlethread_workqueue( - ctlr->work_q_name); + ctlr->work_q = alloc_ordered_workqueue("ctlr_wq_%d", WQ_MEM_RECLAIM, + ctlr->id); if (!ctlr->work_q) goto out_del; - snprintf(ctlr->devloss_work_q_name, - sizeof(ctlr->devloss_work_q_name), - "ctlr_dl_wq_%d", ctlr->id); - ctlr->devloss_work_q = create_singlethread_workqueue( - ctlr->devloss_work_q_name); + ctlr->devloss_work_q = alloc_ordered_workqueue("ctlr_dl_wq_%d", + WQ_MEM_RECLAIM, + ctlr->id); if (!ctlr->devloss_work_q) goto out_del_q; diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 29eead383eb9..0044717d4486 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -1161,14 +1161,16 @@ static int __init fnic_init_module(void) goto err_create_fnic_ioreq_slab; } - fnic_event_queue = create_singlethread_workqueue("fnic_event_wq"); + fnic_event_queue = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, "fnic_event_wq"); if (!fnic_event_queue) { printk(KERN_ERR PFX "fnic work queue create failed\n"); err = -ENOMEM; goto err_create_fnic_workq; } - fnic_fip_queue = create_singlethread_workqueue("fnic_fip_q"); + fnic_fip_queue = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, "fnic_fip_q"); if (!fnic_fip_queue) { printk(KERN_ERR PFX "fnic FIP work queue create failed\n"); err = -ENOMEM; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index ec1a3e7ee94d..6219807ce3b9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2302,7 +2302,8 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) hisi_hba->last_slot_index = 0; - hisi_hba->wq = create_singlethread_workqueue(dev_name(dev)); + hisi_hba->wq = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, dev_name(dev)); if (!hisi_hba->wq) { dev_err(dev, "sas_alloc: failed to create workqueue\n"); goto err_out; diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 7f987335b44c..e021f1106bea 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -292,11 +292,10 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, } if (shost->transportt->create_work_queue) { - snprintf(shost->work_q_name, sizeof(shost->work_q_name), - "scsi_wq_%d", shost->host_no); - shost->work_q = alloc_workqueue("%s", - WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND, - 1, shost->work_q_name); + shost->work_q = alloc_workqueue( + "scsi_wq_%d", + WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND, 1, + shost->host_no); if (!shost->work_q) { error = -EINVAL; diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 2fca17cf8b51..16d085d56e9d 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -3425,7 +3425,6 @@ static int ibmvscsis_probe(struct vio_dev *vdev, struct scsi_info *vscsi; int rc = 0; long hrc = 0; - char wq_name[24]; vscsi = kzalloc(sizeof(*vscsi), GFP_KERNEL); if (!vscsi) { @@ -3536,8 +3535,8 @@ static int ibmvscsis_probe(struct vio_dev *vdev, init_completion(&vscsi->wait_idle); init_completion(&vscsi->unconfig); - snprintf(wq_name, 24, "ibmvscsis%s", dev_name(&vdev->dev)); - vscsi->work_q = create_workqueue(wq_name); + vscsi->work_q = alloc_workqueue("ibmvscsis%s", WQ_MEM_RECLAIM, 1, + dev_name(&vdev->dev)); if (!vscsi->work_q) { rc = -ENOMEM; dev_err(&vscsi->dev, "create_workqueue failed\n"); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index c77d6ca1a210..b2b643c6dbbe 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1030,7 +1030,7 @@ struct ipr_hostrcb_fabric_desc { #define IPR_PATH_FAILED 0x03 __be16 num_entries; - struct ipr_hostrcb_config_element elem[1]; + struct ipr_hostrcb_config_element elem[]; }__attribute__((packed, aligned (4))); struct ipr_hostrcb64_fabric_desc { @@ -1044,7 +1044,7 @@ struct ipr_hostrcb64_fabric_desc { u8 res_path[8]; u8 reserved3[6]; __be16 num_entries; - struct ipr_hostrcb64_config_element elem[1]; + struct ipr_hostrcb64_config_element elem[]; }__attribute__((packed, aligned (8))); #define for_each_hrrq(hrrq, ioa_cfg) \ diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 1d91c457527f..f84a7e6ae379 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -2693,7 +2693,8 @@ int fc_setup_exch_mgr(void) fc_cpu_order = ilog2(roundup_pow_of_two(nr_cpu_ids)); fc_cpu_mask = (1 << fc_cpu_order) - 1; - fc_exch_workqueue = create_singlethread_workqueue("fc_exch_workqueue"); + fc_exch_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, + "fc_exch_workqueue"); if (!fc_exch_workqueue) goto err; return 0; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 33da3c1085f0..308cb4872f96 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -2263,7 +2263,8 @@ struct fc4_prov fc_rport_t0_prov = { */ int fc_setup_rport(void) { - rport_event_queue = create_singlethread_workqueue("fc_rport_eq"); + rport_event_queue = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, "fc_rport_eq"); if (!rport_event_queue) return -ENOMEM; return 0; diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 9c8cc723170d..8566bb1208a0 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -122,12 +122,12 @@ int sas_register_ha(struct sas_ha_struct *sas_ha) error = -ENOMEM; snprintf(name, sizeof(name), "%s_event_q", dev_name(sas_ha->dev)); - sas_ha->event_q = create_singlethread_workqueue(name); + sas_ha->event_q = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, name); if (!sas_ha->event_q) goto Undo_ports; snprintf(name, sizeof(name), "%s_disco_q", dev_name(sas_ha->dev)); - sas_ha->disco_q = create_singlethread_workqueue(name); + sas_ha->disco_q = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, name); if (!sas_ha->disco_q) goto Undo_event_q; diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 7c147d6ea8a8..e5a9c5a323f8 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -306,6 +306,14 @@ struct lpfc_stats { struct lpfc_hba; +/* Data structure to keep withheld FLOGI_ACC information */ +struct lpfc_defer_flogi_acc { + bool flag; + u16 rx_id; + u16 ox_id; + struct lpfc_nodelist *ndlp; + +}; #define LPFC_VMID_TIMER 300 /* timer interval in seconds */ @@ -1430,9 +1438,7 @@ struct lpfc_hba { uint16_t vlan_id; struct list_head fcf_conn_rec_list; - bool defer_flogi_acc_flag; - uint16_t defer_flogi_acc_rx_id; - uint16_t defer_flogi_acc_ox_id; + struct lpfc_defer_flogi_acc defer_flogi_acc; spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */ struct list_head ct_ev_waiters; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 929cbfc95163..de0ec945d2f1 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1099,8 +1099,10 @@ stop_rr_fcf_flogi: sp->cmn.priority_tagging, kref_read(&ndlp->kref)); /* reinitialize the VMID datastructure before returning */ - if (lpfc_is_vmid_enabled(phba)) + if (lpfc_is_vmid_enabled(phba)) { lpfc_reinit_vmid(vport); + vport->vmid_flag = 0; + } if (sp->cmn.priority_tagging) vport->phba->pport->vmid_flag |= (LPFC_VMID_ISSUE_QFPA | LPFC_VMID_TYPE_PRIO); @@ -1390,7 +1392,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->link_flag &= ~LS_EXTERNAL_LOOPBACK; /* Check for a deferred FLOGI ACC condition */ - if (phba->defer_flogi_acc_flag) { + if (phba->defer_flogi_acc.flag) { /* lookup ndlp for received FLOGI */ ndlp = lpfc_findnode_did(vport, 0); if (!ndlp) @@ -1404,34 +1406,38 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (phba->sli_rev == LPFC_SLI_REV4) { bf_set(wqe_ctxt_tag, &defer_flogi_acc.wqe.xmit_els_rsp.wqe_com, - phba->defer_flogi_acc_rx_id); + phba->defer_flogi_acc.rx_id); bf_set(wqe_rcvoxid, &defer_flogi_acc.wqe.xmit_els_rsp.wqe_com, - phba->defer_flogi_acc_ox_id); + phba->defer_flogi_acc.ox_id); } else { icmd = &defer_flogi_acc.iocb; - icmd->ulpContext = phba->defer_flogi_acc_rx_id; + icmd->ulpContext = phba->defer_flogi_acc.rx_id; icmd->unsli3.rcvsli3.ox_id = - phba->defer_flogi_acc_ox_id; + phba->defer_flogi_acc.ox_id; } lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3354 Xmit deferred FLOGI ACC: rx_id: x%x," " ox_id: x%x, hba_flag x%lx\n", - phba->defer_flogi_acc_rx_id, - phba->defer_flogi_acc_ox_id, phba->hba_flag); + phba->defer_flogi_acc.rx_id, + phba->defer_flogi_acc.ox_id, phba->hba_flag); /* Send deferred FLOGI ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, &defer_flogi_acc, ndlp, NULL); - phba->defer_flogi_acc_flag = false; - vport->fc_myDID = did; + phba->defer_flogi_acc.flag = false; - /* Decrement ndlp reference count to indicate the node can be - * released when other references are removed. + /* Decrement the held ndlp that was incremented when the + * deferred flogi acc flag was set. */ - lpfc_nlp_put(ndlp); + if (phba->defer_flogi_acc.ndlp) { + lpfc_nlp_put(phba->defer_flogi_acc.ndlp); + phba->defer_flogi_acc.ndlp = NULL; + } + + vport->fc_myDID = did; } return 0; @@ -5240,9 +5246,10 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* ACC to LOGO completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0109 ACC to LOGO completes to NPort x%x refcnt %d " - "Data: x%x x%x x%x\n", - ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag, - ndlp->nlp_state, ndlp->nlp_rpi); + "last els x%x Data: x%x x%x x%x\n", + ndlp->nlp_DID, kref_read(&ndlp->kref), + ndlp->nlp_last_elscmd, ndlp->nlp_flag, ndlp->nlp_state, + ndlp->nlp_rpi); /* This clause allows the LOGO ACC to complete and free resources * for the Fabric Domain Controller. It does deliberately skip @@ -5254,18 +5261,22 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; if (ndlp->nlp_state == NLP_STE_NPR_NODE) { - /* If PLOGI is being retried, PLOGI completion will cleanup the - * node. The NLP_NPR_2B_DISC flag needs to be retained to make - * progress on nodes discovered from last RSCN. - */ - if ((ndlp->nlp_flag & NLP_DELAY_TMO) && - (ndlp->nlp_last_elscmd == ELS_CMD_PLOGI)) - goto out; - if (ndlp->nlp_flag & NLP_RPI_REGISTERED) lpfc_unreg_rpi(vport, ndlp); + /* If came from PRLO, then PRLO_ACC is done. + * Start rediscovery now. + */ + if (ndlp->nlp_last_elscmd == ELS_CMD_PRLO) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag |= NLP_NPR_2B_DISC; + spin_unlock_irq(&ndlp->lock); + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); + lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); + } } + out: /* * The driver received a LOGO from the rport and has ACK'd it. @@ -8454,9 +8465,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* Defer ACC response until AFTER we issue a FLOGI */ if (!test_bit(HBA_FLOGI_ISSUED, &phba->hba_flag)) { - phba->defer_flogi_acc_rx_id = bf_get(wqe_ctxt_tag, + phba->defer_flogi_acc.rx_id = bf_get(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com); - phba->defer_flogi_acc_ox_id = bf_get(wqe_rcvoxid, + phba->defer_flogi_acc.ox_id = bf_get(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com); vport->fc_myDID = did; @@ -8464,11 +8475,17 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3344 Deferring FLOGI ACC: rx_id: x%x," " ox_id: x%x, hba_flag x%lx\n", - phba->defer_flogi_acc_rx_id, - phba->defer_flogi_acc_ox_id, phba->hba_flag); + phba->defer_flogi_acc.rx_id, + phba->defer_flogi_acc.ox_id, phba->hba_flag); - phba->defer_flogi_acc_flag = true; + phba->defer_flogi_acc.flag = true; + /* This nlp_get is paired with nlp_puts that reset the + * defer_flogi_acc.flag back to false. We need to retain + * a kref on the ndlp until the deferred FLOGI ACC is + * processed or cancelled. + */ + phba->defer_flogi_acc.ndlp = lpfc_nlp_get(ndlp); return 0; } @@ -10504,7 +10521,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_els_rcv_flogi(vport, elsiocb, ndlp); /* retain node if our response is deferred */ - if (phba->defer_flogi_acc_flag) + if (phba->defer_flogi_acc.flag) break; if (newnode) lpfc_disc_state_machine(vport, ndlp, NULL, @@ -10742,7 +10759,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_exp = LSEXP_NOTHING_MORE; /* Unknown ELS command <elsCmd> received from NPORT <did> */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "0115 Unknown ELS command x%x " "received from NPORT x%x\n", cmd, did); if (newnode) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 6943f6c6395c..35c9181c6608 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -175,7 +175,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) ndlp->nlp_state, ndlp->fc4_xpt_flags); /* Don't schedule a worker thread event if the vport is going down. */ - if (test_bit(FC_UNLOADING, &vport->load_flag)) { + if (test_bit(FC_UNLOADING, &vport->load_flag) || + !test_bit(HBA_SETUP, &phba->hba_flag)) { spin_lock_irqsave(&ndlp->lock, iflags); ndlp->rport = NULL; @@ -1254,7 +1255,14 @@ lpfc_linkdown(struct lpfc_hba *phba) lpfc_scsi_dev_block(phba); offline = pci_channel_offline(phba->pcidev); - phba->defer_flogi_acc_flag = false; + /* Decrement the held ndlp if there is a deferred flogi acc */ + if (phba->defer_flogi_acc.flag) { + if (phba->defer_flogi_acc.ndlp) { + lpfc_nlp_put(phba->defer_flogi_acc.ndlp); + phba->defer_flogi_acc.ndlp = NULL; + } + } + phba->defer_flogi_acc.flag = false; /* Clear external loopback plug detected flag */ phba->link_flag &= ~LS_EXTERNAL_LOOPBACK; @@ -1376,7 +1384,7 @@ lpfc_linkup_port(struct lpfc_vport *vport) (vport != phba->pport)) return; - if (phba->defer_flogi_acc_flag) { + if (phba->defer_flogi_acc.flag) { clear_bit(FC_ABORT_DISCOVERY, &vport->fc_flag); clear_bit(FC_RSCN_MODE, &vport->fc_flag); clear_bit(FC_NLP_MORE, &vport->fc_flag); diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index f6a53446e57f..4574716c8764 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -2652,8 +2652,26 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* flush the target */ lpfc_sli_abort_iocb(vport, ndlp->nlp_sid, 0, LPFC_CTX_TGT); - /* Treat like rcv logo */ - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO); + /* Send PRLO_ACC */ + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag |= NLP_LOGO_ACC; + spin_unlock_irq(&ndlp->lock); + lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); + + /* Save ELS_CMD_PRLO as the last elscmd and then set to NPR. + * lpfc_cmpl_els_logo_acc is expected to restart discovery. + */ + ndlp->nlp_last_elscmd = ELS_CMD_PRLO; + ndlp->nlp_prev_state = ndlp->nlp_state; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_ELS | LOG_DISCOVERY, + "3422 DID x%06x nflag x%x lastels x%x ref cnt %u\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_last_elscmd, + kref_read(&ndlp->kref)); + + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + return ndlp->nlp_state; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 98ce9d97a225..60cd60ebff38 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5555,11 +5555,20 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) iocb = &lpfc_cmd->cur_iocbq; if (phba->sli_rev == LPFC_SLI_REV4) { - pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring; - if (!pring_s4) { + /* if the io_wq & pring are gone, the port was reset. */ + if (!phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq || + !phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "2877 SCSI Layer I/O Abort Request " + "IO CMPL Status x%x ID %d LUN %llu " + "HBA_SETUP %d\n", FAILED, + cmnd->device->id, + (u64)cmnd->device->lun, + test_bit(HBA_SETUP, &phba->hba_flag)); ret = FAILED; goto out_unlock_hba; } + pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring; spin_lock(&pring_s4->ring_lock); } /* the command is in process of being cancelled */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 88debef2fb6d..332b8d2348e9 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4687,6 +4687,17 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba) /* Look on all the FCP Rings for the iotag */ if (phba->sli_rev >= LPFC_SLI_REV4) { for (i = 0; i < phba->cfg_hdw_queue; i++) { + if (!phba->sli4_hba.hdwq || + !phba->sli4_hba.hdwq[i].io_wq) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "7777 hdwq's deleted %lx " + "%lx %x %x\n", + phba->pport->load_flag, + phba->hba_flag, + phba->link_state, + phba->sli.sli_flag); + return; + } pring = phba->sli4_hba.hdwq[i].io_wq->pring; spin_lock_irq(&pring->ring_lock); @@ -12473,8 +12484,6 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, cmdiocb->iocb.ulpClass, LPFC_WQE_CQ_ID_DEFAULT, ia, false); - abtsiocbp->vport = vport; - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocbp->hba_wqidx = cmdiocb->hba_wqidx; if (cmdiocb->cmd_flag & LPFC_IO_FCP) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 7ac9ef281881..2fe0386a1fee 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.4.0.3" +#define LPFC_DRIVER_VERSION "14.4.0.4" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/lpfc/lpfc_vmid.c b/drivers/scsi/lpfc/lpfc_vmid.c index 773e02ae20c3..cc3e4736f2fe 100644 --- a/drivers/scsi/lpfc/lpfc_vmid.c +++ b/drivers/scsi/lpfc/lpfc_vmid.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -321,6 +321,5 @@ lpfc_reinit_vmid(struct lpfc_vport *vport) if (!hash_empty(vport->hash_table)) hash_for_each_safe(vport->hash_table, bucket, tmp, cur, hnode) hash_del(&cur->hnode); - vport->vmid_flag = 0; write_unlock(&vport->vmid_lock); } diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 53ee8f84d094..f225bb20aa22 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -102,11 +102,15 @@ __setup("mac5380=", mac_scsi_setup); * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets * so bus errors are unavoidable. * - * If a MOVE.B instruction faults, we assume that zero bytes were transferred - * and simply retry. That assumption probably depends on target behaviour but - * seems to hold up okay. The NOP provides synchronization: without it the - * fault can sometimes occur after the program counter has moved past the - * offending instruction. Post-increment addressing can't be used. + * If a MOVE.B instruction faults during a receive operation, we assume the + * target sent nothing and try again. That assumption probably depends on + * target firmware but it seems to hold up okay. If a fault happens during a + * send operation, the target may or may not have seen /ACK and got the byte. + * It's uncertain so the whole SCSI command gets retried. + * + * The NOP is needed for synchronization because the fault address in the + * exception stack frame may or may not be the instruction that actually + * caused the bus error. Post-increment addressing can't be used. */ #define MOVE_BYTE(operands) \ @@ -208,8 +212,6 @@ __setup("mac5380=", mac_scsi_setup); ".previous \n" \ : "+a" (addr), "+r" (n), "+r" (result) : "a" (io)) -#define MAC_PDMA_DELAY 32 - static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n) { unsigned char *addr = start; @@ -245,22 +247,21 @@ static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n) if (n >= 1) { MOVE_BYTE("%0@,%3@"); if (result) - goto out; + return -1; } if (n >= 1 && ((unsigned long)addr & 1)) { MOVE_BYTE("%0@,%3@"); if (result) - goto out; + return -2; } while (n >= 32) MOVE_16_WORDS("%0@+,%3@"); while (n >= 2) MOVE_WORD("%0@+,%3@"); if (result) - return start - addr; /* Negated to indicate uncertain length */ + return start - addr - 1; /* Negated to indicate uncertain length */ if (n == 1) MOVE_BYTE("%0@,%3@"); -out: return addr - start; } @@ -274,25 +275,56 @@ static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value) out_be32(hostdata->io + (CTRL_REG << 4), value); } +static inline int macscsi_wait_for_drq(struct NCR5380_hostdata *hostdata) +{ + unsigned int n = 1; /* effectively multiplies NCR5380_REG_POLL_TIME */ + unsigned char basr; + +again: + basr = NCR5380_read(BUS_AND_STATUS_REG); + + if (!(basr & BASR_PHASE_MATCH)) + return 1; + + if (basr & BASR_IRQ) + return -1; + + if (basr & BASR_DRQ) + return 0; + + if (n-- == 0) { + NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); + dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, + "%s: DRQ timeout\n", __func__); + return -1; + } + + NCR5380_poll_politely2(hostdata, + BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ, + BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, 0); + goto again; +} + static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, unsigned char *dst, int len) { u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4); unsigned char *d = dst; - int result = 0; hostdata->pdma_residual = len; - while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, - BASR_DRQ | BASR_PHASE_MATCH, - BASR_DRQ | BASR_PHASE_MATCH, 0)) { - int bytes; + while (macscsi_wait_for_drq(hostdata) == 0) { + int bytes, chunk_bytes; if (macintosh_config->ident == MAC_MODEL_IIFX) write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE | CTRL_INTERRUPTS_ENABLE); - bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512)); + chunk_bytes = min(hostdata->pdma_residual, 512); + bytes = mac_pdma_recv(s, d, chunk_bytes); + + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE); if (bytes > 0) { d += bytes; @@ -300,37 +332,25 @@ static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, } if (hostdata->pdma_residual == 0) - goto out; + break; - if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, - BUS_AND_STATUS_REG, BASR_ACK, - BASR_ACK, 0) < 0) - scmd_printk(KERN_DEBUG, hostdata->connected, - "%s: !REQ and !ACK\n", __func__); - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) - goto out; + if (bytes > 0) + continue; - if (bytes == 0) - udelay(MAC_PDMA_DELAY); + NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); + dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, + "%s: bus error [%d/%d] (%d/%d)\n", + __func__, d - dst, len, bytes, chunk_bytes); - if (bytes >= 0) + if (bytes == 0) continue; - dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, - "%s: bus error (%d/%d)\n", __func__, d - dst, len); - NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - result = -1; - goto out; + if (macscsi_wait_for_drq(hostdata) <= 0) + set_host_byte(hostdata->connected, DID_ERROR); + break; } - scmd_printk(KERN_ERR, hostdata->connected, - "%s: phase mismatch or !DRQ\n", __func__); - NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - result = -1; -out: - if (macintosh_config->ident == MAC_MODEL_IIFX) - write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE); - return result; + return 0; } static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, @@ -338,67 +358,47 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, { unsigned char *s = src; u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4); - int result = 0; hostdata->pdma_residual = len; - while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, - BASR_DRQ | BASR_PHASE_MATCH, - BASR_DRQ | BASR_PHASE_MATCH, 0)) { - int bytes; + while (macscsi_wait_for_drq(hostdata) == 0) { + int bytes, chunk_bytes; if (macintosh_config->ident == MAC_MODEL_IIFX) write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE | CTRL_INTERRUPTS_ENABLE); - bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512)); + chunk_bytes = min(hostdata->pdma_residual, 512); + bytes = mac_pdma_send(s, d, chunk_bytes); + + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE); if (bytes > 0) { s += bytes; hostdata->pdma_residual -= bytes; } - if (hostdata->pdma_residual == 0) { - if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG, - TCR_LAST_BYTE_SENT, - TCR_LAST_BYTE_SENT, - 0) < 0) { - scmd_printk(KERN_ERR, hostdata->connected, - "%s: Last Byte Sent timeout\n", __func__); - result = -1; - } - goto out; - } + if (hostdata->pdma_residual == 0) + break; - if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, - BUS_AND_STATUS_REG, BASR_ACK, - BASR_ACK, 0) < 0) - scmd_printk(KERN_DEBUG, hostdata->connected, - "%s: !REQ and !ACK\n", __func__); - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) - goto out; + if (bytes > 0) + continue; - if (bytes == 0) - udelay(MAC_PDMA_DELAY); + NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); + dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, + "%s: bus error [%d/%d] (%d/%d)\n", + __func__, s - src, len, bytes, chunk_bytes); - if (bytes >= 0) + if (bytes == 0) continue; - dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, - "%s: bus error (%d/%d)\n", __func__, s - src, len); - NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - result = -1; - goto out; + if (macscsi_wait_for_drq(hostdata) <= 0) + set_host_byte(hostdata->connected, DID_ERROR); + break; } - scmd_printk(KERN_ERR, hostdata->connected, - "%s: phase mismatch or !DRQ\n", __func__); - NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - result = -1; -out: - if (macintosh_config->ident == MAC_MODEL_IIFX) - write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE); - return result; + return 0; } static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, @@ -432,7 +432,7 @@ static struct scsi_host_template mac_scsi_template = { .eh_host_reset_handler = macscsi_host_reset, .can_queue = 16, .this_id = 7, - .sg_tablesize = 1, + .sg_tablesize = SG_ALL, .cmd_per_lun = 2, .dma_boundary = PAGE_SIZE - 1, .cmd_size = sizeof(struct NCR5380_cmd), @@ -470,6 +470,9 @@ static int __init mac_scsi_probe(struct platform_device *pdev) if (setup_hostid >= 0) mac_scsi_template.this_id = setup_hostid & 7; + if (macintosh_config->ident == MAC_MODEL_IIFX) + mac_scsi_template.sg_tablesize = 1; + instance = scsi_host_alloc(&mac_scsi_template, sizeof(struct NCR5380_hostdata)); if (!instance) @@ -491,6 +494,9 @@ static int __init mac_scsi_probe(struct platform_device *pdev) host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0; + if (instance->sg_tablesize > 1) + host_flags |= FLAG_DMA_FIXUP; + error = NCR5380_init(instance, host_flags | FLAG_LATE_DMA_SETUP); if (error) goto fail_init; diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 5680c6cdb221..088cc40ae866 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -814,12 +814,12 @@ struct MR_HOST_DEVICE_LIST { __le32 size; __le32 count; __le32 reserved[2]; - struct MR_HOST_DEVICE_LIST_ENTRY host_device_list[1]; + struct MR_HOST_DEVICE_LIST_ENTRY host_device_list[] __counted_by_le(count); } __packed; #define HOST_DEVICE_LIST_SZ (sizeof(struct MR_HOST_DEVICE_LIST) + \ (sizeof(struct MR_HOST_DEVICE_LIST_ENTRY) * \ - (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT - 1))) + (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT))) /* @@ -2473,7 +2473,7 @@ struct MR_LD_VF_MAP { union MR_LD_REF ref; u8 ldVfCount; u8 reserved[6]; - u8 policy[1]; + u8 policy[]; }; struct MR_LD_VF_AFFILIATION { diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 6c1fb8149553..1eec23da28e2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1988,8 +1988,8 @@ megasas_fusion_start_watchdog(struct megasas_instance *instance) sizeof(instance->fault_handler_work_q_name), "poll_megasas%d_status", instance->host->host_no); - instance->fw_fault_work_q = - create_singlethread_workqueue(instance->fault_handler_work_q_name); + instance->fw_fault_work_q = alloc_ordered_workqueue( + "%s", WQ_MEM_RECLAIM, instance->fault_handler_work_q_name); if (!instance->fw_fault_work_q) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h index 6a19e17eb1a7..4b7a8f6314a3 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h @@ -1565,16 +1565,13 @@ struct mpi3_sas_io_unit0_phy_data { __le32 reserved10; }; -#ifndef MPI3_SAS_IO_UNIT0_PHY_MAX -#define MPI3_SAS_IO_UNIT0_PHY_MAX (1) -#endif struct mpi3_sas_io_unit_page0 { struct mpi3_config_page_header header; __le32 reserved08; u8 num_phys; u8 init_status; __le16 reserved0e; - struct mpi3_sas_io_unit0_phy_data phy_data[MPI3_SAS_IO_UNIT0_PHY_MAX]; + struct mpi3_sas_io_unit0_phy_data phy_data[]; }; #define MPI3_SASIOUNIT0_PAGEVERSION (0x00) @@ -1606,9 +1603,6 @@ struct mpi3_sas_io_unit1_phy_data { __le32 reserved08; }; -#ifndef MPI3_SAS_IO_UNIT1_PHY_MAX -#define MPI3_SAS_IO_UNIT1_PHY_MAX (1) -#endif struct mpi3_sas_io_unit_page1 { struct mpi3_config_page_header header; __le16 control_flags; @@ -1618,7 +1612,7 @@ struct mpi3_sas_io_unit_page1 { u8 num_phys; u8 sata_max_q_depth; __le16 reserved12; - struct mpi3_sas_io_unit1_phy_data phy_data[MPI3_SAS_IO_UNIT1_PHY_MAX]; + struct mpi3_sas_io_unit1_phy_data phy_data[]; }; #define MPI3_SASIOUNIT1_PAGEVERSION (0x00) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index 028784949873..c9fa0d69b75f 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -453,9 +453,6 @@ struct mpi3_event_data_sas_notify_primitive { #define MPI3_EVENT_NOTIFY_PRIMITIVE_POWER_LOSS_EXPECTED (0x02) #define MPI3_EVENT_NOTIFY_PRIMITIVE_RESERVED1 (0x03) #define MPI3_EVENT_NOTIFY_PRIMITIVE_RESERVED2 (0x04) -#ifndef MPI3_EVENT_SAS_TOPO_PHY_COUNT -#define MPI3_EVENT_SAS_TOPO_PHY_COUNT (1) -#endif struct mpi3_event_sas_topo_phy_entry { __le16 attached_dev_handle; u8 link_rate; @@ -496,7 +493,7 @@ struct mpi3_event_data_sas_topology_change_list { u8 start_phy_num; u8 exp_status; u8 io_unit_port; - struct mpi3_event_sas_topo_phy_entry phy_entry[MPI3_EVENT_SAS_TOPO_PHY_COUNT]; + struct mpi3_event_sas_topo_phy_entry phy_entry[] __counted_by(num_entries); }; #define MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) @@ -545,9 +542,6 @@ struct mpi3_event_data_pcie_enumeration { #define MPI3_EVENT_PCIE_ENUM_ES_MAX_SWITCHES_EXCEED (0x40000000) #define MPI3_EVENT_PCIE_ENUM_ES_MAX_DEVICES_EXCEED (0x20000000) #define MPI3_EVENT_PCIE_ENUM_ES_RESOURCES_EXHAUSTED (0x10000000) -#ifndef MPI3_EVENT_PCIE_TOPO_PORT_COUNT -#define MPI3_EVENT_PCIE_TOPO_PORT_COUNT (1) -#endif struct mpi3_event_pcie_topo_port_entry { __le16 attached_dev_handle; u8 port_status; @@ -588,7 +582,7 @@ struct mpi3_event_data_pcie_topology_change_list { u8 switch_status; u8 io_unit_port; __le32 reserved0c; - struct mpi3_event_pcie_topo_port_entry port_entry[MPI3_EVENT_PCIE_TOPO_PORT_COUNT]; + struct mpi3_event_pcie_topo_port_entry port_entry[] __counted_by(num_entries); }; #define MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH (0x00) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index dc2cdd5f0311..1dc640de3efc 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -57,8 +57,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.9.1.0.51" -#define MPI3MR_DRIVER_RELDATE "29-May-2024" +#define MPI3MR_DRIVER_VERSION "8.10.0.5.50" +#define MPI3MR_DRIVER_RELDATE "08-Aug-2024" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" @@ -213,6 +213,7 @@ extern atomic64_t event_counter; #define MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_INDEX 0 #define MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_DATA 1 +#define MPI3MR_THRESHOLD_REPLY_COUNT 100 /* SGE Flag definition */ #define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \ @@ -1059,7 +1060,6 @@ struct scmd_priv { * @sbq_lock: Sense buffer queue lock * @sbq_host_index: Sense buffer queuehost index * @event_masks: Event mask bitmap - * @fwevt_worker_name: Firmware event worker thread name * @fwevt_worker_thread: Firmware event worker thread * @fwevt_lock: Firmware event lock * @fwevt_list: Firmware event list @@ -1240,7 +1240,6 @@ struct mpi3mr_ioc { u32 sbq_host_index; u32 event_masks[MPI3_EVENT_NOTIFY_EVENTMASK_WORDS]; - char fwevt_worker_name[MPI3MR_NAME_LENGTH]; struct workqueue_struct *fwevt_worker_thread; spinlock_t fwevt_lock; struct list_head fwevt_list; diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index c196dc14ad20..2e1a92d306b2 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -345,6 +345,7 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, { u16 reply_desc_type, host_tag = 0; u16 ioc_status = MPI3_IOCSTATUS_SUCCESS; + u16 masked_ioc_status = MPI3_IOCSTATUS_SUCCESS; u32 ioc_loginfo = 0, sense_count = 0; struct mpi3_status_reply_descriptor *status_desc; struct mpi3_address_reply_descriptor *addr_desc; @@ -366,8 +367,8 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, if (ioc_status & MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info); - ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; - mpi3mr_reply_trigger(mrioc, ioc_status, ioc_loginfo); + masked_ioc_status = ioc_status & MPI3_IOCSTATUS_STATUS_MASK; + mpi3mr_reply_trigger(mrioc, masked_ioc_status, ioc_loginfo); break; case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY: addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc; @@ -380,7 +381,7 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, if (ioc_status & MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info); - ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; + masked_ioc_status = ioc_status & MPI3_IOCSTATUS_STATUS_MASK; if (def_reply->function == MPI3_FUNCTION_SCSI_IO) { scsi_reply = (struct mpi3_scsi_io_reply *)def_reply; sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc, @@ -393,7 +394,7 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, sshdr.asc, sshdr.ascq); } } - mpi3mr_reply_trigger(mrioc, ioc_status, ioc_loginfo); + mpi3mr_reply_trigger(mrioc, masked_ioc_status, ioc_loginfo); break; case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS: success_desc = (struct mpi3_success_reply_descriptor *)reply_desc; @@ -408,7 +409,10 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, if (cmdptr->state & MPI3MR_CMD_PENDING) { cmdptr->state |= MPI3MR_CMD_COMPLETE; cmdptr->ioc_loginfo = ioc_loginfo; - cmdptr->ioc_status = ioc_status; + if (host_tag == MPI3MR_HOSTTAG_BSG_CMDS) + cmdptr->ioc_status = ioc_status; + else + cmdptr->ioc_status = masked_ioc_status; cmdptr->state &= ~MPI3MR_CMD_PENDING; if (def_reply) { cmdptr->state |= MPI3MR_CMD_REPLY_VALID; @@ -439,6 +443,7 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) u32 admin_reply_ci = mrioc->admin_reply_ci; u32 num_admin_replies = 0; u64 reply_dma = 0; + u16 threshold_comps = 0; struct mpi3_default_reply_descriptor *reply_desc; if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1)) @@ -462,6 +467,7 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) if (reply_dma) mpi3mr_repost_reply_buf(mrioc, reply_dma); num_admin_replies++; + threshold_comps++; if (++admin_reply_ci == mrioc->num_admin_replies) { admin_reply_ci = 0; exp_phase ^= 1; @@ -472,6 +478,11 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) if ((le16_to_cpu(reply_desc->reply_flags) & MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) break; + if (threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) { + writel(admin_reply_ci, + &mrioc->sysif_regs->admin_reply_queue_ci); + threshold_comps = 0; + } } while (1); writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); @@ -525,7 +536,7 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, u32 num_op_reply = 0; u64 reply_dma = 0; struct mpi3_default_reply_descriptor *reply_desc; - u16 req_q_idx = 0, reply_qidx; + u16 req_q_idx = 0, reply_qidx, threshold_comps = 0; reply_qidx = op_reply_q->qid - 1; @@ -556,6 +567,7 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, if (reply_dma) mpi3mr_repost_reply_buf(mrioc, reply_dma); num_op_reply++; + threshold_comps++; if (++reply_ci == op_reply_q->num_replies) { reply_ci = 0; @@ -577,13 +589,19 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, break; } #endif + if (threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) { + writel(reply_ci, + &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index); + atomic_sub(threshold_comps, &op_reply_q->pend_ios); + threshold_comps = 0; + } } while (1); writel(reply_ci, &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index); op_reply_q->ci = reply_ci; op_reply_q->ephase = exp_phase; - + atomic_sub(threshold_comps, &op_reply_q->pend_ios); atomic_dec(&op_reply_q->in_use); return num_op_reply; } @@ -2742,8 +2760,8 @@ void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) snprintf(mrioc->watchdog_work_q_name, sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name, mrioc->id); - mrioc->watchdog_work_q = - create_singlethread_workqueue(mrioc->watchdog_work_q_name); + mrioc->watchdog_work_q = alloc_ordered_workqueue( + "%s", WQ_MEM_RECLAIM, mrioc->watchdog_work_q_name); if (!mrioc->watchdog_work_q) { ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__); return; diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 616894571c6a..5f2f67acf8bf 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -5317,10 +5317,8 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) else scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); - snprintf(mrioc->fwevt_worker_name, sizeof(mrioc->fwevt_worker_name), - "%s%d_fwevt_wrkr", mrioc->driver_name, mrioc->id); mrioc->fwevt_worker_thread = alloc_ordered_workqueue( - mrioc->fwevt_worker_name, 0); + "%s%d_fwevt_wrkr", 0, mrioc->driver_name, mrioc->id); if (!mrioc->fwevt_worker_thread) { ioc_err(mrioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index b785a7e88b49..9a24f7776d64 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -846,8 +846,8 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) snprintf(ioc->fault_reset_work_q_name, sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status", ioc->driver_name, ioc->id); - ioc->fault_reset_work_q = - create_singlethread_workqueue(ioc->fault_reset_work_q_name); + ioc->fault_reset_work_q = alloc_ordered_workqueue( + "%s", WQ_MEM_RECLAIM, ioc->fault_reset_work_q_name); if (!ioc->fault_reset_work_q) { ioc_err(ioc, "%s: failed (line=%d)\n", __func__, __LINE__); return; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index fe1e96fda284..eceb5eeb4651 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1162,8 +1162,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @fault_reset_work_q_name: fw fault work queue * @fault_reset_work_q: "" * @fault_reset_work: "" - * @firmware_event_name: fw event work queue - * @firmware_event_thread: "" + * @firmware_event_thread: fw event work queue * @fw_event_lock: * @fw_event_list: list of fw events * @current_evet: current processing firmware event @@ -1351,7 +1350,6 @@ struct MPT3SAS_ADAPTER { struct delayed_work fault_reset_work; /* fw event handler */ - char firmware_event_name[20]; struct workqueue_struct *firmware_event_thread; spinlock_t fw_event_lock; struct list_head fw_event_list; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 97c2472cd434..728cced42b0e 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -12301,10 +12301,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); /* event thread */ - snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), - "fw_event_%s%d", ioc->driver_name, ioc->id); ioc->firmware_event_thread = alloc_ordered_workqueue( - ioc->firmware_event_name, 0); + "fw_event_%s%d", 0, ioc->driver_name, ioc->id); if (!ioc->firmware_event_thread) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); diff --git a/drivers/scsi/myrb.c b/drivers/scsi/myrb.c index f684eb5e0489..bfc2b835e612 100644 --- a/drivers/scsi/myrb.c +++ b/drivers/scsi/myrb.c @@ -112,9 +112,8 @@ static bool myrb_create_mempools(struct pci_dev *pdev, struct myrb_hba *cb) return false; } - snprintf(cb->work_q_name, sizeof(cb->work_q_name), - "myrb_wq_%d", cb->host->host_no); - cb->work_q = create_singlethread_workqueue(cb->work_q_name); + cb->work_q = alloc_ordered_workqueue("myrb_wq_%d", WQ_MEM_RECLAIM, + cb->host->host_no); if (!cb->work_q) { dma_pool_destroy(cb->dcdb_pool); cb->dcdb_pool = NULL; diff --git a/drivers/scsi/myrb.h b/drivers/scsi/myrb.h index fb8eacfceee8..78dc4136fb10 100644 --- a/drivers/scsi/myrb.h +++ b/drivers/scsi/myrb.h @@ -712,7 +712,6 @@ struct myrb_hba { struct Scsi_Host *host; struct workqueue_struct *work_q; - char work_q_name[20]; struct delayed_work monitor_work; unsigned long primary_monitor_time; unsigned long secondary_monitor_time; diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c index e824be9d9bbb..3392feb15cb4 100644 --- a/drivers/scsi/myrs.c +++ b/drivers/scsi/myrs.c @@ -2206,9 +2206,8 @@ static bool myrs_create_mempools(struct pci_dev *pdev, struct myrs_hba *cs) return false; } - snprintf(cs->work_q_name, sizeof(cs->work_q_name), - "myrs_wq_%d", shost->host_no); - cs->work_q = create_singlethread_workqueue(cs->work_q_name); + cs->work_q = alloc_ordered_workqueue("myrs_wq_%d", WQ_MEM_RECLAIM, + shost->host_no); if (!cs->work_q) { dma_pool_destroy(cs->dcdb_pool); cs->dcdb_pool = NULL; diff --git a/drivers/scsi/myrs.h b/drivers/scsi/myrs.h index 9f6696d0ddd5..e1d6b123de7b 100644 --- a/drivers/scsi/myrs.h +++ b/drivers/scsi/myrs.h @@ -904,7 +904,6 @@ struct myrs_hba { bool disable_enc_msg; struct workqueue_struct *work_q; - char work_q_name[20]; struct delayed_work monitor_work; unsigned long primary_monitor_time; unsigned long secondary_monitor_time; diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 4813087e58a1..cf13148ba281 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -3372,9 +3372,8 @@ retry_probe: QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_INFO, "qedf->io_mempool=%p.\n", qedf->io_mempool); - sprintf(host_buf, "qedf_%u_link", - qedf->lport->host->host_no); - qedf->link_update_wq = create_workqueue(host_buf); + qedf->link_update_wq = alloc_workqueue("qedf_%u_link", WQ_MEM_RECLAIM, + 1, qedf->lport->host->host_no); INIT_DELAYED_WORK(&qedf->link_update, qedf_handle_link_update); INIT_DELAYED_WORK(&qedf->link_recovery, qedf_link_recovery); INIT_DELAYED_WORK(&qedf->grcdump_work, qedf_wq_grcdump); @@ -3584,9 +3583,8 @@ retry_probe: ether_addr_copy(params.ll2_mac_address, qedf->mac); /* Start LL2 processing thread */ - snprintf(host_buf, 20, "qedf_%d_ll2", host->host_no); - qedf->ll2_recv_wq = - create_workqueue(host_buf); + qedf->ll2_recv_wq = alloc_workqueue("qedf_%d_ll2", WQ_MEM_RECLAIM, 1, + host->host_no); if (!qedf->ll2_recv_wq) { QEDF_ERR(&(qedf->dbg_ctx), "Failed to LL2 workqueue.\n"); rc = -ENOMEM; @@ -3627,9 +3625,8 @@ retry_probe: } } - sprintf(host_buf, "qedf_%u_timer", qedf->lport->host->host_no); - qedf->timer_work_queue = - create_workqueue(host_buf); + qedf->timer_work_queue = alloc_workqueue("qedf_%u_timer", + WQ_MEM_RECLAIM, 1, qedf->lport->host->host_no); if (!qedf->timer_work_queue) { QEDF_ERR(&(qedf->dbg_ctx), "Failed to start timer " "workqueue.\n"); @@ -3641,7 +3638,8 @@ retry_probe: if (mode != QEDF_MODE_RECOVERY) { sprintf(host_buf, "qedf_%u_dpc", qedf->lport->host->host_no); - qedf->dpc_wq = create_workqueue(host_buf); + qedf->dpc_wq = + alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, host_buf); } INIT_DELAYED_WORK(&qedf->recovery_work, qedf_recovery_handler); @@ -4182,7 +4180,7 @@ static int __init qedf_init(void) goto err3; } - qedf_io_wq = create_workqueue("qedf_io_wq"); + qedf_io_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, "qedf_io_wq"); if (!qedf_io_wq) { QEDF_ERR(NULL, "Could not create qedf_io_wq.\n"); goto err4; diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index cd0180b1f5b9..c5aec26019d6 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -2767,7 +2767,8 @@ retry_probe: } sprintf(host_buf, "host_%d", qedi->shost->host_no); - qedi->tmf_thread = create_singlethread_workqueue(host_buf); + qedi->tmf_thread = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, host_buf); if (!qedi->tmf_thread) { QEDI_ERR(&qedi->dbg_ctx, "Unable to start tmf thread!\n"); @@ -2775,8 +2776,9 @@ retry_probe: goto free_cid_que; } - sprintf(host_buf, "qedi_ofld%d", qedi->shost->host_no); - qedi->offload_thread = create_workqueue(host_buf); + qedi->offload_thread = alloc_workqueue("qedi_ofld%d", + WQ_MEM_RECLAIM, + 1, qedi->shost->host_no); if (!qedi->offload_thread) { QEDI_ERR(&qedi->dbg_ctx, "Unable to start offload thread!\n"); diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 7cf998e3cc68..15066c112817 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2621,7 +2621,6 @@ typedef struct fc_port { struct kref sess_kref; struct qla_tgt *tgt; unsigned long expires; - struct list_head del_list_entry; struct work_struct free_work; struct work_struct reg_work; uint64_t jiffies_at_registration; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index bc3b2aea3f8b..7f980e6141c2 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3501,11 +3501,13 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (IS_QLA8031(ha) || IS_MCTP_CAPABLE(ha)) { sprintf(wq_name, "qla2xxx_%lu_dpc_lp_wq", base_vha->host_no); - ha->dpc_lp_wq = create_singlethread_workqueue(wq_name); + ha->dpc_lp_wq = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, wq_name); INIT_WORK(&ha->idc_aen, qla83xx_service_idc_aen); sprintf(wq_name, "qla2xxx_%lu_dpc_hp_wq", base_vha->host_no); - ha->dpc_hp_wq = create_singlethread_workqueue(wq_name); + ha->dpc_hp_wq = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, wq_name); INIT_WORK(&ha->nic_core_reset, qla83xx_nic_core_reset_work); INIT_WORK(&ha->idc_state_handler, qla83xx_idc_state_handler_work); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 17cccd14765f..d91f54a6e752 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -8806,7 +8806,7 @@ skip_retry_init: DEBUG2(printk("scsi: %s: Starting kernel thread for " "qla4xxx_dpc\n", __func__)); sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no); - ha->dpc_thread = create_singlethread_workqueue(buf); + ha->dpc_thread = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, buf); if (!ha->dpc_thread) { ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n"); ret = -ENODEV; diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 7d088b8da075..62ea7e44460e 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -441,18 +441,13 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, fc_host->next_vport_number = 0; fc_host->npiv_vports_inuse = 0; - snprintf(fc_host->work_q_name, sizeof(fc_host->work_q_name), - "fc_wq_%d", shost->host_no); - fc_host->work_q = alloc_workqueue("%s", 0, 0, fc_host->work_q_name); + fc_host->work_q = alloc_workqueue("fc_wq_%d", 0, 0, shost->host_no); if (!fc_host->work_q) return -ENOMEM; fc_host->dev_loss_tmo = fc_dev_loss_tmo; - snprintf(fc_host->devloss_work_q_name, - sizeof(fc_host->devloss_work_q_name), - "fc_dl_%d", shost->host_no); - fc_host->devloss_work_q = alloc_workqueue("%s", 0, 0, - fc_host->devloss_work_q_name); + fc_host->devloss_work_q = alloc_workqueue("fc_dl_%d", 0, 0, + shost->host_no); if (!fc_host->devloss_work_q) { destroy_workqueue(fc_host->work_q); fc_host->work_q = NULL; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 9db86943d04c..76f488ef6a7e 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1382,7 +1382,7 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) if (protect && sdkp->protection_type == T10_PI_TYPE2_PROTECTION) { ret = sd_setup_rw32_cmnd(cmd, write, lba, nr_blocks, protect | fua, dld); - } else if (rq->cmd_flags & REQ_ATOMIC && write) { + } else if (rq->cmd_flags & REQ_ATOMIC) { ret = sd_setup_atomic_cmnd(cmd, lba, nr_blocks, sdkp->use_atomic_write_boundary, protect | fua); diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index cdedc271857a..fae6db20a6e9 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -505,7 +505,7 @@ struct pqi_vendor_general_request { __le64 buffer_address; __le32 buffer_length; u8 reserved[40]; - } ofa_memory_allocation; + } host_memory_allocation; } data; }; @@ -517,21 +517,30 @@ struct pqi_vendor_general_response { u8 reserved[2]; }; -#define PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE 0 -#define PQI_VENDOR_GENERAL_HOST_MEMORY_UPDATE 1 +#define PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE 0 +#define PQI_VENDOR_GENERAL_OFA_MEMORY_UPDATE 1 +#define PQI_VENDOR_GENERAL_CTRL_LOG_MEMORY_UPDATE 2 #define PQI_OFA_VERSION 1 #define PQI_OFA_SIGNATURE "OFA_QRM" -#define PQI_OFA_MAX_SG_DESCRIPTORS 64 +#define PQI_CTRL_LOG_VERSION 1 +#define PQI_CTRL_LOG_SIGNATURE "FW_DATA" +#define PQI_HOST_MAX_SG_DESCRIPTORS 64 -struct pqi_ofa_memory { - __le64 signature; /* "OFA_QRM" */ +struct pqi_host_memory { + __le64 signature; /* "OFA_QRM", "FW_DATA", etc. */ __le16 version; /* version of this struct (1 = 1st version) */ u8 reserved[62]; __le32 bytes_allocated; /* total allocated memory in bytes */ __le16 num_memory_descriptors; u8 reserved1[2]; - struct pqi_sg_descriptor sg_descriptor[PQI_OFA_MAX_SG_DESCRIPTORS]; + struct pqi_sg_descriptor sg_descriptor[PQI_HOST_MAX_SG_DESCRIPTORS]; +}; + +struct pqi_host_memory_descriptor { + struct pqi_host_memory *host_memory; + dma_addr_t host_memory_dma_handle; + void **host_chunk_virt_address; }; struct pqi_aio_error_info { @@ -867,7 +876,8 @@ struct pqi_config_table_firmware_features { #define PQI_FIRMWARE_FEATURE_FW_TRIAGE 17 #define PQI_FIRMWARE_FEATURE_RPL_EXTENDED_FORMAT_4_5 18 #define PQI_FIRMWARE_FEATURE_MULTI_LUN_DEVICE_SUPPORT 21 -#define PQI_FIRMWARE_FEATURE_MAXIMUM 21 +#define PQI_FIRMWARE_FEATURE_CTRL_LOGGING 22 +#define PQI_FIRMWARE_FEATURE_MAXIMUM 22 struct pqi_config_table_debug { struct pqi_config_table_section_header header; @@ -1096,6 +1106,11 @@ struct pqi_tmf_work { u8 scsi_opcode; }; +struct pqi_raid_io_stats { + u64 raid_bypass_cnt; + u64 write_stream_cnt; +}; + struct pqi_scsi_dev { int devtype; /* as reported by INQUIRY command */ u8 device_type; /* as reported by */ @@ -1158,7 +1173,7 @@ struct pqi_scsi_dev { struct pqi_stream_data stream_data[NUM_STREAMS_PER_LUN]; atomic_t scsi_cmds_outstanding[PQI_MAX_LUNS_PER_DEVICE]; - unsigned int raid_bypass_cnt; + struct pqi_raid_io_stats __percpu *raid_io_stats; struct pqi_tmf_work tmf_work[PQI_MAX_LUNS_PER_DEVICE]; }; @@ -1357,6 +1372,7 @@ struct pqi_ctrl_info { u8 firmware_triage_supported : 1; u8 rpl_extended_format_4_5_supported : 1; u8 multi_lun_device_supported : 1; + u8 ctrl_logging_supported : 1; u8 enable_r1_writes : 1; u8 enable_r5_writes : 1; u8 enable_r6_writes : 1; @@ -1398,13 +1414,12 @@ struct pqi_ctrl_info { wait_queue_head_t block_requests_wait; struct mutex ofa_mutex; - struct pqi_ofa_memory *pqi_ofa_mem_virt_addr; - dma_addr_t pqi_ofa_mem_dma_handle; - void **pqi_ofa_chunk_virt_addr; struct work_struct ofa_memory_alloc_work; struct work_struct ofa_quiesce_work; u32 ofa_bytes_requested; u16 ofa_cancel_reason; + struct pqi_host_memory_descriptor ofa_memory; + struct pqi_host_memory_descriptor ctrl_log_memory; enum pqi_ctrl_removal_state ctrl_removal_state; }; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 24c7cb285dca..7fd5a8c813dc 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -33,11 +33,11 @@ #define BUILD_TIMESTAMP #endif -#define DRIVER_VERSION "2.1.26-030" +#define DRIVER_VERSION "2.1.30-031" #define DRIVER_MAJOR 2 #define DRIVER_MINOR 1 -#define DRIVER_RELEASE 26 -#define DRIVER_REVISION 30 +#define DRIVER_RELEASE 30 +#define DRIVER_REVISION 31 #define DRIVER_NAME "Microchip SmartPQI Driver (v" \ DRIVER_VERSION BUILD_TIMESTAMP ")" @@ -92,9 +92,9 @@ static int pqi_aio_submit_r56_write_io(struct pqi_ctrl_info *ctrl_info, static void pqi_ofa_ctrl_quiesce(struct pqi_ctrl_info *ctrl_info); static void pqi_ofa_ctrl_unquiesce(struct pqi_ctrl_info *ctrl_info); static int pqi_ofa_ctrl_restart(struct pqi_ctrl_info *ctrl_info, unsigned int delay_secs); -static void pqi_ofa_setup_host_buffer(struct pqi_ctrl_info *ctrl_info); -static void pqi_ofa_free_host_buffer(struct pqi_ctrl_info *ctrl_info); -static int pqi_ofa_host_memory_update(struct pqi_ctrl_info *ctrl_info); +static void pqi_host_setup_buffer(struct pqi_ctrl_info *ctrl_info, struct pqi_host_memory_descriptor *host_memory_descriptor, u32 total_size, u32 min_size); +static void pqi_host_free_buffer(struct pqi_ctrl_info *ctrl_info, struct pqi_host_memory_descriptor *host_memory_descriptor); +static int pqi_host_memory_update(struct pqi_ctrl_info *ctrl_info, struct pqi_host_memory_descriptor *host_memory_descriptor, u16 function_code); static int pqi_device_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device, u8 lun, unsigned long timeout_msecs); static void pqi_fail_all_outstanding_requests(struct pqi_ctrl_info *ctrl_info); @@ -1508,6 +1508,12 @@ static int pqi_get_raid_map(struct pqi_ctrl_info *ctrl_info, if (rc) goto error; + device->raid_io_stats = alloc_percpu(struct pqi_raid_io_stats); + if (!device->raid_io_stats) { + rc = -ENOMEM; + goto error; + } + device->raid_map = raid_map; return 0; @@ -2099,6 +2105,10 @@ static void pqi_scsi_update_device(struct pqi_ctrl_info *ctrl_info, /* To prevent this from being freed later. */ new_device->raid_map = NULL; } + if (new_device->raid_bypass_enabled && existing_device->raid_io_stats == NULL) { + existing_device->raid_io_stats = new_device->raid_io_stats; + new_device->raid_io_stats = NULL; + } existing_device->raid_bypass_configured = new_device->raid_bypass_configured; existing_device->raid_bypass_enabled = new_device->raid_bypass_enabled; } @@ -2121,6 +2131,7 @@ static void pqi_scsi_update_device(struct pqi_ctrl_info *ctrl_info, static inline void pqi_free_device(struct pqi_scsi_dev *device) { if (device) { + free_percpu(device->raid_io_stats); kfree(device->raid_map); kfree(device); } @@ -2292,17 +2303,23 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info, * queue depth, device size. */ list_for_each_entry(device, &ctrl_info->scsi_device_list, scsi_device_list_entry) { + /* + * Check for queue depth change. + */ if (device->sdev && device->queue_depth != device->advertised_queue_depth) { device->advertised_queue_depth = device->queue_depth; scsi_change_queue_depth(device->sdev, device->advertised_queue_depth); - spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); - if (pqi_volume_rescan_needed(device)) { - device->rescan = false; - spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); - scsi_rescan_device(device->sdev); - } else { - spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); - } + } + spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); + /* + * Check for changes in the device, such as size. + */ + if (pqi_volume_rescan_needed(device)) { + device->rescan = false; + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); + scsi_rescan_device(device->sdev); + } else { + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); } } @@ -2354,14 +2371,6 @@ static inline void pqi_mask_device(u8 *scsi3addr) scsi3addr[3] |= 0xc0; } -static inline bool pqi_is_multipath_device(struct pqi_scsi_dev *device) -{ - if (pqi_is_logical_device(device)) - return false; - - return (device->path_map & (device->path_map - 1)) != 0; -} - static inline bool pqi_expose_device(struct pqi_scsi_dev *device) { return !device->is_physical_device || !pqi_skip_device(device->scsi3addr); @@ -3244,6 +3253,20 @@ static void pqi_process_raid_io_error(struct pqi_io_request *io_request) sense_data_length); } + if (pqi_cmd_priv(scmd)->this_residual && + !pqi_is_logical_device(scmd->device->hostdata) && + scsi_status == SAM_STAT_CHECK_CONDITION && + host_byte == DID_OK && + sense_data_length && + scsi_normalize_sense(error_info->data, sense_data_length, &sshdr) && + sshdr.sense_key == ILLEGAL_REQUEST && + sshdr.asc == 0x26 && + sshdr.ascq == 0x0) { + host_byte = DID_NO_CONNECT; + pqi_take_device_offline(scmd->device, "AIO"); + scsi_build_sense_buffer(0, scmd->sense_buffer, HARDWARE_ERROR, 0x3e, 0x1); + } + scmd->result = scsi_status; set_host_byte(scmd, host_byte); } @@ -3258,14 +3281,12 @@ static void pqi_process_aio_io_error(struct pqi_io_request *io_request) int residual_count; int xfer_count; bool device_offline; - struct pqi_scsi_dev *device; scmd = io_request->scmd; error_info = io_request->error_info; host_byte = DID_OK; sense_data_length = 0; device_offline = false; - device = scmd->device->hostdata; switch (error_info->service_response) { case PQI_AIO_SERV_RESPONSE_COMPLETE: @@ -3290,14 +3311,8 @@ static void pqi_process_aio_io_error(struct pqi_io_request *io_request) break; case PQI_AIO_STATUS_AIO_PATH_DISABLED: pqi_aio_path_disabled(io_request); - if (pqi_is_multipath_device(device)) { - pqi_device_remove_start(device); - host_byte = DID_NO_CONNECT; - scsi_status = SAM_STAT_CHECK_CONDITION; - } else { - scsi_status = SAM_STAT_GOOD; - io_request->status = -EAGAIN; - } + scsi_status = SAM_STAT_GOOD; + io_request->status = -EAGAIN; break; case PQI_AIO_STATUS_NO_PATH_TO_DEVICE: case PQI_AIO_STATUS_INVALID_DEVICE: @@ -3625,7 +3640,7 @@ static void pqi_process_soft_reset(struct pqi_ctrl_info *ctrl_info) ctrl_info->pqi_mode_enabled = false; pqi_save_ctrl_mode(ctrl_info, SIS_MODE); rc = pqi_ofa_ctrl_restart(ctrl_info, delay_secs); - pqi_ofa_free_host_buffer(ctrl_info); + pqi_host_free_buffer(ctrl_info, &ctrl_info->ofa_memory); pqi_ctrl_ofa_done(ctrl_info); dev_info(&ctrl_info->pci_dev->dev, "Online Firmware Activation: %s\n", @@ -3636,7 +3651,7 @@ static void pqi_process_soft_reset(struct pqi_ctrl_info *ctrl_info) "Online Firmware Activation ABORTED\n"); if (ctrl_info->soft_reset_handshake_supported) pqi_clear_soft_reset_status(ctrl_info); - pqi_ofa_free_host_buffer(ctrl_info); + pqi_host_free_buffer(ctrl_info, &ctrl_info->ofa_memory); pqi_ctrl_ofa_done(ctrl_info); pqi_ofa_ctrl_unquiesce(ctrl_info); break; @@ -3646,7 +3661,7 @@ static void pqi_process_soft_reset(struct pqi_ctrl_info *ctrl_info) dev_err(&ctrl_info->pci_dev->dev, "unexpected Online Firmware Activation reset status: 0x%x\n", reset_status); - pqi_ofa_free_host_buffer(ctrl_info); + pqi_host_free_buffer(ctrl_info, &ctrl_info->ofa_memory); pqi_ctrl_ofa_done(ctrl_info); pqi_ofa_ctrl_unquiesce(ctrl_info); pqi_take_ctrl_offline(ctrl_info, PQI_OFA_RESPONSE_TIMEOUT); @@ -3661,8 +3676,8 @@ static void pqi_ofa_memory_alloc_worker(struct work_struct *work) ctrl_info = container_of(work, struct pqi_ctrl_info, ofa_memory_alloc_work); pqi_ctrl_ofa_start(ctrl_info); - pqi_ofa_setup_host_buffer(ctrl_info); - pqi_ofa_host_memory_update(ctrl_info); + pqi_host_setup_buffer(ctrl_info, &ctrl_info->ofa_memory, ctrl_info->ofa_bytes_requested, ctrl_info->ofa_bytes_requested); + pqi_host_memory_update(ctrl_info, &ctrl_info->ofa_memory, PQI_VENDOR_GENERAL_OFA_MEMORY_UPDATE); } static void pqi_ofa_quiesce_worker(struct work_struct *work) @@ -3702,7 +3717,7 @@ static bool pqi_ofa_process_event(struct pqi_ctrl_info *ctrl_info, dev_info(&ctrl_info->pci_dev->dev, "received Online Firmware Activation cancel request: reason: %u\n", ctrl_info->ofa_cancel_reason); - pqi_ofa_free_host_buffer(ctrl_info); + pqi_host_free_buffer(ctrl_info, &ctrl_info->ofa_memory); pqi_ctrl_ofa_done(ctrl_info); break; default: @@ -5933,7 +5948,7 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info, int rc; struct pqi_scsi_dev *device; struct pqi_stream_data *pqi_stream_data; - struct pqi_scsi_dev_raid_map_data rmd; + struct pqi_scsi_dev_raid_map_data rmd = { 0 }; if (!ctrl_info->enable_stream_detection) return false; @@ -5975,6 +5990,7 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info, pqi_stream_data->next_lba = rmd.first_block + rmd.block_cnt; pqi_stream_data->last_accessed = jiffies; + per_cpu_ptr(device->raid_io_stats, smp_processor_id())->write_stream_cnt++; return true; } @@ -6025,7 +6041,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scm ctrl_info = shost_to_hba(shost); - if (pqi_ctrl_offline(ctrl_info) || pqi_device_in_remove(device)) { + if (pqi_ctrl_offline(ctrl_info) || pqi_device_offline(device) || pqi_device_in_remove(device)) { set_host_byte(scmd, DID_NO_CONNECT); pqi_scsi_done(scmd); return 0; @@ -6053,7 +6069,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scm rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device, scmd, queue_group); if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY) { raid_bypassed = true; - device->raid_bypass_cnt++; + per_cpu_ptr(device->raid_io_stats, smp_processor_id())->raid_bypass_cnt++; } } if (!raid_bypassed) @@ -6190,14 +6206,12 @@ static void pqi_fail_io_queued_for_device(struct pqi_ctrl_info *ctrl_info, continue; scsi_device = scmd->device->hostdata; - if (scsi_device != device) - continue; - - if ((u8)scmd->device->lun != lun) - continue; list_del(&io_request->request_list_entry); - set_host_byte(scmd, DID_RESET); + if (scsi_device == device && (u8)scmd->device->lun == lun) + set_host_byte(scmd, DID_RESET); + else + set_host_byte(scmd, DID_REQUEUE); pqi_free_io_request(io_request); scsi_dma_unmap(scmd); pqi_scsi_done(scmd); @@ -7350,7 +7364,8 @@ static ssize_t pqi_raid_bypass_cnt_show(struct device *dev, struct scsi_device *sdev; struct pqi_scsi_dev *device; unsigned long flags; - unsigned int raid_bypass_cnt; + u64 raid_bypass_cnt; + int cpu; sdev = to_scsi_device(dev); ctrl_info = shost_to_hba(sdev->host); @@ -7366,11 +7381,17 @@ static ssize_t pqi_raid_bypass_cnt_show(struct device *dev, return -ENODEV; } - raid_bypass_cnt = device->raid_bypass_cnt; + raid_bypass_cnt = 0; + + if (device->raid_io_stats) { + for_each_online_cpu(cpu) { + raid_bypass_cnt += per_cpu_ptr(device->raid_io_stats, cpu)->raid_bypass_cnt; + } + } spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); - return scnprintf(buffer, PAGE_SIZE, "0x%x\n", raid_bypass_cnt); + return scnprintf(buffer, PAGE_SIZE, "0x%llx\n", raid_bypass_cnt); } static ssize_t pqi_sas_ncq_prio_enable_show(struct device *dev, @@ -7452,6 +7473,43 @@ static ssize_t pqi_numa_node_show(struct device *dev, return scnprintf(buffer, PAGE_SIZE, "%d\n", ctrl_info->numa_node); } +static ssize_t pqi_write_stream_cnt_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + struct pqi_ctrl_info *ctrl_info; + struct scsi_device *sdev; + struct pqi_scsi_dev *device; + unsigned long flags; + u64 write_stream_cnt; + int cpu; + + sdev = to_scsi_device(dev); + ctrl_info = shost_to_hba(sdev->host); + + if (pqi_ctrl_offline(ctrl_info)) + return -ENODEV; + + spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); + + device = sdev->hostdata; + if (!device) { + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); + return -ENODEV; + } + + write_stream_cnt = 0; + + if (device->raid_io_stats) { + for_each_online_cpu(cpu) { + write_stream_cnt += per_cpu_ptr(device->raid_io_stats, cpu)->write_stream_cnt; + } + } + + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); + + return scnprintf(buffer, PAGE_SIZE, "0x%llx\n", write_stream_cnt); +} + static DEVICE_ATTR(lunid, 0444, pqi_lunid_show, NULL); static DEVICE_ATTR(unique_id, 0444, pqi_unique_id_show, NULL); static DEVICE_ATTR(path_info, 0444, pqi_path_info_show, NULL); @@ -7462,6 +7520,7 @@ static DEVICE_ATTR(raid_bypass_cnt, 0444, pqi_raid_bypass_cnt_show, NULL); static DEVICE_ATTR(sas_ncq_prio_enable, 0644, pqi_sas_ncq_prio_enable_show, pqi_sas_ncq_prio_enable_store); static DEVICE_ATTR(numa_node, 0444, pqi_numa_node_show, NULL); +static DEVICE_ATTR(write_stream_cnt, 0444, pqi_write_stream_cnt_show, NULL); static struct attribute *pqi_sdev_attrs[] = { &dev_attr_lunid.attr, @@ -7473,6 +7532,7 @@ static struct attribute *pqi_sdev_attrs[] = { &dev_attr_raid_bypass_cnt.attr, &dev_attr_sas_ncq_prio_enable.attr, &dev_attr_numa_node.attr, + &dev_attr_write_stream_cnt.attr, NULL }; @@ -7863,6 +7923,9 @@ static void pqi_ctrl_update_feature_flags(struct pqi_ctrl_info *ctrl_info, case PQI_FIRMWARE_FEATURE_MULTI_LUN_DEVICE_SUPPORT: ctrl_info->multi_lun_device_supported = firmware_feature->enabled; break; + case PQI_FIRMWARE_FEATURE_CTRL_LOGGING: + ctrl_info->ctrl_logging_supported = firmware_feature->enabled; + break; } pqi_firmware_feature_status(ctrl_info, firmware_feature); @@ -7968,6 +8031,11 @@ static struct pqi_firmware_feature pqi_firmware_features[] = { .feature_bit = PQI_FIRMWARE_FEATURE_MULTI_LUN_DEVICE_SUPPORT, .feature_status = pqi_ctrl_update_feature_flags, }, + { + .feature_name = "Controller Data Logging", + .feature_bit = PQI_FIRMWARE_FEATURE_CTRL_LOGGING, + .feature_status = pqi_ctrl_update_feature_flags, + }, }; static void pqi_process_firmware_features( @@ -8070,6 +8138,7 @@ static void pqi_ctrl_reset_config(struct pqi_ctrl_info *ctrl_info) ctrl_info->firmware_triage_supported = false; ctrl_info->rpl_extended_format_4_5_supported = false; ctrl_info->multi_lun_device_supported = false; + ctrl_info->ctrl_logging_supported = false; } static int pqi_process_config_table(struct pqi_ctrl_info *ctrl_info) @@ -8210,6 +8279,9 @@ static void pqi_perform_lockup_action(void) } } +#define PQI_CTRL_LOG_TOTAL_SIZE (4 * 1024 * 1024) +#define PQI_CTRL_LOG_MIN_SIZE (PQI_CTRL_LOG_TOTAL_SIZE / PQI_HOST_MAX_SG_DESCRIPTORS) + static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info) { int rc; @@ -8221,6 +8293,12 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info) if (rc) return rc; } + if (sis_is_ctrl_logging_supported(ctrl_info)) { + sis_notify_kdump(ctrl_info); + rc = sis_wait_for_ctrl_logging_completion(ctrl_info); + if (rc) + return rc; + } sis_soft_reset(ctrl_info); ssleep(PQI_POST_RESET_DELAY_SECS); } else { @@ -8402,6 +8480,11 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info) if (rc) return rc; + if (ctrl_info->ctrl_logging_supported && !reset_devices) { + pqi_host_setup_buffer(ctrl_info, &ctrl_info->ctrl_log_memory, PQI_CTRL_LOG_TOTAL_SIZE, PQI_CTRL_LOG_MIN_SIZE); + pqi_host_memory_update(ctrl_info, &ctrl_info->ctrl_log_memory, PQI_VENDOR_GENERAL_CTRL_LOG_MEMORY_UPDATE); + } + rc = pqi_get_ctrl_product_details(ctrl_info); if (rc) { dev_err(&ctrl_info->pci_dev->dev, @@ -8586,8 +8669,22 @@ static int pqi_ctrl_init_resume(struct pqi_ctrl_info *ctrl_info) return rc; } - if (pqi_ofa_in_progress(ctrl_info)) + if (pqi_ofa_in_progress(ctrl_info)) { pqi_ctrl_unblock_scan(ctrl_info); + if (ctrl_info->ctrl_logging_supported) { + if (!ctrl_info->ctrl_log_memory.host_memory) + pqi_host_setup_buffer(ctrl_info, + &ctrl_info->ctrl_log_memory, + PQI_CTRL_LOG_TOTAL_SIZE, + PQI_CTRL_LOG_MIN_SIZE); + pqi_host_memory_update(ctrl_info, + &ctrl_info->ctrl_log_memory, PQI_VENDOR_GENERAL_CTRL_LOG_MEMORY_UPDATE); + } else { + if (ctrl_info->ctrl_log_memory.host_memory) + pqi_host_free_buffer(ctrl_info, + &ctrl_info->ctrl_log_memory); + } + } pqi_scan_scsi_devices(ctrl_info); @@ -8777,6 +8874,7 @@ static void pqi_remove_ctrl(struct pqi_ctrl_info *ctrl_info) pqi_fail_all_outstanding_requests(ctrl_info); ctrl_info->pqi_mode_enabled = false; } + pqi_host_free_buffer(ctrl_info, &ctrl_info->ctrl_log_memory); pqi_unregister_scsi(ctrl_info); if (ctrl_info->pqi_mode_enabled) pqi_revert_to_sis_mode(ctrl_info); @@ -8802,177 +8900,187 @@ static void pqi_ofa_ctrl_unquiesce(struct pqi_ctrl_info *ctrl_info) pqi_ctrl_unblock_scan(ctrl_info); } -static int pqi_ofa_alloc_mem(struct pqi_ctrl_info *ctrl_info, u32 total_size, u32 chunk_size) +static int pqi_ofa_ctrl_restart(struct pqi_ctrl_info *ctrl_info, unsigned int delay_secs) +{ + ssleep(delay_secs); + + return pqi_ctrl_init_resume(ctrl_info); +} + +static int pqi_host_alloc_mem(struct pqi_ctrl_info *ctrl_info, + struct pqi_host_memory_descriptor *host_memory_descriptor, + u32 total_size, u32 chunk_size) { int i; u32 sg_count; struct device *dev; - struct pqi_ofa_memory *ofap; + struct pqi_host_memory *host_memory; struct pqi_sg_descriptor *mem_descriptor; dma_addr_t dma_handle; - ofap = ctrl_info->pqi_ofa_mem_virt_addr; - sg_count = DIV_ROUND_UP(total_size, chunk_size); - if (sg_count == 0 || sg_count > PQI_OFA_MAX_SG_DESCRIPTORS) + if (sg_count == 0 || sg_count > PQI_HOST_MAX_SG_DESCRIPTORS) goto out; - ctrl_info->pqi_ofa_chunk_virt_addr = kmalloc_array(sg_count, sizeof(void *), GFP_KERNEL); - if (!ctrl_info->pqi_ofa_chunk_virt_addr) + host_memory_descriptor->host_chunk_virt_address = kmalloc(sg_count * sizeof(void *), GFP_KERNEL); + if (!host_memory_descriptor->host_chunk_virt_address) goto out; dev = &ctrl_info->pci_dev->dev; + host_memory = host_memory_descriptor->host_memory; for (i = 0; i < sg_count; i++) { - ctrl_info->pqi_ofa_chunk_virt_addr[i] = - dma_alloc_coherent(dev, chunk_size, &dma_handle, GFP_KERNEL); - if (!ctrl_info->pqi_ofa_chunk_virt_addr[i]) + host_memory_descriptor->host_chunk_virt_address[i] = dma_alloc_coherent(dev, chunk_size, &dma_handle, GFP_KERNEL); + if (!host_memory_descriptor->host_chunk_virt_address[i]) goto out_free_chunks; - mem_descriptor = &ofap->sg_descriptor[i]; + mem_descriptor = &host_memory->sg_descriptor[i]; put_unaligned_le64((u64)dma_handle, &mem_descriptor->address); put_unaligned_le32(chunk_size, &mem_descriptor->length); } put_unaligned_le32(CISS_SG_LAST, &mem_descriptor->flags); - put_unaligned_le16(sg_count, &ofap->num_memory_descriptors); - put_unaligned_le32(sg_count * chunk_size, &ofap->bytes_allocated); + put_unaligned_le16(sg_count, &host_memory->num_memory_descriptors); + put_unaligned_le32(sg_count * chunk_size, &host_memory->bytes_allocated); return 0; out_free_chunks: while (--i >= 0) { - mem_descriptor = &ofap->sg_descriptor[i]; + mem_descriptor = &host_memory->sg_descriptor[i]; dma_free_coherent(dev, chunk_size, - ctrl_info->pqi_ofa_chunk_virt_addr[i], + host_memory_descriptor->host_chunk_virt_address[i], get_unaligned_le64(&mem_descriptor->address)); } - kfree(ctrl_info->pqi_ofa_chunk_virt_addr); - + kfree(host_memory_descriptor->host_chunk_virt_address); out: return -ENOMEM; } -static int pqi_ofa_alloc_host_buffer(struct pqi_ctrl_info *ctrl_info) +static int pqi_host_alloc_buffer(struct pqi_ctrl_info *ctrl_info, + struct pqi_host_memory_descriptor *host_memory_descriptor, + u32 total_required_size, u32 min_required_size) { - u32 total_size; u32 chunk_size; u32 min_chunk_size; - if (ctrl_info->ofa_bytes_requested == 0) + if (total_required_size == 0 || min_required_size == 0) return 0; - total_size = PAGE_ALIGN(ctrl_info->ofa_bytes_requested); - min_chunk_size = DIV_ROUND_UP(total_size, PQI_OFA_MAX_SG_DESCRIPTORS); + total_required_size = PAGE_ALIGN(total_required_size); + min_required_size = PAGE_ALIGN(min_required_size); + min_chunk_size = DIV_ROUND_UP(total_required_size, PQI_HOST_MAX_SG_DESCRIPTORS); min_chunk_size = PAGE_ALIGN(min_chunk_size); - for (chunk_size = total_size; chunk_size >= min_chunk_size;) { - if (pqi_ofa_alloc_mem(ctrl_info, total_size, chunk_size) == 0) - return 0; - chunk_size /= 2; - chunk_size = PAGE_ALIGN(chunk_size); + while (total_required_size >= min_required_size) { + for (chunk_size = total_required_size; chunk_size >= min_chunk_size;) { + if (pqi_host_alloc_mem(ctrl_info, + host_memory_descriptor, total_required_size, + chunk_size) == 0) + return 0; + chunk_size /= 2; + chunk_size = PAGE_ALIGN(chunk_size); + } + total_required_size /= 2; + total_required_size = PAGE_ALIGN(total_required_size); } return -ENOMEM; } -static void pqi_ofa_setup_host_buffer(struct pqi_ctrl_info *ctrl_info) +static void pqi_host_setup_buffer(struct pqi_ctrl_info *ctrl_info, + struct pqi_host_memory_descriptor *host_memory_descriptor, + u32 total_size, u32 min_size) { struct device *dev; - struct pqi_ofa_memory *ofap; + struct pqi_host_memory *host_memory; dev = &ctrl_info->pci_dev->dev; - ofap = dma_alloc_coherent(dev, sizeof(*ofap), - &ctrl_info->pqi_ofa_mem_dma_handle, GFP_KERNEL); - if (!ofap) + host_memory = dma_alloc_coherent(dev, sizeof(*host_memory), + &host_memory_descriptor->host_memory_dma_handle, GFP_KERNEL); + if (!host_memory) return; - ctrl_info->pqi_ofa_mem_virt_addr = ofap; + host_memory_descriptor->host_memory = host_memory; - if (pqi_ofa_alloc_host_buffer(ctrl_info) < 0) { - dev_err(dev, - "failed to allocate host buffer for Online Firmware Activation\n"); - dma_free_coherent(dev, sizeof(*ofap), ofap, ctrl_info->pqi_ofa_mem_dma_handle); - ctrl_info->pqi_ofa_mem_virt_addr = NULL; + if (pqi_host_alloc_buffer(ctrl_info, host_memory_descriptor, + total_size, min_size) < 0) { + dev_err(dev, "failed to allocate firmware usable host buffer\n"); + dma_free_coherent(dev, sizeof(*host_memory), host_memory, + host_memory_descriptor->host_memory_dma_handle); + host_memory_descriptor->host_memory = NULL; return; } - - put_unaligned_le16(PQI_OFA_VERSION, &ofap->version); - memcpy(&ofap->signature, PQI_OFA_SIGNATURE, sizeof(ofap->signature)); } -static void pqi_ofa_free_host_buffer(struct pqi_ctrl_info *ctrl_info) +static void pqi_host_free_buffer(struct pqi_ctrl_info *ctrl_info, + struct pqi_host_memory_descriptor *host_memory_descriptor) { unsigned int i; struct device *dev; - struct pqi_ofa_memory *ofap; + struct pqi_host_memory *host_memory; struct pqi_sg_descriptor *mem_descriptor; unsigned int num_memory_descriptors; - ofap = ctrl_info->pqi_ofa_mem_virt_addr; - if (!ofap) + host_memory = host_memory_descriptor->host_memory; + if (!host_memory) return; dev = &ctrl_info->pci_dev->dev; - if (get_unaligned_le32(&ofap->bytes_allocated) == 0) + if (get_unaligned_le32(&host_memory->bytes_allocated) == 0) goto out; - mem_descriptor = ofap->sg_descriptor; - num_memory_descriptors = - get_unaligned_le16(&ofap->num_memory_descriptors); + mem_descriptor = host_memory->sg_descriptor; + num_memory_descriptors = get_unaligned_le16(&host_memory->num_memory_descriptors); for (i = 0; i < num_memory_descriptors; i++) { dma_free_coherent(dev, get_unaligned_le32(&mem_descriptor[i].length), - ctrl_info->pqi_ofa_chunk_virt_addr[i], + host_memory_descriptor->host_chunk_virt_address[i], get_unaligned_le64(&mem_descriptor[i].address)); } - kfree(ctrl_info->pqi_ofa_chunk_virt_addr); + kfree(host_memory_descriptor->host_chunk_virt_address); out: - dma_free_coherent(dev, sizeof(*ofap), ofap, - ctrl_info->pqi_ofa_mem_dma_handle); - ctrl_info->pqi_ofa_mem_virt_addr = NULL; + dma_free_coherent(dev, sizeof(*host_memory), host_memory, + host_memory_descriptor->host_memory_dma_handle); + host_memory_descriptor->host_memory = NULL; } -static int pqi_ofa_host_memory_update(struct pqi_ctrl_info *ctrl_info) +static int pqi_host_memory_update(struct pqi_ctrl_info *ctrl_info, + struct pqi_host_memory_descriptor *host_memory_descriptor, + u16 function_code) { u32 buffer_length; struct pqi_vendor_general_request request; - struct pqi_ofa_memory *ofap; + struct pqi_host_memory *host_memory; memset(&request, 0, sizeof(request)); request.header.iu_type = PQI_REQUEST_IU_VENDOR_GENERAL; - put_unaligned_le16(sizeof(request) - PQI_REQUEST_HEADER_LENGTH, - &request.header.iu_length); - put_unaligned_le16(PQI_VENDOR_GENERAL_HOST_MEMORY_UPDATE, - &request.function_code); - - ofap = ctrl_info->pqi_ofa_mem_virt_addr; - - if (ofap) { - buffer_length = offsetof(struct pqi_ofa_memory, sg_descriptor) + - get_unaligned_le16(&ofap->num_memory_descriptors) * - sizeof(struct pqi_sg_descriptor); - - put_unaligned_le64((u64)ctrl_info->pqi_ofa_mem_dma_handle, - &request.data.ofa_memory_allocation.buffer_address); - put_unaligned_le32(buffer_length, - &request.data.ofa_memory_allocation.buffer_length); + put_unaligned_le16(sizeof(request) - PQI_REQUEST_HEADER_LENGTH, &request.header.iu_length); + put_unaligned_le16(function_code, &request.function_code); + + host_memory = host_memory_descriptor->host_memory; + + if (host_memory) { + buffer_length = offsetof(struct pqi_host_memory, sg_descriptor) + get_unaligned_le16(&host_memory->num_memory_descriptors) * sizeof(struct pqi_sg_descriptor); + put_unaligned_le64((u64)host_memory_descriptor->host_memory_dma_handle, &request.data.host_memory_allocation.buffer_address); + put_unaligned_le32(buffer_length, &request.data.host_memory_allocation.buffer_length); + + if (function_code == PQI_VENDOR_GENERAL_OFA_MEMORY_UPDATE) { + put_unaligned_le16(PQI_OFA_VERSION, &host_memory->version); + memcpy(&host_memory->signature, PQI_OFA_SIGNATURE, sizeof(host_memory->signature)); + } else if (function_code == PQI_VENDOR_GENERAL_CTRL_LOG_MEMORY_UPDATE) { + put_unaligned_le16(PQI_CTRL_LOG_VERSION, &host_memory->version); + memcpy(&host_memory->signature, PQI_CTRL_LOG_SIGNATURE, sizeof(host_memory->signature)); + } } return pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, NULL); } -static int pqi_ofa_ctrl_restart(struct pqi_ctrl_info *ctrl_info, unsigned int delay_secs) -{ - ssleep(delay_secs); - - return pqi_ctrl_init_resume(ctrl_info); -} - static struct pqi_raid_error_info pqi_ctrl_offline_raid_error_info = { .data_out_result = PQI_DATA_IN_OUT_HARDWARE_ERROR, .status = SAM_STAT_CHECK_CONDITION, @@ -9446,6 +9554,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0x0462) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x193d, 0x1104) }, { @@ -9474,6 +9586,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0x1110) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x193d, 0x8460) }, { @@ -9482,6 +9598,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0x8462) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x193d, 0xc460) }, { @@ -9590,6 +9710,14 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x00a1) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1f3a, 0x0104) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x19e5, 0xd227) }, { @@ -10182,6 +10310,110 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1137, 0x02fe) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1137, 0x02ff) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1137, 0x0300) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0045) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0046) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0047) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0048) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x004a) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x004b) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x004c) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x004f) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0051) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0052) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0053) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0054) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x006b) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x006c) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x006d) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x006f) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0070) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0071) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0072) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0086) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0087) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0088) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x0089) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x1e93, 0x1000) }, { @@ -10266,6 +10498,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1ff9, 0x00a3) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_ANY_ID, PCI_ANY_ID) }, { 0 } diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c index 673437c7152b..ca1df36b83f7 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.c +++ b/drivers/scsi/smartpqi/smartpqi_sis.c @@ -29,6 +29,7 @@ #define SIS_ENABLE_INTX 0x80 #define SIS_SOFT_RESET 0x100 #define SIS_CMD_READY 0x200 +#define SIS_NOTIFY_KDUMP 0x400 #define SIS_TRIGGER_SHUTDOWN 0x800000 #define SIS_PQI_RESET_QUIESCE 0x1000000 @@ -52,6 +53,8 @@ #define SIS_BASE_STRUCT_ALIGNMENT 16 #define SIS_CTRL_KERNEL_FW_TRIAGE 0x3 +#define SIS_CTRL_KERNEL_CTRL_LOGGING 0x4 +#define SIS_CTRL_KERNEL_CTRL_LOGGING_STATUS 0x18 #define SIS_CTRL_KERNEL_UP 0x80 #define SIS_CTRL_KERNEL_PANIC 0x100 #define SIS_CTRL_READY_TIMEOUT_SECS 180 @@ -65,6 +68,13 @@ enum sis_fw_triage_status { FW_TRIAGE_COMPLETED }; +enum sis_ctrl_logging_status { + CTRL_LOGGING_NOT_STARTED = 0, + CTRL_LOGGING_STARTED, + CTRL_LOGGING_COND_INVALID, + CTRL_LOGGING_COMPLETED +}; + #pragma pack(1) /* for use with SIS_CMD_INIT_BASE_STRUCT_ADDRESS command */ @@ -442,6 +452,21 @@ static inline enum sis_fw_triage_status SIS_CTRL_KERNEL_FW_TRIAGE)); } +bool sis_is_ctrl_logging_supported(struct pqi_ctrl_info *ctrl_info) +{ + return readl(&ctrl_info->registers->sis_firmware_status) & SIS_CTRL_KERNEL_CTRL_LOGGING; +} + +void sis_notify_kdump(struct pqi_ctrl_info *ctrl_info) +{ + sis_set_doorbell_bit(ctrl_info, SIS_NOTIFY_KDUMP); +} + +static inline enum sis_ctrl_logging_status sis_read_ctrl_logging_status(struct pqi_ctrl_info *ctrl_info) +{ + return ((enum sis_ctrl_logging_status)((readl(&ctrl_info->registers->sis_firmware_status) & SIS_CTRL_KERNEL_CTRL_LOGGING_STATUS) >> 3)); +} + void sis_soft_reset(struct pqi_ctrl_info *ctrl_info) { writel(SIS_SOFT_RESET, @@ -484,6 +509,41 @@ int sis_wait_for_fw_triage_completion(struct pqi_ctrl_info *ctrl_info) return rc; } +#define SIS_CTRL_LOGGING_STATUS_TIMEOUT_SECS 180 +#define SIS_CTRL_LOGGING_STATUS_POLL_INTERVAL_SECS 1 + +int sis_wait_for_ctrl_logging_completion(struct pqi_ctrl_info *ctrl_info) +{ + int rc; + enum sis_ctrl_logging_status status; + unsigned long timeout; + + timeout = (SIS_CTRL_LOGGING_STATUS_TIMEOUT_SECS * HZ) + jiffies; + while (1) { + status = sis_read_ctrl_logging_status(ctrl_info); + if (status == CTRL_LOGGING_COND_INVALID) { + dev_err(&ctrl_info->pci_dev->dev, + "controller data logging condition invalid\n"); + rc = -EINVAL; + break; + } else if (status == CTRL_LOGGING_COMPLETED) { + rc = 0; + break; + } + + if (time_after(jiffies, timeout)) { + dev_err(&ctrl_info->pci_dev->dev, + "timed out waiting for controller data logging status\n"); + rc = -ETIMEDOUT; + break; + } + + ssleep(SIS_CTRL_LOGGING_STATUS_POLL_INTERVAL_SECS); + } + + return rc; +} + void sis_verify_structures(void) { BUILD_BUG_ON(offsetof(struct sis_base_struct, diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h b/drivers/scsi/smartpqi/smartpqi_sis.h index 0c97626d87d4..7e0eac3d07de 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.h +++ b/drivers/scsi/smartpqi/smartpqi_sis.h @@ -31,6 +31,9 @@ u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info); void sis_soft_reset(struct pqi_ctrl_info *ctrl_info); u32 sis_get_product_id(struct pqi_ctrl_info *ctrl_info); int sis_wait_for_fw_triage_completion(struct pqi_ctrl_info *ctrl_info); +bool sis_is_ctrl_logging_supported(struct pqi_ctrl_info *ctrl_info); +void sis_notify_kdump(struct pqi_ctrl_info *ctrl_info); +int sis_wait_for_ctrl_logging_completion(struct pqi_ctrl_info *ctrl_info); extern unsigned int sis_ctrl_ready_timeout_secs; diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c index cc824dcfe7da..9be3f0193145 100644 --- a/drivers/scsi/snic/snic_main.c +++ b/drivers/scsi/snic/snic_main.c @@ -300,9 +300,8 @@ snic_add_host(struct Scsi_Host *shost, struct pci_dev *pdev) } SNIC_BUG_ON(shost->work_q != NULL); - snprintf(shost->work_q_name, sizeof(shost->work_q_name), "scsi_wq_%d", - shost->host_no); - shost->work_q = create_singlethread_workqueue(shost->work_q_name); + shost->work_q = alloc_ordered_workqueue("scsi_wq_%d", WQ_MEM_RECLAIM, + shost->host_no); if (!shost->work_q) { SNIC_HOST_ERR(shost, "Failed to Create ScsiHost wq.\n"); @@ -873,7 +872,7 @@ snic_global_data_init(void) snic_glob->req_cache[SNIC_REQ_CACHE_MAX_SGL] = cachep; len = sizeof(struct snic_host_req); - cachep = kmem_cache_create("snic_req_maxsgl", len, SNIC_SG_DESC_ALIGN, + cachep = kmem_cache_create("snic_req_tm", len, SNIC_SG_DESC_ALIGN, SLAB_HWCACHE_ALIGN, NULL); if (!cachep) { SNIC_ERR("Failed to create snic tm req slab\n"); @@ -884,7 +883,8 @@ snic_global_data_init(void) snic_glob->req_cache[SNIC_REQ_TM_CACHE] = cachep; /* snic_event queue */ - snic_glob->event_q = create_singlethread_workqueue("snic_event_wq"); + snic_glob->event_q = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, "snic_event_wq"); if (!snic_glob->event_q) { SNIC_ERR("snic event queue create failed\n"); ret = -ENOMEM; diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 8ffb75be99bc..0e81125df8c7 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -334,7 +334,6 @@ struct st_hba { struct st_ccb *wait_ccb; __le32 *scratch; - char work_q_name[20]; struct workqueue_struct *work_q; struct work_struct reset_work; wait_queue_head_t reset_waitq; @@ -1795,9 +1794,8 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) hba->pdev = pdev; init_waitqueue_head(&hba->reset_waitq); - snprintf(hba->work_q_name, sizeof(hba->work_q_name), - "stex_wq_%d", host->host_no); - hba->work_q = create_singlethread_workqueue(hba->work_q_name); + hba->work_q = alloc_ordered_workqueue("stex_wq_%d", WQ_MEM_RECLAIM, + host->host_no); if (!hba->work_q) { printk(KERN_ERR DRV_NAME "(%s): create workqueue failed\n", pci_name(pdev)); diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index f51702893306..fffc0fa52594 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -304,7 +304,7 @@ static int sun3scsi_dma_setup(struct NCR5380_hostdata *hostdata, sun3_udc_write(UDC_INT_ENABLE, UDC_CSR); #endif - return count; + return count; } diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index c4fea077265e..32242d86cf5b 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -1137,7 +1137,8 @@ static int pvscsi_setup_msg_workqueue(struct pvscsi_adapter *adapter) snprintf(name, sizeof(name), "vmw_pvscsi_wq_%u", adapter->host->host_no); - adapter->workqueue = create_singlethread_workqueue(name); + adapter->workqueue = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, name); if (!adapter->workqueue) { printk(KERN_ERR "vmw_pvscsi: failed to create work queue\n"); return 0; |