.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* -*- mode: c; c-basic-offset: 8 -*- */ |
---|
2 | 3 | |
---|
3 | 4 | /* NCR (or Symbios) 53c700 and 53c700-66 Driver |
---|
.. | .. |
---|
5 | 6 | * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com |
---|
6 | 7 | **----------------------------------------------------------------------------- |
---|
7 | 8 | ** |
---|
8 | | -** This program is free software; you can redistribute it and/or modify |
---|
9 | | -** it under the terms of the GNU General Public License as published by |
---|
10 | | -** the Free Software Foundation; either version 2 of the License, or |
---|
11 | | -** (at your option) any later version. |
---|
12 | | -** |
---|
13 | | -** This program is distributed in the hope that it will be useful, |
---|
14 | | -** but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | | -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
16 | | -** GNU General Public License for more details. |
---|
17 | | -** |
---|
18 | | -** You should have received a copy of the GNU General Public License |
---|
19 | | -** along with this program; if not, write to the Free Software |
---|
20 | | -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
21 | 9 | ** |
---|
22 | 10 | **----------------------------------------------------------------------------- |
---|
23 | 11 | */ |
---|
.. | .. |
---|
128 | 116 | #include <linux/module.h> |
---|
129 | 117 | #include <linux/interrupt.h> |
---|
130 | 118 | #include <linux/device.h> |
---|
| 119 | +#include <linux/pgtable.h> |
---|
131 | 120 | #include <asm/dma.h> |
---|
132 | 121 | #include <asm/io.h> |
---|
133 | | -#include <asm/pgtable.h> |
---|
134 | 122 | #include <asm/byteorder.h> |
---|
135 | 123 | |
---|
136 | 124 | #include <scsi/scsi.h> |
---|
.. | .. |
---|
281 | 269 | spi_period(SDp->sdev_target)); |
---|
282 | 270 | } |
---|
283 | 271 | |
---|
| 272 | +static inline dma_addr_t virt_to_dma(struct NCR_700_Host_Parameters *h, void *p) |
---|
| 273 | +{ |
---|
| 274 | + return h->pScript + ((uintptr_t)p - (uintptr_t)h->script); |
---|
| 275 | +} |
---|
| 276 | + |
---|
| 277 | +static inline void dma_sync_to_dev(struct NCR_700_Host_Parameters *h, |
---|
| 278 | + void *addr, size_t size) |
---|
| 279 | +{ |
---|
| 280 | + if (h->noncoherent) |
---|
| 281 | + dma_sync_single_for_device(h->dev, virt_to_dma(h, addr), |
---|
| 282 | + size, DMA_BIDIRECTIONAL); |
---|
| 283 | +} |
---|
| 284 | + |
---|
| 285 | +static inline void dma_sync_from_dev(struct NCR_700_Host_Parameters *h, |
---|
| 286 | + void *addr, size_t size) |
---|
| 287 | +{ |
---|
| 288 | + if (h->noncoherent) |
---|
| 289 | + dma_sync_single_for_device(h->dev, virt_to_dma(h, addr), size, |
---|
| 290 | + DMA_BIDIRECTIONAL); |
---|
| 291 | +} |
---|
| 292 | + |
---|
284 | 293 | struct Scsi_Host * |
---|
285 | 294 | NCR_700_detect(struct scsi_host_template *tpnt, |
---|
286 | 295 | struct NCR_700_Host_Parameters *hostdata, struct device *dev) |
---|
.. | .. |
---|
295 | 304 | if(tpnt->sdev_attrs == NULL) |
---|
296 | 305 | tpnt->sdev_attrs = NCR_700_dev_attrs; |
---|
297 | 306 | |
---|
298 | | - memory = dma_alloc_attrs(dev, TOTAL_MEM_SIZE, &pScript, |
---|
299 | | - GFP_KERNEL, DMA_ATTR_NON_CONSISTENT); |
---|
300 | | - if(memory == NULL) { |
---|
| 307 | + memory = dma_alloc_coherent(dev, TOTAL_MEM_SIZE, &pScript, GFP_KERNEL); |
---|
| 308 | + if (!memory) { |
---|
| 309 | + hostdata->noncoherent = 1; |
---|
| 310 | + memory = dma_alloc_noncoherent(dev, TOTAL_MEM_SIZE, &pScript, |
---|
| 311 | + DMA_BIDIRECTIONAL, GFP_KERNEL); |
---|
| 312 | + } |
---|
| 313 | + if (!memory) { |
---|
301 | 314 | printk(KERN_ERR "53c700: Failed to allocate memory for driver, detaching\n"); |
---|
302 | 315 | return NULL; |
---|
303 | 316 | } |
---|
.. | .. |
---|
318 | 331 | tpnt->can_queue = NCR_700_COMMAND_SLOTS_PER_HOST; |
---|
319 | 332 | tpnt->sg_tablesize = NCR_700_SG_SEGMENTS; |
---|
320 | 333 | tpnt->cmd_per_lun = NCR_700_CMD_PER_LUN; |
---|
321 | | - tpnt->use_clustering = ENABLE_CLUSTERING; |
---|
322 | 334 | tpnt->slave_configure = NCR_700_slave_configure; |
---|
323 | 335 | tpnt->slave_destroy = NCR_700_slave_destroy; |
---|
324 | 336 | tpnt->slave_alloc = NCR_700_slave_alloc; |
---|
.. | .. |
---|
352 | 364 | for (j = 0; j < PATCHES; j++) |
---|
353 | 365 | script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]); |
---|
354 | 366 | /* now patch up fixed addresses. */ |
---|
355 | | - script_patch_32(hostdata->dev, script, MessageLocation, |
---|
| 367 | + script_patch_32(hostdata, script, MessageLocation, |
---|
356 | 368 | pScript + MSGOUT_OFFSET); |
---|
357 | | - script_patch_32(hostdata->dev, script, StatusAddress, |
---|
| 369 | + script_patch_32(hostdata, script, StatusAddress, |
---|
358 | 370 | pScript + STATUS_OFFSET); |
---|
359 | | - script_patch_32(hostdata->dev, script, ReceiveMsgAddress, |
---|
| 371 | + script_patch_32(hostdata, script, ReceiveMsgAddress, |
---|
360 | 372 | pScript + MSGIN_OFFSET); |
---|
361 | 373 | |
---|
362 | 374 | hostdata->script = script; |
---|
.. | .. |
---|
408 | 420 | struct NCR_700_Host_Parameters *hostdata = |
---|
409 | 421 | (struct NCR_700_Host_Parameters *)host->hostdata[0]; |
---|
410 | 422 | |
---|
411 | | - dma_free_attrs(hostdata->dev, TOTAL_MEM_SIZE, hostdata->script, |
---|
412 | | - hostdata->pScript, DMA_ATTR_NON_CONSISTENT); |
---|
| 423 | + if (hostdata->noncoherent) |
---|
| 424 | + dma_free_noncoherent(hostdata->dev, TOTAL_MEM_SIZE, |
---|
| 425 | + hostdata->script, hostdata->pScript, |
---|
| 426 | + DMA_BIDIRECTIONAL); |
---|
| 427 | + else |
---|
| 428 | + dma_free_coherent(hostdata->dev, TOTAL_MEM_SIZE, |
---|
| 429 | + hostdata->script, hostdata->pScript); |
---|
413 | 430 | return 1; |
---|
414 | 431 | } |
---|
415 | 432 | |
---|
.. | .. |
---|
817 | 834 | shost_printk(KERN_WARNING, host, |
---|
818 | 835 | "Unexpected SDTR msg\n"); |
---|
819 | 836 | hostdata->msgout[0] = A_REJECT_MSG; |
---|
820 | | - dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE); |
---|
821 | | - script_patch_16(hostdata->dev, hostdata->script, |
---|
| 837 | + dma_sync_to_dev(hostdata, hostdata->msgout, 1); |
---|
| 838 | + script_patch_16(hostdata, hostdata->script, |
---|
822 | 839 | MessageCount, 1); |
---|
823 | 840 | /* SendMsgOut returns, so set up the return |
---|
824 | 841 | * address */ |
---|
.. | .. |
---|
830 | 847 | printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n", |
---|
831 | 848 | host->host_no, pun, lun); |
---|
832 | 849 | hostdata->msgout[0] = A_REJECT_MSG; |
---|
833 | | - dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE); |
---|
834 | | - script_patch_16(hostdata->dev, hostdata->script, MessageCount, |
---|
835 | | - 1); |
---|
| 850 | + dma_sync_to_dev(hostdata, hostdata->msgout, 1); |
---|
| 851 | + script_patch_16(hostdata, hostdata->script, MessageCount, 1); |
---|
836 | 852 | resume_offset = hostdata->pScript + Ent_SendMessageWithATN; |
---|
837 | 853 | |
---|
838 | 854 | break; |
---|
.. | .. |
---|
845 | 861 | printk("\n"); |
---|
846 | 862 | /* just reject it */ |
---|
847 | 863 | hostdata->msgout[0] = A_REJECT_MSG; |
---|
848 | | - dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE); |
---|
849 | | - script_patch_16(hostdata->dev, hostdata->script, MessageCount, |
---|
850 | | - 1); |
---|
| 864 | + dma_sync_to_dev(hostdata, hostdata->msgout, 1); |
---|
| 865 | + script_patch_16(hostdata, hostdata->script, MessageCount, 1); |
---|
851 | 866 | /* SendMsgOut returns, so set up the return |
---|
852 | 867 | * address */ |
---|
853 | 868 | resume_offset = hostdata->pScript + Ent_SendMessageWithATN; |
---|
.. | .. |
---|
930 | 945 | printk("\n"); |
---|
931 | 946 | /* just reject it */ |
---|
932 | 947 | hostdata->msgout[0] = A_REJECT_MSG; |
---|
933 | | - dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE); |
---|
934 | | - script_patch_16(hostdata->dev, hostdata->script, MessageCount, |
---|
935 | | - 1); |
---|
| 948 | + dma_sync_to_dev(hostdata, hostdata->msgout, 1); |
---|
| 949 | + script_patch_16(hostdata, hostdata->script, MessageCount, 1); |
---|
936 | 950 | /* SendMsgOut returns, so set up the return |
---|
937 | 951 | * address */ |
---|
938 | 952 | resume_offset = hostdata->pScript + Ent_SendMessageWithATN; |
---|
.. | .. |
---|
941 | 955 | } |
---|
942 | 956 | NCR_700_writel(temp, host, TEMP_REG); |
---|
943 | 957 | /* set us up to receive another message */ |
---|
944 | | - dma_cache_sync(hostdata->dev, hostdata->msgin, MSG_ARRAY_SIZE, DMA_FROM_DEVICE); |
---|
| 958 | + dma_sync_from_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE); |
---|
945 | 959 | return resume_offset; |
---|
946 | 960 | } |
---|
947 | 961 | |
---|
.. | .. |
---|
1021 | 1035 | slot->SG[1].ins = bS_to_host(SCRIPT_RETURN); |
---|
1022 | 1036 | slot->SG[1].pAddr = 0; |
---|
1023 | 1037 | slot->resume_offset = hostdata->pScript; |
---|
1024 | | - dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG[0])*2, DMA_TO_DEVICE); |
---|
1025 | | - dma_cache_sync(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); |
---|
| 1038 | + dma_sync_to_dev(hostdata, slot->SG, sizeof(slot->SG[0])*2); |
---|
| 1039 | + dma_sync_from_dev(hostdata, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE); |
---|
1026 | 1040 | |
---|
1027 | 1041 | /* queue the command for reissue */ |
---|
1028 | 1042 | slot->state = NCR_700_SLOT_QUEUED; |
---|
.. | .. |
---|
1142 | 1156 | hostdata->cmd = slot->cmnd; |
---|
1143 | 1157 | |
---|
1144 | 1158 | /* re-patch for this command */ |
---|
1145 | | - script_patch_32_abs(hostdata->dev, hostdata->script, |
---|
| 1159 | + script_patch_32_abs(hostdata, hostdata->script, |
---|
1146 | 1160 | CommandAddress, slot->pCmd); |
---|
1147 | | - script_patch_16(hostdata->dev, hostdata->script, |
---|
| 1161 | + script_patch_16(hostdata, hostdata->script, |
---|
1148 | 1162 | CommandCount, slot->cmnd->cmd_len); |
---|
1149 | | - script_patch_32_abs(hostdata->dev, hostdata->script, |
---|
| 1163 | + script_patch_32_abs(hostdata, hostdata->script, |
---|
1150 | 1164 | SGScriptStartAddress, |
---|
1151 | 1165 | to32bit(&slot->pSG[0].ins)); |
---|
1152 | 1166 | |
---|
.. | .. |
---|
1157 | 1171 | * should therefore always clear ACK */ |
---|
1158 | 1172 | NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device), |
---|
1159 | 1173 | host, SXFER_REG); |
---|
1160 | | - dma_cache_sync(hostdata->dev, hostdata->msgin, |
---|
1161 | | - MSG_ARRAY_SIZE, DMA_FROM_DEVICE); |
---|
1162 | | - dma_cache_sync(hostdata->dev, hostdata->msgout, |
---|
1163 | | - MSG_ARRAY_SIZE, DMA_TO_DEVICE); |
---|
| 1174 | + dma_sync_from_dev(hostdata, hostdata->msgin, |
---|
| 1175 | + MSG_ARRAY_SIZE); |
---|
| 1176 | + dma_sync_to_dev(hostdata, hostdata->msgout, |
---|
| 1177 | + MSG_ARRAY_SIZE); |
---|
1164 | 1178 | /* I'm just being paranoid here, the command should |
---|
1165 | 1179 | * already have been flushed from the cache */ |
---|
1166 | | - dma_cache_sync(hostdata->dev, slot->cmnd->cmnd, |
---|
1167 | | - slot->cmnd->cmd_len, DMA_TO_DEVICE); |
---|
| 1180 | + dma_sync_to_dev(hostdata, slot->cmnd->cmnd, |
---|
| 1181 | + slot->cmnd->cmd_len); |
---|
1168 | 1182 | |
---|
1169 | 1183 | |
---|
1170 | 1184 | |
---|
.. | .. |
---|
1227 | 1241 | hostdata->reselection_id = reselection_id; |
---|
1228 | 1242 | /* just in case we have a stale simple tag message, clear it */ |
---|
1229 | 1243 | hostdata->msgin[1] = 0; |
---|
1230 | | - dma_cache_sync(hostdata->dev, hostdata->msgin, |
---|
1231 | | - MSG_ARRAY_SIZE, DMA_BIDIRECTIONAL); |
---|
| 1244 | + dma_sync_to_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE); |
---|
1232 | 1245 | if(hostdata->tag_negotiated & (1<<reselection_id)) { |
---|
1233 | 1246 | resume_offset = hostdata->pScript + Ent_GetReselectionWithTag; |
---|
1234 | 1247 | } else { |
---|
.. | .. |
---|
1342 | 1355 | hostdata->cmd = NULL; |
---|
1343 | 1356 | /* clear any stale simple tag message */ |
---|
1344 | 1357 | hostdata->msgin[1] = 0; |
---|
1345 | | - dma_cache_sync(hostdata->dev, hostdata->msgin, MSG_ARRAY_SIZE, |
---|
1346 | | - DMA_BIDIRECTIONAL); |
---|
| 1358 | + dma_sync_to_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE); |
---|
1347 | 1359 | |
---|
1348 | 1360 | if(id == 0xff) { |
---|
1349 | 1361 | /* Selected as target, Ignore */ |
---|
.. | .. |
---|
1440 | 1452 | NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); |
---|
1441 | 1453 | } |
---|
1442 | 1454 | |
---|
1443 | | - script_patch_16(hostdata->dev, hostdata->script, MessageCount, count); |
---|
| 1455 | + script_patch_16(hostdata, hostdata->script, MessageCount, count); |
---|
1444 | 1456 | |
---|
| 1457 | + script_patch_ID(hostdata, hostdata->script, Device_ID, 1<<scmd_id(SCp)); |
---|
1445 | 1458 | |
---|
1446 | | - script_patch_ID(hostdata->dev, hostdata->script, |
---|
1447 | | - Device_ID, 1<<scmd_id(SCp)); |
---|
1448 | | - |
---|
1449 | | - script_patch_32_abs(hostdata->dev, hostdata->script, CommandAddress, |
---|
| 1459 | + script_patch_32_abs(hostdata, hostdata->script, CommandAddress, |
---|
1450 | 1460 | slot->pCmd); |
---|
1451 | | - script_patch_16(hostdata->dev, hostdata->script, CommandCount, |
---|
1452 | | - SCp->cmd_len); |
---|
| 1461 | + script_patch_16(hostdata, hostdata->script, CommandCount, SCp->cmd_len); |
---|
1453 | 1462 | /* finally plumb the beginning of the SG list into the script |
---|
1454 | 1463 | * */ |
---|
1455 | | - script_patch_32_abs(hostdata->dev, hostdata->script, |
---|
| 1464 | + script_patch_32_abs(hostdata, hostdata->script, |
---|
1456 | 1465 | SGScriptStartAddress, to32bit(&slot->pSG[0].ins)); |
---|
1457 | 1466 | NCR_700_clear_fifo(SCp->device->host); |
---|
1458 | 1467 | |
---|
1459 | 1468 | if(slot->resume_offset == 0) |
---|
1460 | 1469 | slot->resume_offset = hostdata->pScript; |
---|
1461 | 1470 | /* now perform all the writebacks and invalidates */ |
---|
1462 | | - dma_cache_sync(hostdata->dev, hostdata->msgout, count, DMA_TO_DEVICE); |
---|
1463 | | - dma_cache_sync(hostdata->dev, hostdata->msgin, MSG_ARRAY_SIZE, |
---|
1464 | | - DMA_FROM_DEVICE); |
---|
1465 | | - dma_cache_sync(hostdata->dev, SCp->cmnd, SCp->cmd_len, DMA_TO_DEVICE); |
---|
1466 | | - dma_cache_sync(hostdata->dev, hostdata->status, 1, DMA_FROM_DEVICE); |
---|
| 1471 | + dma_sync_to_dev(hostdata, hostdata->msgout, count); |
---|
| 1472 | + dma_sync_from_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE); |
---|
| 1473 | + dma_sync_to_dev(hostdata, SCp->cmnd, SCp->cmd_len); |
---|
| 1474 | + dma_sync_from_dev(hostdata, hostdata->status, 1); |
---|
1467 | 1475 | |
---|
1468 | 1476 | /* set the synchronous period/offset */ |
---|
1469 | 1477 | NCR_700_writeb(NCR_700_get_SXFER(SCp->device), |
---|
.. | .. |
---|
1498 | 1506 | __u8 sstat0 = 0, dstat = 0; |
---|
1499 | 1507 | __u32 dsp; |
---|
1500 | 1508 | struct scsi_cmnd *SCp = hostdata->cmd; |
---|
1501 | | - enum NCR_700_Host_State state; |
---|
1502 | 1509 | |
---|
1503 | 1510 | handled = 1; |
---|
1504 | | - state = hostdata->state; |
---|
1505 | 1511 | SCp = hostdata->cmd; |
---|
1506 | 1512 | |
---|
1507 | 1513 | if(istat & SCSI_INT_PENDING) { |
---|
.. | .. |
---|
1594 | 1600 | printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG))); |
---|
1595 | 1601 | #endif |
---|
1596 | 1602 | resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch; |
---|
1597 | | - } else if(dsp >= to32bit(&slot->pSG[0].ins) && |
---|
| 1603 | + } else if (slot && dsp >= to32bit(&slot->pSG[0].ins) && |
---|
1598 | 1604 | dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) { |
---|
1599 | 1605 | int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff; |
---|
1600 | 1606 | int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List); |
---|
.. | .. |
---|
1639 | 1645 | slot->SG[i].ins = bS_to_host(SCRIPT_NOP); |
---|
1640 | 1646 | slot->SG[i].pAddr = 0; |
---|
1641 | 1647 | } |
---|
1642 | | - dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG), DMA_TO_DEVICE); |
---|
| 1648 | + dma_sync_to_dev(hostdata, slot->SG, sizeof(slot->SG)); |
---|
1643 | 1649 | /* and pretend we disconnected after |
---|
1644 | 1650 | * the command phase */ |
---|
1645 | 1651 | resume_offset = hostdata->pScript + Ent_MsgInDuringData; |
---|
.. | .. |
---|
1752 | 1758 | struct NCR_700_Host_Parameters *hostdata = |
---|
1753 | 1759 | (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0]; |
---|
1754 | 1760 | __u32 move_ins; |
---|
1755 | | - enum dma_data_direction direction; |
---|
1756 | 1761 | struct NCR_700_command_slot *slot; |
---|
1757 | 1762 | |
---|
1758 | 1763 | if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) { |
---|
.. | .. |
---|
1845 | 1850 | case REQUEST_SENSE: |
---|
1846 | 1851 | /* clear the internal sense magic */ |
---|
1847 | 1852 | SCp->cmnd[6] = 0; |
---|
1848 | | - /* fall through */ |
---|
| 1853 | + fallthrough; |
---|
1849 | 1854 | default: |
---|
1850 | 1855 | /* OK, get it from the command */ |
---|
1851 | 1856 | switch(SCp->sc_data_direction) { |
---|
.. | .. |
---|
1869 | 1874 | } |
---|
1870 | 1875 | |
---|
1871 | 1876 | /* now build the scatter gather list */ |
---|
1872 | | - direction = SCp->sc_data_direction; |
---|
1873 | 1877 | if(move_ins != 0) { |
---|
1874 | 1878 | int i; |
---|
1875 | 1879 | int sg_count; |
---|
.. | .. |
---|
1891 | 1895 | } |
---|
1892 | 1896 | slot->SG[i].ins = bS_to_host(SCRIPT_RETURN); |
---|
1893 | 1897 | slot->SG[i].pAddr = 0; |
---|
1894 | | - dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG), DMA_TO_DEVICE); |
---|
| 1898 | + dma_sync_to_dev(hostdata, slot->SG, sizeof(slot->SG)); |
---|
1895 | 1899 | DEBUG((" SETTING %p to %x\n", |
---|
1896 | 1900 | (&slot->pSG[i].ins), |
---|
1897 | 1901 | slot->SG[i].ins)); |
---|