Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e80de370 authored by Stefan Richter's avatar Stefan Richter
Browse files

firewire: fw-sbp2: enforce a retry of __scsi_add_device if bus generation changed



fw-sbp2 is unable to reconnect while performing __scsi_add_device
because there is only a single workqueue thread context available for
both at the moment.  This should be fixed eventually.

An actual failure of __scsi_add_device is easy to handle, but an
incomplete execution of __scsi_add_device with an sdev returned would
remain undetected and leave the SBP-2 target unusable.

Therefore we use a workaround:  If there was a bus reset during
__scsi_add_device (i.e. during the SCSI probe), we remove the new sdev
immediately, log out, and attempt login and SCSI probe again.

Tested-by: Jarod Wilson <jwilson@redhat.com> (earlier version)
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent 7bb6bf7c
Loading
Loading
Loading
Loading
+35 −14
Original line number Diff line number Diff line
@@ -762,7 +762,32 @@ static void sbp2_login(struct work_struct *work)

	sdev = __scsi_add_device(shost, 0, 0,
				 scsilun_to_int(&eight_bytes_lun), lu);
	if (IS_ERR(sdev)) {
	/*
	 * FIXME:  We are unable to perform reconnects while in sbp2_login().
	 * Therefore __scsi_add_device() will get into trouble if a bus reset
	 * happens in parallel.  It will either fail or leave us with an
	 * unusable sdev.  As a workaround we check for this and retry the
	 * whole login and SCSI probing.
	 */

	/* Reported error during __scsi_add_device() */
	if (IS_ERR(sdev))
		goto out_logout_login;

	scsi_device_put(sdev);

	/* Unreported error during __scsi_add_device() */
	smp_rmb(); /* get current card generation */
	if (generation != device->card->generation) {
		scsi_remove_device(sdev);
		goto out_logout_login;
	}

	/* No error during __scsi_add_device() */
	lu->sdev = sdev;
	goto out;

 out_logout_login:
	smp_rmb(); /* generation may have changed */
	generation = device->generation;
	smp_rmb(); /* node_id must not be older than generation */
@@ -770,14 +795,10 @@ static void sbp2_login(struct work_struct *work)
	sbp2_send_management_orb(lu, device->node_id, generation,
				 SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
	/*
		 * Set this back to sbp2_login so we fall back and
		 * retry login on bus reset.
	 * If a bus reset happened, sbp2_update will have requeued
	 * lu->work already.  Reset the work from reconnect to login.
	 */
	PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
	} else {
		lu->sdev = sdev;
		scsi_device_put(sdev);
	}
 out:
	sbp2_target_put(tgt);
}