diff options
| author | Mark Brown <broonie@kernel.org> | 2026-10-13 18:36:09 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-10-13 18:36:12 +0100 |
| commit | 98a2eaef035eb4ce89a04004afcbf0097393fcf2 (patch) | |
| tree | 619abd779f85d120954bca59dbaeccca7a08e8f2 | |
| parent | 53262cb205c8864559a465a68a4ee8879a915ea3 (diff) | |
| parent | 2f4880c22e838d54eae9ab153b0f8dce60531bf1 (diff) | |
| download | linux-next-98a2eaef035eb4ce89a04004afcbf0097393fcf2.tar.gz linux-next-98a2eaef035eb4ce89a04004afcbf0097393fcf2.zip | |
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
| -rw-r--r-- | Documentation/scsi/scsi_mid_low_api.rst | 24 | ||||
| -rw-r--r-- | MAINTAINERS | 1 | ||||
| -rw-r--r-- | drivers/ata/libata-scsi.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/bfa/bfa_fcs.c | 88 | ||||
| -rw-r--r-- | drivers/scsi/scsi_debug.c | 143 | ||||
| -rw-r--r-- | drivers/scsi/scsi_error.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/scsi_lib.c | 3 | ||||
| -rw-r--r-- | drivers/scsi/st.c | 97 | ||||
| -rw-r--r-- | drivers/scsi/st.h | 2 | ||||
| -rw-r--r-- | drivers/ufs/core/ufs-rpmb.c | 3 |
10 files changed, 243 insertions, 121 deletions
diff --git a/Documentation/scsi/scsi_mid_low_api.rst b/Documentation/scsi/scsi_mid_low_api.rst index 5489e9d07ab7..84cf61b2d6ae 100644 --- a/Documentation/scsi/scsi_mid_low_api.rst +++ b/Documentation/scsi/scsi_mid_low_api.rst @@ -865,7 +865,7 @@ Details:: * * Other types of errors that are detected immediately may be * flagged by setting scp->result to an appropriate value, - * invoking the scp->scsi_done callback, and then returning 0 + * invoking the scsi_done() function, and then returning 0 * from this function. If the command is not performed * immediately (and the LLD is starting (or will start) the given * command) then this function should place 0 in scp->result and @@ -873,11 +873,11 @@ Details:: * * Command ownership. If the driver returns zero, it owns the * command and must take responsibility for ensuring the - * scp->scsi_done callback is executed. Note: the driver may - * call scp->scsi_done before returning zero, but after it has - * called scp->scsi_done, it may not return any value other than + * scsi_done() function is called. Note: the driver may + * call scsi_done() before returning zero, but after it has + * called scsi_done(), it may not return any value other than * zero. If the driver makes a non-zero return, it must not - * execute the command's scsi_done callback at any time. + * call scsi_done(scp) at any time. * * Locks: up to and including 2.6.36, struct Scsi_Host::host_lock * held on entry (with "irqsave") and is expected to be @@ -887,16 +887,16 @@ Details:: * Calling context: in interrupt (soft irq) or process context * * Notes: This function should be relatively fast. Normally it - * will not wait for IO to complete. Hence the scp->scsi_done - * callback is invoked (often directly from an interrupt service + * will not wait for IO to complete. Hence the scsi_done() + * function is invoked (often directly from an interrupt service * routine) some time after this function has returned. In some * cases (e.g. pseudo adapter drivers that manufacture the - * response to a SCSI INQUIRY) the scp->scsi_done callback may be - * invoked before this function returns. If the scp->scsi_done - * callback is not invoked within a certain period the SCSI mid + * response to a SCSI INQUIRY) the scsi_done() function may be + * invoked before this function returns. If the scsi_done() + * function is not invoked within a certain period the SCSI mid * level will commence error processing. If a status of CHECK - * CONDITION is placed in "result" when the scp->scsi_done - * callback is invoked, then the LLD driver should perform + * CONDITION is placed in "result" when the scsi_done() + * function is invoked, then the LLD driver should perform * autosense and fill in the struct scsi_cmnd::sense_buffer * array. The scsi_cmnd::sense_buffer array is zeroed prior to * the mid level queuing a command to an LLD. diff --git a/MAINTAINERS b/MAINTAINERS index d63e12a7d038..91a48b225f55 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -28590,7 +28590,6 @@ F: lib/union_find.c UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER R: Alim Akhtar <alim.akhtar@samsung.com> -R: Avri Altman <avri.altman@wdc.com> R: Bart Van Assche <bvanassche@acm.org> L: linux-scsi@vger.kernel.org S: Supported diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index eb08cb978a97..5cde90fe594e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3583,7 +3583,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) unsigned int multi_count = 1 << (cdb[1] >> 5); if (!dev->multi_count) { - ata_scsi_set_sense(dev, scmd, ABORTED_COMMAND, 0, 0); + ata_scsi_set_sense(dev, scmd, ABORTED_COMMAND, NO_ADDITIONAL_SENSE_INFORMATION); return 1; } diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index 9b57312f43f5..3e5d3a141f32 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -760,53 +760,16 @@ bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric) bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model); - /* Model name/number */ - strscpy(port_cfg->sym_name.symname, model, - BFA_SYMNAME_MAXLEN); - strlcat(port_cfg->sym_name.symname, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - BFA_SYMNAME_MAXLEN); - - /* Driver Version */ - strlcat(port_cfg->sym_name.symname, driver_info->version, - BFA_SYMNAME_MAXLEN); - strlcat(port_cfg->sym_name.symname, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - BFA_SYMNAME_MAXLEN); - - /* Host machine name */ - strlcat(port_cfg->sym_name.symname, - driver_info->host_machine_name, - BFA_SYMNAME_MAXLEN); - strlcat(port_cfg->sym_name.symname, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - BFA_SYMNAME_MAXLEN); - - /* - * Host OS Info : - * If OS Patch Info is not there, do not truncate any bytes from the - * OS name string and instead copy the entire OS info string (64 bytes). - */ - if (driver_info->host_os_patch[0] == '\0') { - strlcat(port_cfg->sym_name.symname, - driver_info->host_os_name, - BFA_SYMNAME_MAXLEN); - strlcat(port_cfg->sym_name.symname, - BFA_FCS_PORT_SYMBNAME_SEPARATOR, - BFA_SYMNAME_MAXLEN); - } else { - strlcat(port_cfg->sym_name.symname, - driver_info->host_os_name, - BFA_SYMNAME_MAXLEN); - strlcat(port_cfg->sym_name.symname, - BFA_FCS_PORT_SYMBNAME_SEPARATOR, - BFA_SYMNAME_MAXLEN); - - /* Append host OS Patch Info */ - strlcat(port_cfg->sym_name.symname, - driver_info->host_os_patch, - BFA_SYMNAME_MAXLEN); - } - - /* null terminate */ - port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0; + snprintf(port_cfg->sym_name.symname, BFA_SYMNAME_MAXLEN, + "%s" BFA_FCS_PORT_SYMBNAME_SEPARATOR + "%s" BFA_FCS_PORT_SYMBNAME_SEPARATOR + "%s" BFA_FCS_PORT_SYMBNAME_SEPARATOR + "%s" BFA_FCS_PORT_SYMBNAME_SEPARATOR + "%s", + model, driver_info->version, + driver_info->host_machine_name, + driver_info->host_os_name, + driver_info->host_os_patch); } /* @@ -821,30 +784,13 @@ bfa_fcs_fabric_nsymb_init(struct bfa_fcs_fabric_s *fabric) bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model); - /* Model name/number */ - strscpy(port_cfg->node_sym_name.symname, model, - BFA_SYMNAME_MAXLEN); - strlcat(port_cfg->node_sym_name.symname, - BFA_FCS_PORT_SYMBNAME_SEPARATOR, - BFA_SYMNAME_MAXLEN); - - /* Driver Version */ - strlcat(port_cfg->node_sym_name.symname, (char *)driver_info->version, - BFA_SYMNAME_MAXLEN); - strlcat(port_cfg->node_sym_name.symname, - BFA_FCS_PORT_SYMBNAME_SEPARATOR, - BFA_SYMNAME_MAXLEN); - - /* Host machine name */ - strlcat(port_cfg->node_sym_name.symname, - driver_info->host_machine_name, - BFA_SYMNAME_MAXLEN); - strlcat(port_cfg->node_sym_name.symname, - BFA_FCS_PORT_SYMBNAME_SEPARATOR, - BFA_SYMNAME_MAXLEN); - - /* null terminate */ - port_cfg->node_sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0; + /* Model name/number, Driver Version, Host machine name */ + snprintf(port_cfg->node_sym_name.symname, BFA_SYMNAME_MAXLEN, + "%s" BFA_FCS_PORT_SYMBNAME_SEPARATOR + "%s" BFA_FCS_PORT_SYMBNAME_SEPARATOR + "%s" BFA_FCS_PORT_SYMBNAME_SEPARATOR, + model, (char *)driver_info->version, + driver_info->host_machine_name); } /* diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 6941809dfdb7..e679df1993aa 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -3980,6 +3980,16 @@ static int check_zbc_access_params(struct scsi_cmnd *scp, UNALIGNED_WRITE_COMMAND); return check_condition_result; } + /* + * Writes must end on a physical block boundary, that is, the + * transfer length must be a multiple of the physical block + * size. + */ + if (!IS_ALIGNED(lba + num, 1U << sdebug_physblk_exp)) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + UNALIGNED_WRITE_COMMAND); + return check_condition_result; + } } /* Handle implicit open of closed and empty zones */ @@ -4263,6 +4273,8 @@ static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, u64 block; enum dma_data_direction dir; struct scsi_data_buffer *sdb = &scp->sdb; + struct scsi_device *sdp = scp->device; + struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; u8 *fsp; int i, total = 0; @@ -4290,6 +4302,25 @@ static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, fsp = sip->storep; + /* + * A write to a sequential write required zone has to end on a physical + * block boundary, so if the data-out buffer does not hold all of the + * data that the command asks for, write up to the last whole physical + * block that it does hold. What is left over is reported as part of + * the residual. + */ + if (do_write && sdebug_dev_is_zoned(devip)) { + struct sdeb_zone_state *zsp = zbc_zone(devip, lba); + + if (zsp->z_type == ZBC_ZTYPE_SWR) { + u32 avail = (sdb->length - sg_skip) + >> ilog2(sdebug_sector_size); + + if (avail < num) + num = round_down(avail, 1U << sdebug_physblk_exp); + } + } + block = do_div(lba, sdebug_store_sectors); /* Only allow 1x atomic write or multiple non-atomic writes at any given time */ @@ -4845,6 +4876,11 @@ static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba, return mapped; } +/* + * Callers may map the whole range of a write without checking how much of + * it was written. SBC-6 4.7.4.6.2 allows a deallocated LBA to become mapped + * at any time, and only requires an LBA that was written to be mapped. + */ static void map_region(struct sdeb_store_info *sip, sector_t lba, unsigned int len) { @@ -4953,12 +4989,11 @@ static int corrupt_lbas(struct sdebug_dev_info *devip, u64 lba, u32 num, { struct sdeb_store_info *sip = devip2sip(devip, false); bool meta_data_locked = false; + bool lbp = scsi_debug_lbp(); u32 block, num_mapped, b, i; int error = 0; - if (sdebug_dev_is_zoned(devip) || - sdebug_dix || - scsi_debug_lbp()) { + if (sdebug_dev_is_zoned(devip) || sdebug_dix || lbp) { sdeb_meta_write_lock(sip); meta_data_locked = true; } @@ -4975,8 +5010,7 @@ static int corrupt_lbas(struct sdebug_dev_info *devip, u64 lba, u32 num, goto out_unlock; } - if (scsi_debug_lbp() && - (!map_state(sip, lba, &num_mapped) || num > num_mapped)) { + if (lbp && (!map_state(sip, lba, &num_mapped) || num > num_mapped)) { pr_err("can't modify unmapped logical blocks: %llu:%u", lba, num); error = -EINVAL; @@ -5035,6 +5069,7 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) struct sdeb_store_info *sip = devip2sip(devip, true); u8 *cmd = scp->cmnd; bool meta_data_locked = false; + bool lbp = scsi_debug_lbp(); if (unlikely(sdebug_opts & SDEBUG_OPT_UNALIGNED_WRITE && atomic_read(&sdeb_inject_pending))) { @@ -5101,8 +5136,7 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) } if (sdebug_dev_is_zoned(devip) || - (sdebug_dix && scsi_prot_sg_count(scp)) || - scsi_debug_lbp()) { + (sdebug_dix && scsi_prot_sg_count(scp)) || lbp) { sdeb_meta_write_lock(sip); meta_data_locked = true; } @@ -5147,12 +5181,12 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) } ret = do_device_access(sip, scp, 0, lba, num, group, true, false); - if (unlikely(scsi_debug_lbp())) + if (unlikely(lbp)) map_region(sip, lba, num); - /* If ZBC zone then bump its write pointer */ - if (sdebug_dev_is_zoned(devip)) - zbc_inc_wp(devip, lba, num); + /* If ZBC zone then bump its write pointer over the data written */ + if (sdebug_dev_is_zoned(devip) && ret > 0) + zbc_inc_wp(devip, lba, ret >> ilog2(sdebug_sector_size)); if (meta_data_locked) sdeb_meta_write_unlock(sip); @@ -5164,6 +5198,9 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) "%s: write: cdb indicated=%u, IO sent=%d bytes\n", my_name, num * sdebug_sector_size, ret); + if (ret < scsi_bufflen(scp)) + scsi_set_resid(scp, scsi_bufflen(scp) - ret); + if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && atomic_read(&sdeb_inject_pending))) { if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { @@ -5199,7 +5236,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, struct sdeb_store_info *sip = devip2sip(devip, true); u8 wrprotect; u16 lbdof, num_lrd, k; - u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb; + u32 num, bt_len, lbdof_blen, cum_lb; + u64 num_by, sg_off; u32 lb_size = sdebug_sector_size; u32 ei_lba; u64 lba; @@ -5235,8 +5273,10 @@ static int resp_write_scat(struct scsi_cmnd *scp, "Unprotected WR to DIF device\n"); } } - if ((num_lrd == 0) || (bt_len == 0)) + if (num_lrd == 0 || bt_len == 0) { + scsi_set_resid(scp, scsi_bufflen(scp)); return 0; /* T10 says these do-nothings are not errors */ + } if (lbdof == 0) { if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, @@ -5275,14 +5315,14 @@ static int resp_write_scat(struct scsi_cmnd *scp, num = get_unaligned_be32(up + 8); if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: k=%d LBA=0x%llx num=%u sg_off=%u\n", + "%s: k=%d LBA=0x%llx num=%u sg_off=%llu\n", my_name, k, lba, num, sg_off); if (num == 0) continue; ret = check_device_access_params(scp, lba, num, true); if (ret) goto err_out_unlock; - num_by = num * lb_size; + num_by = (u64)num * lb_size; ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12); if ((cum_lb + num) > bt_len) { @@ -5313,10 +5353,13 @@ static int resp_write_scat(struct scsi_cmnd *scp, * Write ranges atomically to keep as close to pre-atomic * writes behaviour as possible. */ - ret = do_device_access(sip, scp, sg_off, lba, num, group, true, true); - /* If ZBC zone then bump its write pointer */ - if (sdebug_dev_is_zoned(devip)) - zbc_inc_wp(devip, lba, num); + ret = do_device_access(sip, scp, + min_t(u64, sg_off, scsi_bufflen(scp)), + lba, num, group, true, true); + /* If ZBC zone then bump its write pointer over the data written */ + if (sdebug_dev_is_zoned(devip) && ret > 0) + zbc_inc_wp(devip, lba, + ret >> ilog2(sdebug_sector_size)); if (unlikely(scsi_debug_lbp())) map_region(sip, lba, num); if (unlikely(-1 == ret)) { @@ -5324,11 +5367,13 @@ static int resp_write_scat(struct scsi_cmnd *scp, goto err_out_unlock; } else if (unlikely(sdebug_verbose && (ret < num_by))) sdev_printk(KERN_INFO, scp->device, - "%s: write: cdb indicated=%u, IO sent=%d bytes\n", + "%s: write: cdb indicated=%llu, IO sent=%d bytes\n", my_name, num_by, ret); if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && atomic_read(&sdeb_inject_pending))) { + /* This range has been written */ + sg_off += num_by; if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { mk_sense_buffer(scp, RECOVERED_ERROR, FAILURE_PREDICTION_THRESHOLD_EXCEEDED); @@ -5354,6 +5399,13 @@ static int resp_write_scat(struct scsi_cmnd *scp, } ret = 0; err_out_unlock: + /* + * sg_off counts what the command asked for, which can exceed the + * buffer: lbdof is not validated against it, and a range is counted + * in full even if do_device_access() copied less. + */ + if (scsi_bufflen(scp) > sg_off) + scsi_set_resid(scp, scsi_bufflen(scp) - sg_off); sdeb_meta_write_unlock(sip); err_out: kfree(lrdp); @@ -5374,8 +5426,9 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u8 *fs1p; u8 *fsp; bool meta_data_locked = false; + bool lbp = scsi_debug_lbp(); - if (sdebug_dev_is_zoned(devip) || scsi_debug_lbp()) { + if (sdebug_dev_is_zoned(devip) || lbp) { sdeb_meta_write_lock(sip); meta_data_locked = true; } @@ -5384,7 +5437,7 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, if (ret) goto out; - if (unmap && scsi_debug_lbp()) { + if (unmap && lbp) { unmap_region(sip, lba, num); goto out; } @@ -5414,7 +5467,7 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, block = do_div(lbaa, sdebug_store_sectors); memmove(fsp + (block * lb_size), fs1p, lb_size); } - if (scsi_debug_lbp()) + if (lbp) map_region(sip, lba, num); /* If ZBC zone then bump its write pointer */ if (sdebug_dev_is_zoned(devip)) @@ -5575,8 +5628,8 @@ static int resp_comp_write(struct scsi_cmnd *scp, "indicated=%u, IO sent=%d bytes\n", my_name, dnum * lb_size, ret); - sdeb_data_write_lock(sip); sdeb_meta_write_lock(sip); + sdeb_data_write_lock(sip); if (!comp_write_worker(sip, lba, num, arr, false)) { mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_DURING_VERIFY_OPERATION); @@ -5584,12 +5637,12 @@ static int resp_comp_write(struct scsi_cmnd *scp, goto cleanup_unlock; } - /* Cover sip->map_storep (which map_region()) sets with data lock */ + /* Cover sip->map_storep (which map_region() sets) with the meta lock */ if (scsi_debug_lbp()) map_region(sip, lba, num); cleanup_unlock: - sdeb_meta_write_unlock(sip); sdeb_data_write_unlock(sip); + sdeb_meta_write_unlock(sip); cleanup_free: kfree(arr); return retval; @@ -6158,6 +6211,7 @@ static int resp_atomic_write(struct scsi_cmnd *scp, u8 *cmd = scp->cmnd; u16 boundary, len; u64 lba, lba_tmp; + bool lbp = scsi_debug_lbp(); int ret; if (!scsi_debug_atomic_write()) { @@ -6202,11 +6256,34 @@ static int resp_atomic_write(struct scsi_cmnd *scp, } } + ret = check_device_access_params(scp, lba, len, true); + if (ret) + return ret; + + /* + * Short atomic writes are not allowed: SBC-6 4.28.2 requires an + * atomic write that cannot complete to leave its LBAs unaltered, and + * do_device_access() would already have written part of it. + */ + if (scsi_bufflen(scp) < len * sdebug_sector_size) + return DID_ERROR << 16; + + if (lbp) + sdeb_meta_write_lock(sip); + ret = do_device_access(sip, scp, 0, lba, len, 0, true, true); + if (lbp) { + map_region(sip, lba, len); + sdeb_meta_write_unlock(sip); + } + if (unlikely(ret == -1)) return DID_ERROR << 16; if (unlikely(ret != len * sdebug_sector_size)) return DID_ERROR << 16; + + if (ret < scsi_bufflen(scp)) + scsi_set_resid(scp, scsi_bufflen(scp) - ret); return 0; } @@ -8656,8 +8733,8 @@ static int __init scsi_debug_init(void) return -EINVAL; } - if (sdebug_physblk_exp > 15) { - pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); + if (sdebug_physblk_exp < 0 || sdebug_physblk_exp > 15) { + pr_err("invalid physblk_exp %d\n", sdebug_physblk_exp); return -EINVAL; } @@ -8734,6 +8811,16 @@ static int __init scsi_debug_init(void) sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB; } + if (sdeb_zbc_in_use && sdebug_lowest_aligned) { + pr_err("lowest_aligned is not supported by a zoned device\n"); + return -EINVAL; + } + + if (sdeb_zbc_in_use && sdebug_atomic_wr) { + pr_err("atomic_wr is not supported by a zoned device\n"); + return -EINVAL; + } + if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) sdebug_dev_size_mb = DEF_DEV_SIZE_MB; if (sdebug_dev_size_mb < 1) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 2e0b1909dc69..75442d60c30e 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -270,7 +270,6 @@ scsi_abort_command(struct scsi_cmnd *scmd) spin_lock_irqsave(&shost->host_lock, flags); if (shost->eh_deadline != -1 && !shost->last_reset) shost->last_reset = jiffies; - BUG_ON(!list_empty(&scmd->eh_entry)); list_add_tail(&scmd->eh_entry, &shost->eh_abort_list); spin_unlock_irqrestore(&shost->host_lock, flags); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index db64470f5229..f695a6605815 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1322,7 +1322,6 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd) } cmd->device = dev; - INIT_LIST_HEAD(&cmd->eh_entry); INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler); } @@ -1590,8 +1589,6 @@ static void scsi_complete(struct request *rq) return; } - INIT_LIST_HEAD(&cmd->eh_entry); - atomic_inc(&cmd->device->iodone_cnt); if (cmd->result) atomic_inc(&cmd->device->ioerr_cnt); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 1ca9753cb734..3dc6723e80a8 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -368,6 +368,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) if (ctr != STp->por_ctr) { STp->por_ctr = ctr; STp->pos_unknown = 1; /* ASC => power on / reset */ + /* The reset allowed medium removal; relock at next access */ + STp->door_locked = ST_UNLOCKED; st_printk(KERN_WARNING, STp, "Power on/reset recognized."); } @@ -428,6 +430,7 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) ASC_POWER_ON_RESET_OR_BUS_DEVICE_RESET_OCCURRED && !STp->pos_unknown) { STp->pos_unknown = 1; + STp->door_locked = ST_UNLOCKED; st_printk(KERN_WARNING, STp, "Power on/reset recognized."); } @@ -2688,6 +2691,30 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod else { STp->rew_at_close = STp->autorew_dev; retval = check_tape(STp, filp); + /* + * LOAD leaves the medium at the beginning of partition + * 0. check_tape() records that only for a new session; + * without a new-medium unit attention (the medium was + * already loaded) the partition and the partition state + * would be left as before the load. Reset them as a + * new session does, for all partitions: a stale + * ST_WRITING state would make st_flush() write a + * filemark at the beginning of partition 0. + */ + if (retval == CHKRES_READY) { + int i; + + STp->partition = STp->new_partition = 0; + for (i = 0; i < ST_NBR_PARTITIONS; i++) { + STps = &(STp->ps[i]); + STps->rw = ST_IDLE; + STps->eof = ST_NOEOF; + STps->at_sm = 0; + STps->last_block_valid = 0; + STps->drv_block = 0; + STps->drv_file = 0; + } + } if (retval > 0) retval = 0; } @@ -2941,9 +2968,11 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon direction = DMA_TO_DEVICE; memset((STp->buffer)->b_data, 0, 12); - if (cmd_in == MTSETDRVBUFFER) + if (cmd_in == MTSETDRVBUFFER) { (STp->buffer)->b_data[2] = (arg & 7) << 4; - else + STp->drv_buffer_changed = 1; /* At least we tried ;-) */ + STp->changed_drv_buffer = arg & 7; + } else (STp->buffer)->b_data[2] = STp->drv_buffer << 4; (STp->buffer)->b_data[3] = 8; /* block descriptor length */ @@ -3589,6 +3618,26 @@ out: return retval; } +/* + * Re-apply a drive buffering mode, density and block size that were changed + * by the user before a device reset (a negative value means "not changed"). + * The buffering mode goes first: the other MODE SELECTs send the current + * STp->drv_buffer. A unit attention still pending after the operation + * (e.g. new medium after a load) fails the first MODE SELECT, so retry each + * once. As in the other post-reset restore path, errors are ignored and one + * setting failing does not prevent restoring the others. + */ +static void st_restore_changed_settings(struct scsi_tape *STp, int drv_buffer, + int density, int blksize) +{ + if (drv_buffer >= 0 && st_int_ioctl(STp, MTSETDRVBUFFER, drv_buffer)) + st_int_ioctl(STp, MTSETDRVBUFFER, drv_buffer); + if (density >= 0 && st_int_ioctl(STp, MTSETDENSITY, density)) + st_int_ioctl(STp, MTSETDENSITY, density); + if (blksize >= 0 && st_int_ioctl(STp, MTSETBLK, blksize)) + st_int_ioctl(STp, MTSETBLK, blksize); +} + /* The ioctl command */ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) { @@ -3597,6 +3646,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) int retval = 0; unsigned int blk; bool cmd_mtiocget; + int restore_drv_buffer = -1, restore_density = -1, restore_blksize = -1; struct scsi_tape *STp = file->private_data; struct st_modedef *STm; struct st_partstat *STps; @@ -3739,10 +3789,26 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) STp->partition = 0; switch_partition(STp); } + if (STp->drv_buffer_changed) + st_int_ioctl(STp, MTSETDRVBUFFER, + STp->changed_drv_buffer); if (STp->density_changed) st_int_ioctl(STp, MTSETDENSITY, STp->changed_density); if (STp->blksize_changed) st_int_ioctl(STp, MTSETBLK, STp->changed_blksize); + } else if (mtc.mt_op == MTLOAD || mtc.mt_op == MTRETEN) { + /* + * The same medium ends up at BOT, so the settings + * apply as with MTREW. The operation may start a + * new session, which clears the "changed" flags: + * save the values and restore them afterwards. + */ + if (STp->drv_buffer_changed) + restore_drv_buffer = STp->changed_drv_buffer; + if (STp->density_changed) + restore_density = STp->changed_density; + if (STp->blksize_changed) + restore_blksize = STp->changed_blksize; } } @@ -3822,6 +3888,15 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) if (mtc.mt_op == MTLOAD) { retval = do_load_unload(STp, file, max(1, mtc.mt_count)); + /* + * Restore only if the drive is ready: after an + * immediate-mode load with O_NONBLOCK, check_tape() + * does not wait and the drive may still be loading. + */ + if (!retval && STp->ready == ST_READY) + st_restore_changed_settings(STp, restore_drv_buffer, + restore_density, + restore_blksize); goto out; } @@ -3840,6 +3915,22 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) retval = st_compression(STp, (mtc.mt_count & 1)); else retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count); + if (!retval && mtc.mt_op == MTRETEN && !STp->immediate && + (restore_drv_buffer >= 0 || restore_density >= 0 || + restore_blksize >= 0)) { + /* + * Retension reloads the medium and the drive may + * report a new medium. Let check_tape() start the new + * session (applying the mode defaults) now, as for + * MTLOAD; otherwise it happens at the next open and + * overrides the restored settings. + */ + if (check_tape(STp, file) >= 0 && + STp->ready == ST_READY) + st_restore_changed_settings(STp, restore_drv_buffer, + restore_density, + restore_blksize); + } goto out; } if (!STm->defined) { @@ -4445,7 +4536,7 @@ static int st_probe(struct scsi_device *SDp) tpnt->modes[0].defined = 1; tpnt->density_changed = tpnt->compression_changed = - tpnt->blksize_changed = 0; + tpnt->blksize_changed = tpnt->drv_buffer_changed = 0; mutex_init(&tpnt->lock); idr_preload(GFP_KERNEL); diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 0d7c4b8c2c8a..c580024880c3 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -162,10 +162,12 @@ struct scsi_tape { unsigned char in_use; unsigned char blksize_changed; unsigned char density_changed; + unsigned char drv_buffer_changed; unsigned char compression_changed; unsigned char drv_buffer; unsigned char density; unsigned char changed_density; + unsigned char changed_drv_buffer; unsigned char door_locked; unsigned char autorew_dev; /* auto-rewind device */ unsigned char rew_at_close; /* rewind necessary at close */ diff --git a/drivers/ufs/core/ufs-rpmb.c b/drivers/ufs/core/ufs-rpmb.c index 50ef63afd528..65f2d71cf073 100644 --- a/drivers/ufs/core/ufs-rpmb.c +++ b/drivers/ufs/core/ufs-rpmb.c @@ -47,7 +47,8 @@ static int ufs_sec_submit(struct ufs_hba *hba, u16 spsp, void *buffer, size_t le { .sense_key = UNIT_ATTENTION, .sense_code = - POWER_ON_RESET_OR_BUS_DEVICE_RESET_OCCURRED, + scsi_sense_code(ASC_POWER_ON_RESET_OR_BUS_DEVICE_RESET_OCCURRED, + SCMD_FAILURE_ASCQ_ANY), .allowed = UFS_RPMB_UA_RETRIES, .result = SAM_STAT_CHECK_CONDITION, }, |
