diff options
author | nickcheng(鄭守謙 <nick.cheng@areca.com.tw> | 2007-06-14 23:43:32 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-06-17 15:49:01 -0400 |
commit | a1f6e0211b71a6c3ff401ad1d345ab024d0c6f01 (patch) | |
tree | 779c34c385f962a5d68429b90d22a2b7c7b43f6f /drivers/scsi/arcmsr/arcmsr_hba.c | |
parent | 727eead62e22cf0a9498cf34e075c08269402978 (diff) |
[SCSI] areca: improve driver stability and compatibility
Description:
1. Implement PCI-Express error recovery function and AER
capability, especially thanks to Yanmin Zhang's openhanded help
about AER
2. Implement the selection of ARCMSR_MAX_XFER_SECTORS_B=4096 if
firmware version is latter than 1.42
3. Add arcmsr_done4_abort_postqueue in arcmsr_iop_reset function
to improve the stability as hot-unplug/plug
4. Modify the ISR, arcmsr_interrupt routine, to prevent the
inconsistency with sg_mod driver if application directly calls
the arcmsr driver w/o passing through scsi midlayer
Signed-off-by: Nick Cheng <nick.cheng@areca.com.tw>
[jejb: unused variable removal]
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/arcmsr/arcmsr_hba.c')
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr_hba.c | 456 |
1 files changed, 423 insertions, 33 deletions
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 672df79d7e39..0ddfc21e9f7d 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c | |||
@@ -57,6 +57,7 @@ | |||
57 | #include <linux/dma-mapping.h> | 57 | #include <linux/dma-mapping.h> |
58 | #include <linux/timer.h> | 58 | #include <linux/timer.h> |
59 | #include <linux/pci.h> | 59 | #include <linux/pci.h> |
60 | #include <linux/aer.h> | ||
60 | #include <asm/dma.h> | 61 | #include <asm/dma.h> |
61 | #include <asm/io.h> | 62 | #include <asm/io.h> |
62 | #include <asm/system.h> | 63 | #include <asm/system.h> |
@@ -71,7 +72,7 @@ | |||
71 | #include "arcmsr.h" | 72 | #include "arcmsr.h" |
72 | 73 | ||
73 | MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>"); | 74 | MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>"); |
74 | MODULE_DESCRIPTION("ARECA (ARC11xx/12xx) SATA RAID HOST Adapter"); | 75 | MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter"); |
75 | MODULE_LICENSE("Dual BSD/GPL"); | 76 | MODULE_LICENSE("Dual BSD/GPL"); |
76 | MODULE_VERSION(ARCMSR_DRIVER_VERSION); | 77 | MODULE_VERSION(ARCMSR_DRIVER_VERSION); |
77 | 78 | ||
@@ -93,7 +94,9 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb); | |||
93 | static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb); | 94 | static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb); |
94 | static const char *arcmsr_info(struct Scsi_Host *); | 95 | static const char *arcmsr_info(struct Scsi_Host *); |
95 | static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); | 96 | static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); |
96 | 97 | static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev, | |
98 | pci_channel_state_t state); | ||
99 | static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev); | ||
97 | static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth) | 100 | static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth) |
98 | { | 101 | { |
99 | if (queue_depth > ARCMSR_MAX_CMD_PERLUN) | 102 | if (queue_depth > ARCMSR_MAX_CMD_PERLUN) |
@@ -104,7 +107,8 @@ static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_de | |||
104 | 107 | ||
105 | static struct scsi_host_template arcmsr_scsi_host_template = { | 108 | static struct scsi_host_template arcmsr_scsi_host_template = { |
106 | .module = THIS_MODULE, | 109 | .module = THIS_MODULE, |
107 | .name = "ARCMSR ARECA SATA RAID HOST Adapter" ARCMSR_DRIVER_VERSION, | 110 | .name = "ARCMSR ARECA SATA/SAS RAID HOST Adapter" |
111 | ARCMSR_DRIVER_VERSION, | ||
108 | .info = arcmsr_info, | 112 | .info = arcmsr_info, |
109 | .queuecommand = arcmsr_queue_command, | 113 | .queuecommand = arcmsr_queue_command, |
110 | .eh_abort_handler = arcmsr_abort, | 114 | .eh_abort_handler = arcmsr_abort, |
@@ -119,6 +123,10 @@ static struct scsi_host_template arcmsr_scsi_host_template = { | |||
119 | .use_clustering = ENABLE_CLUSTERING, | 123 | .use_clustering = ENABLE_CLUSTERING, |
120 | .shost_attrs = arcmsr_host_attrs, | 124 | .shost_attrs = arcmsr_host_attrs, |
121 | }; | 125 | }; |
126 | static struct pci_error_handlers arcmsr_pci_error_handlers = { | ||
127 | .error_detected = arcmsr_pci_error_detected, | ||
128 | .slot_reset = arcmsr_pci_slot_reset, | ||
129 | }; | ||
122 | 130 | ||
123 | static struct pci_device_id arcmsr_device_id_table[] = { | 131 | static struct pci_device_id arcmsr_device_id_table[] = { |
124 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)}, | 132 | {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)}, |
@@ -144,7 +152,8 @@ static struct pci_driver arcmsr_pci_driver = { | |||
144 | .id_table = arcmsr_device_id_table, | 152 | .id_table = arcmsr_device_id_table, |
145 | .probe = arcmsr_probe, | 153 | .probe = arcmsr_probe, |
146 | .remove = arcmsr_remove, | 154 | .remove = arcmsr_remove, |
147 | .shutdown = arcmsr_shutdown | 155 | .shutdown = arcmsr_shutdown, |
156 | .err_handler = &arcmsr_pci_error_handlers, | ||
148 | }; | 157 | }; |
149 | 158 | ||
150 | static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) | 159 | static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) |
@@ -328,6 +337,8 @@ static int arcmsr_probe(struct pci_dev *pdev, | |||
328 | 337 | ||
329 | arcmsr_iop_init(acb); | 338 | arcmsr_iop_init(acb); |
330 | pci_set_drvdata(pdev, host); | 339 | pci_set_drvdata(pdev, host); |
340 | if (strncmp(acb->firm_version, "V1.42", 5) >= 0) | ||
341 | host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B; | ||
331 | 342 | ||
332 | error = scsi_add_host(host, &pdev->dev); | 343 | error = scsi_add_host(host, &pdev->dev); |
333 | if (error) | 344 | if (error) |
@@ -338,6 +349,7 @@ static int arcmsr_probe(struct pci_dev *pdev, | |||
338 | goto out_free_sysfs; | 349 | goto out_free_sysfs; |
339 | 350 | ||
340 | scsi_scan_host(host); | 351 | scsi_scan_host(host); |
352 | pci_enable_pcie_error_reporting(pdev); | ||
341 | return 0; | 353 | return 0; |
342 | out_free_sysfs: | 354 | out_free_sysfs: |
343 | out_free_irq: | 355 | out_free_irq: |
@@ -488,7 +500,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, | |||
488 | 500 | ||
489 | static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) | 501 | static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) |
490 | { | 502 | { |
491 | struct MessageUnit __iomem *reg=acb->pmu; | 503 | struct MessageUnit __iomem *reg = acb->pmu; |
492 | 504 | ||
493 | writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); | 505 | writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); |
494 | if (arcmsr_wait_msgint_ready(acb)) | 506 | if (arcmsr_wait_msgint_ready(acb)) |
@@ -718,7 +730,7 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) | |||
718 | int id, lun; | 730 | int id, lun; |
719 | /* | 731 | /* |
720 | **************************************************************** | 732 | **************************************************************** |
721 | ** areca cdb command done | 733 | ** areca cdb command done |
722 | **************************************************************** | 734 | **************************************************************** |
723 | */ | 735 | */ |
724 | while (1) { | 736 | while (1) { |
@@ -729,20 +741,20 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) | |||
729 | (flag_ccb << 5)); | 741 | (flag_ccb << 5)); |
730 | if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { | 742 | if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { |
731 | if (ccb->startdone == ARCMSR_CCB_ABORTED) { | 743 | if (ccb->startdone == ARCMSR_CCB_ABORTED) { |
732 | struct scsi_cmnd *abortcmd=ccb->pcmd; | 744 | struct scsi_cmnd *abortcmd = ccb->pcmd; |
733 | if (abortcmd) { | 745 | if (abortcmd) { |
734 | abortcmd->result |= DID_ABORT >> 16; | 746 | abortcmd->result |= DID_ABORT >> 16; |
735 | arcmsr_ccb_complete(ccb, 1); | 747 | arcmsr_ccb_complete(ccb, 1); |
736 | printk(KERN_NOTICE | 748 | printk(KERN_NOTICE |
737 | "arcmsr%d: ccb='0x%p' isr got aborted command \n" | 749 | "arcmsr%d: ccb ='0x%p' isr got aborted command \n" |
738 | , acb->host->host_no, ccb); | 750 | , acb->host->host_no, ccb); |
739 | } | 751 | } |
740 | continue; | 752 | continue; |
741 | } | 753 | } |
742 | printk(KERN_NOTICE | 754 | printk(KERN_NOTICE |
743 | "arcmsr%d: isr get an illegal ccb command done acb='0x%p'" | 755 | "arcmsr%d: isr get an illegal ccb command done acb = '0x%p'" |
744 | "ccb='0x%p' ccbacb='0x%p' startdone = 0x%x" | 756 | "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x" |
745 | " ccboutstandingcount=%d \n" | 757 | " ccboutstandingcount = %d \n" |
746 | , acb->host->host_no | 758 | , acb->host->host_no |
747 | , acb | 759 | , acb |
748 | , ccb | 760 | , ccb |
@@ -762,7 +774,7 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) | |||
762 | switch(ccb->arcmsr_cdb.DeviceStatus) { | 774 | switch(ccb->arcmsr_cdb.DeviceStatus) { |
763 | case ARCMSR_DEV_SELECT_TIMEOUT: { | 775 | case ARCMSR_DEV_SELECT_TIMEOUT: { |
764 | acb->devstate[id][lun] = ARECA_RAID_GONE; | 776 | acb->devstate[id][lun] = ARECA_RAID_GONE; |
765 | ccb->pcmd->result = DID_TIME_OUT << 16; | 777 | ccb->pcmd->result = DID_NO_CONNECT << 16; |
766 | arcmsr_ccb_complete(ccb, 1); | 778 | arcmsr_ccb_complete(ccb, 1); |
767 | } | 779 | } |
768 | break; | 780 | break; |
@@ -781,8 +793,8 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) | |||
781 | break; | 793 | break; |
782 | default: | 794 | default: |
783 | printk(KERN_NOTICE | 795 | printk(KERN_NOTICE |
784 | "arcmsr%d: scsi id=%d lun=%d" | 796 | "arcmsr%d: scsi id = %d lun = %d" |
785 | " isr get command error done," | 797 | " isr get command error done, " |
786 | "but got unknown DeviceStatus = 0x%x \n" | 798 | "but got unknown DeviceStatus = 0x%x \n" |
787 | , acb->host->host_no | 799 | , acb->host->host_no |
788 | , id | 800 | , id |
@@ -1062,7 +1074,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, | |||
1062 | inqdata[1] = 0; | 1074 | inqdata[1] = 0; |
1063 | /* rem media bit & Dev Type Modifier */ | 1075 | /* rem media bit & Dev Type Modifier */ |
1064 | inqdata[2] = 0; | 1076 | inqdata[2] = 0; |
1065 | /* ISO,ECMA,& ANSI versions */ | 1077 | /* ISO, ECMA, & ANSI versions */ |
1066 | inqdata[4] = 31; | 1078 | inqdata[4] = 31; |
1067 | /* length of additional data */ | 1079 | /* length of additional data */ |
1068 | strncpy(&inqdata[8], "Areca ", 8); | 1080 | strncpy(&inqdata[8], "Areca ", 8); |
@@ -1112,7 +1124,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, | |||
1112 | , acb->host->host_no); | 1124 | , acb->host->host_no); |
1113 | return SCSI_MLQUEUE_HOST_BUSY; | 1125 | return SCSI_MLQUEUE_HOST_BUSY; |
1114 | } | 1126 | } |
1115 | if(target == 16) { | 1127 | if (target == 16) { |
1116 | /* virtual device for iop message transfer */ | 1128 | /* virtual device for iop message transfer */ |
1117 | arcmsr_handle_virtual_command(acb, cmd); | 1129 | arcmsr_handle_virtual_command(acb, cmd); |
1118 | return 0; | 1130 | return 0; |
@@ -1125,7 +1137,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, | |||
1125 | printk(KERN_NOTICE | 1137 | printk(KERN_NOTICE |
1126 | "arcmsr%d: block 'read/write'" | 1138 | "arcmsr%d: block 'read/write'" |
1127 | "command with gone raid volume" | 1139 | "command with gone raid volume" |
1128 | " Cmd=%2x, TargetId=%d, Lun=%d \n" | 1140 | " Cmd = %2x, TargetId = %d, Lun = %d \n" |
1129 | , acb->host->host_no | 1141 | , acb->host->host_no |
1130 | , cmd->cmnd[0] | 1142 | , cmd->cmnd[0] |
1131 | , target, lun); | 1143 | , target, lun); |
@@ -1216,7 +1228,7 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, | |||
1216 | if ((ccb->startdone == ARCMSR_CCB_ABORTED) || | 1228 | if ((ccb->startdone == ARCMSR_CCB_ABORTED) || |
1217 | (ccb == poll_ccb)) { | 1229 | (ccb == poll_ccb)) { |
1218 | printk(KERN_NOTICE | 1230 | printk(KERN_NOTICE |
1219 | "arcmsr%d: scsi id=%d lun=%d ccb='0x%p'" | 1231 | "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" |
1220 | " poll command abort successfully \n" | 1232 | " poll command abort successfully \n" |
1221 | , acb->host->host_no | 1233 | , acb->host->host_no |
1222 | , ccb->pcmd->device->id | 1234 | , ccb->pcmd->device->id |
@@ -1229,8 +1241,8 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, | |||
1229 | } | 1241 | } |
1230 | printk(KERN_NOTICE | 1242 | printk(KERN_NOTICE |
1231 | "arcmsr%d: polling get an illegal ccb" | 1243 | "arcmsr%d: polling get an illegal ccb" |
1232 | " command done ccb='0x%p'" | 1244 | " command done ccb ='0x%p'" |
1233 | "ccboutstandingcount=%d \n" | 1245 | "ccboutstandingcount = %d \n" |
1234 | , acb->host->host_no | 1246 | , acb->host->host_no |
1235 | , ccb | 1247 | , ccb |
1236 | , atomic_read(&acb->ccboutstandingcount)); | 1248 | , atomic_read(&acb->ccboutstandingcount)); |
@@ -1247,7 +1259,7 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, | |||
1247 | switch(ccb->arcmsr_cdb.DeviceStatus) { | 1259 | switch(ccb->arcmsr_cdb.DeviceStatus) { |
1248 | case ARCMSR_DEV_SELECT_TIMEOUT: { | 1260 | case ARCMSR_DEV_SELECT_TIMEOUT: { |
1249 | acb->devstate[id][lun] = ARECA_RAID_GONE; | 1261 | acb->devstate[id][lun] = ARECA_RAID_GONE; |
1250 | ccb->pcmd->result = DID_TIME_OUT << 16; | 1262 | ccb->pcmd->result = DID_NO_CONNECT << 16; |
1251 | arcmsr_ccb_complete(ccb, 1); | 1263 | arcmsr_ccb_complete(ccb, 1); |
1252 | } | 1264 | } |
1253 | break; | 1265 | break; |
@@ -1266,7 +1278,7 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, | |||
1266 | break; | 1278 | break; |
1267 | default: | 1279 | default: |
1268 | printk(KERN_NOTICE | 1280 | printk(KERN_NOTICE |
1269 | "arcmsr%d: scsi id=%d lun=%d" | 1281 | "arcmsr%d: scsi id = %d lun = %d" |
1270 | " polling and getting command error done" | 1282 | " polling and getting command error done" |
1271 | "but got unknown DeviceStatus = 0x%x \n" | 1283 | "but got unknown DeviceStatus = 0x%x \n" |
1272 | , acb->host->host_no | 1284 | , acb->host->host_no |
@@ -1281,6 +1293,94 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, | |||
1281 | } | 1293 | } |
1282 | } | 1294 | } |
1283 | } | 1295 | } |
1296 | static void arcmsr_done4_abort_postqueue(struct AdapterControlBlock *acb) | ||
1297 | { | ||
1298 | int i = 0, found = 0; | ||
1299 | int id, lun; | ||
1300 | uint32_t flag_ccb, outbound_intstatus; | ||
1301 | struct MessageUnit __iomem *reg = acb->pmu; | ||
1302 | struct CommandControlBlock *ccb; | ||
1303 | /*clear and abort all outbound posted Q*/ | ||
1304 | |||
1305 | while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && | ||
1306 | (i++ < 256)){ | ||
1307 | ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + | ||
1308 | (flag_ccb << 5)); | ||
1309 | if (ccb){ | ||
1310 | if ((ccb->acb != acb)||(ccb->startdone != \ | ||
1311 | ARCMSR_CCB_START)){ | ||
1312 | printk(KERN_NOTICE "arcmsr%d: polling get \ | ||
1313 | an illegal ccb" "command done ccb = '0x%p'""ccboutstandingcount = %d \n", | ||
1314 | acb->host->host_no, ccb, | ||
1315 | atomic_read(&acb->ccboutstandingcount)); | ||
1316 | continue; | ||
1317 | } | ||
1318 | |||
1319 | id = ccb->pcmd->device->id; | ||
1320 | lun = ccb->pcmd->device->lun; | ||
1321 | if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)){ | ||
1322 | if (acb->devstate[id][lun] == ARECA_RAID_GONE) | ||
1323 | acb->devstate[id][lun] = ARECA_RAID_GOOD; | ||
1324 | ccb->pcmd->result = DID_OK << 16; | ||
1325 | arcmsr_ccb_complete(ccb, 1); | ||
1326 | } | ||
1327 | else { | ||
1328 | switch(ccb->arcmsr_cdb.DeviceStatus) { | ||
1329 | case ARCMSR_DEV_SELECT_TIMEOUT: { | ||
1330 | acb->devstate[id][lun] = ARECA_RAID_GONE; | ||
1331 | ccb->pcmd->result = DID_NO_CONNECT << 16; | ||
1332 | arcmsr_ccb_complete(ccb, 1); | ||
1333 | } | ||
1334 | break; | ||
1335 | |||
1336 | case ARCMSR_DEV_ABORTED: | ||
1337 | |||
1338 | case ARCMSR_DEV_INIT_FAIL: { | ||
1339 | acb->devstate[id][lun] = | ||
1340 | ARECA_RAID_GONE; | ||
1341 | ccb->pcmd->result = | ||
1342 | DID_BAD_TARGET << 16; | ||
1343 | arcmsr_ccb_complete(ccb, 1); | ||
1344 | } | ||
1345 | break; | ||
1346 | |||
1347 | case ARCMSR_DEV_CHECK_CONDITION: { | ||
1348 | acb->devstate[id][lun] = | ||
1349 | ARECA_RAID_GOOD; | ||
1350 | arcmsr_report_sense_info(ccb); | ||
1351 | arcmsr_ccb_complete(ccb, 1); | ||
1352 | } | ||
1353 | break; | ||
1354 | |||
1355 | default: | ||
1356 | printk(KERN_NOTICE | ||
1357 | "arcmsr%d: scsi id = %d \ | ||
1358 | lun = %d""polling and \ | ||
1359 | getting command error \ | ||
1360 | done""but got unknown \ | ||
1361 | DeviceStatus = 0x%x \n", | ||
1362 | acb->host->host_no, id, | ||
1363 | lun, ccb->arcmsr_cdb.DeviceStatus); | ||
1364 | acb->devstate[id][lun] = | ||
1365 | ARECA_RAID_GONE; | ||
1366 | ccb->pcmd->result = | ||
1367 | DID_BAD_TARGET << 16; | ||
1368 | arcmsr_ccb_complete(ccb, 1); | ||
1369 | break; | ||
1370 | } | ||
1371 | } | ||
1372 | found = 1; | ||
1373 | } | ||
1374 | } | ||
1375 | if (found){ | ||
1376 | outbound_intstatus = readl(®->outbound_intstatus) & \ | ||
1377 | acb->outbound_int_enable; | ||
1378 | writel(outbound_intstatus, ®->outbound_intstatus); | ||
1379 | /*clear interrupt*/ | ||
1380 | } | ||
1381 | return; | ||
1382 | } | ||
1383 | |||
1284 | 1384 | ||
1285 | static void arcmsr_iop_init(struct AdapterControlBlock *acb) | 1385 | static void arcmsr_iop_init(struct AdapterControlBlock *acb) |
1286 | { | 1386 | { |
@@ -1314,7 +1414,6 @@ static void arcmsr_iop_init(struct AdapterControlBlock *acb) | |||
1314 | 1414 | ||
1315 | static void arcmsr_iop_reset(struct AdapterControlBlock *acb) | 1415 | static void arcmsr_iop_reset(struct AdapterControlBlock *acb) |
1316 | { | 1416 | { |
1317 | struct MessageUnit __iomem *reg = acb->pmu; | ||
1318 | struct CommandControlBlock *ccb; | 1417 | struct CommandControlBlock *ccb; |
1319 | uint32_t intmask_org; | 1418 | uint32_t intmask_org; |
1320 | int i = 0; | 1419 | int i = 0; |
@@ -1327,21 +1426,17 @@ static void arcmsr_iop_reset(struct AdapterControlBlock *acb) | |||
1327 | /* disable all outbound interrupt */ | 1426 | /* disable all outbound interrupt */ |
1328 | intmask_org = arcmsr_disable_outbound_ints(acb); | 1427 | intmask_org = arcmsr_disable_outbound_ints(acb); |
1329 | /* clear all outbound posted Q */ | 1428 | /* clear all outbound posted Q */ |
1330 | for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) | 1429 | arcmsr_done4_abort_postqueue(acb); |
1331 | readl(®->outbound_queueport); | ||
1332 | for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { | 1430 | for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { |
1333 | ccb = acb->pccb_pool[i]; | 1431 | ccb = acb->pccb_pool[i]; |
1334 | if ((ccb->startdone == ARCMSR_CCB_START) || | 1432 | if (ccb->startdone == ARCMSR_CCB_START) { |
1335 | (ccb->startdone == ARCMSR_CCB_ABORTED)) { | ||
1336 | ccb->startdone = ARCMSR_CCB_ABORTED; | 1433 | ccb->startdone = ARCMSR_CCB_ABORTED; |
1337 | ccb->pcmd->result = DID_ABORT << 16; | ||
1338 | arcmsr_ccb_complete(ccb, 1); | ||
1339 | } | 1434 | } |
1340 | } | 1435 | } |
1341 | /* enable all outbound interrupt */ | 1436 | /* enable all outbound interrupt */ |
1342 | arcmsr_enable_outbound_ints(acb, intmask_org); | 1437 | arcmsr_enable_outbound_ints(acb, intmask_org); |
1343 | } | 1438 | } |
1344 | atomic_set(&acb->ccboutstandingcount, 0); | 1439 | |
1345 | } | 1440 | } |
1346 | 1441 | ||
1347 | static int arcmsr_bus_reset(struct scsi_cmnd *cmd) | 1442 | static int arcmsr_bus_reset(struct scsi_cmnd *cmd) |
@@ -1387,10 +1482,9 @@ static int arcmsr_abort(struct scsi_cmnd *cmd) | |||
1387 | int i = 0; | 1482 | int i = 0; |
1388 | 1483 | ||
1389 | printk(KERN_NOTICE | 1484 | printk(KERN_NOTICE |
1390 | "arcmsr%d: abort device command of scsi id=%d lun=%d \n", | 1485 | "arcmsr%d: abort device command of scsi id = %d lun = %d \n", |
1391 | acb->host->host_no, cmd->device->id, cmd->device->lun); | 1486 | acb->host->host_no, cmd->device->id, cmd->device->lun); |
1392 | acb->num_aborts++; | 1487 | acb->num_aborts++; |
1393 | |||
1394 | /* | 1488 | /* |
1395 | ************************************************ | 1489 | ************************************************ |
1396 | ** the all interrupt service routine is locked | 1490 | ** the all interrupt service routine is locked |
@@ -1445,10 +1539,306 @@ static const char *arcmsr_info(struct Scsi_Host *host) | |||
1445 | type = "X-TYPE"; | 1539 | type = "X-TYPE"; |
1446 | break; | 1540 | break; |
1447 | } | 1541 | } |
1448 | sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s", | 1542 | sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s", |
1449 | type, raid6 ? "( RAID6 capable)" : "", | 1543 | type, raid6 ? "( RAID6 capable)" : "", |
1450 | ARCMSR_DRIVER_VERSION); | 1544 | ARCMSR_DRIVER_VERSION); |
1451 | return buf; | 1545 | return buf; |
1452 | } | 1546 | } |
1453 | 1547 | ||
1548 | static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev) | ||
1549 | { | ||
1550 | struct Scsi_Host *host; | ||
1551 | struct AdapterControlBlock *acb; | ||
1552 | uint8_t bus, dev_fun; | ||
1553 | int error; | ||
1554 | |||
1555 | error = pci_enable_device(pdev); | ||
1556 | if (error) | ||
1557 | return PCI_ERS_RESULT_DISCONNECT; | ||
1558 | pci_set_master(pdev); | ||
1559 | |||
1560 | host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof \ | ||
1561 | (struct AdapterControlBlock)); | ||
1562 | if (!host) | ||
1563 | return PCI_ERS_RESULT_DISCONNECT; | ||
1564 | acb = (struct AdapterControlBlock *)host->hostdata; | ||
1565 | memset(acb, 0, sizeof (struct AdapterControlBlock)); | ||
1566 | |||
1567 | error = pci_set_dma_mask(pdev, DMA_64BIT_MASK); | ||
1568 | if (error) { | ||
1569 | error = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
1570 | if (error) { | ||
1571 | printk(KERN_WARNING | ||
1572 | "scsi%d: No suitable DMA mask available\n", | ||
1573 | host->host_no); | ||
1574 | return PCI_ERS_RESULT_DISCONNECT; | ||
1575 | } | ||
1576 | } | ||
1577 | bus = pdev->bus->number; | ||
1578 | dev_fun = pdev->devfn; | ||
1579 | acb = (struct AdapterControlBlock *) host->hostdata; | ||
1580 | memset(acb, 0, sizeof(struct AdapterControlBlock)); | ||
1581 | acb->pdev = pdev; | ||
1582 | acb->host = host; | ||
1583 | host->max_sectors = ARCMSR_MAX_XFER_SECTORS; | ||
1584 | host->max_lun = ARCMSR_MAX_TARGETLUN; | ||
1585 | host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/ | ||
1586 | host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/ | ||
1587 | host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES; | ||
1588 | host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ | ||
1589 | host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; | ||
1590 | host->this_id = ARCMSR_SCSI_INITIATOR_ID; | ||
1591 | host->unique_id = (bus << 8) | dev_fun; | ||
1592 | host->irq = pdev->irq; | ||
1593 | error = pci_request_regions(pdev, "arcmsr"); | ||
1594 | if (error) | ||
1595 | return PCI_ERS_RESULT_DISCONNECT; | ||
1596 | |||
1597 | acb->pmu = ioremap(pci_resource_start(pdev, 0), | ||
1598 | pci_resource_len(pdev, 0)); | ||
1599 | if (!acb->pmu) { | ||
1600 | printk(KERN_NOTICE "arcmsr%d: memory" | ||
1601 | " mapping region fail \n", acb->host->host_no); | ||
1602 | return PCI_ERS_RESULT_DISCONNECT; | ||
1603 | } | ||
1604 | acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | | ||
1605 | ACB_F_MESSAGE_RQBUFFER_CLEARED | | ||
1606 | ACB_F_MESSAGE_WQBUFFER_READED); | ||
1607 | acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; | ||
1608 | INIT_LIST_HEAD(&acb->ccb_free_list); | ||
1609 | |||
1610 | error = arcmsr_alloc_ccb_pool(acb); | ||
1611 | if (error) | ||
1612 | return PCI_ERS_RESULT_DISCONNECT; | ||
1613 | |||
1614 | error = request_irq(pdev->irq, arcmsr_do_interrupt, | ||
1615 | IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb); | ||
1616 | if (error) | ||
1617 | return PCI_ERS_RESULT_DISCONNECT; | ||
1618 | |||
1619 | arcmsr_iop_init(acb); | ||
1620 | if (strncmp(acb->firm_version, "V1.42", 5) >= 0) | ||
1621 | host->max_sectors = ARCMSR_MAX_XFER_SECTORS_B; | ||
1622 | |||
1623 | pci_set_drvdata(pdev, host); | ||
1624 | |||
1625 | error = scsi_add_host(host, &pdev->dev); | ||
1626 | if (error) | ||
1627 | return PCI_ERS_RESULT_DISCONNECT; | ||
1628 | |||
1629 | error = arcmsr_alloc_sysfs_attr(acb); | ||
1630 | if (error) | ||
1631 | return PCI_ERS_RESULT_DISCONNECT; | ||
1632 | |||
1633 | scsi_scan_host(host); | ||
1634 | return PCI_ERS_RESULT_RECOVERED; | ||
1635 | } | ||
1636 | |||
1637 | static void arcmsr_pci_ers_need_reset_forepart(struct pci_dev *pdev) | ||
1638 | { | ||
1639 | struct Scsi_Host *host = pci_get_drvdata(pdev); | ||
1640 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
1641 | struct MessageUnit __iomem *reg = acb->pmu; | ||
1642 | struct CommandControlBlock *ccb; | ||
1643 | /*clear and abort all outbound posted Q*/ | ||
1644 | int i = 0, found = 0; | ||
1645 | int id, lun; | ||
1646 | uint32_t flag_ccb, outbound_intstatus; | ||
1647 | |||
1648 | while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && | ||
1649 | (i++ < 256)){ | ||
1650 | ccb = (struct CommandControlBlock *)(acb->vir2phy_offset | ||
1651 | + (flag_ccb << 5)); | ||
1652 | if (ccb){ | ||
1653 | if ((ccb->acb != acb)||(ccb->startdone != | ||
1654 | ARCMSR_CCB_START)){ | ||
1655 | printk(KERN_NOTICE "arcmsr%d: polling \ | ||
1656 | get an illegal ccb"" command done ccb = '0x%p'" | ||
1657 | "ccboutstandingcount = %d \n", | ||
1658 | acb->host->host_no, ccb, | ||
1659 | atomic_read(&acb->ccboutstandingcount)); | ||
1660 | continue; | ||
1661 | } | ||
1662 | |||
1663 | id = ccb->pcmd->device->id; | ||
1664 | lun = ccb->pcmd->device->lun; | ||
1665 | if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { | ||
1666 | if (acb->devstate[id][lun] == | ||
1667 | ARECA_RAID_GONE) | ||
1668 | acb->devstate[id][lun] = | ||
1669 | ARECA_RAID_GOOD; | ||
1670 | ccb->pcmd->result = DID_OK << 16; | ||
1671 | arcmsr_ccb_complete(ccb, 1); | ||
1672 | } | ||
1673 | else { | ||
1674 | switch(ccb->arcmsr_cdb.DeviceStatus) { | ||
1675 | case ARCMSR_DEV_SELECT_TIMEOUT: { | ||
1676 | acb->devstate[id][lun] = | ||
1677 | ARECA_RAID_GONE; | ||
1678 | ccb->pcmd->result = | ||
1679 | DID_NO_CONNECT << 16; | ||
1680 | arcmsr_ccb_complete(ccb, 1); | ||
1681 | } | ||
1682 | break; | ||
1683 | |||
1684 | case ARCMSR_DEV_ABORTED: | ||
1685 | |||
1686 | case ARCMSR_DEV_INIT_FAIL: { | ||
1687 | acb->devstate[id][lun] = | ||
1688 | ARECA_RAID_GONE; | ||
1689 | ccb->pcmd->result = | ||
1690 | DID_BAD_TARGET << 16; | ||
1691 | arcmsr_ccb_complete(ccb, 1); | ||
1692 | } | ||
1693 | break; | ||
1694 | |||
1695 | case ARCMSR_DEV_CHECK_CONDITION: { | ||
1696 | acb->devstate[id][lun] = | ||
1697 | ARECA_RAID_GOOD; | ||
1698 | arcmsr_report_sense_info(ccb); | ||
1699 | arcmsr_ccb_complete(ccb, 1); | ||
1700 | } | ||
1701 | break; | ||
1702 | |||
1703 | default: | ||
1704 | printk(KERN_NOTICE | ||
1705 | "arcmsr%d: scsi \ | ||
1706 | id = %d lun = %d" | ||
1707 | " polling and \ | ||
1708 | getting command \ | ||
1709 | error done" | ||
1710 | "but got unknown \ | ||
1711 | DeviceStatus = 0x%x \n" | ||
1712 | , acb->host->host_no, | ||
1713 | id, lun, | ||
1714 | ccb->arcmsr_cdb.DeviceStatus); | ||
1715 | acb->devstate[id][lun] = | ||
1716 | ARECA_RAID_GONE; | ||
1717 | ccb->pcmd->result = | ||
1718 | DID_BAD_TARGET << 16; | ||
1719 | arcmsr_ccb_complete(ccb, 1); | ||
1720 | break; | ||
1721 | } | ||
1722 | } | ||
1723 | found = 1; | ||
1724 | } | ||
1725 | } | ||
1726 | if (found){ | ||
1727 | outbound_intstatus = readl(®->outbound_intstatus) & | ||
1728 | acb->outbound_int_enable; | ||
1729 | writel(outbound_intstatus, ®->outbound_intstatus); | ||
1730 | /*clear interrupt*/ | ||
1731 | } | ||
1732 | return; | ||
1733 | } | ||
1734 | |||
1454 | 1735 | ||
1736 | static void arcmsr_pci_ers_disconnect_forepart(struct pci_dev *pdev) | ||
1737 | { | ||
1738 | struct Scsi_Host *host = pci_get_drvdata(pdev); | ||
1739 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | ||
1740 | struct MessageUnit __iomem *reg = acb->pmu; | ||
1741 | struct CommandControlBlock *ccb; | ||
1742 | /*clear and abort all outbound posted Q*/ | ||
1743 | int i = 0, found = 0; | ||
1744 | int id, lun; | ||
1745 | uint32_t flag_ccb, outbound_intstatus; | ||
1746 | |||
1747 | while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && | ||
1748 | (i++ < 256)){ | ||
1749 | ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + | ||
1750 | (flag_ccb << 5)); | ||
1751 | if (ccb){ | ||
1752 | if ((ccb->acb != acb)||(ccb->startdone != | ||
1753 | ARCMSR_CCB_START)){ | ||
1754 | printk(KERN_NOTICE | ||
1755 | "arcmsr%d: polling get an illegal ccb" | ||
1756 | " command done ccb = '0x%p'" | ||
1757 | "ccboutstandingcount = %d \n", | ||
1758 | acb->host->host_no, ccb, | ||
1759 | atomic_read(&acb->ccboutstandingcount)); | ||
1760 | continue; | ||
1761 | } | ||
1762 | |||
1763 | id = ccb->pcmd->device->id; | ||
1764 | lun = ccb->pcmd->device->lun; | ||
1765 | if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { | ||
1766 | if (acb->devstate[id][lun] == ARECA_RAID_GONE) | ||
1767 | acb->devstate[id][lun] = ARECA_RAID_GOOD; | ||
1768 | ccb->pcmd->result = DID_OK << 16; | ||
1769 | arcmsr_ccb_complete(ccb, 1); | ||
1770 | } | ||
1771 | else { | ||
1772 | switch(ccb->arcmsr_cdb.DeviceStatus) { | ||
1773 | case ARCMSR_DEV_SELECT_TIMEOUT: { | ||
1774 | acb->devstate[id][lun] = | ||
1775 | ARECA_RAID_GONE; | ||
1776 | ccb->pcmd->result = | ||
1777 | DID_NO_CONNECT << 16; | ||
1778 | arcmsr_ccb_complete(ccb, 1); | ||
1779 | } | ||
1780 | break; | ||
1781 | |||
1782 | case ARCMSR_DEV_ABORTED: | ||
1783 | |||
1784 | case ARCMSR_DEV_INIT_FAIL: { | ||
1785 | acb->devstate[id][lun] = | ||
1786 | ARECA_RAID_GONE; | ||
1787 | ccb->pcmd->result = | ||
1788 | DID_BAD_TARGET << 16; | ||
1789 | arcmsr_ccb_complete(ccb, 1); | ||
1790 | } | ||
1791 | break; | ||
1792 | |||
1793 | case ARCMSR_DEV_CHECK_CONDITION: { | ||
1794 | acb->devstate[id][lun] = | ||
1795 | ARECA_RAID_GOOD; | ||
1796 | arcmsr_report_sense_info(ccb); | ||
1797 | arcmsr_ccb_complete(ccb, 1); | ||
1798 | } | ||
1799 | break; | ||
1800 | |||
1801 | default: | ||
1802 | printk(KERN_NOTICE "arcmsr%d: \ | ||
1803 | scsi id = %d lun = %d" | ||
1804 | " polling and \ | ||
1805 | getting command error done" | ||
1806 | "but got unknown \ | ||
1807 | DeviceStatus = 0x%x \n" | ||
1808 | , acb->host->host_no, | ||
1809 | id, lun, ccb->arcmsr_cdb.DeviceStatus); | ||
1810 | acb->devstate[id][lun] = | ||
1811 | ARECA_RAID_GONE; | ||
1812 | ccb->pcmd->result = | ||
1813 | DID_BAD_TARGET << 16; | ||
1814 | arcmsr_ccb_complete(ccb, 1); | ||
1815 | break; | ||
1816 | } | ||
1817 | } | ||
1818 | found = 1; | ||
1819 | } | ||
1820 | } | ||
1821 | if (found){ | ||
1822 | outbound_intstatus = readl(®->outbound_intstatus) & | ||
1823 | acb->outbound_int_enable; | ||
1824 | writel(outbound_intstatus, ®->outbound_intstatus); | ||
1825 | /*clear interrupt*/ | ||
1826 | } | ||
1827 | return; | ||
1828 | } | ||
1829 | |||
1830 | static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev, | ||
1831 | pci_channel_state_t state) | ||
1832 | { | ||
1833 | switch (state) { | ||
1834 | case pci_channel_io_frozen: | ||
1835 | arcmsr_pci_ers_need_reset_forepart(pdev); | ||
1836 | return PCI_ERS_RESULT_NEED_RESET; | ||
1837 | case pci_channel_io_perm_failure: | ||
1838 | arcmsr_pci_ers_disconnect_forepart(pdev); | ||
1839 | return PCI_ERS_RESULT_DISCONNECT; | ||
1840 | break; | ||
1841 | default: | ||
1842 | return PCI_ERS_RESULT_NEED_RESET; | ||
1843 | } | ||
1844 | } | ||