diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 27b446c0c5d0..4179f29b3066 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -276,8 +276,10 @@ static void blogic_create_addlccbs(struct blogic_adapter *adapter, Lock should already have been acquired by the caller. */ -static struct blogic_ccb *blogic_alloc_ccb(struct blogic_adapter *adapter) +static struct blogic_ccb *blogic_alloc_ccb(struct Scsi_Host *host) + __must_hold(&host->host_lock) { + struct blogic_adapter *adapter = (void *)host->hostdata; static unsigned long serial; struct blogic_ccb *ccb; ccb = adapter->free_ccbs; @@ -307,7 +309,9 @@ static struct blogic_ccb *blogic_alloc_ccb(struct blogic_adapter *adapter) caller. */ -static void blogic_dealloc_ccb(struct blogic_ccb *ccb, int dma_unmap) +static void blogic_dealloc_ccb(struct Scsi_Host *host, struct blogic_ccb *ccb, + int dma_unmap) + __must_hold(&host->host_lock) { struct blogic_adapter *adapter = ccb->adapter; @@ -2596,8 +2600,11 @@ static void blogic_scan_inbox(struct blogic_adapter *adapter) should already have been acquired by the caller. */ -static void blogic_process_ccbs(struct blogic_adapter *adapter) +static void blogic_process_ccbs(struct Scsi_Host *host) + __must_hold(&host->host_lock) { + struct blogic_adapter *adapter = (void *)host->hostdata; + if (adapter->processing_ccbs) return; adapter->processing_ccbs = true; @@ -2621,7 +2628,7 @@ static void blogic_process_ccbs(struct blogic_adapter *adapter) /* Place CCB back on the Host Adapter's free list. */ - blogic_dealloc_ccb(ccb, 1); + blogic_dealloc_ccb(host, ccb, 1); #if 0 /* this needs to be redone different for new EH */ /* Bus Device Reset CCBs have the command field @@ -2650,7 +2657,7 @@ static void blogic_process_ccbs(struct blogic_adapter *adapter) if (ccb->status == BLOGIC_CCB_RESET && ccb->tgt_id == tgt_id) { command = ccb->command; - blogic_dealloc_ccb(ccb, 1); + blogic_dealloc_ccb(host, ccb, 1); adapter->active_cmds[tgt_id]--; command->result = DID_RESET << 16; scsi_done(command); @@ -2721,7 +2728,7 @@ static void blogic_process_ccbs(struct blogic_adapter *adapter) /* Place CCB back on the Host Adapter's free list. */ - blogic_dealloc_ccb(ccb, 1); + blogic_dealloc_ccb(host, ccb, 1); /* Call the SCSI Command Completion Routine. */ @@ -2740,11 +2747,12 @@ static void blogic_process_ccbs(struct blogic_adapter *adapter) static irqreturn_t blogic_inthandler(int irq_ch, void *devid) { struct blogic_adapter *adapter = (struct blogic_adapter *) devid; + struct Scsi_Host *host = adapter->scsi_host; unsigned long processor_flag; /* Acquire exclusive access to Host Adapter. */ - spin_lock_irqsave(&adapter->scsi_host->host_lock, processor_flag); + spin_lock_irqsave(&host->host_lock, processor_flag); /* Handle Interrupts appropriately for each Host Adapter type. */ @@ -2794,25 +2802,25 @@ static irqreturn_t blogic_inthandler(int irq_ch, void *devid) Process any completed CCBs. */ if (adapter->firstccb != NULL) - blogic_process_ccbs(adapter); + blogic_process_ccbs(host); /* Reset the Host Adapter if requested. */ if (adapter->adapter_extreset) { blogic_warn("Resetting %s due to External SCSI Bus Reset\n", adapter, adapter->full_model); blogic_inc_count(&adapter->ext_resets); - blogic_resetadapter(adapter, false); + blogic_resetadapter(host, false); adapter->adapter_extreset = false; } else if (adapter->adapter_intern_err) { blogic_warn("Resetting %s due to Host Adapter Internal Error\n", adapter, adapter->full_model); blogic_inc_count(&adapter->adapter_intern_errors); - blogic_resetadapter(adapter, true); + blogic_resetadapter(host, true); adapter->adapter_intern_err = false; } /* Release exclusive access to Host Adapter. */ - spin_unlock_irqrestore(&adapter->scsi_host->host_lock, processor_flag); + spin_unlock_irqrestore(&host->host_lock, processor_flag); return IRQ_HANDLED; } @@ -2823,9 +2831,11 @@ static irqreturn_t blogic_inthandler(int irq_ch, void *devid) already have been acquired by the caller. */ -static bool blogic_write_outbox(struct blogic_adapter *adapter, +static bool blogic_write_outbox(struct Scsi_Host *host, enum blogic_action action, struct blogic_ccb *ccb) + __must_hold(&host->host_lock) { + struct blogic_adapter *adapter = (void *)host->hostdata; struct blogic_outbox *next_outbox; next_outbox = adapter->next_outbox; @@ -2859,17 +2869,16 @@ static int blogic_hostreset(struct scsi_cmnd *SCpnt) { struct blogic_adapter *adapter = (struct blogic_adapter *) SCpnt->device->host->hostdata; - + struct Scsi_Host *shost = adapter->scsi_host; unsigned int id = SCpnt->device->id; struct blogic_tgt_stats *stats = &adapter->tgt_stats[id]; int rc; - spin_lock_irq(&SCpnt->device->host->host_lock); - + spin_lock_irq(&shost->host_lock); blogic_inc_count(&stats->adapter_reset_req); + rc = blogic_resetadapter(shost, false); + spin_unlock_irq(&shost->host_lock); - rc = blogic_resetadapter(adapter, false); - spin_unlock_irq(&SCpnt->device->host->host_lock); return rc; } @@ -2878,11 +2887,12 @@ static int blogic_hostreset(struct scsi_cmnd *SCpnt) Outgoing Mailbox for execution by the associated Host Adapter. */ -static enum scsi_qc_status blogic_qcmd_lck(struct scsi_cmnd *command) +static enum scsi_qc_status blogic_qcmd_lck(struct Scsi_Host *shost, struct scsi_cmnd *command) + __must_hold(&shost->host_lock) { void (*comp_cb)(struct scsi_cmnd *) = scsi_done; struct blogic_adapter *adapter = - (struct blogic_adapter *) command->device->host->hostdata; + (struct blogic_adapter *) shost->hostdata; struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[command->device->id]; struct blogic_tgt_stats *tgt_stats = adapter->tgt_stats; @@ -2913,12 +2923,12 @@ static enum scsi_qc_status blogic_qcmd_lck(struct scsi_cmnd *command) probably hung so signal an error as a Host Adapter Hard Reset should be initiated soon. */ - ccb = blogic_alloc_ccb(adapter); + ccb = blogic_alloc_ccb(shost); if (ccb == NULL) { - spin_unlock_irq(&adapter->scsi_host->host_lock); + spin_unlock_irq(&shost->host_lock); blogic_delay(1); - spin_lock_irq(&adapter->scsi_host->host_lock); - ccb = blogic_alloc_ccb(adapter); + spin_lock_irq(&shost->host_lock); + ccb = blogic_alloc_ccb(shost); if (ccb == NULL) { command->result = DID_ERROR << 16; comp_cb(command); @@ -3046,7 +3056,7 @@ static enum scsi_qc_status blogic_qcmd_lck(struct scsi_cmnd *command) if (dma_mapping_error(&adapter->pci_device->dev, sense_buf)) { blogic_err("DMA mapping for sense data buffer failed\n", adapter); - blogic_dealloc_ccb(ccb, 0); + blogic_dealloc_ccb(shost, ccb, 0); return SCSI_MLQUEUE_HOST_BUSY; } ccb->sensedata = sense_buf; @@ -3061,15 +3071,15 @@ static enum scsi_qc_status blogic_qcmd_lck(struct scsi_cmnd *command) so signal an error as a Host Adapter Hard Reset should be initiated soon. */ - if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START, ccb)) { - spin_unlock_irq(&adapter->scsi_host->host_lock); + if (!blogic_write_outbox(shost, BLOGIC_MBOX_START, ccb)) { + spin_unlock_irq(&shost->host_lock); blogic_warn("Unable to write Outgoing Mailbox - Pausing for 1 second\n", adapter); blogic_delay(1); - spin_lock_irq(&adapter->scsi_host->host_lock); - if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START, + spin_lock_irq(&shost->host_lock); + if (!blogic_write_outbox(shost, BLOGIC_MBOX_START, ccb)) { blogic_warn("Still unable to write Outgoing Mailbox - Host Adapter Dead?\n", adapter); - blogic_dealloc_ccb(ccb, 1); + blogic_dealloc_ccb(shost, ccb, 1); command->result = DID_ERROR << 16; scsi_done(command); } @@ -3089,12 +3099,20 @@ static enum scsi_qc_status blogic_qcmd_lck(struct scsi_cmnd *command) pending. */ if (ccb->status == BLOGIC_CCB_COMPLETE) - blogic_process_ccbs(adapter); + blogic_process_ccbs(shost); } return 0; } -static DEF_SCSI_QCMD(blogic_qcmd) +static enum scsi_qc_status blogic_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd) +{ + enum scsi_qc_status rc; + + spin_lock_irq(&shost->host_lock); + rc = blogic_qcmd_lck(shost, cmd); + spin_unlock_irq(&shost->host_lock); + return rc; +} #if 0 /* @@ -3103,9 +3121,8 @@ static DEF_SCSI_QCMD(blogic_qcmd) static int blogic_abort(struct scsi_cmnd *command) { - struct blogic_adapter *adapter = - (struct blogic_adapter *) command->device->host->hostdata; - + struct Scsi_Host *const shost = command->device->host; + struct blogic_adapter *adapter = (void *) shost->hostdata; int tgt_id = command->device->id; struct blogic_ccb *ccb; blogic_inc_count(&adapter->tgt_stats[tgt_id].aborts_request); @@ -3144,7 +3161,7 @@ static int blogic_abort(struct scsi_cmnd *command) adapter->fw_ver[0] < '5') { blogic_warn("Unable to Abort CCB #%ld to Target %d - Abort Tag Not Supported\n", adapter, ccb->serial, tgt_id); return FAILURE; - } else if (blogic_write_outbox(adapter, BLOGIC_MBOX_ABORT, + } else if (blogic_write_outbox(shost, BLOGIC_MBOX_ABORT, ccb)) { blogic_warn("Aborting CCB #%ld to Target %d\n", adapter, ccb->serial, tgt_id); @@ -3169,7 +3186,7 @@ static int blogic_abort(struct scsi_cmnd *command) may still be pending. */ if (ccb->status == BLOGIC_CCB_COMPLETE) - blogic_process_ccbs(adapter); + blogic_process_ccbs(shost); return SUCCESS; } return SUCCESS; @@ -3181,8 +3198,10 @@ static int blogic_abort(struct scsi_cmnd *command) currently executing SCSI Commands as having been Reset. */ -static int blogic_resetadapter(struct blogic_adapter *adapter, bool hard_reset) +static int blogic_resetadapter(struct Scsi_Host *host, bool hard_reset) + __must_hold(&host->host_lock) { + struct blogic_adapter *adapter = (void *)host->hostdata; struct blogic_ccb *ccb; int tgt_id; @@ -3203,7 +3222,7 @@ static int blogic_resetadapter(struct blogic_adapter *adapter, bool hard_reset) for (ccb = adapter->all_ccbs; ccb != NULL; ccb = ccb->next_all) if (ccb->status == BLOGIC_CCB_ACTIVE) - blogic_dealloc_ccb(ccb, 1); + blogic_dealloc_ccb(host, ccb, 1); /* * Wait a few seconds between the Host Adapter Hard Reset which * initiates a SCSI Bus Reset and issuing any SCSI Commands. Some @@ -3212,9 +3231,9 @@ static int blogic_resetadapter(struct blogic_adapter *adapter, bool hard_reset) */ if (hard_reset) { - spin_unlock_irq(&adapter->scsi_host->host_lock); + spin_unlock_irq(&host->host_lock); blogic_delay(adapter->bus_settle_time); - spin_lock_irq(&adapter->scsi_host->host_lock); + spin_lock_irq(&host->host_lock); } for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) { diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index 24697a5bedc8..455d442525f6 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -1279,7 +1279,8 @@ static int blogic_sdev_configure(struct scsi_device *, struct queue_limits *lim); static void blogic_qcompleted_ccb(struct blogic_ccb *); static irqreturn_t blogic_inthandler(int, void *); -static int blogic_resetadapter(struct blogic_adapter *, bool hard_reset); +static int blogic_resetadapter(struct Scsi_Host *host, bool hard_reset) + __must_hold(&host->host_lock); static void blogic_msg(enum blogic_msglevel, char *, struct blogic_adapter *, ...); static int __init blogic_setup(char *); diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 7ea38d509072..8191d258f162 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -271,8 +271,6 @@ static void aha1542_free_cmd(struct scsi_cmnd *cmd) buf += bv.bv_len; } } - - scsi_dma_unmap(cmd); } static irqreturn_t aha1542_interrupt(int irq, void *dev_id) diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 3602a1fc40e4..4abc7948187f 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -8942,8 +8942,10 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) } #endif - if (ahd_perform_autosense(scb) == 0) + if (ahd_perform_autosense(scb) == 0) { + ahd_done(ahd, scb); break; + } ahd_compile_devinfo(&devinfo, SCB_GET_OUR_ID(scb), SCB_GET_TARGET(ahd, scb), diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index c6eb2b97e929..1facfd238f89 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -501,6 +501,8 @@ int ahd_linux_show_info(struct seq_file *,struct Scsi_Host *); static inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status) { + if (!cmd) + return; cmd->result &= ~(CAM_STATUS_MASK << 16); cmd->result |= status << 16; } @@ -514,6 +516,8 @@ void ahd_set_transaction_status(struct scb *scb, uint32_t status) static inline void ahd_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status) { + if (!cmd) + return; cmd->result &= ~0xFFFF; cmd->result |= status; } @@ -527,6 +531,8 @@ void ahd_set_scsi_status(struct scb *scb, uint32_t status) static inline uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd) { + if (!cmd) + return CAM_REQ_INPROG; return ((cmd->result >> 16) & CAM_STATUS_MASK); } @@ -539,6 +545,8 @@ uint32_t ahd_get_transaction_status(struct scb *scb) static inline uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd) { + if (!cmd) + return SAM_STAT_GOOD; return (cmd->result & 0xFFFF); } @@ -566,13 +574,16 @@ u_long ahd_get_transfer_length(struct scb *scb) static inline int ahd_get_transfer_dir(struct scb *scb) { + if (!scb->io_ctx) + return DMA_NONE; return (scb->io_ctx->sc_data_direction); } static inline void ahd_set_residual(struct scb *scb, u_long resid) { - scsi_set_resid(scb->io_ctx, resid); + if (scb->io_ctx) + scsi_set_resid(scb->io_ctx, resid); } static inline @@ -584,6 +595,8 @@ void ahd_set_sense_residual(struct scb *scb, u_long resid) static inline u_long ahd_get_residual(struct scb *scb) { + if (!scb->io_ctx) + return 0; return scsi_get_resid(scb->io_ctx); } @@ -597,11 +610,12 @@ static inline int ahd_perform_autosense(struct scb *scb) { /* - * We always perform autosense in Linux. - * On other platforms this is set on a - * per-transaction basis. + * We always perform autosense in Linux, except for the device + * reset SCB, which has no command to return sense data to. */ - return (1); + if (!scb->io_ctx) + return 0; + return 1; } static inline uint32_t @@ -631,6 +645,8 @@ void ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb); static inline void ahd_freeze_scb(struct scb *scb) { + if (!scb->io_ctx) + return; if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) { scb->io_ctx->result |= CAM_DEV_QFRZN << 16; scb->platform_data->dev->qfrozen++; diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index b9761f9f0bbc..af6115bfb280 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -1097,7 +1097,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) sc->byte2 = SCB_GET_LUN(scb) << 5; sc->unused[0] = 0; sc->unused[1] = 0; - sc->length = sg->len; + sc->length = ahc_get_sense_bufsize(ahc, scb); sc->control = 0; /* @@ -5266,9 +5266,13 @@ ahc_init(struct ahc_softc *ahc) /* * Assume we have a board at this stage and it has been reset. + * PCI controllers keep the host ID ahc_pci_config() chose. */ - if ((ahc->flags & AHC_USEDEFAULTS) != 0) - ahc->our_id = ahc->our_id_b = 7; + if ((ahc->flags & AHC_USEDEFAULTS) != 0) { + if ((ahc->chip & AHC_PCI) == 0) + ahc->our_id = 7; + ahc->our_id_b = 7; + } /* * Default to allowing initiator operations. diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index 2d4c85426dc3..5a04c7d55e4b 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -701,6 +701,21 @@ ahc_find_pci_device(ahc_dev_softc_t pci) return (NULL); } +/* + * The SGI O2 firmware runs its onboard controllers, in slots 1 and 2 of the + * root bus, without the Adaptec BIOS and at host ID 0. It leaves no settings + * in scratch RAM, which may still hold power-on contents with bad parity. + */ +static bool +ahc_pci_sgi_o2_onboard(struct ahc_softc *ahc) +{ + int slot = ahc_get_pci_slot(ahc->dev_softc); + + return IS_ENABLED(CONFIG_SGI_IP32) && + ahc_get_pci_bus(ahc->dev_softc) == 0 && + (slot == 1 || slot == 2); +} + int ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) { @@ -782,6 +797,9 @@ ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) ahc->bus_intr = ahc_pci_intr; ahc->bus_chip_init = ahc_pci_chip_init; + if (ahc_pci_sgi_o2_onboard(ahc)) + ahc->flags |= AHC_NO_BIOS_INIT; + /* Remember how the card was setup in case there is no SEEPROM */ if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { ahc_pause(ahc); @@ -898,7 +916,7 @@ ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) * Assume only one connector and always turn * on termination. */ - our_id = 0x07; + our_id = ahc_pci_sgi_o2_onboard(ahc) ? 0 : 0x07; sxfrctl1 = STPWEN; } ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI); diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 2340790c9f6b..8f5f1ef6f619 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -372,6 +372,7 @@ static int local_ata_check_ready(struct ata_link *link) } } +__printf(3, 4) static int sas_ata_printk(const char *level, const struct domain_device *ddev, const char *fmt, ...) { diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 085d4672db85..a77bbc3d2b66 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -7700,7 +7700,9 @@ _scsih_determine_disposition(struct MPT3SAS_ADAPTER *ioc, u16 scode = scsi_sense_code(sense_info.asc, sense_info.ascq); - if (scode == + if (scode == LU_NOT_READY_SANITIZE_IN_PROGRESS) + rc = DEVICE_READY; + else if (scode == LU_NOT_READY_MANUAL_INTERVENTION_REQUIRED || scode == LU_NOT_ACCESSIBLE_TARGET_PORT_IN_STANDBY_STATE || diff --git a/drivers/scsi/scsi_bsg.c b/drivers/scsi/scsi_bsg.c index 5eec248a77a6..e4a65d7a2374 100644 --- a/drivers/scsi/scsi_bsg.c +++ b/drivers/scsi/scsi_bsg.c @@ -41,7 +41,7 @@ static void scsi_bsg_uring_task_cb(struct io_tw_req tw_req, io_tw_token_t tw) u8 sense_len_wr = 0; if (pdu->bio) - blk_rq_unmap_user(pdu->bio); + ret = blk_rq_unmap_user(pdu->bio); if (scsi_status_is_check_condition(scmd->result)) { driver_status = DRIVER_SENSE; @@ -199,7 +199,7 @@ static int scsi_bsg_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr, struct scsi_cmnd *scmd; struct request *rq; struct bio *bio; - int ret; + int ret, unmap_ret; if (hdr->protocol != BSG_PROTOCOL_SCSI || hdr->subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD) @@ -273,7 +273,9 @@ static int scsi_bsg_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr, else hdr->dout_resid = scmd->resid_len; - blk_rq_unmap_user(bio); + unmap_ret = blk_rq_unmap_user(bio); + if (!ret) + ret = unmap_ret; out_put_request: blk_mq_free_request(rq); diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index a922c8318a2f..c5c4312e23aa 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -9053,6 +9053,7 @@ static void __exit scsi_debug_exit(void) sdebug_erase_all_stores(false); xa_destroy(per_store_ap); + async_synchronize_full_domain(&sdebug_async_domain); debugfs_remove(sdebug_debugfs_root); } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 8aae12fd38f3..52f3b525d2fd 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -2154,14 +2154,13 @@ struct scsi_device *scsi_get_pseudo_sdev(struct Scsi_Host *shost) goto out; sdev = scsi_alloc_sdev(starget, U64_MAX, NULL); - if (!sdev) { - scsi_target_reap(starget); + if (!sdev) goto put_target; - } sdev->borken = 0; put_target: + scsi_target_reap(starget); /* See also the get_device(dev) call in scsi_alloc_target(). */ put_device(&starget->dev); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 9db2201aa553..c5d5d6a91fee 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -349,6 +349,19 @@ int core_enable_device_list_for_node( new->attach_count++; mutex_lock(&nacl->lun_entry_mutex); + /* + * Do not attach a new dev entry to an se_lun that is being torn down. + * lun_shutdown is set by core_tpg_remove_lun() before its + * core_clear_lun_from_tpg() sweep; checking it here under the same + * nacl->lun_entry_mutex the sweep takes guarantees that once the sweep + * has passed this ACL no dev entry can be left dangling on the + * se_lun->lun_deve_list that is about to be freed. + */ + if (lun->lun_shutdown) { + mutex_unlock(&nacl->lun_entry_mutex); + ret = -ENODEV; + goto free_stats; + } orig = target_nacl_find_deve(nacl, mapped_lun); if (orig && orig->se_lun) { struct se_lun *orig_lun = orig->se_lun; @@ -375,12 +388,12 @@ int core_enable_device_list_for_node( new->se_lun_acl = lun_acl; hlist_del_rcu(&orig->link); hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); - mutex_unlock(&nacl->lun_entry_mutex); spin_lock(&lun->lun_deve_lock); list_del(&orig->lun_link); list_add_tail(&new->lun_link, &lun->lun_deve_list); spin_unlock(&lun->lun_deve_lock); + mutex_unlock(&nacl->lun_entry_mutex); kref_put(&orig->pr_kref, target_pr_kref_release); wait_for_completion(&orig->pr_comp); @@ -393,11 +406,10 @@ int core_enable_device_list_for_node( new->se_lun = lun; new->se_lun_acl = lun_acl; hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); - mutex_unlock(&nacl->lun_entry_mutex); - spin_lock(&lun->lun_deve_lock); list_add_tail(&new->lun_link, &lun->lun_deve_list); spin_unlock(&lun->lun_deve_lock); + mutex_unlock(&nacl->lun_entry_mutex); target_luns_data_has_changed(nacl, new, true); return 0; diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 2853b95b2c59..ad024009df56 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -371,6 +371,16 @@ static bool iscsi_parse_pr_out_transport_id( pr_err("Missing ISID in iSCSI Initiator port TransportID\n"); return false; } + /* + * The registration code reads the ISID as a C string, + * and its first 8 bytes with get_unaligned_be64(), so + * require 8 bytes after the separator and a NUL inside + * the rest of the descriptor. + */ + if (buf + tid_len - p < 8 || !memchr(p, '\0', buf + tid_len - p)) { + pr_err("Incomplete or unterminated ISID in iSCSI Initiator port TransportID\n"); + return false; + } *port_nexus_ptr = p; /* * Go ahead and do the lower case conversion of the received diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 25b1bcacc0c8..ca1a2802aa22 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -3226,10 +3226,11 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, transport_kunmap_data_sg(cmd); buf = NULL; - if ((tid_len + 24) != cmd->data_length) { - pr_err("SPC-3 PR: Illegal tid_len: %u + 24 byte header" - " does not equal CDB data_length: %u\n", tid_len, - cmd->data_length); + /* TransportID is at least 24 bytes. buf[24] is its first byte. */ + if (tid_len < 24 || + tid_len != cmd->data_length - 24) { + pr_err("SPC-3 PR: Illegal tid_len: %u for data_length: %u\n", + tid_len, cmd->data_length); ret = TCM_INVALID_PARAMETER_LIST; goto out_put_pr_reg; } diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index ccff9f6e4826..e615e5e30427 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -266,6 +266,15 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( kref_get(&acl->acl_kref); acl->dynamic_node_acl = 1; + /* + * Publish the dynamic NodeACL on tpg->acl_node_list before creating + * its demo-mode MappedLUN dev entries below, so that a concurrent LUN + * teardown sweep (core_clear_lun_from_tpg(), which walks acl_node_list) + * can observe and disable those dev entries. Otherwise a dev entry can + * be left on an se_lun->lun_deve_list that is about to be freed. + */ + target_add_node_acl(acl); + /* * Here we only create demo-mode MappedLUNs from the active * TPG LUNs if the fabric is not explicitly asking for @@ -275,7 +284,6 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) != 1)) core_tpg_add_node_to_devs(acl, tpg, NULL); - target_add_node_acl(acl); return acl; } EXPORT_SYMBOL(core_tpg_check_initiator_node_acl); diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 425ad1246a75..07b514678176 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2524,6 +2524,11 @@ static int tcmu_set_data_pages_per_blk(struct tcmu_dev *udev, substring_t *arg) return ret; } + if (val <= 0) { + pr_err("Invalid data_pages_per_blk %d.\n", val); + return -EINVAL; + } + if (val > TCMU_MBS_TO_PAGES(udev->data_area_mb)) { pr_err("Invalid data_pages_per_blk %d: greater than max_data_area_mb %d -> %zd pages).\n", val, udev->data_area_mb, diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index ee643830a57a..fd52deb72d21 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5931,18 +5931,26 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) { irqreturn_t retval = IRQ_NONE; struct uic_command *cmd; + bool ah8_err; guard(spinlock_irqsave)(&hba->host->host_lock); + + /* + * Auto-hibern8 is performed without a UIC command, so check for + * auto-hibern8 errors before checking for an active UIC command. + */ + ah8_err = ufshcd_is_auto_hibern8_error(hba, intr_status); + if (ah8_err) + hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status); + cmd = hba->active_uic_cmd; if (!cmd) { - dev_err(hba->dev, - "No active UIC command. Maybe a timeout occurred?\n"); + if (!ah8_err) + dev_err(hba->dev, + "No active UIC command. Maybe a timeout occurred?\n"); return retval; } - if (ufshcd_is_auto_hibern8_error(hba, intr_status)) - hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status); - if (intr_status & UIC_COMMAND_COMPL) { /* * Store the UIC command result in the lowest byte of