diff options
Diffstat (limited to 'drivers/scsi/esp.c')
-rw-r--r-- | drivers/scsi/esp.c | 315 |
1 files changed, 154 insertions, 161 deletions
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 0a3e45d7a972..ddb512463b45 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c | |||
@@ -1,7 +1,6 @@ | |||
1 | /* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $ | 1 | /* esp.c: ESP Sun SCSI driver. |
2 | * esp.c: EnhancedScsiProcessor Sun SCSI driver code. | ||
3 | * | 2 | * |
4 | * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) | 3 | * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net) |
5 | */ | 4 | */ |
6 | 5 | ||
7 | /* TODO: | 6 | /* TODO: |
@@ -185,11 +184,6 @@ enum { | |||
185 | /*5*/ do_intr_end | 184 | /*5*/ do_intr_end |
186 | }; | 185 | }; |
187 | 186 | ||
188 | /* The master ring of all esp hosts we are managing in this driver. */ | ||
189 | static struct esp *espchain; | ||
190 | static DEFINE_SPINLOCK(espchain_lock); | ||
191 | static int esps_running = 0; | ||
192 | |||
193 | /* Forward declarations. */ | 187 | /* Forward declarations. */ |
194 | static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs); | 188 | static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs); |
195 | 189 | ||
@@ -694,36 +688,6 @@ static void __init esp_bootup_reset(struct esp *esp) | |||
694 | sbus_readb(esp->eregs + ESP_INTRPT); | 688 | sbus_readb(esp->eregs + ESP_INTRPT); |
695 | } | 689 | } |
696 | 690 | ||
697 | static void esp_chain_add(struct esp *esp) | ||
698 | { | ||
699 | spin_lock_irq(&espchain_lock); | ||
700 | if (espchain) { | ||
701 | struct esp *elink = espchain; | ||
702 | while (elink->next) | ||
703 | elink = elink->next; | ||
704 | elink->next = esp; | ||
705 | } else { | ||
706 | espchain = esp; | ||
707 | } | ||
708 | esp->next = NULL; | ||
709 | spin_unlock_irq(&espchain_lock); | ||
710 | } | ||
711 | |||
712 | static void esp_chain_del(struct esp *esp) | ||
713 | { | ||
714 | spin_lock_irq(&espchain_lock); | ||
715 | if (espchain == esp) { | ||
716 | espchain = esp->next; | ||
717 | } else { | ||
718 | struct esp *elink = espchain; | ||
719 | while (elink->next != esp) | ||
720 | elink = elink->next; | ||
721 | elink->next = esp->next; | ||
722 | } | ||
723 | esp->next = NULL; | ||
724 | spin_unlock_irq(&espchain_lock); | ||
725 | } | ||
726 | |||
727 | static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev) | 691 | static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev) |
728 | { | 692 | { |
729 | struct sbus_dev *sdev = esp->sdev; | 693 | struct sbus_dev *sdev = esp->sdev; |
@@ -830,19 +794,20 @@ static int __init esp_register_irq(struct esp *esp) | |||
830 | static void __init esp_get_scsi_id(struct esp *esp) | 794 | static void __init esp_get_scsi_id(struct esp *esp) |
831 | { | 795 | { |
832 | struct sbus_dev *sdev = esp->sdev; | 796 | struct sbus_dev *sdev = esp->sdev; |
797 | struct device_node *dp = sdev->ofdev.node; | ||
833 | 798 | ||
834 | esp->scsi_id = prom_getintdefault(esp->prom_node, | 799 | esp->scsi_id = of_getintprop_default(dp, |
835 | "initiator-id", | 800 | "initiator-id", |
836 | -1); | 801 | -1); |
837 | if (esp->scsi_id == -1) | 802 | if (esp->scsi_id == -1) |
838 | esp->scsi_id = prom_getintdefault(esp->prom_node, | 803 | esp->scsi_id = of_getintprop_default(dp, |
839 | "scsi-initiator-id", | 804 | "scsi-initiator-id", |
840 | -1); | 805 | -1); |
841 | if (esp->scsi_id == -1) | 806 | if (esp->scsi_id == -1) |
842 | esp->scsi_id = (sdev->bus == NULL) ? 7 : | 807 | esp->scsi_id = (sdev->bus == NULL) ? 7 : |
843 | prom_getintdefault(sdev->bus->prom_node, | 808 | of_getintprop_default(sdev->bus->ofdev.node, |
844 | "scsi-initiator-id", | 809 | "scsi-initiator-id", |
845 | 7); | 810 | 7); |
846 | esp->ehost->this_id = esp->scsi_id; | 811 | esp->ehost->this_id = esp->scsi_id; |
847 | esp->scsi_id_mask = (1 << esp->scsi_id); | 812 | esp->scsi_id_mask = (1 << esp->scsi_id); |
848 | 813 | ||
@@ -1067,28 +1032,30 @@ static void __init esp_init_swstate(struct esp *esp) | |||
1067 | esp->prev_hme_dmacsr = 0xffffffff; | 1032 | esp->prev_hme_dmacsr = 0xffffffff; |
1068 | } | 1033 | } |
1069 | 1034 | ||
1070 | static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_dev *esp_dev, | 1035 | static int __init detect_one_esp(struct scsi_host_template *tpnt, |
1071 | struct sbus_dev *espdma, struct sbus_bus *sbus, | 1036 | struct device *dev, |
1072 | int id, int hme) | 1037 | struct sbus_dev *esp_dev, |
1038 | struct sbus_dev *espdma, | ||
1039 | struct sbus_bus *sbus, | ||
1040 | int hme) | ||
1073 | { | 1041 | { |
1074 | struct Scsi_Host *esp_host = scsi_register(tpnt, sizeof(struct esp)); | 1042 | static int instance; |
1043 | struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp)); | ||
1075 | struct esp *esp; | 1044 | struct esp *esp; |
1076 | 1045 | ||
1077 | if (!esp_host) { | 1046 | if (!esp_host) |
1078 | printk("ESP: Cannot register SCSI host\n"); | 1047 | return -ENOMEM; |
1079 | return -1; | 1048 | |
1080 | } | ||
1081 | if (hme) | 1049 | if (hme) |
1082 | esp_host->max_id = 16; | 1050 | esp_host->max_id = 16; |
1083 | esp = (struct esp *) esp_host->hostdata; | 1051 | esp = (struct esp *) esp_host->hostdata; |
1084 | esp->ehost = esp_host; | 1052 | esp->ehost = esp_host; |
1085 | esp->sdev = esp_dev; | 1053 | esp->sdev = esp_dev; |
1086 | esp->esp_id = id; | 1054 | esp->esp_id = instance; |
1087 | esp->prom_node = esp_dev->prom_node; | 1055 | esp->prom_node = esp_dev->prom_node; |
1088 | prom_getstring(esp->prom_node, "name", esp->prom_name, | 1056 | prom_getstring(esp->prom_node, "name", esp->prom_name, |
1089 | sizeof(esp->prom_name)); | 1057 | sizeof(esp->prom_name)); |
1090 | 1058 | ||
1091 | esp_chain_add(esp); | ||
1092 | if (esp_find_dvma(esp, espdma) < 0) | 1059 | if (esp_find_dvma(esp, espdma) < 0) |
1093 | goto fail_unlink; | 1060 | goto fail_unlink; |
1094 | if (esp_map_regs(esp, hme) < 0) { | 1061 | if (esp_map_regs(esp, hme) < 0) { |
@@ -1115,8 +1082,19 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de | |||
1115 | 1082 | ||
1116 | esp_bootup_reset(esp); | 1083 | esp_bootup_reset(esp); |
1117 | 1084 | ||
1085 | if (scsi_add_host(esp_host, dev)) | ||
1086 | goto fail_free_irq; | ||
1087 | |||
1088 | dev_set_drvdata(&esp_dev->ofdev.dev, esp); | ||
1089 | |||
1090 | scsi_scan_host(esp_host); | ||
1091 | instance++; | ||
1092 | |||
1118 | return 0; | 1093 | return 0; |
1119 | 1094 | ||
1095 | fail_free_irq: | ||
1096 | free_irq(esp->ehost->irq, esp); | ||
1097 | |||
1120 | fail_unmap_cmdarea: | 1098 | fail_unmap_cmdarea: |
1121 | sbus_free_consistent(esp->sdev, 16, | 1099 | sbus_free_consistent(esp->sdev, 16, |
1122 | (void *) esp->esp_command, | 1100 | (void *) esp->esp_command, |
@@ -1129,119 +1107,98 @@ fail_dvma_release: | |||
1129 | esp->dma->allocated = 0; | 1107 | esp->dma->allocated = 0; |
1130 | 1108 | ||
1131 | fail_unlink: | 1109 | fail_unlink: |
1132 | esp_chain_del(esp); | 1110 | scsi_host_put(esp_host); |
1133 | scsi_unregister(esp_host); | ||
1134 | return -1; | 1111 | return -1; |
1135 | } | 1112 | } |
1136 | 1113 | ||
1137 | /* Detecting ESP chips on the machine. This is the simple and easy | 1114 | /* Detecting ESP chips on the machine. This is the simple and easy |
1138 | * version. | 1115 | * version. |
1139 | */ | 1116 | */ |
1117 | static int __devexit esp_remove_common(struct esp *esp) | ||
1118 | { | ||
1119 | unsigned int irq = esp->ehost->irq; | ||
1120 | |||
1121 | scsi_remove_host(esp->ehost); | ||
1122 | |||
1123 | ESP_INTSOFF(esp->dregs); | ||
1124 | #if 0 | ||
1125 | esp_reset_dma(esp); | ||
1126 | esp_reset_esp(esp); | ||
1127 | #endif | ||
1128 | |||
1129 | free_irq(irq, esp); | ||
1130 | sbus_free_consistent(esp->sdev, 16, | ||
1131 | (void *) esp->esp_command, esp->esp_command_dvma); | ||
1132 | sbus_iounmap(esp->eregs, ESP_REG_SIZE); | ||
1133 | esp->dma->allocated = 0; | ||
1134 | |||
1135 | scsi_host_put(esp->ehost); | ||
1136 | |||
1137 | return 0; | ||
1138 | } | ||
1139 | |||
1140 | 1140 | ||
1141 | #ifdef CONFIG_SUN4 | 1141 | #ifdef CONFIG_SUN4 |
1142 | 1142 | ||
1143 | #include <asm/sun4paddr.h> | 1143 | #include <asm/sun4paddr.h> |
1144 | 1144 | ||
1145 | static int __init esp_detect(struct scsi_host_template *tpnt) | 1145 | static struct sbus_dev sun4_esp_dev; |
1146 | { | ||
1147 | static struct sbus_dev esp_dev; | ||
1148 | int esps_in_use = 0; | ||
1149 | |||
1150 | espchain = NULL; | ||
1151 | 1146 | ||
1147 | static int __init esp_sun4_probe(struct scsi_host_template *tpnt) | ||
1148 | { | ||
1152 | if (sun4_esp_physaddr) { | 1149 | if (sun4_esp_physaddr) { |
1153 | memset (&esp_dev, 0, sizeof(esp_dev)); | 1150 | memset(&sun4_esp_dev, 0, sizeof(esp_dev)); |
1154 | esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr; | 1151 | sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr; |
1155 | esp_dev.irqs[0] = 4; | 1152 | sun4_esp_dev.irqs[0] = 4; |
1156 | esp_dev.resource[0].start = sun4_esp_physaddr; | 1153 | sun4_esp_dev.resource[0].start = sun4_esp_physaddr; |
1157 | esp_dev.resource[0].end = sun4_esp_physaddr + ESP_REG_SIZE - 1; | 1154 | sun4_esp_dev.resource[0].end = |
1158 | esp_dev.resource[0].flags = IORESOURCE_IO; | 1155 | sun4_esp_physaddr + ESP_REG_SIZE - 1; |
1159 | 1156 | sun4_esp_dev.resource[0].flags = IORESOURCE_IO; | |
1160 | if (!detect_one_esp(tpnt, &esp_dev, NULL, NULL, 0, 0)) | 1157 | |
1161 | esps_in_use++; | 1158 | return detect_one_esp(tpnt, NULL, |
1162 | printk("ESP: Total of 1 ESP hosts found, %d actually in use.\n", esps_in_use); | 1159 | &sun4_esp_dev, NULL, NULL, 0); |
1163 | esps_running = esps_in_use; | ||
1164 | } | 1160 | } |
1165 | return esps_in_use; | 1161 | return 0; |
1166 | } | 1162 | } |
1167 | 1163 | ||
1168 | #else /* !CONFIG_SUN4 */ | 1164 | static int __devexit esp_sun4_remove(void) |
1169 | |||
1170 | static int __init esp_detect(struct scsi_host_template *tpnt) | ||
1171 | { | 1165 | { |
1172 | struct sbus_bus *sbus; | 1166 | struct esp *esp = dev_get_drvdata(&dev->dev); |
1173 | struct sbus_dev *esp_dev, *sbdev_iter; | ||
1174 | int nesps = 0, esps_in_use = 0; | ||
1175 | 1167 | ||
1176 | espchain = 0; | 1168 | return esp_remove_common(esp); |
1177 | if (!sbus_root) { | ||
1178 | #ifdef CONFIG_PCI | ||
1179 | return 0; | ||
1180 | #else | ||
1181 | panic("No SBUS in esp_detect()"); | ||
1182 | #endif | ||
1183 | } | ||
1184 | for_each_sbus(sbus) { | ||
1185 | for_each_sbusdev(sbdev_iter, sbus) { | ||
1186 | struct sbus_dev *espdma = NULL; | ||
1187 | int hme = 0; | ||
1188 | |||
1189 | /* Is it an esp sbus device? */ | ||
1190 | esp_dev = sbdev_iter; | ||
1191 | if (strcmp(esp_dev->prom_name, "esp") && | ||
1192 | strcmp(esp_dev->prom_name, "SUNW,esp")) { | ||
1193 | if (!strcmp(esp_dev->prom_name, "SUNW,fas")) { | ||
1194 | hme = 1; | ||
1195 | espdma = esp_dev; | ||
1196 | } else { | ||
1197 | if (!esp_dev->child || | ||
1198 | (strcmp(esp_dev->prom_name, "espdma") && | ||
1199 | strcmp(esp_dev->prom_name, "dma"))) | ||
1200 | continue; /* nope... */ | ||
1201 | espdma = esp_dev; | ||
1202 | esp_dev = esp_dev->child; | ||
1203 | if (strcmp(esp_dev->prom_name, "esp") && | ||
1204 | strcmp(esp_dev->prom_name, "SUNW,esp")) | ||
1205 | continue; /* how can this happen? */ | ||
1206 | } | ||
1207 | } | ||
1208 | |||
1209 | if (detect_one_esp(tpnt, esp_dev, espdma, sbus, nesps++, hme) < 0) | ||
1210 | continue; | ||
1211 | |||
1212 | esps_in_use++; | ||
1213 | } /* for each sbusdev */ | ||
1214 | } /* for each sbus */ | ||
1215 | printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, | ||
1216 | esps_in_use); | ||
1217 | esps_running = esps_in_use; | ||
1218 | return esps_in_use; | ||
1219 | } | 1169 | } |
1220 | 1170 | ||
1221 | #endif /* !CONFIG_SUN4 */ | 1171 | #else /* !CONFIG_SUN4 */ |
1222 | 1172 | ||
1223 | /* | 1173 | static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match) |
1224 | */ | ||
1225 | static int esp_release(struct Scsi_Host *host) | ||
1226 | { | 1174 | { |
1227 | struct esp *esp = (struct esp *) host->hostdata; | 1175 | struct sbus_dev *sdev = to_sbus_device(&dev->dev); |
1176 | struct device_node *dp = dev->node; | ||
1177 | struct sbus_dev *dma_sdev = NULL; | ||
1178 | int hme = 0; | ||
1179 | |||
1180 | if (dp->parent && | ||
1181 | (!strcmp(dp->parent->name, "espdma") || | ||
1182 | !strcmp(dp->parent->name, "dma"))) | ||
1183 | dma_sdev = sdev->parent; | ||
1184 | else if (!strcmp(dp->name, "SUNW,fas")) { | ||
1185 | dma_sdev = sdev; | ||
1186 | hme = 1; | ||
1187 | } | ||
1228 | 1188 | ||
1229 | ESP_INTSOFF(esp->dregs); | 1189 | return detect_one_esp(match->data, &dev->dev, |
1230 | #if 0 | 1190 | sdev, dma_sdev, sdev->bus, hme); |
1231 | esp_reset_dma(esp); | 1191 | } |
1232 | esp_reset_esp(esp); | ||
1233 | #endif | ||
1234 | 1192 | ||
1235 | free_irq(esp->ehost->irq, esp); | 1193 | static int __devexit esp_sbus_remove(struct of_device *dev) |
1236 | sbus_free_consistent(esp->sdev, 16, | 1194 | { |
1237 | (void *) esp->esp_command, esp->esp_command_dvma); | 1195 | struct esp *esp = dev_get_drvdata(&dev->dev); |
1238 | sbus_iounmap(esp->eregs, ESP_REG_SIZE); | ||
1239 | esp->dma->allocated = 0; | ||
1240 | esp_chain_del(esp); | ||
1241 | 1196 | ||
1242 | return 0; | 1197 | return esp_remove_common(esp); |
1243 | } | 1198 | } |
1244 | 1199 | ||
1200 | #endif /* !CONFIG_SUN4 */ | ||
1201 | |||
1245 | /* The info function will return whatever useful | 1202 | /* The info function will return whatever useful |
1246 | * information the developer sees fit. If not provided, then | 1203 | * information the developer sees fit. If not provided, then |
1247 | * the name field will be used instead. | 1204 | * the name field will be used instead. |
@@ -1415,18 +1372,11 @@ static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len) | |||
1415 | static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, | 1372 | static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, |
1416 | int length, int inout) | 1373 | int length, int inout) |
1417 | { | 1374 | { |
1418 | struct esp *esp; | 1375 | struct esp *esp = (struct esp *) host->hostdata; |
1419 | 1376 | ||
1420 | if (inout) | 1377 | if (inout) |
1421 | return -EINVAL; /* not yet */ | 1378 | return -EINVAL; /* not yet */ |
1422 | 1379 | ||
1423 | for_each_esp(esp) { | ||
1424 | if (esp->ehost == host) | ||
1425 | break; | ||
1426 | } | ||
1427 | if (!esp) | ||
1428 | return -EINVAL; | ||
1429 | |||
1430 | if (start) | 1380 | if (start) |
1431 | *start = buffer; | 1381 | *start = buffer; |
1432 | 1382 | ||
@@ -4377,15 +4327,12 @@ static void esp_slave_destroy(struct scsi_device *SDptr) | |||
4377 | SDptr->hostdata = NULL; | 4327 | SDptr->hostdata = NULL; |
4378 | } | 4328 | } |
4379 | 4329 | ||
4380 | static struct scsi_host_template driver_template = { | 4330 | static struct scsi_host_template esp_template = { |
4381 | .proc_name = "esp", | 4331 | .module = THIS_MODULE, |
4382 | .proc_info = esp_proc_info, | 4332 | .name = "esp", |
4383 | .name = "Sun ESP 100/100a/200", | 4333 | .info = esp_info, |
4384 | .detect = esp_detect, | ||
4385 | .slave_alloc = esp_slave_alloc, | 4334 | .slave_alloc = esp_slave_alloc, |
4386 | .slave_destroy = esp_slave_destroy, | 4335 | .slave_destroy = esp_slave_destroy, |
4387 | .release = esp_release, | ||
4388 | .info = esp_info, | ||
4389 | .queuecommand = esp_queue, | 4336 | .queuecommand = esp_queue, |
4390 | .eh_abort_handler = esp_abort, | 4337 | .eh_abort_handler = esp_abort, |
4391 | .eh_bus_reset_handler = esp_reset, | 4338 | .eh_bus_reset_handler = esp_reset, |
@@ -4394,12 +4341,58 @@ static struct scsi_host_template driver_template = { | |||
4394 | .sg_tablesize = SG_ALL, | 4341 | .sg_tablesize = SG_ALL, |
4395 | .cmd_per_lun = 1, | 4342 | .cmd_per_lun = 1, |
4396 | .use_clustering = ENABLE_CLUSTERING, | 4343 | .use_clustering = ENABLE_CLUSTERING, |
4344 | .proc_name = "esp", | ||
4345 | .proc_info = esp_proc_info, | ||
4346 | }; | ||
4347 | |||
4348 | #ifndef CONFIG_SUN4 | ||
4349 | static struct of_device_id esp_match[] = { | ||
4350 | { | ||
4351 | .name = "SUNW,esp", | ||
4352 | .data = &esp_template, | ||
4353 | }, | ||
4354 | { | ||
4355 | .name = "SUNW,fas", | ||
4356 | .data = &esp_template, | ||
4357 | }, | ||
4358 | { | ||
4359 | .name = "esp", | ||
4360 | .data = &esp_template, | ||
4361 | }, | ||
4362 | {}, | ||
4363 | }; | ||
4364 | MODULE_DEVICE_TABLE(of, esp_match); | ||
4365 | |||
4366 | static struct of_platform_driver esp_sbus_driver = { | ||
4367 | .name = "esp", | ||
4368 | .match_table = esp_match, | ||
4369 | .probe = esp_sbus_probe, | ||
4370 | .remove = __devexit_p(esp_sbus_remove), | ||
4397 | }; | 4371 | }; |
4372 | #endif | ||
4373 | |||
4374 | static int __init esp_init(void) | ||
4375 | { | ||
4376 | #ifdef CONFIG_SUN4 | ||
4377 | return esp_sun4_probe(&esp_template); | ||
4378 | #else | ||
4379 | return of_register_driver(&esp_sbus_driver, &sbus_bus_type); | ||
4380 | #endif | ||
4381 | } | ||
4398 | 4382 | ||
4399 | #include "scsi_module.c" | 4383 | static void __exit esp_exit(void) |
4384 | { | ||
4385 | #ifdef CONFIG_SUN4 | ||
4386 | esp_sun4_remove(); | ||
4387 | #else | ||
4388 | of_unregister_driver(&esp_sbus_driver); | ||
4389 | #endif | ||
4390 | } | ||
4400 | 4391 | ||
4401 | MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver"); | 4392 | MODULE_DESCRIPTION("ESP Sun SCSI driver"); |
4402 | MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); | 4393 | MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); |
4403 | MODULE_LICENSE("GPL"); | 4394 | MODULE_LICENSE("GPL"); |
4404 | MODULE_VERSION(DRV_VERSION); | 4395 | MODULE_VERSION(DRV_VERSION); |
4405 | 4396 | ||
4397 | module_init(esp_init); | ||
4398 | module_exit(esp_exit); | ||