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

Commit b3d6e151 authored by Kristian Høgsberg's avatar Kristian Høgsberg Committed by Stefan Richter
Browse files

firewire: Add ref-counting for sbp2_device and hold a ref while we have work scheduled.

parent 7e35f7f3
Loading
Loading
Loading
Loading
+30 −12
Original line number Original line Diff line number Diff line
@@ -51,6 +51,7 @@ typedef void (*scsi_done_fn_t) (struct scsi_cmnd *);
static const char sbp2_driver_name[] = "sbp2";
static const char sbp2_driver_name[] = "sbp2";


struct sbp2_device {
struct sbp2_device {
	struct kref kref;
	struct fw_unit *unit;
	struct fw_unit *unit;
	struct fw_address_handler address_handler;
	struct fw_address_handler address_handler;
	struct list_head orb_list;
	struct list_head orb_list;
@@ -513,6 +514,22 @@ static int add_scsi_devices(struct fw_unit *unit);
static void remove_scsi_devices(struct fw_unit *unit);
static void remove_scsi_devices(struct fw_unit *unit);
static void sbp2_reconnect(struct work_struct *work);
static void sbp2_reconnect(struct work_struct *work);


static void
release_sbp2_device(struct kref *kref)
{
	struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref);

	sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation,
				 SBP2_LOGOUT_REQUEST, sd->login_id, NULL);

	remove_scsi_devices(sd->unit);

	fw_core_remove_address_handler(&sd->address_handler);
	fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id);
	put_device(&sd->unit->device);
	kfree(sd);
}

static void sbp2_login(struct work_struct *work)
static void sbp2_login(struct work_struct *work)
{
{
	struct sbp2_device *sd =
	struct sbp2_device *sd =
@@ -537,6 +554,7 @@ static void sbp2_login(struct work_struct *work)
			fw_error("failed to login to %s\n",
			fw_error("failed to login to %s\n",
				 unit->device.bus_id);
				 unit->device.bus_id);
			remove_scsi_devices(unit);
			remove_scsi_devices(unit);
			kref_put(&sd->kref, release_sbp2_device);
		}
		}
		return;
		return;
	}
	}
@@ -577,6 +595,7 @@ static void sbp2_login(struct work_struct *work)
		 * retry login on bus reset. */
		 * retry login on bus reset. */
		PREPARE_DELAYED_WORK(&sd->work, sbp2_login);
		PREPARE_DELAYED_WORK(&sd->work, sbp2_login);
	}
	}
	kref_put(&sd->kref, release_sbp2_device);
}
}


static int sbp2_probe(struct device *dev)
static int sbp2_probe(struct device *dev)
@@ -595,6 +614,7 @@ static int sbp2_probe(struct device *dev)
	unit->device.driver_data = sd;
	unit->device.driver_data = sd;
	sd->unit = unit;
	sd->unit = unit;
	INIT_LIST_HEAD(&sd->orb_list);
	INIT_LIST_HEAD(&sd->orb_list);
	kref_init(&sd->kref);


	sd->address_handler.length = 0x100;
	sd->address_handler.length = 0x100;
	sd->address_handler.address_callback = sbp2_status_write;
	sd->address_handler.address_callback = sbp2_status_write;
@@ -650,10 +670,14 @@ static int sbp2_probe(struct device *dev)
			  unit->device.bus_id,
			  unit->device.bus_id,
			  sd->workarounds, firmware_revision, model);
			  sd->workarounds, firmware_revision, model);


	get_device(&unit->device);

	/* We schedule work to do the login so we can easily
	/* We schedule work to do the login so we can easily
	 * reschedule retries. */
	 * reschedule retries. Always get the ref before scheduling
	 * work.*/
	INIT_DELAYED_WORK(&sd->work, sbp2_login);
	INIT_DELAYED_WORK(&sd->work, sbp2_login);
	schedule_delayed_work(&sd->work, 0);
	if (schedule_delayed_work(&sd->work, 0))
		kref_get(&sd->kref);


	return 0;
	return 0;
}
}
@@ -663,15 +687,7 @@ static int sbp2_remove(struct device *dev)
	struct fw_unit *unit = fw_unit(dev);
	struct fw_unit *unit = fw_unit(dev);
	struct sbp2_device *sd = unit->device.driver_data;
	struct sbp2_device *sd = unit->device.driver_data;


	sbp2_send_management_orb(unit, sd->node_id, sd->generation,
	kref_put(&sd->kref, release_sbp2_device);
				 SBP2_LOGOUT_REQUEST, sd->login_id, NULL);

	remove_scsi_devices(unit);

	fw_core_remove_address_handler(&sd->address_handler);
	kfree(sd);

	fw_notify("removed sbp2 unit %s\n", dev->bus_id);


	return 0;
	return 0;
}
}
@@ -710,6 +726,7 @@ static void sbp2_reconnect(struct work_struct *work)
		  unit->device.bus_id, sd->retries);
		  unit->device.bus_id, sd->retries);
	sbp2_agent_reset(unit);
	sbp2_agent_reset(unit);
	sbp2_cancel_orbs(unit);
	sbp2_cancel_orbs(unit);
	kref_put(&sd->kref, release_sbp2_device);
}
}


static void sbp2_update(struct fw_unit *unit)
static void sbp2_update(struct fw_unit *unit)
@@ -719,7 +736,8 @@ static void sbp2_update(struct fw_unit *unit)


	sd->retries = 0;
	sd->retries = 0;
	fw_device_enable_phys_dma(device);
	fw_device_enable_phys_dma(device);
	schedule_delayed_work(&sd->work, 0);
	if (schedule_delayed_work(&sd->work, 0))
		kref_get(&sd->kref);
}
}


#define SBP2_UNIT_SPEC_ID_ENTRY	0x0000609e
#define SBP2_UNIT_SPEC_ID_ENTRY	0x0000609e