Loading drivers/scsi/scsi_scan.c +38 −10 Original line number Diff line number Diff line Loading @@ -400,6 +400,35 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, return found_target; } struct work_queue_wrapper { struct work_struct work; struct scsi_target *starget; }; static void scsi_target_reap_work(void *data) { struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; struct scsi_target *starget = wqw->starget; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); unsigned long flags; kfree(wqw); spin_lock_irqsave(shost->host_lock, flags); if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { list_del_init(&starget->siblings); spin_unlock_irqrestore(shost->host_lock, flags); device_del(&starget->dev); transport_unregister_device(&starget->dev); put_device(&starget->dev); return; } spin_unlock_irqrestore(shost->host_lock, flags); return; } /** * scsi_target_reap - check to see if target is in use and destroy if not * Loading @@ -411,19 +440,18 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, */ void scsi_target_reap(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); unsigned long flags; spin_lock_irqsave(shost->host_lock, flags); struct work_queue_wrapper *wqw = kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { list_del_init(&starget->siblings); spin_unlock_irqrestore(shost->host_lock, flags); device_del(&starget->dev); transport_unregister_device(&starget->dev); put_device(&starget->dev); if (!wqw) { starget_printk(KERN_ERR, starget, "Failed to allocate memory in scsi_reap_target()\n"); return; } spin_unlock_irqrestore(shost->host_lock, flags); INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); wqw->starget = starget; schedule_work(&wqw->work); } /** Loading drivers/scsi/scsi_transport_fc.c +55 −4 Original line number Diff line number Diff line Loading @@ -105,6 +105,7 @@ static struct { { FC_PORTSTATE_LINKDOWN, "Linkdown" }, { FC_PORTSTATE_ERROR, "Error" }, { FC_PORTSTATE_LOOPBACK, "Loopback" }, { FC_PORTSTATE_DELETED, "Deleted" }, }; fc_enum_name_search(port_state, fc_port_state, fc_port_state_names) #define FC_PORTSTATE_MAX_NAMELEN 20 Loading Loading @@ -211,6 +212,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) #define FC_MGMTSRVR_PORTID 0x00000a static void fc_shost_remove_rports(void *data); static void fc_timeout_deleted_rport(void *data); static void fc_scsi_scan_rport(void *data); static void fc_rport_terminate(struct fc_rport *rport); Loading Loading @@ -318,6 +320,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, fc_host_next_rport_number(shost) = 0; fc_host_next_target_id(shost) = 0; fc_host_flags(shost) = 0; INIT_WORK(&fc_host_rport_del_work(shost), fc_shost_remove_rports, shost); return 0; } Loading Loading @@ -387,6 +391,7 @@ show_fc_rport_##field (struct class_device *cdev, char *buf) \ struct fc_internal *i = to_fc_internal(shost->transportt); \ if ((i->f->get_rport_##field) && \ !((rport->port_state == FC_PORTSTATE_BLOCKED) || \ (rport->port_state == FC_PORTSTATE_DELETED) || \ (rport->port_state == FC_PORTSTATE_NOTPRESENT))) \ i->f->get_rport_##field(rport); \ return snprintf(buf, sz, format_string, cast rport->field); \ Loading @@ -402,6 +407,7 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \ struct Scsi_Host *shost = rport_to_shost(rport); \ struct fc_internal *i = to_fc_internal(shost->transportt); \ if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ (rport->port_state == FC_PORTSTATE_DELETED) || \ (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ return -EBUSY; \ val = simple_strtoul(buf, NULL, 0); \ Loading Loading @@ -519,6 +525,7 @@ store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf, struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); if ((rport->port_state == FC_PORTSTATE_BLOCKED) || (rport->port_state == FC_PORTSTATE_DELETED) || (rport->port_state == FC_PORTSTATE_NOTPRESENT)) return -EBUSY; val = simple_strtoul(buf, NULL, 0); Loading Loading @@ -1769,7 +1776,7 @@ fc_timeout_deleted_rport(void *data) rport->maxframe_size = -1; rport->supported_classes = FC_COS_UNSPECIFIED; rport->roles = FC_RPORT_ROLE_UNKNOWN; rport->port_state = FC_PORTSTATE_NOTPRESENT; rport->port_state = FC_PORTSTATE_DELETED; /* remove the identifiers that aren't used in the consisting binding */ switch (fc_host_tgtid_bind_type(shost)) { Loading @@ -1789,14 +1796,23 @@ fc_timeout_deleted_rport(void *data) break; } spin_unlock_irqrestore(shost->host_lock, flags); /* * As this only occurs if the remote port (scsi target) * went away and didn't come back - we'll remove * all attached scsi devices. * * We'll schedule the shost work item to perform the actual removal * to avoid recursion in the different flush calls if we perform * the removal in each target - and there are lots of targets * whose timeouts fire at the same time. */ fc_rport_tgt_remove(rport); if ( !(fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED)) { fc_host_flags(shost) |= FC_SHOST_RPORT_DEL_SCHEDULED; scsi_queue_work(shost, &fc_host_rport_del_work(shost)); } spin_unlock_irqrestore(shost->host_lock, flags); } /** Loading @@ -1818,6 +1834,41 @@ fc_scsi_scan_rport(void *data) } /** * fc_shost_remove_rports - called to remove all rports that are marked * as in a deleted (not connected) state. * * @data: shost whose rports are to be looked at **/ static void fc_shost_remove_rports(void *data) { struct Scsi_Host *shost = (struct Scsi_Host *)data; struct fc_rport *rport, *next_rport; unsigned long flags; spin_lock_irqsave(shost->host_lock, flags); while (fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED) { fc_host_flags(shost) &= ~FC_SHOST_RPORT_DEL_SCHEDULED; restart_search: list_for_each_entry_safe(rport, next_rport, &fc_host_rport_bindings(shost), peers) { if (rport->port_state == FC_PORTSTATE_DELETED) { rport->port_state = FC_PORTSTATE_NOTPRESENT; spin_unlock_irqrestore(shost->host_lock, flags); fc_rport_tgt_remove(rport); spin_lock_irqsave(shost->host_lock, flags); goto restart_search; } } } spin_unlock_irqrestore(shost->host_lock, flags); } MODULE_AUTHOR("Martin Hicks"); MODULE_DESCRIPTION("FC Transport Attributes"); MODULE_LICENSE("GPL"); Loading include/scsi/scsi_transport_fc.h +11 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ enum fc_port_state { FC_PORTSTATE_LINKDOWN, FC_PORTSTATE_ERROR, FC_PORTSTATE_LOOPBACK, FC_PORTSTATE_DELETED, }; Loading Loading @@ -325,8 +326,14 @@ struct fc_host_attrs { struct list_head rport_bindings; u32 next_rport_number; u32 next_target_id; u8 flags; struct work_struct rport_del_work; }; /* values for struct fc_host_attrs "flags" field: */ #define FC_SHOST_RPORT_DEL_SCHEDULED 0x01 #define fc_host_node_name(x) \ (((struct fc_host_attrs *)(x)->shost_data)->node_name) #define fc_host_port_name(x) \ Loading Loading @@ -365,6 +372,10 @@ struct fc_host_attrs { (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number) #define fc_host_next_target_id(x) \ (((struct fc_host_attrs *)(x)->shost_data)->next_target_id) #define fc_host_flags(x) \ (((struct fc_host_attrs *)(x)->shost_data)->flags) #define fc_host_rport_del_work(x) \ (((struct fc_host_attrs *)(x)->shost_data)->rport_del_work) /* The functions by which the transport class and the driver communicate */ Loading Loading
drivers/scsi/scsi_scan.c +38 −10 Original line number Diff line number Diff line Loading @@ -400,6 +400,35 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, return found_target; } struct work_queue_wrapper { struct work_struct work; struct scsi_target *starget; }; static void scsi_target_reap_work(void *data) { struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; struct scsi_target *starget = wqw->starget; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); unsigned long flags; kfree(wqw); spin_lock_irqsave(shost->host_lock, flags); if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { list_del_init(&starget->siblings); spin_unlock_irqrestore(shost->host_lock, flags); device_del(&starget->dev); transport_unregister_device(&starget->dev); put_device(&starget->dev); return; } spin_unlock_irqrestore(shost->host_lock, flags); return; } /** * scsi_target_reap - check to see if target is in use and destroy if not * Loading @@ -411,19 +440,18 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, */ void scsi_target_reap(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); unsigned long flags; spin_lock_irqsave(shost->host_lock, flags); struct work_queue_wrapper *wqw = kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { list_del_init(&starget->siblings); spin_unlock_irqrestore(shost->host_lock, flags); device_del(&starget->dev); transport_unregister_device(&starget->dev); put_device(&starget->dev); if (!wqw) { starget_printk(KERN_ERR, starget, "Failed to allocate memory in scsi_reap_target()\n"); return; } spin_unlock_irqrestore(shost->host_lock, flags); INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); wqw->starget = starget; schedule_work(&wqw->work); } /** Loading
drivers/scsi/scsi_transport_fc.c +55 −4 Original line number Diff line number Diff line Loading @@ -105,6 +105,7 @@ static struct { { FC_PORTSTATE_LINKDOWN, "Linkdown" }, { FC_PORTSTATE_ERROR, "Error" }, { FC_PORTSTATE_LOOPBACK, "Loopback" }, { FC_PORTSTATE_DELETED, "Deleted" }, }; fc_enum_name_search(port_state, fc_port_state, fc_port_state_names) #define FC_PORTSTATE_MAX_NAMELEN 20 Loading Loading @@ -211,6 +212,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) #define FC_MGMTSRVR_PORTID 0x00000a static void fc_shost_remove_rports(void *data); static void fc_timeout_deleted_rport(void *data); static void fc_scsi_scan_rport(void *data); static void fc_rport_terminate(struct fc_rport *rport); Loading Loading @@ -318,6 +320,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, fc_host_next_rport_number(shost) = 0; fc_host_next_target_id(shost) = 0; fc_host_flags(shost) = 0; INIT_WORK(&fc_host_rport_del_work(shost), fc_shost_remove_rports, shost); return 0; } Loading Loading @@ -387,6 +391,7 @@ show_fc_rport_##field (struct class_device *cdev, char *buf) \ struct fc_internal *i = to_fc_internal(shost->transportt); \ if ((i->f->get_rport_##field) && \ !((rport->port_state == FC_PORTSTATE_BLOCKED) || \ (rport->port_state == FC_PORTSTATE_DELETED) || \ (rport->port_state == FC_PORTSTATE_NOTPRESENT))) \ i->f->get_rport_##field(rport); \ return snprintf(buf, sz, format_string, cast rport->field); \ Loading @@ -402,6 +407,7 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \ struct Scsi_Host *shost = rport_to_shost(rport); \ struct fc_internal *i = to_fc_internal(shost->transportt); \ if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ (rport->port_state == FC_PORTSTATE_DELETED) || \ (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ return -EBUSY; \ val = simple_strtoul(buf, NULL, 0); \ Loading Loading @@ -519,6 +525,7 @@ store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf, struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); if ((rport->port_state == FC_PORTSTATE_BLOCKED) || (rport->port_state == FC_PORTSTATE_DELETED) || (rport->port_state == FC_PORTSTATE_NOTPRESENT)) return -EBUSY; val = simple_strtoul(buf, NULL, 0); Loading Loading @@ -1769,7 +1776,7 @@ fc_timeout_deleted_rport(void *data) rport->maxframe_size = -1; rport->supported_classes = FC_COS_UNSPECIFIED; rport->roles = FC_RPORT_ROLE_UNKNOWN; rport->port_state = FC_PORTSTATE_NOTPRESENT; rport->port_state = FC_PORTSTATE_DELETED; /* remove the identifiers that aren't used in the consisting binding */ switch (fc_host_tgtid_bind_type(shost)) { Loading @@ -1789,14 +1796,23 @@ fc_timeout_deleted_rport(void *data) break; } spin_unlock_irqrestore(shost->host_lock, flags); /* * As this only occurs if the remote port (scsi target) * went away and didn't come back - we'll remove * all attached scsi devices. * * We'll schedule the shost work item to perform the actual removal * to avoid recursion in the different flush calls if we perform * the removal in each target - and there are lots of targets * whose timeouts fire at the same time. */ fc_rport_tgt_remove(rport); if ( !(fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED)) { fc_host_flags(shost) |= FC_SHOST_RPORT_DEL_SCHEDULED; scsi_queue_work(shost, &fc_host_rport_del_work(shost)); } spin_unlock_irqrestore(shost->host_lock, flags); } /** Loading @@ -1818,6 +1834,41 @@ fc_scsi_scan_rport(void *data) } /** * fc_shost_remove_rports - called to remove all rports that are marked * as in a deleted (not connected) state. * * @data: shost whose rports are to be looked at **/ static void fc_shost_remove_rports(void *data) { struct Scsi_Host *shost = (struct Scsi_Host *)data; struct fc_rport *rport, *next_rport; unsigned long flags; spin_lock_irqsave(shost->host_lock, flags); while (fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED) { fc_host_flags(shost) &= ~FC_SHOST_RPORT_DEL_SCHEDULED; restart_search: list_for_each_entry_safe(rport, next_rport, &fc_host_rport_bindings(shost), peers) { if (rport->port_state == FC_PORTSTATE_DELETED) { rport->port_state = FC_PORTSTATE_NOTPRESENT; spin_unlock_irqrestore(shost->host_lock, flags); fc_rport_tgt_remove(rport); spin_lock_irqsave(shost->host_lock, flags); goto restart_search; } } } spin_unlock_irqrestore(shost->host_lock, flags); } MODULE_AUTHOR("Martin Hicks"); MODULE_DESCRIPTION("FC Transport Attributes"); MODULE_LICENSE("GPL"); Loading
include/scsi/scsi_transport_fc.h +11 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ enum fc_port_state { FC_PORTSTATE_LINKDOWN, FC_PORTSTATE_ERROR, FC_PORTSTATE_LOOPBACK, FC_PORTSTATE_DELETED, }; Loading Loading @@ -325,8 +326,14 @@ struct fc_host_attrs { struct list_head rport_bindings; u32 next_rport_number; u32 next_target_id; u8 flags; struct work_struct rport_del_work; }; /* values for struct fc_host_attrs "flags" field: */ #define FC_SHOST_RPORT_DEL_SCHEDULED 0x01 #define fc_host_node_name(x) \ (((struct fc_host_attrs *)(x)->shost_data)->node_name) #define fc_host_port_name(x) \ Loading Loading @@ -365,6 +372,10 @@ struct fc_host_attrs { (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number) #define fc_host_next_target_id(x) \ (((struct fc_host_attrs *)(x)->shost_data)->next_target_id) #define fc_host_flags(x) \ (((struct fc_host_attrs *)(x)->shost_data)->flags) #define fc_host_rport_del_work(x) \ (((struct fc_host_attrs *)(x)->shost_data)->rport_del_work) /* The functions by which the transport class and the driver communicate */ Loading