diff options
Diffstat (limited to 'drivers/firewire/fw-sbp2.c')
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 134 |
1 files changed, 50 insertions, 84 deletions
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 282e4066e8c6..c6fd7d353685 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c | |||
@@ -74,7 +74,6 @@ struct sbp2_device { | |||
74 | 74 | ||
75 | int retries; | 75 | int retries; |
76 | struct delayed_work work; | 76 | struct delayed_work work; |
77 | struct Scsi_Host *scsi_host; | ||
78 | }; | 77 | }; |
79 | 78 | ||
80 | #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 | 79 | #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 |
@@ -519,30 +518,32 @@ static int sbp2_agent_reset(struct fw_unit *unit) | |||
519 | return 0; | 518 | return 0; |
520 | } | 519 | } |
521 | 520 | ||
522 | static int add_scsi_devices(struct fw_unit *unit); | ||
523 | static void remove_scsi_devices(struct fw_unit *unit); | ||
524 | static void sbp2_reconnect(struct work_struct *work); | 521 | static void sbp2_reconnect(struct work_struct *work); |
522 | static struct scsi_host_template scsi_driver_template; | ||
525 | 523 | ||
526 | static void | 524 | static void |
527 | release_sbp2_device(struct kref *kref) | 525 | release_sbp2_device(struct kref *kref) |
528 | { | 526 | { |
529 | struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref); | 527 | struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref); |
528 | struct Scsi_Host *host = | ||
529 | container_of((void *)sd, struct Scsi_Host, hostdata[0]); | ||
530 | 530 | ||
531 | sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation, | 531 | sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation, |
532 | SBP2_LOGOUT_REQUEST, sd->login_id, NULL); | 532 | SBP2_LOGOUT_REQUEST, sd->login_id, NULL); |
533 | 533 | ||
534 | remove_scsi_devices(sd->unit); | 534 | scsi_remove_host(host); |
535 | |||
536 | fw_core_remove_address_handler(&sd->address_handler); | 535 | fw_core_remove_address_handler(&sd->address_handler); |
537 | fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id); | 536 | fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id); |
538 | put_device(&sd->unit->device); | 537 | put_device(&sd->unit->device); |
539 | kfree(sd); | 538 | scsi_host_put(host); |
540 | } | 539 | } |
541 | 540 | ||
542 | static void sbp2_login(struct work_struct *work) | 541 | static void sbp2_login(struct work_struct *work) |
543 | { | 542 | { |
544 | struct sbp2_device *sd = | 543 | struct sbp2_device *sd = |
545 | container_of(work, struct sbp2_device, work.work); | 544 | container_of(work, struct sbp2_device, work.work); |
545 | struct Scsi_Host *host = | ||
546 | container_of((void *)sd, struct Scsi_Host, hostdata[0]); | ||
546 | struct fw_unit *unit = sd->unit; | 547 | struct fw_unit *unit = sd->unit; |
547 | struct fw_device *device = fw_device(unit->device.parent); | 548 | struct fw_device *device = fw_device(unit->device.parent); |
548 | struct sbp2_login_response response; | 549 | struct sbp2_login_response response; |
@@ -562,7 +563,6 @@ static void sbp2_login(struct work_struct *work) | |||
562 | } else { | 563 | } else { |
563 | fw_error("failed to login to %s\n", | 564 | fw_error("failed to login to %s\n", |
564 | unit->device.bus_id); | 565 | unit->device.bus_id); |
565 | remove_scsi_devices(unit); | ||
566 | kref_put(&sd->kref, release_sbp2_device); | 566 | kref_put(&sd->kref, release_sbp2_device); |
567 | } | 567 | } |
568 | return; | 568 | return; |
@@ -595,7 +595,9 @@ static void sbp2_login(struct work_struct *work) | |||
595 | PREPARE_DELAYED_WORK(&sd->work, sbp2_reconnect); | 595 | PREPARE_DELAYED_WORK(&sd->work, sbp2_reconnect); |
596 | sbp2_agent_reset(unit); | 596 | sbp2_agent_reset(unit); |
597 | 597 | ||
598 | retval = add_scsi_devices(unit); | 598 | /* FIXME: Loop over luns here. */ |
599 | lun = 0; | ||
600 | retval = scsi_add_device(host, 0, 0, lun); | ||
599 | if (retval < 0) { | 601 | if (retval < 0) { |
600 | sbp2_send_management_orb(unit, sd->node_id, sd->generation, | 602 | sbp2_send_management_orb(unit, sd->node_id, sd->generation, |
601 | SBP2_LOGOUT_REQUEST, sd->login_id, | 603 | SBP2_LOGOUT_REQUEST, sd->login_id, |
@@ -615,13 +617,16 @@ static int sbp2_probe(struct device *dev) | |||
615 | struct fw_device *device = fw_device(unit->device.parent); | 617 | struct fw_device *device = fw_device(unit->device.parent); |
616 | struct sbp2_device *sd; | 618 | struct sbp2_device *sd; |
617 | struct fw_csr_iterator ci; | 619 | struct fw_csr_iterator ci; |
618 | int i, key, value; | 620 | struct Scsi_Host *host; |
621 | int i, key, value, err; | ||
619 | u32 model, firmware_revision; | 622 | u32 model, firmware_revision; |
620 | 623 | ||
621 | sd = kzalloc(sizeof *sd, GFP_KERNEL); | 624 | err = -ENOMEM; |
622 | if (sd == NULL) | 625 | host = scsi_host_alloc(&scsi_driver_template, sizeof(*sd)); |
623 | return -ENOMEM; | 626 | if (host == NULL) |
627 | goto fail; | ||
624 | 628 | ||
629 | sd = (struct sbp2_device *) host->hostdata; | ||
625 | unit->device.driver_data = sd; | 630 | unit->device.driver_data = sd; |
626 | sd->unit = unit; | 631 | sd->unit = unit; |
627 | INIT_LIST_HEAD(&sd->orb_list); | 632 | INIT_LIST_HEAD(&sd->orb_list); |
@@ -631,17 +636,18 @@ static int sbp2_probe(struct device *dev) | |||
631 | sd->address_handler.address_callback = sbp2_status_write; | 636 | sd->address_handler.address_callback = sbp2_status_write; |
632 | sd->address_handler.callback_data = sd; | 637 | sd->address_handler.callback_data = sd; |
633 | 638 | ||
634 | if (fw_core_add_address_handler(&sd->address_handler, | 639 | err = fw_core_add_address_handler(&sd->address_handler, |
635 | &fw_high_memory_region) < 0) { | 640 | &fw_high_memory_region); |
636 | kfree(sd); | 641 | if (err < 0) |
637 | return -EBUSY; | 642 | goto fail_host; |
638 | } | ||
639 | 643 | ||
640 | if (fw_device_enable_phys_dma(device) < 0) { | 644 | err = fw_device_enable_phys_dma(device); |
641 | fw_core_remove_address_handler(&sd->address_handler); | 645 | if (err < 0) |
642 | kfree(sd); | 646 | goto fail_address_handler; |
643 | return -EBUSY; | 647 | |
644 | } | 648 | err = scsi_add_host(host, &unit->device); |
649 | if (err < 0) | ||
650 | goto fail_address_handler; | ||
645 | 651 | ||
646 | /* | 652 | /* |
647 | * Scan unit directory to get management agent address, | 653 | * Scan unit directory to get management agent address, |
@@ -695,6 +701,13 @@ static int sbp2_probe(struct device *dev) | |||
695 | kref_get(&sd->kref); | 701 | kref_get(&sd->kref); |
696 | 702 | ||
697 | return 0; | 703 | return 0; |
704 | |||
705 | fail_address_handler: | ||
706 | fw_core_remove_address_handler(&sd->address_handler); | ||
707 | fail_host: | ||
708 | scsi_host_put(host); | ||
709 | fail: | ||
710 | return err; | ||
698 | } | 711 | } |
699 | 712 | ||
700 | static int sbp2_remove(struct device *dev) | 713 | static int sbp2_remove(struct device *dev) |
@@ -881,10 +894,10 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) | |||
881 | 894 | ||
882 | static void sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) | 895 | static void sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) |
883 | { | 896 | { |
884 | struct fw_unit *unit = | 897 | struct sbp2_device *sd = |
885 | (struct fw_unit *)orb->cmd->device->host->hostdata[0]; | 898 | (struct sbp2_device *)orb->cmd->device->host->hostdata; |
899 | struct fw_unit *unit = sd->unit; | ||
886 | struct fw_device *device = fw_device(unit->device.parent); | 900 | struct fw_device *device = fw_device(unit->device.parent); |
887 | struct sbp2_device *sd = unit->device.driver_data; | ||
888 | struct scatterlist *sg; | 901 | struct scatterlist *sg; |
889 | int sg_len, l, i, j, count; | 902 | int sg_len, l, i, j, count; |
890 | size_t size; | 903 | size_t size; |
@@ -950,10 +963,10 @@ static void sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) | |||
950 | 963 | ||
951 | static void sbp2_command_orb_map_buffer(struct sbp2_command_orb *orb) | 964 | static void sbp2_command_orb_map_buffer(struct sbp2_command_orb *orb) |
952 | { | 965 | { |
953 | struct fw_unit *unit = | 966 | struct sbp2_device *sd = |
954 | (struct fw_unit *)orb->cmd->device->host->hostdata[0]; | 967 | (struct sbp2_device *)orb->cmd->device->host->hostdata; |
968 | struct fw_unit *unit = sd->unit; | ||
955 | struct fw_device *device = fw_device(unit->device.parent); | 969 | struct fw_device *device = fw_device(unit->device.parent); |
956 | struct sbp2_device *sd = unit->device.driver_data; | ||
957 | 970 | ||
958 | /* | 971 | /* |
959 | * As for map_scatterlist, we need to fill in the high bits of | 972 | * As for map_scatterlist, we need to fill in the high bits of |
@@ -975,9 +988,10 @@ static void sbp2_command_orb_map_buffer(struct sbp2_command_orb *orb) | |||
975 | 988 | ||
976 | static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) | 989 | static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) |
977 | { | 990 | { |
978 | struct fw_unit *unit = (struct fw_unit *)cmd->device->host->hostdata[0]; | 991 | struct sbp2_device *sd = |
992 | (struct sbp2_device *)cmd->device->host->hostdata; | ||
993 | struct fw_unit *unit = sd->unit; | ||
979 | struct fw_device *device = fw_device(unit->device.parent); | 994 | struct fw_device *device = fw_device(unit->device.parent); |
980 | struct sbp2_device *sd = unit->device.driver_data; | ||
981 | struct sbp2_command_orb *orb; | 995 | struct sbp2_command_orb *orb; |
982 | 996 | ||
983 | /* | 997 | /* |
@@ -1067,8 +1081,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) | |||
1067 | 1081 | ||
1068 | static int sbp2_scsi_slave_alloc(struct scsi_device *sdev) | 1082 | static int sbp2_scsi_slave_alloc(struct scsi_device *sdev) |
1069 | { | 1083 | { |
1070 | struct fw_unit *unit = (struct fw_unit *)sdev->host->hostdata[0]; | 1084 | struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata; |
1071 | struct sbp2_device *sd = unit->device.driver_data; | ||
1072 | 1085 | ||
1073 | sdev->allow_restart = 1; | 1086 | sdev->allow_restart = 1; |
1074 | 1087 | ||
@@ -1079,8 +1092,8 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev) | |||
1079 | 1092 | ||
1080 | static int sbp2_scsi_slave_configure(struct scsi_device *sdev) | 1093 | static int sbp2_scsi_slave_configure(struct scsi_device *sdev) |
1081 | { | 1094 | { |
1082 | struct fw_unit *unit = (struct fw_unit *)sdev->host->hostdata[0]; | 1095 | struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata; |
1083 | struct sbp2_device *sd = unit->device.driver_data; | 1096 | struct fw_unit *unit = sd->unit; |
1084 | 1097 | ||
1085 | sdev->use_10_for_rw = 1; | 1098 | sdev->use_10_for_rw = 1; |
1086 | 1099 | ||
@@ -1103,7 +1116,9 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) | |||
1103 | */ | 1116 | */ |
1104 | static int sbp2_scsi_abort(struct scsi_cmnd *cmd) | 1117 | static int sbp2_scsi_abort(struct scsi_cmnd *cmd) |
1105 | { | 1118 | { |
1106 | struct fw_unit *unit = (struct fw_unit *)cmd->device->host->hostdata[0]; | 1119 | struct sbp2_device *sd = |
1120 | (struct sbp2_device *)cmd->device->host->hostdata; | ||
1121 | struct fw_unit *unit = sd->unit; | ||
1107 | 1122 | ||
1108 | fw_notify("sbp2_scsi_abort\n"); | 1123 | fw_notify("sbp2_scsi_abort\n"); |
1109 | sbp2_agent_reset(unit); | 1124 | sbp2_agent_reset(unit); |
@@ -1127,55 +1142,6 @@ static struct scsi_host_template scsi_driver_template = { | |||
1127 | .can_queue = 1, | 1142 | .can_queue = 1, |
1128 | }; | 1143 | }; |
1129 | 1144 | ||
1130 | static int add_scsi_devices(struct fw_unit *unit) | ||
1131 | { | ||
1132 | struct sbp2_device *sd = unit->device.driver_data; | ||
1133 | int retval, lun; | ||
1134 | |||
1135 | if (sd->scsi_host != NULL) | ||
1136 | return 0; | ||
1137 | |||
1138 | sd->scsi_host = scsi_host_alloc(&scsi_driver_template, | ||
1139 | sizeof(unsigned long)); | ||
1140 | if (sd->scsi_host == NULL) { | ||
1141 | fw_error("failed to register scsi host\n"); | ||
1142 | return -1; | ||
1143 | } | ||
1144 | |||
1145 | sd->scsi_host->hostdata[0] = (unsigned long)unit; | ||
1146 | retval = scsi_add_host(sd->scsi_host, &unit->device); | ||
1147 | if (retval < 0) { | ||
1148 | fw_error("failed to add scsi host\n"); | ||
1149 | scsi_host_put(sd->scsi_host); | ||
1150 | sd->scsi_host = NULL; | ||
1151 | return retval; | ||
1152 | } | ||
1153 | |||
1154 | /* FIXME: Loop over luns here. */ | ||
1155 | lun = 0; | ||
1156 | retval = scsi_add_device(sd->scsi_host, 0, 0, lun); | ||
1157 | if (retval < 0) { | ||
1158 | fw_error("failed to add scsi device\n"); | ||
1159 | scsi_remove_host(sd->scsi_host); | ||
1160 | scsi_host_put(sd->scsi_host); | ||
1161 | sd->scsi_host = NULL; | ||
1162 | return retval; | ||
1163 | } | ||
1164 | |||
1165 | return 0; | ||
1166 | } | ||
1167 | |||
1168 | static void remove_scsi_devices(struct fw_unit *unit) | ||
1169 | { | ||
1170 | struct sbp2_device *sd = unit->device.driver_data; | ||
1171 | |||
1172 | if (sd->scsi_host != NULL) { | ||
1173 | scsi_remove_host(sd->scsi_host); | ||
1174 | scsi_host_put(sd->scsi_host); | ||
1175 | } | ||
1176 | sd->scsi_host = NULL; | ||
1177 | } | ||
1178 | |||
1179 | MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); | 1145 | MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); |
1180 | MODULE_DESCRIPTION("SCSI over IEEE1394"); | 1146 | MODULE_DESCRIPTION("SCSI over IEEE1394"); |
1181 | MODULE_LICENSE("GPL"); | 1147 | MODULE_LICENSE("GPL"); |