Commit 8f2975c2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ata fixes from Damien Le Moal:
 "Several libata generic code fixes for rc5:

   - Add missing translation of the SYNCHRONIZE CACHE 16 scsi command as
     this command is mandatory for host-managed ZBC drives.

     The lack of support for it in libata-scsi was causing issues with
     some passthrough applications using ZBC drives (from Shin'ichiro).

   - Fix the error path of libata-transport host, port, link and device
     attributes initialization (from Yingliang).

   - Prevent issuing new commands to a drive that is in the NCQ error
     state and undergoing recovery (From Niklas).

     This bug went unnoticed for a long time as commands issued to a
     drive in error state are aborted immediately and retried by the
     scsi layer, hiding the useless abort-and-retry sequence"

* tag 'ata-6.1-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata:
  ata: libata-core: do not issue non-internal commands once EH is pending
  ata: libata-transport: fix error handling in ata_tdev_add()
  ata: libata-transport: fix error handling in ata_tlink_add()
  ata: libata-transport: fix error handling in ata_tport_add()
  ata: libata-transport: fix double ata_host_put() in ata_tport_add()
  ata: libata-scsi: fix SYNCHRONIZE CACHE (16) command failure
parents d7c2b1f6 e20e81a2
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -3264,6 +3264,7 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
	case REPORT_LUNS:
	case REQUEST_SENSE:
	case SYNCHRONIZE_CACHE:
	case SYNCHRONIZE_CACHE_16:
	case REZERO_UNIT:
	case SEEK_6:
	case SEEK_10:
@@ -3922,6 +3923,7 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
		return ata_scsi_write_same_xlat;

	case SYNCHRONIZE_CACHE:
	case SYNCHRONIZE_CACHE_16:
		if (ata_try_flush_cache(dev))
			return ata_scsi_flush_xlat;
		break;
@@ -3962,9 +3964,19 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)

int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev)
{
	struct ata_port *ap = dev->link->ap;
	u8 scsi_op = scmd->cmnd[0];
	ata_xlat_func_t xlat_func;

	/*
	 * scsi_queue_rq() will defer commands if scsi_host_in_recovery().
	 * However, this check is done without holding the ap->lock (a libata
	 * specific lock), so we can have received an error irq since then,
	 * therefore we must check if EH is pending, while holding ap->lock.
	 */
	if (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS))
		return SCSI_MLQUEUE_DEVICE_BUSY;

	if (unlikely(!scmd->cmd_len))
		goto bad_cdb_len;

@@ -4145,6 +4157,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
	 * turning this into a no-op.
	 */
	case SYNCHRONIZE_CACHE:
	case SYNCHRONIZE_CACHE_16:
		fallthrough;

	/* no-op's, complete with success */
+15 −4
Original line number Diff line number Diff line
@@ -301,7 +301,9 @@ int ata_tport_add(struct device *parent,
	pm_runtime_enable(dev);
	pm_runtime_forbid(dev);

	transport_add_device(dev);
	error = transport_add_device(dev);
	if (error)
		goto tport_transport_add_err;
	transport_configure_device(dev);

	error = ata_tlink_add(&ap->link);
@@ -312,12 +314,12 @@ int ata_tport_add(struct device *parent,

 tport_link_err:
	transport_remove_device(dev);
 tport_transport_add_err:
	device_del(dev);

 tport_err:
	transport_destroy_device(dev);
	put_device(dev);
	ata_host_put(ap->host);
	return error;
}

@@ -456,7 +458,9 @@ int ata_tlink_add(struct ata_link *link)
		goto tlink_err;
	}

	transport_add_device(dev);
	error = transport_add_device(dev);
	if (error)
		goto tlink_transport_err;
	transport_configure_device(dev);

	ata_for_each_dev(ata_dev, link, ALL) {
@@ -471,6 +475,7 @@ int ata_tlink_add(struct ata_link *link)
		ata_tdev_delete(ata_dev);
	}
	transport_remove_device(dev);
  tlink_transport_err:
	device_del(dev);
  tlink_err:
	transport_destroy_device(dev);
@@ -708,7 +713,13 @@ static int ata_tdev_add(struct ata_device *ata_dev)
		return error;
	}

	transport_add_device(dev);
	error = transport_add_device(dev);
	if (error) {
		device_del(dev);
		ata_tdev_free(ata_dev);
		return error;
	}

	transport_configure_device(dev);
	return 0;
}