Pull SCSI updates from James Bottomley: "Updates to the usual drivers (scsi_debug, ufs, lpfc, st, fnic, mpi3mr, mpt3sas) and the removal of cxlflash. The only non-trivial core change is an addition to unit attention handling to recognize UAs for power on/reset and new media so the tape driver can use it" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (107 commits) scsi: st: Tighten the page format heuristics with MODE SELECT scsi: st: ERASE does not change tape location scsi: st: Fix array overflow in st_setup() scsi: target: tcm_loop: Fix wrong abort tag scsi: lpfc: Restore clearing of NLP_UNREG_INP in ndlp->nlp_flag scsi: hisi_sas: Fixed failure to issue vendor specific commands scsi: fnic: Remove unnecessary NUL-terminations scsi: fnic: Remove redundant flush_workqueue() calls scsi: core: Use a switch statement when attaching VPD pages scsi: ufs: renesas: Add initialization code for R-Car S4-8 ES1.2 scsi: ufs: renesas: Add reusable functions scsi: ufs: renesas: Refactor 0x10ad/0x10af PHY settings scsi: ufs: renesas: Remove register control helper function scsi: ufs: renesas: Add register read to remove save/set/restore scsi: ufs: renesas: Replace init data by init code scsi: ufs: dt-bindings: renesas,ufs: Add calibration data scsi: mpi3mr: Task Abort EH Support scsi: storvsc: Don't report the host packet status as the hv status scsi: isci: Make most module parameters static scsi: megaraid_sas: Make most module parameters static ...
Unified · Split
| @@ -1559,3 +1559,48 @@ Description: · 1558 unmodified lines | ||
| 1559 | 1559 | Symbol - HCMID. This file shows the UFSHCD manufacturer id. |
| 1560 | 1560 | The Manufacturer ID is defined by JEDEC in JEDEC-JEP106. |
| 1561 | 1561 | The file is read only. |
| 1562 | + | |
| 1563 | +What: /sys/bus/platform/drivers/ufshcd/*/critical_health | |
| 1564 | +What: /sys/bus/platform/devices/*.ufs/critical_health | |
| 1565 | +Date: February 2025 | |
| 1566 | +Contact: Avri Altman <avri.altman@wdc.com> | |
| 1567 | +Description: Report the number of times a critical health event has been | |
| 1568 | + reported by a UFS device. Further insight into the specific | |
| 1569 | + issue can be gained by reading one of: bPreEOLInfo, | |
| 1570 | + bDeviceLifeTimeEstA, bDeviceLifeTimeEstB, | |
| 1571 | + bWriteBoosterBufferLifeTimeEst, and bRPMBLifeTimeEst. | |
| 1572 | + | |
| 1573 | + The file is read only. | |
| 1574 | + | |
| 1575 | +What: /sys/bus/platform/drivers/ufshcd/*/clkscale_enable | |
| 1576 | +What: /sys/bus/platform/devices/*.ufs/clkscale_enable | |
| 1577 | +Date: January 2025 | |
| 1578 | +Contact: Ziqi Chen <quic_ziqichen@quicinc.com> | |
| 1579 | +Description: | |
| 1580 | + This attribute shows whether the UFS clock scaling is enabled or not. | |
| 1581 | + And it can be used to enable/disable the clock scaling by writing | |
| 1582 | + 1 or 0 to this attribute. | |
| 1583 | + | |
| 1584 | + The attribute is read/write. | |
| 1585 | + | |
| 1586 | +What: /sys/bus/platform/drivers/ufshcd/*/clkgate_enable | |
| 1587 | +What: /sys/bus/platform/devices/*.ufs/clkgate_enable | |
| 1588 | +Date: January 2025 | |
| 1589 | +Contact: Ziqi Chen <quic_ziqichen@quicinc.com> | |
| 1590 | +Description: | |
| 1591 | + This attribute shows whether the UFS clock gating is enabled or not. | |
| 1592 | + And it can be used to enable/disable the clock gating by writing | |
| 1593 | + 1 or 0 to this attribute. | |
| 1594 | + | |
| 1595 | + The attribute is read/write. | |
| 1596 | + | |
| 1597 | +What: /sys/bus/platform/drivers/ufshcd/*/clkgate_delay_ms | |
| 1598 | +What: /sys/bus/platform/devices/*.ufs/clkgate_delay_ms | |
| 1599 | +Date: January 2025 | |
| 1600 | +Contact: Ziqi Chen <quic_ziqichen@quicinc.com> | |
| 1601 | +Description: | |
| 1602 | + This attribute shows and sets the number of milliseconds of idle time | |
| 1603 | + before the UFS driver starts to perform clock gating. This can | |
| 1604 | + prevent the UFS from frequently performing clock gating/ungating. | |
| 1605 | + | |
| 1606 | + The attribute is read/write. | |
| @@ -1,433 +0,0 @@ | ||
| 1 | −================================ | |
| 2 | −Coherent Accelerator (CXL) Flash | |
| 3 | −================================ | |
| 4 | − | |
| 5 | −Introduction | |
| 6 | −============ | |
| 7 | − | |
| 8 | − The IBM Power architecture provides support for CAPI (Coherent | |
| 9 | − Accelerator Power Interface), which is available to certain PCIe slots | |
| 10 | − on Power 8 systems. CAPI can be thought of as a special tunneling | |
| 11 | − protocol through PCIe that allow PCIe adapters to look like special | |
| 12 | − purpose co-processors which can read or write an application's | |
| 13 | − memory and generate page faults. As a result, the host interface to | |
| 14 | − an adapter running in CAPI mode does not require the data buffers to | |
| 15 | − be mapped to the device's memory (IOMMU bypass) nor does it require | |
| 16 | − memory to be pinned. | |
| 17 | − | |
| 18 | − On Linux, Coherent Accelerator (CXL) kernel services present CAPI | |
| 19 | − devices as a PCI device by implementing a virtual PCI host bridge. | |
| 20 | − This abstraction simplifies the infrastructure and programming | |
| 21 | − model, allowing for drivers to look similar to other native PCI | |
| 22 | − device drivers. | |
| 23 | − | |
| 24 | − CXL provides a mechanism by which user space applications can | |
| 25 | − directly talk to a device (network or storage) bypassing the typical | |
| 26 | − kernel/device driver stack. The CXL Flash Adapter Driver enables a | |
| 27 | − user space application direct access to Flash storage. | |
| 28 | − | |
| 29 | − The CXL Flash Adapter Driver is a kernel module that sits in the | |
| 30 | − SCSI stack as a low level device driver (below the SCSI disk and | |
| 31 | − protocol drivers) for the IBM CXL Flash Adapter. This driver is | |
| 32 | − responsible for the initialization of the adapter, setting up the | |
| 33 | − special path for user space access, and performing error recovery. It | |
| 34 | − communicates directly the Flash Accelerator Functional Unit (AFU) | |
| 35 | − as described in Documentation/arch/powerpc/cxl.rst. | |
| 36 | − | |
| 37 | − The cxlflash driver supports two, mutually exclusive, modes of | |
| 38 | − operation at the device (LUN) level: | |
| 39 | − | |
| 40 | − - Any flash device (LUN) can be configured to be accessed as a | |
| 41 | − regular disk device (i.e.: /dev/sdc). This is the default mode. | |
| 42 | − | |
| 43 | − - Any flash device (LUN) can be configured to be accessed from | |
| 44 | − user space with a special block library. This mode further | |
| 45 | − specifies the means of accessing the device and provides for | |
| 46 | − either raw access to the entire LUN (referred to as direct | |
| 47 | − or physical LUN access) or access to a kernel/AFU-mediated | |
| 48 | − partition of the LUN (referred to as virtual LUN access). The | |
| 49 | − segmentation of a disk device into virtual LUNs is assisted | |
| 50 | − by special translation services provided by the Flash AFU. | |
| 51 | − | |
| 52 | −Overview | |
| 53 | −======== | |
| 54 | − | |
| 55 | − The Coherent Accelerator Interface Architecture (CAIA) introduces a | |
| 56 | − concept of a master context. A master typically has special privileges | |
| 57 | − granted to it by the kernel or hypervisor allowing it to perform AFU | |
| 58 | − wide management and control. The master may or may not be involved | |
| 59 | − directly in each user I/O, but at the minimum is involved in the | |
| 60 | − initial setup before the user application is allowed to send requests | |
| 61 | − directly to the AFU. | |
| 62 | − | |
| 63 | − The CXL Flash Adapter Driver establishes a master context with the | |
| 64 | − AFU. It uses memory mapped I/O (MMIO) for this control and setup. The | |
| 65 | − Adapter Problem Space Memory Map looks like this:: | |
| 66 | − | |
| 67 | − +-------------------------------+ | |
| 68 | − | 512 * 64 KB User MMIO | | |
| 69 | − | (per context) | | |
| 70 | − | User Accessible | | |
| 71 | − +-------------------------------+ | |
| 72 | − | 512 * 128 B per context | | |
| 73 | − | Provisioning and Control | | |
| 74 | − | Trusted Process accessible | | |
| 75 | − +-------------------------------+ | |
| 76 | − | 64 KB Global | | |
| 77 | − | Trusted Process accessible | | |
| 78 | − +-------------------------------+ | |
| 79 | − | |
| 80 | − This driver configures itself into the SCSI software stack as an | |
| 81 | − adapter driver. The driver is the only entity that is considered a | |
| 82 | − Trusted Process to program the Provisioning and Control and Global | |
| 83 | − areas in the MMIO Space shown above. The master context driver | |
| 84 | − discovers all LUNs attached to the CXL Flash adapter and instantiates | |
| 85 | − scsi block devices (/dev/sdb, /dev/sdc etc.) for each unique LUN | |
| 86 | − seen from each path. | |
| 87 | − | |
| 88 | − Once these scsi block devices are instantiated, an application | |
| 89 | − written to a specification provided by the block library may get | |
| 90 | − access to the Flash from user space (without requiring a system call). | |
| 91 | − | |
| 92 | − This master context driver also provides a series of ioctls for this | |
| 93 | − block library to enable this user space access. The driver supports | |
| 94 | − two modes for accessing the block device. | |
| 95 | − | |
| 96 | − The first mode is called a virtual mode. In this mode a single scsi | |
| 97 | − block device (/dev/sdb) may be carved up into any number of distinct | |
| 98 | − virtual LUNs. The virtual LUNs may be resized as long as the sum of | |
| 99 | − the sizes of all the virtual LUNs, along with the meta-data associated | |
| 100 | − with it does not exceed the physical capacity. | |
| 101 | − | |
| 102 | − The second mode is called the physical mode. In this mode a single | |
| 103 | − block device (/dev/sdb) may be opened directly by the block library | |
| 104 | − and the entire space for the LUN is available to the application. | |
| 105 | − | |
| 106 | − Only the physical mode provides persistence of the data. i.e. The | |
| 107 | − data written to the block device will survive application exit and | |
| 108 | − restart and also reboot. The virtual LUNs do not persist (i.e. do | |
| 109 | − not survive after the application terminates or the system reboots). | |
| 110 | − | |
| 111 | − | |
| 112 | −Block library API | |
| 113 | −================= | |
| 114 | − | |
| 115 | − Applications intending to get access to the CXL Flash from user | |
| 116 | − space should use the block library, as it abstracts the details of | |
| 117 | − interfacing directly with the cxlflash driver that are necessary for | |
| 118 | − performing administrative actions (i.e.: setup, tear down, resize). | |
| 119 | − The block library can be thought of as a 'user' of services, | |
| 120 | − implemented as IOCTLs, that are provided by the cxlflash driver | |
| 121 | − specifically for devices (LUNs) operating in user space access | |
| 122 | − mode. While it is not a requirement that applications understand | |
| 123 | − the interface between the block library and the cxlflash driver, | |
| 124 | − a high-level overview of each supported service (IOCTL) is provided | |
| 125 | − below. | |
| 126 | − | |
| 127 | − The block library can be found on GitHub: | |
| 128 | − http://github.com/open-power/capiflash | |
| 129 | − | |
| 130 | − | |
| 131 | −CXL Flash Driver LUN IOCTLs | |
| 132 | −=========================== | |
| 133 | − | |
| 134 | − Users, such as the block library, that wish to interface with a flash | |
| 135 | − device (LUN) via user space access need to use the services provided | |
| 136 | − by the cxlflash driver. As these services are implemented as ioctls, | |
| 137 | − a file descriptor handle must first be obtained in order to establish | |
| 138 | − the communication channel between a user and the kernel. This file | |
| 139 | − descriptor is obtained by opening the device special file associated | |
| 140 | − with the scsi disk device (/dev/sdb) that was created during LUN | |
| 141 | − discovery. As per the location of the cxlflash driver within the | |
| 142 | − SCSI protocol stack, this open is actually not seen by the cxlflash | |
| 143 | − driver. Upon successful open, the user receives a file descriptor | |
| 144 | − (herein referred to as fd1) that should be used for issuing the | |
| 145 | − subsequent ioctls listed below. | |
| 146 | − | |
| 147 | − The structure definitions for these IOCTLs are available in: | |
| 148 | − uapi/scsi/cxlflash_ioctl.h | |
| 149 | − | |
| 150 | −DK_CXLFLASH_ATTACH | |
| 151 | −------------------ | |
| 152 | − | |
| 153 | − This ioctl obtains, initializes, and starts a context using the CXL | |
| 154 | − kernel services. These services specify a context id (u16) by which | |
| 155 | − to uniquely identify the context and its allocated resources. The | |
| 156 | − services additionally provide a second file descriptor (herein | |
| 157 | − referred to as fd2) that is used by the block library to initiate | |
| 158 | − memory mapped I/O (via mmap()) to the CXL flash device and poll for | |
| 159 | − completion events. This file descriptor is intentionally installed by | |
| 160 | − this driver and not the CXL kernel services to allow for intermediary | |
| 161 | − notification and access in the event of a non-user-initiated close(), | |
| 162 | − such as a killed process. This design point is described in further | |
| 163 | − detail in the description for the DK_CXLFLASH_DETACH ioctl. | |
| 164 | − | |
| 165 | − There are a few important aspects regarding the "tokens" (context id | |
| 166 | − and fd2) that are provided back to the user: | |
| 167 | − | |
| 168 | − - These tokens are only valid for the process under which they | |
| 169 | − were created. The child of a forked process cannot continue | |
| 170 | − to use the context id or file descriptor created by its parent | |
| 171 | − (see DK_CXLFLASH_VLUN_CLONE for further details). | |
| 172 | − | |
| 173 | − - These tokens are only valid for the lifetime of the context and | |
| 174 | − the process under which they were created. Once either is | |
| 175 | − destroyed, the tokens are to be considered stale and subsequent | |
| 176 | − usage will result in errors. | |
| 177 | − | |
| 178 | − - A valid adapter file descriptor (fd2 >= 0) is only returned on | |
| 179 | − the initial attach for a context. Subsequent attaches to an | |
| 180 | − existing context (DK_CXLFLASH_ATTACH_REUSE_CONTEXT flag present) | |
| 181 | − do not provide the adapter file descriptor as it was previously | |
| 182 | − made known to the application. | |
| 183 | − | |
| 184 | − - When a context is no longer needed, the user shall detach from | |
| 185 | − the context via the DK_CXLFLASH_DETACH ioctl. When this ioctl | |
| 186 | − returns with a valid adapter file descriptor and the return flag | |
| 187 | − DK_CXLFLASH_APP_CLOSE_ADAP_FD is present, the application _must_ | |
| 188 | − close the adapter file descriptor following a successful detach. | |
| 189 | − | |
| 190 | − - When this ioctl returns with a valid fd2 and the return flag | |
| 191 | − DK_CXLFLASH_APP_CLOSE_ADAP_FD is present, the application _must_ | |
| 192 | − close fd2 in the following circumstances: | |
| 193 | − | |
| 194 | − + Following a successful detach of the last user of the context | |
| 195 | − + Following a successful recovery on the context's original fd2 | |
| 196 | − + In the child process of a fork(), following a clone ioctl, | |
| 197 | − on the fd2 associated with the source context | |
| 198 | − | |
| 199 | − - At any time, a close on fd2 will invalidate the tokens. Applications | |
| 200 | − should exercise caution to only close fd2 when appropriate (outlined | |
| 201 | − in the previous bullet) to avoid premature loss of I/O. | |
| 202 | − | |
| 203 | −DK_CXLFLASH_USER_DIRECT | |
| 204 | −----------------------- | |
| 205 | − This ioctl is responsible for transitioning the LUN to direct | |
| 206 | − (physical) mode access and configuring the AFU for direct access from | |
| 207 | − user space on a per-context basis. Additionally, the block size and | |
| 208 | − last logical block address (LBA) are returned to the user. | |
| 209 | − | |
| 210 | − As mentioned previously, when operating in user space access mode, | |
| 211 | − LUNs may be accessed in whole or in part. Only one mode is allowed | |
| 212 | − at a time and if one mode is active (outstanding references exist), | |
| 213 | − requests to use the LUN in a different mode are denied. | |
| 214 | − | |
| 215 | − The AFU is configured for direct access from user space by adding an | |
| 216 | − entry to the AFU's resource handle table. The index of the entry is | |
| 217 | − treated as a resource handle that is returned to the user. The user | |
| 218 | − is then able to use the handle to reference the LUN during I/O. | |
| 219 | − | |
| 220 | −DK_CXLFLASH_USER_VIRTUAL | |
| 221 | −------------------------ | |
| 222 | − This ioctl is responsible for transitioning the LUN to virtual mode | |
| 223 | − of access and configuring the AFU for virtual access from user space | |
| 224 | − on a per-context basis. Additionally, the block size and last logical | |
| 225 | − block address (LBA) are returned to the user. | |
| 226 | − | |
| 227 | − As mentioned previously, when operating in user space access mode, | |
| 228 | − LUNs may be accessed in whole or in part. Only one mode is allowed | |
| 229 | − at a time and if one mode is active (outstanding references exist), | |
| 230 | − requests to use the LUN in a different mode are denied. | |
| 231 | − | |
| 232 | − The AFU is configured for virtual access from user space by adding | |
| 233 | − an entry to the AFU's resource handle table. The index of the entry | |
| 234 | − is treated as a resource handle that is returned to the user. The | |
| 235 | − user is then able to use the handle to reference the LUN during I/O. | |
| 236 | − | |
| 237 | − By default, the virtual LUN is created with a size of 0. The user | |
| 238 | − would need to use the DK_CXLFLASH_VLUN_RESIZE ioctl to adjust the grow | |
| 239 | − the virtual LUN to a desired size. To avoid having to perform this | |
| 240 | − resize for the initial creation of the virtual LUN, the user has the | |
| 241 | − option of specifying a size as part of the DK_CXLFLASH_USER_VIRTUAL | |
| 242 | − ioctl, such that when success is returned to the user, the | |
| 243 | − resource handle that is provided is already referencing provisioned | |
| 244 | − storage. This is reflected by the last LBA being a non-zero value. | |
| 245 | − | |
| 246 | − When a LUN is accessible from more than one port, this ioctl will | |
| 247 | − return with the DK_CXLFLASH_ALL_PORTS_ACTIVE return flag set. This | |
| 248 | − provides the user with a hint that I/O can be retried in the event | |
| 249 | − of an I/O error as the LUN can be reached over multiple paths. | |
| 250 | − | |
| 251 | −DK_CXLFLASH_VLUN_RESIZE | |
| 252 | −----------------------- | |
| 253 | − This ioctl is responsible for resizing a previously created virtual | |
| 254 | − LUN and will fail if invoked upon a LUN that is not in virtual | |
| 255 | − mode. Upon success, an updated last LBA is returned to the user | |
| 256 | − indicating the new size of the virtual LUN associated with the | |
| 257 | − resource handle. | |
| 258 | − | |
| 259 | − The partitioning of virtual LUNs is jointly mediated by the cxlflash | |
| 260 | − driver and the AFU. An allocation table is kept for each LUN that is | |
| 261 | − operating in the virtual mode and used to program a LUN translation | |
| 262 | − table that the AFU references when provided with a resource handle. | |
| 263 | − | |
| 264 | − This ioctl can return -EAGAIN if an AFU sync operation takes too long. | |
| 265 | − In addition to returning a failure to user, cxlflash will also schedule | |
| 266 | − an asynchronous AFU reset. Should the user choose to retry the operation, | |
| 267 | − it is expected to succeed. If this ioctl fails with -EAGAIN, the user | |
| 268 | − can either retry the operation or treat it as a failure. | |
| 269 | − | |
| 270 | −DK_CXLFLASH_RELEASE | |
| 271 | −------------------- | |
| 272 | − This ioctl is responsible for releasing a previously obtained | |
| 273 | − reference to either a physical or virtual LUN. This can be | |
| 274 | − thought of as the inverse of the DK_CXLFLASH_USER_DIRECT or | |
| 275 | − DK_CXLFLASH_USER_VIRTUAL ioctls. Upon success, the resource handle | |
| 276 | − is no longer valid and the entry in the resource handle table is | |
| 277 | − made available to be used again. | |
| 278 | − | |
| 279 | − As part of the release process for virtual LUNs, the virtual LUN | |
| 280 | − is first resized to 0 to clear out and free the translation tables | |
| 281 | − associated with the virtual LUN reference. | |
| 282 | − | |
| 283 | −DK_CXLFLASH_DETACH | |
| 284 | −------------------ | |
| 285 | − This ioctl is responsible for unregistering a context with the | |
| 286 | − cxlflash driver and release outstanding resources that were | |
| 287 | − not explicitly released via the DK_CXLFLASH_RELEASE ioctl. Upon | |
| 288 | − success, all "tokens" which had been provided to the user from the | |
| 289 | − DK_CXLFLASH_ATTACH onward are no longer valid. | |
| 290 | − | |
| 291 | − When the DK_CXLFLASH_APP_CLOSE_ADAP_FD flag was returned on a successful | |
| 292 | − attach, the application _must_ close the fd2 associated with the context | |
| 293 | − following the detach of the final user of the context. | |
| 294 | − | |
| 295 | −DK_CXLFLASH_VLUN_CLONE | |
| 296 | −---------------------- | |
| 297 | − This ioctl is responsible for cloning a previously created | |
| 298 | − context to a more recently created context. It exists solely to | |
| 299 | − support maintaining user space access to storage after a process | |
| 300 | − forks. Upon success, the child process (which invoked the ioctl) | |
| 301 | − will have access to the same LUNs via the same resource handle(s) | |
| 302 | − as the parent, but under a different context. | |
| 303 | − | |
| 304 | − Context sharing across processes is not supported with CXL and | |
| 305 | − therefore each fork must be met with establishing a new context | |
| 306 | − for the child process. This ioctl simplifies the state management | |
| 307 | − and playback required by a user in such a scenario. When a process | |
| 308 | − forks, child process can clone the parents context by first creating | |
| 309 | − a context (via DK_CXLFLASH_ATTACH) and then using this ioctl to | |
| 310 | − perform the clone from the parent to the child. | |
| 311 | − | |
| 312 | − The clone itself is fairly simple. The resource handle and lun | |
| 313 | − translation tables are copied from the parent context to the child's | |
| 314 | − and then synced with the AFU. | |
| 315 | − | |
| 316 | − When the DK_CXLFLASH_APP_CLOSE_ADAP_FD flag was returned on a successful | |
| 317 | − attach, the application _must_ close the fd2 associated with the source | |
| 318 | − context (still resident/accessible in the parent process) following the | |
| 319 | − clone. This is to avoid a stale entry in the file descriptor table of the | |
| 320 | − child process. | |
| 321 | − | |
| 322 | − This ioctl can return -EAGAIN if an AFU sync operation takes too long. | |
| 323 | − In addition to returning a failure to user, cxlflash will also schedule | |
| 324 | − an asynchronous AFU reset. Should the user choose to retry the operation, | |
| 325 | − it is expected to succeed. If this ioctl fails with -EAGAIN, the user | |
| 326 | − can either retry the operation or treat it as a failure. | |
| 327 | − | |
| 328 | −DK_CXLFLASH_VERIFY | |
| 329 | −------------------ | |
| 330 | − This ioctl is used to detect various changes such as the capacity of | |
| 331 | − the disk changing, the number of LUNs visible changing, etc. In cases | |
| 332 | − where the changes affect the application (such as a LUN resize), the | |
| 333 | − cxlflash driver will report the changed state to the application. | |
| 334 | − | |
| 335 | − The user calls in when they want to validate that a LUN hasn't been | |
| 336 | − changed in response to a check condition. As the user is operating out | |
| 337 | − of band from the kernel, they will see these types of events without | |
| 338 | − the kernel's knowledge. When encountered, the user's architected | |
| 339 | − behavior is to call in to this ioctl, indicating what they want to | |
| 340 | − verify and passing along any appropriate information. For now, only | |
| 341 | − verifying a LUN change (ie: size different) with sense data is | |
| 342 | − supported. | |
| 343 | − | |
| 344 | −DK_CXLFLASH_RECOVER_AFU | |
| 345 | −----------------------- | |
| 346 | − This ioctl is used to drive recovery (if such an action is warranted) | |
| 347 | − of a specified user context. Any state associated with the user context | |
| 348 | − is re-established upon successful recovery. | |
| 349 | − | |
| 350 | − User contexts are put into an error condition when the device needs to | |
| 351 | − be reset or is terminating. Users are notified of this error condition | |
| 352 | − by seeing all 0xF's on an MMIO read. Upon encountering this, the | |
| 353 | − architected behavior for a user is to call into this ioctl to recover | |
| 354 | − their context. A user may also call into this ioctl at any time to | |
| 355 | − check if the device is operating normally. If a failure is returned | |
| 356 | − from this ioctl, the user is expected to gracefully clean up their | |
| 357 | − context via release/detach ioctls. Until they do, the context they | |
| 358 | − hold is not relinquished. The user may also optionally exit the process | |
| 359 | − at which time the context/resources they held will be freed as part of | |
| 360 | − the release fop. | |
| 361 | − | |
| 362 | − When the DK_CXLFLASH_APP_CLOSE_ADAP_FD flag was returned on a successful | |
| 363 | − attach, the application _must_ unmap and close the fd2 associated with the | |
| 364 | − original context following this ioctl returning success and indicating that | |
| 365 | − the context was recovered (DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET). | |
| 366 | − | |
| 367 | −DK_CXLFLASH_MANAGE_LUN | |
| 368 | −---------------------- | |
| 369 | − This ioctl is used to switch a LUN from a mode where it is available | |
| 370 | − for file-system access (legacy), to a mode where it is set aside for | |
| 371 | − exclusive user space access (superpipe). In case a LUN is visible | |
| 372 | − across multiple ports and adapters, this ioctl is used to uniquely | |
| 373 | − identify each LUN by its World Wide Node Name (WWNN). | |
| 374 | − | |
| 375 | − | |
| 376 | −CXL Flash Driver Host IOCTLs | |
| 377 | −============================ | |
| 378 | − | |
| 379 | − Each host adapter instance that is supported by the cxlflash driver | |
| 380 | − has a special character device associated with it to enable a set of | |
| 381 | − host management function. These character devices are hosted in a | |
| 382 | − class dedicated for cxlflash and can be accessed via `/dev/cxlflash/*`. | |
| 383 | − | |
| 384 | − Applications can be written to perform various functions using the | |
| 385 | − host ioctl APIs below. | |
| 386 | − | |
| 387 | − The structure definitions for these IOCTLs are available in: | |
| 388 | − uapi/scsi/cxlflash_ioctl.h | |
| 389 | − | |
| 390 | −HT_CXLFLASH_LUN_PROVISION | |
| 391 | −------------------------- | |
| 392 | − This ioctl is used to create and delete persistent LUNs on cxlflash | |
| 393 | − devices that lack an external LUN management interface. It is only | |
| 394 | − valid when used with AFUs that support the LUN provision capability. | |
| 395 | − | |
| 396 | − When sufficient space is available, LUNs can be created by specifying | |
| 397 | − the target port to host the LUN and a desired size in 4K blocks. Upon | |
| 398 | − success, the LUN ID and WWID of the created LUN will be returned and | |
| 399 | − the SCSI bus can be scanned to detect the change in LUN topology. Note | |
| 400 | − that partial allocations are not supported. Should a creation fail due | |
| 401 | − to a space issue, the target port can be queried for its current LUN | |
| 402 | − geometry. | |
| 403 | − | |
| 404 | − To remove a LUN, the device must first be disassociated from the Linux | |
| 405 | − SCSI subsystem. The LUN deletion can then be initiated by specifying a | |
| 406 | − target port and LUN ID. Upon success, the LUN geometry associated with | |
| 407 | − the port will be updated to reflect new number of provisioned LUNs and | |
| 408 | − available capacity. | |
| 409 | − | |
| 410 | − To query the LUN geometry of a port, the target port is specified and | |
| 411 | − upon success, the following information is presented: | |
| 412 | − | |
| 413 | − - Maximum number of provisioned LUNs allowed for the port | |
| 414 | − - Current number of provisioned LUNs for the port | |
| 415 | − - Maximum total capacity of provisioned LUNs for the port (4K blocks) | |
| 416 | − - Current total capacity of provisioned LUNs for the port (4K blocks) | |
| 417 | − | |
| 418 | − With this information, the number of available LUNs and capacity can be | |
| 419 | − can be calculated. | |
| 420 | − | |
| 421 | −HT_CXLFLASH_AFU_DEBUG | |
| 422 | −--------------------- | |
| 423 | − This ioctl is used to debug AFUs by supporting a command pass-through | |
| 424 | − interface. It is only valid when used with AFUs that support the AFU | |
| 425 | − debug capability. | |
| 426 | − | |
| 427 | − With exception of buffer management, AFU debug commands are opaque to | |
| 428 | − cxlflash and treated as pass-through. For debug commands that do require | |
| 429 | − data transfer, the user supplies an adequately sized data buffer and must | |
| 430 | − specify the data transfer direction with respect to the host. There is a | |
| 431 | − maximum transfer size of 256K imposed. Note that partial read completions | |
| 432 | − are not supported - when errors are experienced with a host read data | |
| 433 | − transfer, the data buffer is not copied back to the user. | |
| @@ -13,7 +13,6 @@ powerpc · 12 unmodified lines | ||
| 13 | 13 | cpu_families |
| 14 | 14 | cpu_features |
| 15 | 15 | cxl |
| 16 | − cxlflash | |
| 17 | 16 | dawr-power9 |
| 18 | 17 | dexcr |
| 19 | 18 | dscr |
| @@ -33,6 +33,16 @@ properties: · 32 unmodified lines | ||
| 33 | 33 | resets: |
| 34 | 34 | maxItems: 1 |
| 35 | 35 | |
| 36 | + nvmem-cells: | |
| 37 | + maxItems: 1 | |
| 38 | + | |
| 39 | + nvmem-cell-names: | |
| 40 | + items: | |
| 41 | + - const: calibration | |
| 42 | + | |
| 43 | +dependencies: | |
| 44 | + nvmem-cells: [ nvmem-cell-names ] | |
| 45 | + | |
| 36 | 46 | required: |
| 37 | 47 | - compatible |
| 38 | 48 | - reg |
| @@ -58,4 +68,6 @@ examples: · 19 unmodified lines | ||
| 58 | 68 | freq-table-hz = <200000000 200000000>, <38400000 38400000>; |
| 59 | 69 | power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>; |
| 60 | 70 | resets = <&cpg 1514>; |
| 71 | + nvmem-cells = <&ufs_tune>; | |
| 72 | + nvmem-cell-names = "calibration"; | |
| 61 | 73 | }; |
| @@ -0,0 +1,105 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/ufs/rockchip,rk3576-ufshc.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Rockchip UFS Host Controller | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Shawn Lin <shawn.lin@rock-chips.com> | |
| 11 | + | |
| 12 | +allOf: | |
| 13 | + - $ref: ufs-common.yaml | |
| 14 | + | |
| 15 | +properties: | |
| 16 | + compatible: | |
| 17 | + const: rockchip,rk3576-ufshc | |
| 18 | + | |
| 19 | + reg: | |
| 20 | + maxItems: 5 | |
| 21 | + | |
| 22 | + reg-names: | |
| 23 | + items: | |
| 24 | + - const: hci | |
| 25 | + - const: mphy | |
| 26 | + - const: hci_grf | |
| 27 | + - const: mphy_grf | |
| 28 | + - const: hci_apb | |
| 29 | + | |
| 30 | + clocks: | |
| 31 | + maxItems: 4 | |
| 32 | + | |
| 33 | + clock-names: | |
| 34 | + items: | |
| 35 | + - const: core | |
| 36 | + - const: pclk | |
| 37 | + - const: pclk_mphy | |
| 38 | + - const: ref_out | |
| 39 | + | |
| 40 | + power-domains: | |
| 41 | + maxItems: 1 | |
| 42 | + | |
| 43 | + resets: | |
| 44 | + maxItems: 4 | |
| 45 | + | |
| 46 | + reset-names: | |
| 47 | + items: | |
| 48 | + - const: biu | |
| 49 | + - const: sys | |
| 50 | + - const: ufs | |
| 51 | + - const: grf | |
| 52 | + | |
| 53 | + reset-gpios: | |
| 54 | + maxItems: 1 | |
| 55 | + description: | | |
| 56 | + GPIO specifiers for host to reset the whole UFS device including PHY and | |
| 57 | + memory. This gpio is active low and should choose the one whose high output | |
| 58 | + voltage is lower than 1.5V based on the UFS spec. | |
| 59 | + | |
| 60 | +required: | |
| 61 | + - compatible | |
| 62 | + - reg | |
| 63 | + - reg-names | |
| 64 | + - clocks | |
| 65 | + - clock-names | |
| 66 | + - interrupts | |
| 67 | + - power-domains | |
| 68 | + - resets | |
| 69 | + - reset-names | |
| 70 | + - reset-gpios | |
| 71 | + | |
| 72 | +unevaluatedProperties: false | |
| 73 | + | |
| 74 | +examples: | |
| 75 | + - | | |
| 76 | + #include <dt-bindings/clock/rockchip,rk3576-cru.h> | |
| 77 | + #include <dt-bindings/reset/rockchip,rk3576-cru.h> | |
| 78 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 79 | + #include <dt-bindings/power/rockchip,rk3576-power.h> | |
| 80 | + #include <dt-bindings/pinctrl/rockchip.h> | |
| 81 | + #include <dt-bindings/gpio/gpio.h> | |
| 82 | + | |
| 83 | + soc { | |
| 84 | + #address-cells = <2>; | |
| 85 | + #size-cells = <2>; | |
| 86 | + | |
| 87 | + ufshc: ufshc@2a2d0000 { | |
| 88 | + compatible = "rockchip,rk3576-ufshc"; | |
| 89 | + reg = <0x0 0x2a2d0000 0x0 0x10000>, | |
| 90 | + <0x0 0x2b040000 0x0 0x10000>, | |
| 91 | + <0x0 0x2601f000 0x0 0x1000>, | |
| 92 | + <0x0 0x2603c000 0x0 0x1000>, | |
| 93 | + <0x0 0x2a2e0000 0x0 0x10000>; | |
| 94 | + reg-names = "hci", "mphy", "hci_grf", "mphy_grf", "hci_apb"; | |
| 95 | + clocks = <&cru ACLK_UFS_SYS>, <&cru PCLK_USB_ROOT>, <&cru PCLK_MPHY>, | |
| 96 | + <&cru CLK_REF_UFS_CLKOUT>; | |
| 97 | + clock-names = "core", "pclk", "pclk_mphy", "ref_out"; | |
| 98 | + interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>; | |
| 99 | + power-domains = <&power RK3576_PD_USB>; | |
| 100 | + resets = <&cru SRST_A_UFS_BIU>, <&cru SRST_A_UFS_SYS>, <&cru SRST_A_UFS>, | |
| 101 | + <&cru SRST_P_UFS_GRF>; | |
| 102 | + reset-names = "biu", "sys", "ufs", "grf"; | |
| 103 | + reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_LOW>; | |
| 104 | + }; | |
| 105 | + }; | |
| @@ -157,6 +157,11 @@ enabled driver and mode options. The value in the file is a bit mask where the · 156 unmodified lines | ||
| 157 | 157 | bit definitions are the same as those used with MTSETDRVBUFFER in setting the |
| 158 | 158 | options. |
| 159 | 159 | |
| 160 | +Each directory contains the entry 'position_lost_in_reset'. If this value is | |
| 161 | +one, reading and writing to the device is blocked after device reset. Most | |
| 162 | +devices rewind the tape after reset and the writes/read don't access the | |
| 163 | +tape position the user expects. | |
| 164 | + | |
| 160 | 165 | A link named 'tape' is made from the SCSI device directory to the class |
| 161 | 166 | directory corresponding to the mode 0 auto-rewind device (e.g., st0). |
| 162 | 167 | |
| @@ -377,7 +377,7 @@ Code Seq# Include File Comments · 376 unmodified lines | ||
| 377 | 377 | 0xC0 00-0F linux/usb/iowarrior.h |
| 378 | 378 | 0xCA 00-0F uapi/misc/cxl.h |
| 379 | 379 | 0xCA 10-2F uapi/misc/ocxl.h |
| 380 | −0xCA 80-BF uapi/scsi/cxlflash_ioctl.h | |
| 380 | +0xCA 80-BF uapi/scsi/cxlflash_ioctl.h Dead since 6.14 | |
| 381 | 381 | 0xCB 00-1F CBM serial IEC bus in development: |
| 382 | 382 | <mailto:michael.klein@puffin.lb.shuttle.de> |
| 383 | 383 | 0xCC 00-0F drivers/misc/ibmvmc.h pseries VMC driver |
| @@ -6354,15 +6354,6 @@ F: drivers/misc/cxl/ · 6353 unmodified lines | ||
| 6354 | 6354 | F: include/misc/cxl* |
| 6355 | 6355 | F: include/uapi/misc/cxl.h |
| 6356 | 6356 | |
| 6357 | −CXLFLASH (IBM Coherent Accelerator Processor Interface CAPI Flash) SCSI DRIVER | |
| 6358 | −M: Manoj N. Kumar <manoj@linux.ibm.com> | |
| 6359 | −M: Uma Krishnan <ukrishn@linux.ibm.com> | |
| 6360 | −L: linux-scsi@vger.kernel.org | |
| 6361 | −S: Obsolete | |
| 6362 | −F: Documentation/arch/powerpc/cxlflash.rst | |
| 6363 | −F: drivers/scsi/cxlflash/ | |
| 6364 | −F: include/uapi/scsi/cxlflash_ioctl.h | |
| 6365 | − | |
| 6366 | 6357 | CYBERPRO FB DRIVER |
| 6367 | 6358 | M: Russell King <linux@armlinux.org.uk> |
| 6368 | 6359 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) |
| @@ -1221,6 +1221,30 @@ · 1220 unmodified lines | ||
| 1221 | 1221 | }; |
| 1222 | 1222 | }; |
| 1223 | 1223 | |
| 1224 | + ufshc: ufshc@2a2d0000 { | |
| 1225 | + compatible = "rockchip,rk3576-ufshc"; | |
| 1226 | + reg = <0x0 0x2a2d0000 0x0 0x10000>, | |
| 1227 | + <0x0 0x2b040000 0x0 0x10000>, | |
| 1228 | + <0x0 0x2601f000 0x0 0x1000>, | |
| 1229 | + <0x0 0x2603c000 0x0 0x1000>, | |
| 1230 | + <0x0 0x2a2e0000 0x0 0x10000>; | |
| 1231 | + reg-names = "hci", "mphy", "hci_grf", "mphy_grf", "hci_apb"; | |
| 1232 | + clocks = <&cru ACLK_UFS_SYS>, <&cru PCLK_USB_ROOT>, <&cru PCLK_MPHY>, | |
| 1233 | + <&cru CLK_REF_UFS_CLKOUT>; | |
| 1234 | + clock-names = "core", "pclk", "pclk_mphy", "ref_out"; | |
| 1235 | + assigned-clocks = <&cru CLK_REF_OSC_MPHY>; | |
| 1236 | + assigned-clock-parents = <&cru CLK_REF_MPHY_26M>; | |
| 1237 | + interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>; | |
| 1238 | + power-domains = <&power RK3576_PD_USB>; | |
| 1239 | + pinctrl-0 = <&ufs_refclk>; | |
| 1240 | + pinctrl-names = "default"; | |
| 1241 | + resets = <&cru SRST_A_UFS_BIU>, <&cru SRST_A_UFS_SYS>, | |
| 1242 | + <&cru SRST_A_UFS>, <&cru SRST_P_UFS_GRF>; | |
| 1243 | + reset-names = "biu", "sys", "ufs", "grf"; | |
| 1244 | + reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_LOW>; | |
| 1245 | + status = "disabled"; | |
| 1246 | + }; | |
| 1247 | + | |
| 1224 | 1248 | sdmmc: mmc@2a310000 { |
| 1225 | 1249 | compatible = "rockchip,rk3576-dw-mshc"; |
| 1226 | 1250 | reg = <0x0 0x2a310000 0x0 0x4000>; |
| @@ -1843,65 +1843,6 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) · 1842 unmodified lines | ||
| 1843 | 1843 | return FAILED; |
| 1844 | 1844 | } |
| 1845 | 1845 | |
| 1846 | −/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | |
| 1847 | −/** | |
| 1848 | − * mptscsih_target_reset - Perform a SCSI TARGET_RESET! | |
| 1849 | − * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to | |
| 1850 | − * | |
| 1851 | − * (linux scsi_host_template.eh_target_reset_handler routine) | |
| 1852 | − * | |
| 1853 | − * Returns SUCCESS or FAILED. | |
| 1854 | − **/ | |
| 1855 | −int | |
| 1856 | −mptscsih_target_reset(struct scsi_cmnd * SCpnt) | |
| 1857 | −{ | |
| 1858 | − MPT_SCSI_HOST *hd; | |
| 1859 | − int retval; | |
| 1860 | − VirtDevice *vdevice; | |
| 1861 | − MPT_ADAPTER *ioc; | |
| 1862 | − | |
| 1863 | − /* If we can't locate our host adapter structure, return FAILED status. | |
| 1864 | − */ | |
| 1865 | − if ((hd = shost_priv(SCpnt->device->host)) == NULL){ | |
| 1866 | − printk(KERN_ERR MYNAM ": target reset: " | |
| 1867 | − "Can't locate host! (sc=%p)\n", SCpnt); | |
| 1868 | − return FAILED; | |
| 1869 | − } | |
| 1870 | − | |
| 1871 | − ioc = hd->ioc; | |
| 1872 | − printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n", | |
| 1873 | − ioc->name, SCpnt); | |
| 1874 | − scsi_print_command(SCpnt); | |
| 1875 | − | |
| 1876 | − vdevice = SCpnt->device->hostdata; | |
| 1877 | − if (!vdevice || !vdevice->vtarget) { | |
| 1878 | − retval = 0; | |
| 1879 | − goto out; | |
| 1880 | − } | |
| 1881 | − | |
| 1882 | − /* Target reset to hidden raid component is not supported | |
| 1883 | − */ | |
| 1884 | − if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { | |
| 1885 | − retval = FAILED; | |
| 1886 | − goto out; | |
| 1887 | − } | |
| 1888 | − | |
| 1889 | − retval = mptscsih_IssueTaskMgmt(hd, | |
| 1890 | − MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, | |
| 1891 | − vdevice->vtarget->channel, | |
| 1892 | − vdevice->vtarget->id, 0, 0, | |
| 1893 | − mptscsih_get_tm_timeout(ioc)); | |
| 1894 | − | |
| 1895 | − out: | |
| 1896 | − printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n", | |
| 1897 | − ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); | |
| 1898 | − | |
| 1899 | − if (retval == 0) | |
| 1900 | − return SUCCESS; | |
| 1901 | − else | |
| 1902 | − return FAILED; | |
| 1903 | −} | |
| 1904 | − | |
| 1905 | 1846 | |
| 1906 | 1847 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
| 1907 | 1848 | /** |
| @@ -2915,14 +2856,14 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) · 1007 unmodified lines | ||
| 2915 | 2856 | timeout = 10; |
| 2916 | 2857 | break; |
| 2917 | 2858 | |
| 2918 | − case RESERVE: | |
| 2859 | + case RESERVE_6: | |
| 2919 | 2860 | cmdLen = 6; |
| 2920 | 2861 | dir = MPI_SCSIIO_CONTROL_READ; |
| 2921 | 2862 | CDB[0] = cmd; |
| 2922 | 2863 | timeout = 10; |
| 2923 | 2864 | break; |
| 2924 | 2865 | |
| 2925 | − case RELEASE: | |
| 2866 | + case RELEASE_6: | |
| 2926 | 2867 | cmdLen = 6; |
| 2927 | 2868 | dir = MPI_SCSIIO_CONTROL_READ; |
| 2928 | 2869 | CDB[0] = cmd; |
| @@ -3306,7 +3247,6 @@ EXPORT_SYMBOL(mptscsih_sdev_destroy); · 377 unmodified lines | ||
| 3306 | 3247 | EXPORT_SYMBOL(mptscsih_sdev_configure); |
| 3307 | 3248 | EXPORT_SYMBOL(mptscsih_abort); |
| 3308 | 3249 | EXPORT_SYMBOL(mptscsih_dev_reset); |
| 3309 | −EXPORT_SYMBOL(mptscsih_target_reset); | |
| 3310 | 3250 | EXPORT_SYMBOL(mptscsih_bus_reset); |
| 3311 | 3251 | EXPORT_SYMBOL(mptscsih_host_reset); |
| 3312 | 3252 | EXPORT_SYMBOL(mptscsih_bios_param); |
| @@ -121,7 +121,6 @@ extern int mptscsih_sdev_configure(struct scsi_device *device, · 120 unmodified lines | ||
| 121 | 121 | struct queue_limits *lim); |
| 122 | 122 | extern int mptscsih_abort(struct scsi_cmnd * SCpnt); |
| 123 | 123 | extern int mptscsih_dev_reset(struct scsi_cmnd * SCpnt); |
| 124 | −extern int mptscsih_target_reset(struct scsi_cmnd * SCpnt); | |
| 125 | 124 | extern int mptscsih_bus_reset(struct scsi_cmnd * SCpnt); |
| 126 | 125 | extern int mptscsih_host_reset(struct scsi_cmnd *SCpnt); |
| 127 | 126 | extern int mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, sector_t capacity, int geom[]); |
| @@ -303,9 +303,9 @@ if SCSI_LOWLEVEL && SCSI · 302 unmodified lines | ||
| 303 | 303 | config ISCSI_TCP |
| 304 | 304 | tristate "iSCSI Initiator over TCP/IP" |
| 305 | 305 | depends on SCSI && INET |
| 306 | + select CRC32 | |
| 306 | 307 | select CRYPTO |
| 307 | 308 | select CRYPTO_MD5 |
| 308 | − select CRYPTO_CRC32C | |
| 309 | 309 | select SCSI_ISCSI_ATTRS |
| 310 | 310 | help |
| 311 | 311 | The iSCSI Driver provides a host with the ability to access storage |
| @@ -336,7 +336,6 @@ source "drivers/scsi/cxgbi/Kconfig" · 24 unmodified lines | ||
| 336 | 336 | source "drivers/scsi/bnx2i/Kconfig" |
| 337 | 337 | source "drivers/scsi/bnx2fc/Kconfig" |
| 338 | 338 | source "drivers/scsi/be2iscsi/Kconfig" |
| 339 | −source "drivers/scsi/cxlflash/Kconfig" | |
| 340 | 339 | |
| 341 | 340 | config SGIWD93_SCSI |
| 342 | 341 | tristate "SGI WD93C93 SCSI Driver" |
| @@ -96,7 +96,6 @@ obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/ · 95 unmodified lines | ||
| 96 | 96 | obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o |
| 97 | 97 | obj-$(CONFIG_SCSI_DC395x) += dc395x.o |
| 98 | 98 | obj-$(CONFIG_SCSI_AM53C974) += esp_scsi.o am53c974.o |
| 99 | −obj-$(CONFIG_CXLFLASH) += cxlflash/ | |
| 100 | 99 | obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o |
| 101 | 100 | obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ |
| 102 | 101 | obj-$(CONFIG_MEGARAID_SAS) += megaraid/ |
| @@ -3221,8 +3221,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) · 3220 unmodified lines | ||
| 3221 | 3221 | break; |
| 3222 | 3222 | } |
| 3223 | 3223 | fallthrough; |
| 3224 | − case RESERVE: | |
| 3225 | − case RELEASE: | |
| 3224 | + case RESERVE_6: | |
| 3225 | + case RELEASE_6: | |
| 3226 | 3226 | case REZERO_UNIT: |
| 3227 | 3227 | case REASSIGN_BLOCKS: |
| 3228 | 3228 | case SEEK_10: |
| @@ -2029,7 +2029,7 @@ static void aac_pci_resume(struct pci_dev *pdev) · 2028 unmodified lines | ||
| 2029 | 2029 | dev_err(&pdev->dev, "aacraid: PCI error - resume\n"); |
| 2030 | 2030 | } |
| 2031 | 2031 | |
| 2032 | −static struct pci_error_handlers aac_pci_err_handler = { | |
| 2032 | +static const struct pci_error_handlers aac_pci_err_handler = { | |
| 2033 | 2033 | .error_detected = aac_pci_error_detected, |
| 2034 | 2034 | .mmio_enabled = aac_pci_mmio_enabled, |
| 2035 | 2035 | .slot_reset = aac_pci_slot_reset, |
| @@ -591,7 +591,7 @@ datadir_t acornscsi_datadirection(int command) · 590 unmodified lines | ||
| 591 | 591 | case CHANGE_DEFINITION: case COMPARE: case COPY: |
| 592 | 592 | case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT: |
| 593 | 593 | case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER: |
| 594 | − case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: | |
| 594 | + case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE_6: | |
| 595 | 595 | case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: |
| 596 | 596 | case WRITE_6: case WRITE_10: case WRITE_VERIFY: |
| 597 | 597 | case UPDATE_BLOCK: case WRITE_LONG: case WRITE_SAME: |
| @@ -5776,7 +5776,7 @@ static void beiscsi_remove(struct pci_dev *pcidev) · 5775 unmodified lines | ||
| 5776 | 5776 | } |
| 5777 | 5777 | |
| 5778 | 5778 | |
| 5779 | −static struct pci_error_handlers beiscsi_eeh_handlers = { | |
| 5779 | +static const struct pci_error_handlers beiscsi_eeh_handlers = { | |
| 5780 | 5780 | .error_detected = beiscsi_eeh_err_detected, |
| 5781 | 5781 | .slot_reset = beiscsi_eeh_reset, |
| 5782 | 5782 | .resume = beiscsi_eeh_resume, |
| @@ -1642,7 +1642,7 @@ MODULE_DEVICE_TABLE(pci, bfad_id_table); · 1641 unmodified lines | ||
| 1642 | 1642 | /* |
| 1643 | 1643 | * PCI error recovery handlers. |
| 1644 | 1644 | */ |
| 1645 | −static struct pci_error_handlers bfad_err_handler = { | |
| 1645 | +static const struct pci_error_handlers bfad_err_handler = { | |
| 1646 | 1646 | .error_detected = bfad_pci_error_detected, |
| 1647 | 1647 | .slot_reset = bfad_pci_slot_reset, |
| 1648 | 1648 | .mmio_enabled = bfad_pci_mmio_enabled, |
| @@ -1162,7 +1162,7 @@ err_resume_exit: · 1161 unmodified lines | ||
| 1162 | 1162 | dev_err(&pdev->dev, "resume of device failed: %d\n", rv); |
| 1163 | 1163 | } |
| 1164 | 1164 | |
| 1165 | −static struct pci_error_handlers csio_err_handler = { | |
| 1165 | +static const struct pci_error_handlers csio_err_handler = { | |
| 1166 | 1166 | .error_detected = csio_pci_error_detected, |
| 1167 | 1167 | .slot_reset = csio_pci_slot_reset, |
| 1168 | 1168 | .resume = csio_pci_resume, |
| @@ -1,15 +0,0 @@ | ||
| 1 | −# SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −# | |
| 3 | −# IBM CXL-attached Flash Accelerator SCSI Driver | |
| 4 | −# | |
| 5 | − | |
| 6 | −config CXLFLASH | |
| 7 | − tristate "Support for IBM CAPI Flash (DEPRECATED)" | |
| 8 | − depends on PCI && SCSI && (CXL || OCXL) && EEH | |
| 9 | − select IRQ_POLL | |
| 10 | − help | |
| 11 | − The cxlflash driver is deprecated and will be removed in a future | |
| 12 | − kernel release. | |
| 13 | − | |
| 14 | − Allows CAPI Accelerated IO to Flash | |
| 15 | − If unsure, say N. | |
| @@ -1,5 +0,0 @@ | ||
| 1 | −# SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −obj-$(CONFIG_CXLFLASH) += cxlflash.o | |
| 3 | −cxlflash-y += main.o superpipe.o lunmgt.o vlun.o | |
| 4 | −cxlflash-$(CONFIG_CXL) += cxl_hw.o | |
| 5 | −cxlflash-$(CONFIG_OCXL) += ocxl_hw.o | |
| @@ -1,48 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2018 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#ifndef _CXLFLASH_BACKEND_H | |
| 12 | −#define _CXLFLASH_BACKEND_H | |
| 13 | − | |
| 14 | −extern const struct cxlflash_backend_ops cxlflash_cxl_ops; | |
| 15 | −extern const struct cxlflash_backend_ops cxlflash_ocxl_ops; | |
| 16 | − | |
| 17 | −struct cxlflash_backend_ops { | |
| 18 | − struct module *module; | |
| 19 | − void __iomem * (*psa_map)(void *ctx_cookie); | |
| 20 | − void (*psa_unmap)(void __iomem *addr); | |
| 21 | − int (*process_element)(void *ctx_cookie); | |
| 22 | − int (*map_afu_irq)(void *ctx_cookie, int num, irq_handler_t handler, | |
| 23 | − void *cookie, char *name); | |
| 24 | − void (*unmap_afu_irq)(void *ctx_cookie, int num, void *cookie); | |
| 25 | − u64 (*get_irq_objhndl)(void *ctx_cookie, int irq); | |
| 26 | − int (*start_context)(void *ctx_cookie); | |
| 27 | − int (*stop_context)(void *ctx_cookie); | |
| 28 | − int (*afu_reset)(void *ctx_cookie); | |
| 29 | − void (*set_master)(void *ctx_cookie); | |
| 30 | − void * (*get_context)(struct pci_dev *dev, void *afu_cookie); | |
| 31 | − void * (*dev_context_init)(struct pci_dev *dev, void *afu_cookie); | |
| 32 | − int (*release_context)(void *ctx_cookie); | |
| 33 | − void (*perst_reloads_same_image)(void *afu_cookie, bool image); | |
| 34 | − ssize_t (*read_adapter_vpd)(struct pci_dev *dev, void *buf, | |
| 35 | − size_t count); | |
| 36 | − int (*allocate_afu_irqs)(void *ctx_cookie, int num); | |
| 37 | − void (*free_afu_irqs)(void *ctx_cookie); | |
| 38 | − void * (*create_afu)(struct pci_dev *dev); | |
| 39 | − void (*destroy_afu)(void *afu_cookie); | |
| 40 | − struct file * (*get_fd)(void *ctx_cookie, struct file_operations *fops, | |
| 41 | − int *fd); | |
| 42 | − void * (*fops_get_context)(struct file *file); | |
| 43 | − int (*start_work)(void *ctx_cookie, u64 irqs); | |
| 44 | − int (*fd_mmap)(struct file *file, struct vm_area_struct *vm); | |
| 45 | − int (*fd_release)(struct inode *inode, struct file *file); | |
| 46 | −}; | |
| 47 | − | |
| 48 | −#endif /* _CXLFLASH_BACKEND_H */ | |
| @@ -1,340 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2015 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#ifndef _CXLFLASH_COMMON_H | |
| 12 | −#define _CXLFLASH_COMMON_H | |
| 13 | − | |
| 14 | −#include <linux/async.h> | |
| 15 | −#include <linux/cdev.h> | |
| 16 | −#include <linux/irq_poll.h> | |
| 17 | −#include <linux/list.h> | |
| 18 | −#include <linux/rwsem.h> | |
| 19 | −#include <linux/types.h> | |
| 20 | −#include <scsi/scsi.h> | |
| 21 | −#include <scsi/scsi_cmnd.h> | |
| 22 | −#include <scsi/scsi_device.h> | |
| 23 | − | |
| 24 | −#include "backend.h" | |
| 25 | − | |
| 26 | −extern const struct file_operations cxlflash_cxl_fops; | |
| 27 | − | |
| 28 | −#define MAX_CONTEXT CXLFLASH_MAX_CONTEXT /* num contexts per afu */ | |
| 29 | −#define MAX_FC_PORTS CXLFLASH_MAX_FC_PORTS /* max ports per AFU */ | |
| 30 | −#define LEGACY_FC_PORTS 2 /* legacy ports per AFU */ | |
| 31 | − | |
| 32 | −#define CHAN2PORTBANK(_x) ((_x) >> ilog2(CXLFLASH_NUM_FC_PORTS_PER_BANK)) | |
| 33 | −#define CHAN2BANKPORT(_x) ((_x) & (CXLFLASH_NUM_FC_PORTS_PER_BANK - 1)) | |
| 34 | − | |
| 35 | −#define CHAN2PORTMASK(_x) (1 << (_x)) /* channel to port mask */ | |
| 36 | −#define PORTMASK2CHAN(_x) (ilog2((_x))) /* port mask to channel */ | |
| 37 | −#define PORTNUM2CHAN(_x) ((_x) - 1) /* port number to channel */ | |
| 38 | − | |
| 39 | −#define CXLFLASH_BLOCK_SIZE 4096 /* 4K blocks */ | |
| 40 | −#define CXLFLASH_MAX_XFER_SIZE 16777216 /* 16MB transfer */ | |
| 41 | −#define CXLFLASH_MAX_SECTORS (CXLFLASH_MAX_XFER_SIZE/512) /* SCSI wants | |
| 42 | − * max_sectors | |
| 43 | − * in units of | |
| 44 | − * 512 byte | |
| 45 | − * sectors | |
| 46 | − */ | |
| 47 | − | |
| 48 | −#define MAX_RHT_PER_CONTEXT (PAGE_SIZE / sizeof(struct sisl_rht_entry)) | |
| 49 | − | |
| 50 | −/* AFU command retry limit */ | |
| 51 | −#define MC_RETRY_CNT 5 /* Sufficient for SCSI and certain AFU errors */ | |
| 52 | − | |
| 53 | −/* Command management definitions */ | |
| 54 | −#define CXLFLASH_MAX_CMDS 256 | |
| 55 | −#define CXLFLASH_MAX_CMDS_PER_LUN CXLFLASH_MAX_CMDS | |
| 56 | − | |
| 57 | −/* RRQ for master issued cmds */ | |
| 58 | −#define NUM_RRQ_ENTRY CXLFLASH_MAX_CMDS | |
| 59 | − | |
| 60 | −/* SQ for master issued cmds */ | |
| 61 | −#define NUM_SQ_ENTRY CXLFLASH_MAX_CMDS | |
| 62 | − | |
| 63 | −/* Hardware queue definitions */ | |
| 64 | −#define CXLFLASH_DEF_HWQS 1 | |
| 65 | −#define CXLFLASH_MAX_HWQS 8 | |
| 66 | −#define PRIMARY_HWQ 0 | |
| 67 | − | |
| 68 | − | |
| 69 | −static inline void check_sizes(void) | |
| 70 | −{ | |
| 71 | − BUILD_BUG_ON_NOT_POWER_OF_2(CXLFLASH_NUM_FC_PORTS_PER_BANK); | |
| 72 | − BUILD_BUG_ON_NOT_POWER_OF_2(CXLFLASH_MAX_CMDS); | |
| 73 | −} | |
| 74 | − | |
| 75 | −/* AFU defines a fixed size of 4K for command buffers (borrow 4K page define) */ | |
| 76 | −#define CMD_BUFSIZE SIZE_4K | |
| 77 | − | |
| 78 | −enum cxlflash_lr_state { | |
| 79 | − LINK_RESET_INVALID, | |
| 80 | − LINK_RESET_REQUIRED, | |
| 81 | − LINK_RESET_COMPLETE | |
| 82 | −}; | |
| 83 | − | |
| 84 | −enum cxlflash_init_state { | |
| 85 | − INIT_STATE_NONE, | |
| 86 | − INIT_STATE_PCI, | |
| 87 | − INIT_STATE_AFU, | |
| 88 | − INIT_STATE_SCSI, | |
| 89 | − INIT_STATE_CDEV | |
| 90 | −}; | |
| 91 | − | |
| 92 | −enum cxlflash_state { | |
| 93 | − STATE_PROBING, /* Initial state during probe */ | |
| 94 | − STATE_PROBED, /* Temporary state, probe completed but EEH occurred */ | |
| 95 | − STATE_NORMAL, /* Normal running state, everything good */ | |
| 96 | − STATE_RESET, /* Reset state, trying to reset/recover */ | |
| 97 | − STATE_FAILTERM /* Failed/terminating state, error out users/threads */ | |
| 98 | −}; | |
| 99 | − | |
| 100 | −enum cxlflash_hwq_mode { | |
| 101 | − HWQ_MODE_RR, /* Roundrobin (default) */ | |
| 102 | − HWQ_MODE_TAG, /* Distribute based on block MQ tag */ | |
| 103 | − HWQ_MODE_CPU, /* CPU affinity */ | |
| 104 | − MAX_HWQ_MODE | |
| 105 | −}; | |
| 106 | − | |
| 107 | −/* | |
| 108 | − * Each context has its own set of resource handles that is visible | |
| 109 | − * only from that context. | |
| 110 | − */ | |
| 111 | − | |
| 112 | −struct cxlflash_cfg { | |
| 113 | − struct afu *afu; | |
| 114 | − | |
| 115 | − const struct cxlflash_backend_ops *ops; | |
| 116 | − struct pci_dev *dev; | |
| 117 | − struct pci_device_id *dev_id; | |
| 118 | − struct Scsi_Host *host; | |
| 119 | − int num_fc_ports; | |
| 120 | − struct cdev cdev; | |
| 121 | − struct device *chardev; | |
| 122 | − | |
| 123 | − ulong cxlflash_regs_pci; | |
| 124 | − | |
| 125 | − struct work_struct work_q; | |
| 126 | − enum cxlflash_init_state init_state; | |
| 127 | − enum cxlflash_lr_state lr_state; | |
| 128 | − int lr_port; | |
| 129 | − atomic_t scan_host_needed; | |
| 130 | − | |
| 131 | − void *afu_cookie; | |
| 132 | − | |
| 133 | − atomic_t recovery_threads; | |
| 134 | − struct mutex ctx_recovery_mutex; | |
| 135 | − struct mutex ctx_tbl_list_mutex; | |
| 136 | − struct rw_semaphore ioctl_rwsem; | |
| 137 | − struct ctx_info *ctx_tbl[MAX_CONTEXT]; | |
| 138 | − struct list_head ctx_err_recovery; /* contexts w/ recovery pending */ | |
| 139 | − struct file_operations cxl_fops; | |
| 140 | − | |
| 141 | − /* Parameters that are LUN table related */ | |
| 142 | − int last_lun_index[MAX_FC_PORTS]; | |
| 143 | − int promote_lun_index; | |
| 144 | − struct list_head lluns; /* list of llun_info structs */ | |
| 145 | − | |
| 146 | − wait_queue_head_t tmf_waitq; | |
| 147 | − spinlock_t tmf_slock; | |
| 148 | − bool tmf_active; | |
| 149 | − bool ws_unmap; /* Write-same unmap supported */ | |
| 150 | − wait_queue_head_t reset_waitq; | |
| 151 | − enum cxlflash_state state; | |
| 152 | − async_cookie_t async_reset_cookie; | |
| 153 | −}; | |
| 154 | − | |
| 155 | −struct afu_cmd { | |
| 156 | − struct sisl_ioarcb rcb; /* IOARCB (cache line aligned) */ | |
| 157 | − struct sisl_ioasa sa; /* IOASA must follow IOARCB */ | |
| 158 | − struct afu *parent; | |
| 159 | − struct scsi_cmnd *scp; | |
| 160 | − struct completion cevent; | |
| 161 | − struct list_head queue; | |
| 162 | − u32 hwq_index; | |
| 163 | − | |
| 164 | − u8 cmd_tmf:1, | |
| 165 | − cmd_aborted:1; | |
| 166 | − | |
| 167 | − struct list_head list; /* Pending commands link */ | |
| 168 | − | |
| 169 | − /* As per the SISLITE spec the IOARCB EA has to be 16-byte aligned. | |
| 170 | − * However for performance reasons the IOARCB/IOASA should be | |
| 171 | − * cache line aligned. | |
| 172 | − */ | |
| 173 | −} __aligned(cache_line_size()); | |
| 174 | − | |
| 175 | −static inline struct afu_cmd *sc_to_afuc(struct scsi_cmnd *sc) | |
| 176 | −{ | |
| 177 | − return PTR_ALIGN(scsi_cmd_priv(sc), __alignof__(struct afu_cmd)); | |
| 178 | −} | |
| 179 | − | |
| 180 | −static inline struct afu_cmd *sc_to_afuci(struct scsi_cmnd *sc) | |
| 181 | −{ | |
| 182 | − struct afu_cmd *afuc = sc_to_afuc(sc); | |
| 183 | − | |
| 184 | − INIT_LIST_HEAD(&afuc->queue); | |
| 185 | − return afuc; | |
| 186 | −} | |
| 187 | − | |
| 188 | −static inline struct afu_cmd *sc_to_afucz(struct scsi_cmnd *sc) | |
| 189 | −{ | |
| 190 | − struct afu_cmd *afuc = sc_to_afuc(sc); | |
| 191 | − | |
| 192 | − memset(afuc, 0, sizeof(*afuc)); | |
| 193 | − return sc_to_afuci(sc); | |
| 194 | −} | |
| 195 | − | |
| 196 | −struct hwq { | |
| 197 | − /* Stuff requiring alignment go first. */ | |
| 198 | − struct sisl_ioarcb sq[NUM_SQ_ENTRY]; /* 16K SQ */ | |
| 199 | − u64 rrq_entry[NUM_RRQ_ENTRY]; /* 2K RRQ */ | |
| 200 | − | |
| 201 | − /* Beware of alignment till here. Preferably introduce new | |
| 202 | − * fields after this point | |
| 203 | − */ | |
| 204 | − struct afu *afu; | |
| 205 | − void *ctx_cookie; | |
| 206 | − struct sisl_host_map __iomem *host_map; /* MC host map */ | |
| 207 | − struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */ | |
| 208 | − ctx_hndl_t ctx_hndl; /* master's context handle */ | |
| 209 | − u32 index; /* Index of this hwq */ | |
| 210 | − int num_irqs; /* Number of interrupts requested for context */ | |
| 211 | − struct list_head pending_cmds; /* Commands pending completion */ | |
| 212 | − | |
| 213 | − atomic_t hsq_credits; | |
| 214 | − spinlock_t hsq_slock; /* Hardware send queue lock */ | |
| 215 | − struct sisl_ioarcb *hsq_start; | |
| 216 | − struct sisl_ioarcb *hsq_end; | |
| 217 | − struct sisl_ioarcb *hsq_curr; | |
| 218 | − spinlock_t hrrq_slock; | |
| 219 | − u64 *hrrq_start; | |
| 220 | − u64 *hrrq_end; | |
| 221 | − u64 *hrrq_curr; | |
| 222 | − bool toggle; | |
| 223 | − bool hrrq_online; | |
| 224 | − | |
| 225 | − s64 room; | |
| 226 | − | |
| 227 | − struct irq_poll irqpoll; | |
| 228 | −} __aligned(cache_line_size()); | |
| 229 | − | |
| 230 | −struct afu { | |
| 231 | − struct hwq hwqs[CXLFLASH_MAX_HWQS]; | |
| 232 | − int (*send_cmd)(struct afu *afu, struct afu_cmd *cmd); | |
| 233 | − int (*context_reset)(struct hwq *hwq); | |
| 234 | − | |
| 235 | − /* AFU HW */ | |
| 236 | − struct cxlflash_afu_map __iomem *afu_map; /* entire MMIO map */ | |
| 237 | − | |
| 238 | − atomic_t cmds_active; /* Number of currently active AFU commands */ | |
| 239 | − struct mutex sync_active; /* Mutex to serialize AFU commands */ | |
| 240 | − u64 hb; | |
| 241 | − u32 internal_lun; /* User-desired LUN mode for this AFU */ | |
| 242 | − | |
| 243 | − u32 num_hwqs; /* Number of hardware queues */ | |
| 244 | − u32 desired_hwqs; /* Desired h/w queues, effective on AFU reset */ | |
| 245 | − enum cxlflash_hwq_mode hwq_mode; /* Steering mode for h/w queues */ | |
| 246 | − u32 hwq_rr_count; /* Count to distribute traffic for roundrobin */ | |
| 247 | − | |
| 248 | − char version[16]; | |
| 249 | − u64 interface_version; | |
| 250 | − | |
| 251 | − u32 irqpoll_weight; | |
| 252 | − struct cxlflash_cfg *parent; /* Pointer back to parent cxlflash_cfg */ | |
| 253 | −}; | |
| 254 | − | |
| 255 | −static inline struct hwq *get_hwq(struct afu *afu, u32 index) | |
| 256 | −{ | |
| 257 | − WARN_ON(index >= CXLFLASH_MAX_HWQS); | |
| 258 | − | |
| 259 | − return &afu->hwqs[index]; | |
| 260 | −} | |
| 261 | − | |
| 262 | −static inline bool afu_is_irqpoll_enabled(struct afu *afu) | |
| 263 | −{ | |
| 264 | − return !!afu->irqpoll_weight; | |
| 265 | −} | |
| 266 | − | |
| 267 | −static inline bool afu_has_cap(struct afu *afu, u64 cap) | |
| 268 | −{ | |
| 269 | − u64 afu_cap = afu->interface_version >> SISL_INTVER_CAP_SHIFT; | |
| 270 | − | |
| 271 | − return afu_cap & cap; | |
| 272 | −} | |
| 273 | − | |
| 274 | −static inline bool afu_is_ocxl_lisn(struct afu *afu) | |
| 275 | −{ | |
| 276 | − return afu_has_cap(afu, SISL_INTVER_CAP_OCXL_LISN); | |
| 277 | −} | |
| 278 | − | |
| 279 | −static inline bool afu_is_afu_debug(struct afu *afu) | |
| 280 | −{ | |
| 281 | − return afu_has_cap(afu, SISL_INTVER_CAP_AFU_DEBUG); | |
| 282 | −} | |
| 283 | − | |
| 284 | −static inline bool afu_is_lun_provision(struct afu *afu) | |
| 285 | −{ | |
| 286 | − return afu_has_cap(afu, SISL_INTVER_CAP_LUN_PROVISION); | |
| 287 | −} | |
| 288 | − | |
| 289 | −static inline bool afu_is_sq_cmd_mode(struct afu *afu) | |
| 290 | −{ | |
| 291 | − return afu_has_cap(afu, SISL_INTVER_CAP_SQ_CMD_MODE); | |
| 292 | −} | |
| 293 | − | |
| 294 | −static inline bool afu_is_ioarrin_cmd_mode(struct afu *afu) | |
| 295 | −{ | |
| 296 | − return afu_has_cap(afu, SISL_INTVER_CAP_IOARRIN_CMD_MODE); | |
| 297 | −} | |
| 298 | − | |
| 299 | −static inline u64 lun_to_lunid(u64 lun) | |
| 300 | −{ | |
| 301 | − __be64 lun_id; | |
| 302 | − | |
| 303 | − int_to_scsilun(lun, (struct scsi_lun *)&lun_id); | |
| 304 | − return be64_to_cpu(lun_id); | |
| 305 | −} | |
| 306 | − | |
| 307 | −static inline struct fc_port_bank __iomem *get_fc_port_bank( | |
| 308 | − struct cxlflash_cfg *cfg, int i) | |
| 309 | −{ | |
| 310 | − struct afu *afu = cfg->afu; | |
| 311 | − | |
| 312 | − return &afu->afu_map->global.bank[CHAN2PORTBANK(i)]; | |
| 313 | −} | |
| 314 | − | |
| 315 | −static inline __be64 __iomem *get_fc_port_regs(struct cxlflash_cfg *cfg, int i) | |
| 316 | −{ | |
| 317 | − struct fc_port_bank __iomem *fcpb = get_fc_port_bank(cfg, i); | |
| 318 | − | |
| 319 | − return &fcpb->fc_port_regs[CHAN2BANKPORT(i)][0]; | |
| 320 | −} | |
| 321 | − | |
| 322 | −static inline __be64 __iomem *get_fc_port_luns(struct cxlflash_cfg *cfg, int i) | |
| 323 | −{ | |
| 324 | − struct fc_port_bank __iomem *fcpb = get_fc_port_bank(cfg, i); | |
| 325 | − | |
| 326 | − return &fcpb->fc_port_luns[CHAN2BANKPORT(i)][0]; | |
| 327 | −} | |
| 328 | − | |
| 329 | −int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t c, res_hndl_t r, u8 mode); | |
| 330 | −void cxlflash_list_init(void); | |
| 331 | −void cxlflash_term_global_luns(void); | |
| 332 | −void cxlflash_free_errpage(void); | |
| 333 | −int cxlflash_ioctl(struct scsi_device *sdev, unsigned int cmd, | |
| 334 | − void __user *arg); | |
| 335 | −void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg); | |
| 336 | −int cxlflash_mark_contexts_error(struct cxlflash_cfg *cfg); | |
| 337 | −void cxlflash_term_local_luns(struct cxlflash_cfg *cfg); | |
| 338 | −void cxlflash_restore_luntable(struct cxlflash_cfg *cfg); | |
| 339 | − | |
| 340 | −#endif /* ifndef _CXLFLASH_COMMON_H */ | |
| @@ -1,177 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2018 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#include <misc/cxl.h> | |
| 12 | − | |
| 13 | −#include "backend.h" | |
| 14 | − | |
| 15 | −/* | |
| 16 | − * The following routines map the cxlflash backend operations to existing CXL | |
| 17 | − * kernel API function and are largely simple shims that provide an abstraction | |
| 18 | − * for converting generic context and AFU cookies into cxl_context or cxl_afu | |
| 19 | − * pointers. | |
| 20 | − */ | |
| 21 | − | |
| 22 | −static void __iomem *cxlflash_psa_map(void *ctx_cookie) | |
| 23 | −{ | |
| 24 | − return cxl_psa_map(ctx_cookie); | |
| 25 | −} | |
| 26 | − | |
| 27 | −static void cxlflash_psa_unmap(void __iomem *addr) | |
| 28 | −{ | |
| 29 | − cxl_psa_unmap(addr); | |
| 30 | −} | |
| 31 | − | |
| 32 | −static int cxlflash_process_element(void *ctx_cookie) | |
| 33 | −{ | |
| 34 | − return cxl_process_element(ctx_cookie); | |
| 35 | −} | |
| 36 | − | |
| 37 | −static int cxlflash_map_afu_irq(void *ctx_cookie, int num, | |
| 38 | − irq_handler_t handler, void *cookie, char *name) | |
| 39 | −{ | |
| 40 | − return cxl_map_afu_irq(ctx_cookie, num, handler, cookie, name); | |
| 41 | −} | |
| 42 | − | |
| 43 | −static void cxlflash_unmap_afu_irq(void *ctx_cookie, int num, void *cookie) | |
| 44 | −{ | |
| 45 | − cxl_unmap_afu_irq(ctx_cookie, num, cookie); | |
| 46 | −} | |
| 47 | − | |
| 48 | −static u64 cxlflash_get_irq_objhndl(void *ctx_cookie, int irq) | |
| 49 | −{ | |
| 50 | − /* Dummy fop for cxl */ | |
| 51 | − return 0; | |
| 52 | −} | |
| 53 | − | |
| 54 | −static int cxlflash_start_context(void *ctx_cookie) | |
| 55 | −{ | |
| 56 | − return cxl_start_context(ctx_cookie, 0, NULL); | |
| 57 | −} | |
| 58 | − | |
| 59 | −static int cxlflash_stop_context(void *ctx_cookie) | |
| 60 | −{ | |
| 61 | − return cxl_stop_context(ctx_cookie); | |
| 62 | −} | |
| 63 | − | |
| 64 | −static int cxlflash_afu_reset(void *ctx_cookie) | |
| 65 | −{ | |
| 66 | − return cxl_afu_reset(ctx_cookie); | |
| 67 | −} | |
| 68 | − | |
| 69 | −static void cxlflash_set_master(void *ctx_cookie) | |
| 70 | −{ | |
| 71 | − cxl_set_master(ctx_cookie); | |
| 72 | −} | |
| 73 | − | |
| 74 | −static void *cxlflash_get_context(struct pci_dev *dev, void *afu_cookie) | |
| 75 | −{ | |
| 76 | − return cxl_get_context(dev); | |
| 77 | −} | |
| 78 | − | |
| 79 | −static void *cxlflash_dev_context_init(struct pci_dev *dev, void *afu_cookie) | |
| 80 | −{ | |
| 81 | − return cxl_dev_context_init(dev); | |
| 82 | −} | |
| 83 | − | |
| 84 | −static int cxlflash_release_context(void *ctx_cookie) | |
| 85 | −{ | |
| 86 | − return cxl_release_context(ctx_cookie); | |
| 87 | −} | |
| 88 | − | |
| 89 | −static void cxlflash_perst_reloads_same_image(void *afu_cookie, bool image) | |
| 90 | −{ | |
| 91 | − cxl_perst_reloads_same_image(afu_cookie, image); | |
| 92 | −} | |
| 93 | − | |
| 94 | −static ssize_t cxlflash_read_adapter_vpd(struct pci_dev *dev, | |
| 95 | − void *buf, size_t count) | |
| 96 | −{ | |
| 97 | − return cxl_read_adapter_vpd(dev, buf, count); | |
| 98 | −} | |
| 99 | − | |
| 100 | −static int cxlflash_allocate_afu_irqs(void *ctx_cookie, int num) | |
| 101 | −{ | |
| 102 | − return cxl_allocate_afu_irqs(ctx_cookie, num); | |
| 103 | −} | |
| 104 | − | |
| 105 | −static void cxlflash_free_afu_irqs(void *ctx_cookie) | |
| 106 | −{ | |
| 107 | − cxl_free_afu_irqs(ctx_cookie); | |
| 108 | −} | |
| 109 | − | |
| 110 | −static void *cxlflash_create_afu(struct pci_dev *dev) | |
| 111 | −{ | |
| 112 | − return cxl_pci_to_afu(dev); | |
| 113 | −} | |
| 114 | − | |
| 115 | −static void cxlflash_destroy_afu(void *afu) | |
| 116 | −{ | |
| 117 | − /* Dummy fop for cxl */ | |
| 118 | −} | |
| 119 | − | |
| 120 | −static struct file *cxlflash_get_fd(void *ctx_cookie, | |
| 121 | − struct file_operations *fops, int *fd) | |
| 122 | −{ | |
| 123 | − return cxl_get_fd(ctx_cookie, fops, fd); | |
| 124 | −} | |
| 125 | − | |
| 126 | −static void *cxlflash_fops_get_context(struct file *file) | |
| 127 | −{ | |
| 128 | − return cxl_fops_get_context(file); | |
| 129 | −} | |
| 130 | − | |
| 131 | −static int cxlflash_start_work(void *ctx_cookie, u64 irqs) | |
| 132 | −{ | |
| 133 | − struct cxl_ioctl_start_work work = { 0 }; | |
| 134 | − | |
| 135 | − work.num_interrupts = irqs; | |
| 136 | − work.flags = CXL_START_WORK_NUM_IRQS; | |
| 137 | − | |
| 138 | − return cxl_start_work(ctx_cookie, &work); | |
| 139 | −} | |
| 140 | − | |
| 141 | −static int cxlflash_fd_mmap(struct file *file, struct vm_area_struct *vm) | |
| 142 | −{ | |
| 143 | − return cxl_fd_mmap(file, vm); | |
| 144 | −} | |
| 145 | − | |
| 146 | −static int cxlflash_fd_release(struct inode *inode, struct file *file) | |
| 147 | −{ | |
| 148 | − return cxl_fd_release(inode, file); | |
| 149 | −} | |
| 150 | − | |
| 151 | −const struct cxlflash_backend_ops cxlflash_cxl_ops = { | |
| 152 | − .module = THIS_MODULE, | |
| 153 | − .psa_map = cxlflash_psa_map, | |
| 154 | − .psa_unmap = cxlflash_psa_unmap, | |
| 155 | − .process_element = cxlflash_process_element, | |
| 156 | − .map_afu_irq = cxlflash_map_afu_irq, | |
| 157 | − .unmap_afu_irq = cxlflash_unmap_afu_irq, | |
| 158 | − .get_irq_objhndl = cxlflash_get_irq_objhndl, | |
| 159 | − .start_context = cxlflash_start_context, | |
| 160 | − .stop_context = cxlflash_stop_context, | |
| 161 | − .afu_reset = cxlflash_afu_reset, | |
| 162 | − .set_master = cxlflash_set_master, | |
| 163 | − .get_context = cxlflash_get_context, | |
| 164 | − .dev_context_init = cxlflash_dev_context_init, | |
| 165 | − .release_context = cxlflash_release_context, | |
| 166 | − .perst_reloads_same_image = cxlflash_perst_reloads_same_image, | |
| 167 | − .read_adapter_vpd = cxlflash_read_adapter_vpd, | |
| 168 | − .allocate_afu_irqs = cxlflash_allocate_afu_irqs, | |
| 169 | − .free_afu_irqs = cxlflash_free_afu_irqs, | |
| 170 | − .create_afu = cxlflash_create_afu, | |
| 171 | − .destroy_afu = cxlflash_destroy_afu, | |
| 172 | − .get_fd = cxlflash_get_fd, | |
| 173 | − .fops_get_context = cxlflash_fops_get_context, | |
| 174 | − .start_work = cxlflash_start_work, | |
| 175 | − .fd_mmap = cxlflash_fd_mmap, | |
| 176 | − .fd_release = cxlflash_fd_release, | |
| 177 | −}; | |
| @@ -1,278 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2015 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#include <linux/unaligned.h> | |
| 12 | − | |
| 13 | −#include <linux/interrupt.h> | |
| 14 | −#include <linux/pci.h> | |
| 15 | − | |
| 16 | −#include <scsi/scsi_host.h> | |
| 17 | −#include <uapi/scsi/cxlflash_ioctl.h> | |
| 18 | − | |
| 19 | −#include "sislite.h" | |
| 20 | −#include "common.h" | |
| 21 | −#include "vlun.h" | |
| 22 | −#include "superpipe.h" | |
| 23 | − | |
| 24 | −/** | |
| 25 | − * create_local() - allocate and initialize a local LUN information structure | |
| 26 | − * @sdev: SCSI device associated with LUN. | |
| 27 | − * @wwid: World Wide Node Name for LUN. | |
| 28 | − * | |
| 29 | − * Return: Allocated local llun_info structure on success, NULL on failure | |
| 30 | − */ | |
| 31 | −static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid) | |
| 32 | −{ | |
| 33 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 34 | − struct device *dev = &cfg->dev->dev; | |
| 35 | − struct llun_info *lli = NULL; | |
| 36 | − | |
| 37 | − lli = kzalloc(sizeof(*lli), GFP_KERNEL); | |
| 38 | − if (unlikely(!lli)) { | |
| 39 | − dev_err(dev, "%s: could not allocate lli\n", __func__); | |
| 40 | − goto out; | |
| 41 | − } | |
| 42 | − | |
| 43 | − lli->sdev = sdev; | |
| 44 | − lli->host_no = sdev->host->host_no; | |
| 45 | − lli->in_table = false; | |
| 46 | − | |
| 47 | − memcpy(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN); | |
| 48 | −out: | |
| 49 | − return lli; | |
| 50 | −} | |
| 51 | − | |
| 52 | −/** | |
| 53 | − * create_global() - allocate and initialize a global LUN information structure | |
| 54 | − * @sdev: SCSI device associated with LUN. | |
| 55 | − * @wwid: World Wide Node Name for LUN. | |
| 56 | − * | |
| 57 | − * Return: Allocated global glun_info structure on success, NULL on failure | |
| 58 | − */ | |
| 59 | −static struct glun_info *create_global(struct scsi_device *sdev, u8 *wwid) | |
| 60 | −{ | |
| 61 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 62 | − struct device *dev = &cfg->dev->dev; | |
| 63 | − struct glun_info *gli = NULL; | |
| 64 | − | |
| 65 | − gli = kzalloc(sizeof(*gli), GFP_KERNEL); | |
| 66 | − if (unlikely(!gli)) { | |
| 67 | − dev_err(dev, "%s: could not allocate gli\n", __func__); | |
| 68 | − goto out; | |
| 69 | − } | |
| 70 | − | |
| 71 | − mutex_init(&gli->mutex); | |
| 72 | − memcpy(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN); | |
| 73 | −out: | |
| 74 | − return gli; | |
| 75 | −} | |
| 76 | − | |
| 77 | −/** | |
| 78 | − * lookup_local() - find a local LUN information structure by WWID | |
| 79 | − * @cfg: Internal structure associated with the host. | |
| 80 | − * @wwid: WWID associated with LUN. | |
| 81 | − * | |
| 82 | − * Return: Found local lun_info structure on success, NULL on failure | |
| 83 | − */ | |
| 84 | −static struct llun_info *lookup_local(struct cxlflash_cfg *cfg, u8 *wwid) | |
| 85 | −{ | |
| 86 | − struct llun_info *lli, *temp; | |
| 87 | − | |
| 88 | − list_for_each_entry_safe(lli, temp, &cfg->lluns, list) | |
| 89 | − if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) | |
| 90 | − return lli; | |
| 91 | − | |
| 92 | − return NULL; | |
| 93 | −} | |
| 94 | − | |
| 95 | −/** | |
| 96 | − * lookup_global() - find a global LUN information structure by WWID | |
| 97 | − * @wwid: WWID associated with LUN. | |
| 98 | − * | |
| 99 | − * Return: Found global lun_info structure on success, NULL on failure | |
| 100 | − */ | |
| 101 | −static struct glun_info *lookup_global(u8 *wwid) | |
| 102 | −{ | |
| 103 | − struct glun_info *gli, *temp; | |
| 104 | − | |
| 105 | − list_for_each_entry_safe(gli, temp, &global.gluns, list) | |
| 106 | − if (!memcmp(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) | |
| 107 | − return gli; | |
| 108 | − | |
| 109 | − return NULL; | |
| 110 | −} | |
| 111 | − | |
| 112 | −/** | |
| 113 | − * find_and_create_lun() - find or create a local LUN information structure | |
| 114 | − * @sdev: SCSI device associated with LUN. | |
| 115 | − * @wwid: WWID associated with LUN. | |
| 116 | − * | |
| 117 | − * The LUN is kept both in a local list (per adapter) and in a global list | |
| 118 | − * (across all adapters). Certain attributes of the LUN are local to the | |
| 119 | − * adapter (such as index, port selection mask, etc.). | |
| 120 | − * | |
| 121 | − * The block allocation map is shared across all adapters (i.e. associated | |
| 122 | − * wih the global list). Since different attributes are associated with | |
| 123 | − * the per adapter and global entries, allocate two separate structures for each | |
| 124 | − * LUN (one local, one global). | |
| 125 | − * | |
| 126 | − * Keep a pointer back from the local to the global entry. | |
| 127 | − * | |
| 128 | − * This routine assumes the caller holds the global mutex. | |
| 129 | − * | |
| 130 | − * Return: Found/Allocated local lun_info structure on success, NULL on failure | |
| 131 | − */ | |
| 132 | −static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) | |
| 133 | −{ | |
| 134 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 135 | − struct device *dev = &cfg->dev->dev; | |
| 136 | − struct llun_info *lli = NULL; | |
| 137 | − struct glun_info *gli = NULL; | |
| 138 | − | |
| 139 | − if (unlikely(!wwid)) | |
| 140 | − goto out; | |
| 141 | − | |
| 142 | − lli = lookup_local(cfg, wwid); | |
| 143 | − if (lli) | |
| 144 | − goto out; | |
| 145 | − | |
| 146 | − lli = create_local(sdev, wwid); | |
| 147 | − if (unlikely(!lli)) | |
| 148 | − goto out; | |
| 149 | − | |
| 150 | − gli = lookup_global(wwid); | |
| 151 | − if (gli) { | |
| 152 | − lli->parent = gli; | |
| 153 | − list_add(&lli->list, &cfg->lluns); | |
| 154 | − goto out; | |
| 155 | − } | |
| 156 | − | |
| 157 | − gli = create_global(sdev, wwid); | |
| 158 | − if (unlikely(!gli)) { | |
| 159 | − kfree(lli); | |
| 160 | − lli = NULL; | |
| 161 | − goto out; | |
| 162 | − } | |
| 163 | − | |
| 164 | − lli->parent = gli; | |
| 165 | − list_add(&lli->list, &cfg->lluns); | |
| 166 | − | |
| 167 | − list_add(&gli->list, &global.gluns); | |
| 168 | − | |
| 169 | −out: | |
| 170 | − dev_dbg(dev, "%s: returning lli=%p, gli=%p\n", __func__, lli, gli); | |
| 171 | − return lli; | |
| 172 | −} | |
| 173 | − | |
| 174 | −/** | |
| 175 | − * cxlflash_term_local_luns() - Delete all entries from local LUN list, free. | |
| 176 | − * @cfg: Internal structure associated with the host. | |
| 177 | − */ | |
| 178 | −void cxlflash_term_local_luns(struct cxlflash_cfg *cfg) | |
| 179 | −{ | |
| 180 | − struct llun_info *lli, *temp; | |
| 181 | − | |
| 182 | − mutex_lock(&global.mutex); | |
| 183 | − list_for_each_entry_safe(lli, temp, &cfg->lluns, list) { | |
| 184 | − list_del(&lli->list); | |
| 185 | − kfree(lli); | |
| 186 | − } | |
| 187 | − mutex_unlock(&global.mutex); | |
| 188 | −} | |
| 189 | − | |
| 190 | −/** | |
| 191 | − * cxlflash_list_init() - initializes the global LUN list | |
| 192 | − */ | |
| 193 | −void cxlflash_list_init(void) | |
| 194 | −{ | |
| 195 | − INIT_LIST_HEAD(&global.gluns); | |
| 196 | − mutex_init(&global.mutex); | |
| 197 | − global.err_page = NULL; | |
| 198 | −} | |
| 199 | − | |
| 200 | −/** | |
| 201 | − * cxlflash_term_global_luns() - frees resources associated with global LUN list | |
| 202 | − */ | |
| 203 | −void cxlflash_term_global_luns(void) | |
| 204 | −{ | |
| 205 | − struct glun_info *gli, *temp; | |
| 206 | − | |
| 207 | − mutex_lock(&global.mutex); | |
| 208 | − list_for_each_entry_safe(gli, temp, &global.gluns, list) { | |
| 209 | − list_del(&gli->list); | |
| 210 | − cxlflash_ba_terminate(&gli->blka.ba_lun); | |
| 211 | − kfree(gli); | |
| 212 | − } | |
| 213 | − mutex_unlock(&global.mutex); | |
| 214 | −} | |
| 215 | − | |
| 216 | −/** | |
| 217 | − * cxlflash_manage_lun() - handles LUN management activities | |
| 218 | − * @sdev: SCSI device associated with LUN. | |
| 219 | − * @arg: Manage ioctl data structure. | |
| 220 | − * | |
| 221 | − * This routine is used to notify the driver about a LUN's WWID and associate | |
| 222 | − * SCSI devices (sdev) with a global LUN instance. Additionally it serves to | |
| 223 | − * change a LUN's operating mode: legacy or superpipe. | |
| 224 | − * | |
| 225 | − * Return: 0 on success, -errno on failure | |
| 226 | − */ | |
| 227 | −int cxlflash_manage_lun(struct scsi_device *sdev, void *arg) | |
| 228 | −{ | |
| 229 | − struct dk_cxlflash_manage_lun *manage = arg; | |
| 230 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 231 | − struct device *dev = &cfg->dev->dev; | |
| 232 | − struct llun_info *lli = NULL; | |
| 233 | − int rc = 0; | |
| 234 | − u64 flags = manage->hdr.flags; | |
| 235 | − u32 chan = sdev->channel; | |
| 236 | − | |
| 237 | − mutex_lock(&global.mutex); | |
| 238 | − lli = find_and_create_lun(sdev, manage->wwid); | |
| 239 | − dev_dbg(dev, "%s: WWID=%016llx%016llx, flags=%016llx lli=%p\n", | |
| 240 | − __func__, get_unaligned_be64(&manage->wwid[0]), | |
| 241 | − get_unaligned_be64(&manage->wwid[8]), manage->hdr.flags, lli); | |
| 242 | − if (unlikely(!lli)) { | |
| 243 | − rc = -ENOMEM; | |
| 244 | − goto out; | |
| 245 | − } | |
| 246 | − | |
| 247 | − if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) { | |
| 248 | − /* | |
| 249 | − * Update port selection mask based upon channel, store off LUN | |
| 250 | − * in unpacked, AFU-friendly format, and hang LUN reference in | |
| 251 | − * the sdev. | |
| 252 | − */ | |
| 253 | − lli->port_sel |= CHAN2PORTMASK(chan); | |
| 254 | − lli->lun_id[chan] = lun_to_lunid(sdev->lun); | |
| 255 | − sdev->hostdata = lli; | |
| 256 | − } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) { | |
| 257 | − if (lli->parent->mode != MODE_NONE) | |
| 258 | − rc = -EBUSY; | |
| 259 | − else { | |
| 260 | − /* | |
| 261 | − * Clean up local LUN for this port and reset table | |
| 262 | − * tracking when no more references exist. | |
| 263 | − */ | |
| 264 | − sdev->hostdata = NULL; | |
| 265 | − lli->port_sel &= ~CHAN2PORTMASK(chan); | |
| 266 | − if (lli->port_sel == 0U) | |
| 267 | − lli->in_table = false; | |
| 268 | − } | |
| 269 | − } | |
| 270 | − | |
| 271 | − dev_dbg(dev, "%s: port_sel=%08x chan=%u lun_id=%016llx\n", | |
| 272 | − __func__, lli->port_sel, chan, lli->lun_id[chan]); | |
| 273 | − | |
| 274 | −out: | |
| 275 | − mutex_unlock(&global.mutex); | |
| 276 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 277 | − return rc; | |
| 278 | −} | |
| @@ -1,3970 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2015 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#include <linux/delay.h> | |
| 12 | −#include <linux/list.h> | |
| 13 | −#include <linux/module.h> | |
| 14 | −#include <linux/pci.h> | |
| 15 | − | |
| 16 | −#include <linux/unaligned.h> | |
| 17 | − | |
| 18 | −#include <scsi/scsi_cmnd.h> | |
| 19 | −#include <scsi/scsi_host.h> | |
| 20 | −#include <uapi/scsi/cxlflash_ioctl.h> | |
| 21 | − | |
| 22 | −#include "main.h" | |
| 23 | −#include "sislite.h" | |
| 24 | −#include "common.h" | |
| 25 | − | |
| 26 | −MODULE_DESCRIPTION(CXLFLASH_ADAPTER_NAME); | |
| 27 | −MODULE_AUTHOR("Manoj N. Kumar <manoj@linux.vnet.ibm.com>"); | |
| 28 | −MODULE_AUTHOR("Matthew R. Ochs <mrochs@linux.vnet.ibm.com>"); | |
| 29 | −MODULE_LICENSE("GPL"); | |
| 30 | − | |
| 31 | −static char *cxlflash_devnode(const struct device *dev, umode_t *mode); | |
| 32 | −static const struct class cxlflash_class = { | |
| 33 | − .name = "cxlflash", | |
| 34 | − .devnode = cxlflash_devnode, | |
| 35 | −}; | |
| 36 | − | |
| 37 | −static u32 cxlflash_major; | |
| 38 | −static DECLARE_BITMAP(cxlflash_minor, CXLFLASH_MAX_ADAPTERS); | |
| 39 | − | |
| 40 | −/** | |
| 41 | − * process_cmd_err() - command error handler | |
| 42 | − * @cmd: AFU command that experienced the error. | |
| 43 | − * @scp: SCSI command associated with the AFU command in error. | |
| 44 | − * | |
| 45 | − * Translates error bits from AFU command to SCSI command results. | |
| 46 | − */ | |
| 47 | −static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) | |
| 48 | −{ | |
| 49 | − struct afu *afu = cmd->parent; | |
| 50 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 51 | − struct device *dev = &cfg->dev->dev; | |
| 52 | − struct sisl_ioasa *ioasa; | |
| 53 | − u32 resid; | |
| 54 | − | |
| 55 | − ioasa = &(cmd->sa); | |
| 56 | − | |
| 57 | − if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) { | |
| 58 | − resid = ioasa->resid; | |
| 59 | − scsi_set_resid(scp, resid); | |
| 60 | − dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p, resid = %d\n", | |
| 61 | − __func__, cmd, scp, resid); | |
| 62 | − } | |
| 63 | − | |
| 64 | − if (ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN) { | |
| 65 | − dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p\n", | |
| 66 | − __func__, cmd, scp); | |
| 67 | − scp->result = (DID_ERROR << 16); | |
| 68 | − } | |
| 69 | − | |
| 70 | − dev_dbg(dev, "%s: cmd failed afu_rc=%02x scsi_rc=%02x fc_rc=%02x " | |
| 71 | − "afu_extra=%02x scsi_extra=%02x fc_extra=%02x\n", __func__, | |
| 72 | − ioasa->rc.afu_rc, ioasa->rc.scsi_rc, ioasa->rc.fc_rc, | |
| 73 | − ioasa->afu_extra, ioasa->scsi_extra, ioasa->fc_extra); | |
| 74 | − | |
| 75 | − if (ioasa->rc.scsi_rc) { | |
| 76 | − /* We have a SCSI status */ | |
| 77 | − if (ioasa->rc.flags & SISL_RC_FLAGS_SENSE_VALID) { | |
| 78 | − memcpy(scp->sense_buffer, ioasa->sense_data, | |
| 79 | − SISL_SENSE_DATA_LEN); | |
| 80 | − scp->result = ioasa->rc.scsi_rc; | |
| 81 | − } else | |
| 82 | − scp->result = ioasa->rc.scsi_rc | (DID_ERROR << 16); | |
| 83 | − } | |
| 84 | − | |
| 85 | − /* | |
| 86 | − * We encountered an error. Set scp->result based on nature | |
| 87 | − * of error. | |
| 88 | − */ | |
| 89 | − if (ioasa->rc.fc_rc) { | |
| 90 | − /* We have an FC status */ | |
| 91 | − switch (ioasa->rc.fc_rc) { | |
| 92 | − case SISL_FC_RC_LINKDOWN: | |
| 93 | − scp->result = (DID_REQUEUE << 16); | |
| 94 | − break; | |
| 95 | − case SISL_FC_RC_RESID: | |
| 96 | − /* This indicates an FCP resid underrun */ | |
| 97 | − if (!(ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN)) { | |
| 98 | − /* If the SISL_RC_FLAGS_OVERRUN flag was set, | |
| 99 | − * then we will handle this error else where. | |
| 100 | − * If not then we must handle it here. | |
| 101 | − * This is probably an AFU bug. | |
| 102 | − */ | |
| 103 | − scp->result = (DID_ERROR << 16); | |
| 104 | − } | |
| 105 | − break; | |
| 106 | − case SISL_FC_RC_RESIDERR: | |
| 107 | − /* Resid mismatch between adapter and device */ | |
| 108 | − case SISL_FC_RC_TGTABORT: | |
| 109 | − case SISL_FC_RC_ABORTOK: | |
| 110 | − case SISL_FC_RC_ABORTFAIL: | |
| 111 | − case SISL_FC_RC_NOLOGI: | |
| 112 | − case SISL_FC_RC_ABORTPEND: | |
| 113 | − case SISL_FC_RC_WRABORTPEND: | |
| 114 | − case SISL_FC_RC_NOEXP: | |
| 115 | − case SISL_FC_RC_INUSE: | |
| 116 | − scp->result = (DID_ERROR << 16); | |
| 117 | − break; | |
| 118 | − } | |
| 119 | − } | |
| 120 | − | |
| 121 | − if (ioasa->rc.afu_rc) { | |
| 122 | − /* We have an AFU error */ | |
| 123 | − switch (ioasa->rc.afu_rc) { | |
| 124 | − case SISL_AFU_RC_NO_CHANNELS: | |
| 125 | − scp->result = (DID_NO_CONNECT << 16); | |
| 126 | − break; | |
| 127 | − case SISL_AFU_RC_DATA_DMA_ERR: | |
| 128 | − switch (ioasa->afu_extra) { | |
| 129 | − case SISL_AFU_DMA_ERR_PAGE_IN: | |
| 130 | − /* Retry */ | |
| 131 | − scp->result = (DID_IMM_RETRY << 16); | |
| 132 | − break; | |
| 133 | − case SISL_AFU_DMA_ERR_INVALID_EA: | |
| 134 | − default: | |
| 135 | − scp->result = (DID_ERROR << 16); | |
| 136 | − } | |
| 137 | − break; | |
| 138 | − case SISL_AFU_RC_OUT_OF_DATA_BUFS: | |
| 139 | − /* Retry */ | |
| 140 | − scp->result = (DID_ERROR << 16); | |
| 141 | − break; | |
| 142 | − default: | |
| 143 | − scp->result = (DID_ERROR << 16); | |
| 144 | − } | |
| 145 | − } | |
| 146 | −} | |
| 147 | − | |
| 148 | −/** | |
| 149 | − * cmd_complete() - command completion handler | |
| 150 | − * @cmd: AFU command that has completed. | |
| 151 | − * | |
| 152 | − * For SCSI commands this routine prepares and submits commands that have | |
| 153 | − * either completed or timed out to the SCSI stack. For internal commands | |
| 154 | − * (TMF or AFU), this routine simply notifies the originator that the | |
| 155 | − * command has completed. | |
| 156 | − */ | |
| 157 | −static void cmd_complete(struct afu_cmd *cmd) | |
| 158 | −{ | |
| 159 | − struct scsi_cmnd *scp; | |
| 160 | − ulong lock_flags; | |
| 161 | − struct afu *afu = cmd->parent; | |
| 162 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 163 | − struct device *dev = &cfg->dev->dev; | |
| 164 | − struct hwq *hwq = get_hwq(afu, cmd->hwq_index); | |
| 165 | − | |
| 166 | − spin_lock_irqsave(&hwq->hsq_slock, lock_flags); | |
| 167 | − list_del(&cmd->list); | |
| 168 | − spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); | |
| 169 | − | |
| 170 | − if (cmd->scp) { | |
| 171 | − scp = cmd->scp; | |
| 172 | − if (unlikely(cmd->sa.ioasc)) | |
| 173 | − process_cmd_err(cmd, scp); | |
| 174 | − else | |
| 175 | − scp->result = (DID_OK << 16); | |
| 176 | − | |
| 177 | − dev_dbg_ratelimited(dev, "%s:scp=%p result=%08x ioasc=%08x\n", | |
| 178 | − __func__, scp, scp->result, cmd->sa.ioasc); | |
| 179 | − scsi_done(scp); | |
| 180 | − } else if (cmd->cmd_tmf) { | |
| 181 | − spin_lock_irqsave(&cfg->tmf_slock, lock_flags); | |
| 182 | − cfg->tmf_active = false; | |
| 183 | − wake_up_all_locked(&cfg->tmf_waitq); | |
| 184 | − spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); | |
| 185 | − } else | |
| 186 | − complete(&cmd->cevent); | |
| 187 | −} | |
| 188 | − | |
| 189 | −/** | |
| 190 | − * flush_pending_cmds() - flush all pending commands on this hardware queue | |
| 191 | − * @hwq: Hardware queue to flush. | |
| 192 | − * | |
| 193 | − * The hardware send queue lock associated with this hardware queue must be | |
| 194 | − * held when calling this routine. | |
| 195 | − */ | |
| 196 | −static void flush_pending_cmds(struct hwq *hwq) | |
| 197 | −{ | |
| 198 | − struct cxlflash_cfg *cfg = hwq->afu->parent; | |
| 199 | − struct afu_cmd *cmd, *tmp; | |
| 200 | − struct scsi_cmnd *scp; | |
| 201 | − ulong lock_flags; | |
| 202 | − | |
| 203 | − list_for_each_entry_safe(cmd, tmp, &hwq->pending_cmds, list) { | |
| 204 | − /* Bypass command when on a doneq, cmd_complete() will handle */ | |
| 205 | − if (!list_empty(&cmd->queue)) | |
| 206 | − continue; | |
| 207 | − | |
| 208 | − list_del(&cmd->list); | |
| 209 | − | |
| 210 | − if (cmd->scp) { | |
| 211 | − scp = cmd->scp; | |
| 212 | − scp->result = (DID_IMM_RETRY << 16); | |
| 213 | − scsi_done(scp); | |
| 214 | − } else { | |
| 215 | − cmd->cmd_aborted = true; | |
| 216 | − | |
| 217 | − if (cmd->cmd_tmf) { | |
| 218 | − spin_lock_irqsave(&cfg->tmf_slock, lock_flags); | |
| 219 | − cfg->tmf_active = false; | |
| 220 | − wake_up_all_locked(&cfg->tmf_waitq); | |
| 221 | − spin_unlock_irqrestore(&cfg->tmf_slock, | |
| 222 | − lock_flags); | |
| 223 | − } else | |
| 224 | − complete(&cmd->cevent); | |
| 225 | − } | |
| 226 | − } | |
| 227 | −} | |
| 228 | − | |
| 229 | −/** | |
| 230 | − * context_reset() - reset context via specified register | |
| 231 | − * @hwq: Hardware queue owning the context to be reset. | |
| 232 | − * @reset_reg: MMIO register to perform reset. | |
| 233 | − * | |
| 234 | − * When the reset is successful, the SISLite specification guarantees that | |
| 235 | − * the AFU has aborted all currently pending I/O. Accordingly, these commands | |
| 236 | − * must be flushed. | |
| 237 | − * | |
| 238 | − * Return: 0 on success, -errno on failure | |
| 239 | − */ | |
| 240 | −static int context_reset(struct hwq *hwq, __be64 __iomem *reset_reg) | |
| 241 | −{ | |
| 242 | − struct cxlflash_cfg *cfg = hwq->afu->parent; | |
| 243 | − struct device *dev = &cfg->dev->dev; | |
| 244 | − int rc = -ETIMEDOUT; | |
| 245 | − int nretry = 0; | |
| 246 | − u64 val = 0x1; | |
| 247 | − ulong lock_flags; | |
| 248 | − | |
| 249 | − dev_dbg(dev, "%s: hwq=%p\n", __func__, hwq); | |
| 250 | − | |
| 251 | − spin_lock_irqsave(&hwq->hsq_slock, lock_flags); | |
| 252 | − | |
| 253 | − writeq_be(val, reset_reg); | |
| 254 | − do { | |
| 255 | − val = readq_be(reset_reg); | |
| 256 | − if ((val & 0x1) == 0x0) { | |
| 257 | − rc = 0; | |
| 258 | − break; | |
| 259 | − } | |
| 260 | − | |
| 261 | − /* Double delay each time */ | |
| 262 | − udelay(1 << nretry); | |
| 263 | − } while (nretry++ < MC_ROOM_RETRY_CNT); | |
| 264 | − | |
| 265 | − if (!rc) | |
| 266 | − flush_pending_cmds(hwq); | |
| 267 | − | |
| 268 | − spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); | |
| 269 | − | |
| 270 | − dev_dbg(dev, "%s: returning rc=%d, val=%016llx nretry=%d\n", | |
| 271 | − __func__, rc, val, nretry); | |
| 272 | − return rc; | |
| 273 | −} | |
| 274 | − | |
| 275 | −/** | |
| 276 | − * context_reset_ioarrin() - reset context via IOARRIN register | |
| 277 | − * @hwq: Hardware queue owning the context to be reset. | |
| 278 | − * | |
| 279 | − * Return: 0 on success, -errno on failure | |
| 280 | − */ | |
| 281 | −static int context_reset_ioarrin(struct hwq *hwq) | |
| 282 | −{ | |
| 283 | − return context_reset(hwq, &hwq->host_map->ioarrin); | |
| 284 | −} | |
| 285 | − | |
| 286 | −/** | |
| 287 | − * context_reset_sq() - reset context via SQ_CONTEXT_RESET register | |
| 288 | − * @hwq: Hardware queue owning the context to be reset. | |
| 289 | − * | |
| 290 | − * Return: 0 on success, -errno on failure | |
| 291 | − */ | |
| 292 | −static int context_reset_sq(struct hwq *hwq) | |
| 293 | −{ | |
| 294 | − return context_reset(hwq, &hwq->host_map->sq_ctx_reset); | |
| 295 | −} | |
| 296 | − | |
| 297 | −/** | |
| 298 | − * send_cmd_ioarrin() - sends an AFU command via IOARRIN register | |
| 299 | − * @afu: AFU associated with the host. | |
| 300 | − * @cmd: AFU command to send. | |
| 301 | − * | |
| 302 | − * Return: | |
| 303 | − * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure | |
| 304 | − */ | |
| 305 | −static int send_cmd_ioarrin(struct afu *afu, struct afu_cmd *cmd) | |
| 306 | −{ | |
| 307 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 308 | − struct device *dev = &cfg->dev->dev; | |
| 309 | − struct hwq *hwq = get_hwq(afu, cmd->hwq_index); | |
| 310 | − int rc = 0; | |
| 311 | − s64 room; | |
| 312 | − ulong lock_flags; | |
| 313 | − | |
| 314 | − /* | |
| 315 | − * To avoid the performance penalty of MMIO, spread the update of | |
| 316 | − * 'room' over multiple commands. | |
| 317 | − */ | |
| 318 | − spin_lock_irqsave(&hwq->hsq_slock, lock_flags); | |
| 319 | − if (--hwq->room < 0) { | |
| 320 | − room = readq_be(&hwq->host_map->cmd_room); | |
| 321 | − if (room <= 0) { | |
| 322 | − dev_dbg_ratelimited(dev, "%s: no cmd_room to send " | |
| 323 | − "0x%02X, room=0x%016llX\n", | |
| 324 | − __func__, cmd->rcb.cdb[0], room); | |
| 325 | − hwq->room = 0; | |
| 326 | − rc = SCSI_MLQUEUE_HOST_BUSY; | |
| 327 | − goto out; | |
| 328 | − } | |
| 329 | − hwq->room = room - 1; | |
| 330 | − } | |
| 331 | − | |
| 332 | − list_add(&cmd->list, &hwq->pending_cmds); | |
| 333 | − writeq_be((u64)&cmd->rcb, &hwq->host_map->ioarrin); | |
| 334 | −out: | |
| 335 | − spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); | |
| 336 | − dev_dbg_ratelimited(dev, "%s: cmd=%p len=%u ea=%016llx rc=%d\n", | |
| 337 | − __func__, cmd, cmd->rcb.data_len, cmd->rcb.data_ea, rc); | |
| 338 | − return rc; | |
| 339 | −} | |
| 340 | − | |
| 341 | −/** | |
| 342 | − * send_cmd_sq() - sends an AFU command via SQ ring | |
| 343 | − * @afu: AFU associated with the host. | |
| 344 | − * @cmd: AFU command to send. | |
| 345 | − * | |
| 346 | − * Return: | |
| 347 | − * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure | |
| 348 | − */ | |
| 349 | −static int send_cmd_sq(struct afu *afu, struct afu_cmd *cmd) | |
| 350 | −{ | |
| 351 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 352 | − struct device *dev = &cfg->dev->dev; | |
| 353 | − struct hwq *hwq = get_hwq(afu, cmd->hwq_index); | |
| 354 | − int rc = 0; | |
| 355 | − int newval; | |
| 356 | − ulong lock_flags; | |
| 357 | − | |
| 358 | − newval = atomic_dec_if_positive(&hwq->hsq_credits); | |
| 359 | − if (newval <= 0) { | |
| 360 | − rc = SCSI_MLQUEUE_HOST_BUSY; | |
| 361 | − goto out; | |
| 362 | − } | |
| 363 | − | |
| 364 | − cmd->rcb.ioasa = &cmd->sa; | |
| 365 | − | |
| 366 | − spin_lock_irqsave(&hwq->hsq_slock, lock_flags); | |
| 367 | − | |
| 368 | − *hwq->hsq_curr = cmd->rcb; | |
| 369 | − if (hwq->hsq_curr < hwq->hsq_end) | |
| 370 | − hwq->hsq_curr++; | |
| 371 | − else | |
| 372 | − hwq->hsq_curr = hwq->hsq_start; | |
| 373 | − | |
| 374 | − list_add(&cmd->list, &hwq->pending_cmds); | |
| 375 | − writeq_be((u64)hwq->hsq_curr, &hwq->host_map->sq_tail); | |
| 376 | − | |
| 377 | − spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); | |
| 378 | −out: | |
| 379 | − dev_dbg(dev, "%s: cmd=%p len=%u ea=%016llx ioasa=%p rc=%d curr=%p " | |
| 380 | − "head=%016llx tail=%016llx\n", __func__, cmd, cmd->rcb.data_len, | |
| 381 | − cmd->rcb.data_ea, cmd->rcb.ioasa, rc, hwq->hsq_curr, | |
| 382 | − readq_be(&hwq->host_map->sq_head), | |
| 383 | − readq_be(&hwq->host_map->sq_tail)); | |
| 384 | − return rc; | |
| 385 | −} | |
| 386 | − | |
| 387 | −/** | |
| 388 | − * wait_resp() - polls for a response or timeout to a sent AFU command | |
| 389 | − * @afu: AFU associated with the host. | |
| 390 | − * @cmd: AFU command that was sent. | |
| 391 | − * | |
| 392 | − * Return: 0 on success, -errno on failure | |
| 393 | − */ | |
| 394 | −static int wait_resp(struct afu *afu, struct afu_cmd *cmd) | |
| 395 | −{ | |
| 396 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 397 | − struct device *dev = &cfg->dev->dev; | |
| 398 | − int rc = 0; | |
| 399 | − ulong timeout = msecs_to_jiffies(cmd->rcb.timeout * 2 * 1000); | |
| 400 | − | |
| 401 | − timeout = wait_for_completion_timeout(&cmd->cevent, timeout); | |
| 402 | − if (!timeout) | |
| 403 | − rc = -ETIMEDOUT; | |
| 404 | − | |
| 405 | − if (cmd->cmd_aborted) | |
| 406 | − rc = -EAGAIN; | |
| 407 | − | |
| 408 | − if (unlikely(cmd->sa.ioasc != 0)) { | |
| 409 | − dev_err(dev, "%s: cmd %02x failed, ioasc=%08x\n", | |
| 410 | − __func__, cmd->rcb.cdb[0], cmd->sa.ioasc); | |
| 411 | − rc = -EIO; | |
| 412 | − } | |
| 413 | − | |
| 414 | − return rc; | |
| 415 | −} | |
| 416 | − | |
| 417 | −/** | |
| 418 | − * cmd_to_target_hwq() - selects a target hardware queue for a SCSI command | |
| 419 | − * @host: SCSI host associated with device. | |
| 420 | − * @scp: SCSI command to send. | |
| 421 | − * @afu: SCSI command to send. | |
| 422 | − * | |
| 423 | − * Hashes a command based upon the hardware queue mode. | |
| 424 | − * | |
| 425 | − * Return: Trusted index of target hardware queue | |
| 426 | − */ | |
| 427 | −static u32 cmd_to_target_hwq(struct Scsi_Host *host, struct scsi_cmnd *scp, | |
| 428 | − struct afu *afu) | |
| 429 | −{ | |
| 430 | − u32 tag; | |
| 431 | − u32 hwq = 0; | |
| 432 | − | |
| 433 | − if (afu->num_hwqs == 1) | |
| 434 | − return 0; | |
| 435 | − | |
| 436 | − switch (afu->hwq_mode) { | |
| 437 | − case HWQ_MODE_RR: | |
| 438 | − hwq = afu->hwq_rr_count++ % afu->num_hwqs; | |
| 439 | − break; | |
| 440 | − case HWQ_MODE_TAG: | |
| 441 | − tag = blk_mq_unique_tag(scsi_cmd_to_rq(scp)); | |
| 442 | − hwq = blk_mq_unique_tag_to_hwq(tag); | |
| 443 | − break; | |
| 444 | − case HWQ_MODE_CPU: | |
| 445 | − hwq = smp_processor_id() % afu->num_hwqs; | |
| 446 | − break; | |
| 447 | − default: | |
| 448 | − WARN_ON_ONCE(1); | |
| 449 | − } | |
| 450 | − | |
| 451 | − return hwq; | |
| 452 | −} | |
| 453 | − | |
| 454 | −/** | |
| 455 | − * send_tmf() - sends a Task Management Function (TMF) | |
| 456 | − * @cfg: Internal structure associated with the host. | |
| 457 | − * @sdev: SCSI device destined for TMF. | |
| 458 | − * @tmfcmd: TMF command to send. | |
| 459 | − * | |
| 460 | − * Return: | |
| 461 | − * 0 on success, SCSI_MLQUEUE_HOST_BUSY or -errno on failure | |
| 462 | − */ | |
| 463 | −static int send_tmf(struct cxlflash_cfg *cfg, struct scsi_device *sdev, | |
| 464 | − u64 tmfcmd) | |
| 465 | −{ | |
| 466 | − struct afu *afu = cfg->afu; | |
| 467 | − struct afu_cmd *cmd = NULL; | |
| 468 | − struct device *dev = &cfg->dev->dev; | |
| 469 | − struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); | |
| 470 | − bool needs_deletion = false; | |
| 471 | − char *buf = NULL; | |
| 472 | − ulong lock_flags; | |
| 473 | − int rc = 0; | |
| 474 | − ulong to; | |
| 475 | − | |
| 476 | − buf = kzalloc(sizeof(*cmd) + __alignof__(*cmd) - 1, GFP_KERNEL); | |
| 477 | − if (unlikely(!buf)) { | |
| 478 | − dev_err(dev, "%s: no memory for command\n", __func__); | |
| 479 | − rc = -ENOMEM; | |
| 480 | − goto out; | |
| 481 | − } | |
| 482 | − | |
| 483 | − cmd = (struct afu_cmd *)PTR_ALIGN(buf, __alignof__(*cmd)); | |
| 484 | − INIT_LIST_HEAD(&cmd->queue); | |
| 485 | − | |
| 486 | − /* When Task Management Function is active do not send another */ | |
| 487 | − spin_lock_irqsave(&cfg->tmf_slock, lock_flags); | |
| 488 | − if (cfg->tmf_active) | |
| 489 | − wait_event_interruptible_lock_irq(cfg->tmf_waitq, | |
| 490 | − !cfg->tmf_active, | |
| 491 | − cfg->tmf_slock); | |
| 492 | − cfg->tmf_active = true; | |
| 493 | − spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); | |
| 494 | − | |
| 495 | − cmd->parent = afu; | |
| 496 | − cmd->cmd_tmf = true; | |
| 497 | − cmd->hwq_index = hwq->index; | |
| 498 | − | |
| 499 | − cmd->rcb.ctx_id = hwq->ctx_hndl; | |
| 500 | − cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; | |
| 501 | − cmd->rcb.port_sel = CHAN2PORTMASK(sdev->channel); | |
| 502 | − cmd->rcb.lun_id = lun_to_lunid(sdev->lun); | |
| 503 | − cmd->rcb.req_flags = (SISL_REQ_FLAGS_PORT_LUN_ID | | |
| 504 | − SISL_REQ_FLAGS_SUP_UNDERRUN | | |
| 505 | − SISL_REQ_FLAGS_TMF_CMD); | |
| 506 | − memcpy(cmd->rcb.cdb, &tmfcmd, sizeof(tmfcmd)); | |
| 507 | − | |
| 508 | − rc = afu->send_cmd(afu, cmd); | |
| 509 | − if (unlikely(rc)) { | |
| 510 | − spin_lock_irqsave(&cfg->tmf_slock, lock_flags); | |
| 511 | − cfg->tmf_active = false; | |
| 512 | − spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); | |
| 513 | − goto out; | |
| 514 | − } | |
| 515 | − | |
| 516 | − spin_lock_irqsave(&cfg->tmf_slock, lock_flags); | |
| 517 | − to = msecs_to_jiffies(5000); | |
| 518 | − to = wait_event_interruptible_lock_irq_timeout(cfg->tmf_waitq, | |
| 519 | − !cfg->tmf_active, | |
| 520 | − cfg->tmf_slock, | |
| 521 | − to); | |
| 522 | − if (!to) { | |
| 523 | − dev_err(dev, "%s: TMF timed out\n", __func__); | |
| 524 | − rc = -ETIMEDOUT; | |
| 525 | − needs_deletion = true; | |
| 526 | − } else if (cmd->cmd_aborted) { | |
| 527 | − dev_err(dev, "%s: TMF aborted\n", __func__); | |
| 528 | − rc = -EAGAIN; | |
| 529 | − } else if (cmd->sa.ioasc) { | |
| 530 | − dev_err(dev, "%s: TMF failed ioasc=%08x\n", | |
| 531 | − __func__, cmd->sa.ioasc); | |
| 532 | − rc = -EIO; | |
| 533 | − } | |
| 534 | − cfg->tmf_active = false; | |
| 535 | − spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); | |
| 536 | − | |
| 537 | − if (needs_deletion) { | |
| 538 | − spin_lock_irqsave(&hwq->hsq_slock, lock_flags); | |
| 539 | − list_del(&cmd->list); | |
| 540 | − spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); | |
| 541 | − } | |
| 542 | −out: | |
| 543 | − kfree(buf); | |
| 544 | − return rc; | |
| 545 | −} | |
| 546 | − | |
| 547 | −/** | |
| 548 | − * cxlflash_driver_info() - information handler for this host driver | |
| 549 | − * @host: SCSI host associated with device. | |
| 550 | − * | |
| 551 | − * Return: A string describing the device. | |
| 552 | − */ | |
| 553 | −static const char *cxlflash_driver_info(struct Scsi_Host *host) | |
| 554 | −{ | |
| 555 | − return CXLFLASH_ADAPTER_NAME; | |
| 556 | −} | |
| 557 | − | |
| 558 | −/** | |
| 559 | − * cxlflash_queuecommand() - sends a mid-layer request | |
| 560 | − * @host: SCSI host associated with device. | |
| 561 | − * @scp: SCSI command to send. | |
| 562 | − * | |
| 563 | − * Return: 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure | |
| 564 | − */ | |
| 565 | −static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) | |
| 566 | −{ | |
| 567 | − struct cxlflash_cfg *cfg = shost_priv(host); | |
| 568 | − struct afu *afu = cfg->afu; | |
| 569 | − struct device *dev = &cfg->dev->dev; | |
| 570 | − struct afu_cmd *cmd = sc_to_afuci(scp); | |
| 571 | − struct scatterlist *sg = scsi_sglist(scp); | |
| 572 | − int hwq_index = cmd_to_target_hwq(host, scp, afu); | |
| 573 | − struct hwq *hwq = get_hwq(afu, hwq_index); | |
| 574 | − u16 req_flags = SISL_REQ_FLAGS_SUP_UNDERRUN; | |
| 575 | − ulong lock_flags; | |
| 576 | − int rc = 0; | |
| 577 | − | |
| 578 | − dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu " | |
| 579 | − "cdb=(%08x-%08x-%08x-%08x)\n", | |
| 580 | − __func__, scp, host->host_no, scp->device->channel, | |
| 581 | − scp->device->id, scp->device->lun, | |
| 582 | − get_unaligned_be32(&((u32 *)scp->cmnd)[0]), | |
| 583 | − get_unaligned_be32(&((u32 *)scp->cmnd)[1]), | |
| 584 | − get_unaligned_be32(&((u32 *)scp->cmnd)[2]), | |
| 585 | − get_unaligned_be32(&((u32 *)scp->cmnd)[3])); | |
| 586 | − | |
| 587 | − /* | |
| 588 | − * If a Task Management Function is active, wait for it to complete | |
| 589 | − * before continuing with regular commands. | |
| 590 | − */ | |
| 591 | − spin_lock_irqsave(&cfg->tmf_slock, lock_flags); | |
| 592 | − if (cfg->tmf_active) { | |
| 593 | − spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); | |
| 594 | − rc = SCSI_MLQUEUE_HOST_BUSY; | |
| 595 | − goto out; | |
| 596 | − } | |
| 597 | − spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); | |
| 598 | − | |
| 599 | − switch (cfg->state) { | |
| 600 | − case STATE_PROBING: | |
| 601 | − case STATE_PROBED: | |
| 602 | − case STATE_RESET: | |
| 603 | − dev_dbg_ratelimited(dev, "%s: device is in reset\n", __func__); | |
| 604 | − rc = SCSI_MLQUEUE_HOST_BUSY; | |
| 605 | − goto out; | |
| 606 | − case STATE_FAILTERM: | |
| 607 | − dev_dbg_ratelimited(dev, "%s: device has failed\n", __func__); | |
| 608 | − scp->result = (DID_NO_CONNECT << 16); | |
| 609 | − scsi_done(scp); | |
| 610 | − rc = 0; | |
| 611 | − goto out; | |
| 612 | − default: | |
| 613 | − atomic_inc(&afu->cmds_active); | |
| 614 | − break; | |
| 615 | − } | |
| 616 | − | |
| 617 | − if (likely(sg)) { | |
| 618 | − cmd->rcb.data_len = sg->length; | |
| 619 | − cmd->rcb.data_ea = (uintptr_t)sg_virt(sg); | |
| 620 | − } | |
| 621 | − | |
| 622 | − cmd->scp = scp; | |
| 623 | − cmd->parent = afu; | |
| 624 | − cmd->hwq_index = hwq_index; | |
| 625 | − | |
| 626 | − cmd->sa.ioasc = 0; | |
| 627 | − cmd->rcb.ctx_id = hwq->ctx_hndl; | |
| 628 | − cmd->rcb.msi = SISL_MSI_RRQ_UPDATED; | |
| 629 | − cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel); | |
| 630 | − cmd->rcb.lun_id = lun_to_lunid(scp->device->lun); | |
| 631 | − | |
| 632 | − if (scp->sc_data_direction == DMA_TO_DEVICE) | |
| 633 | − req_flags |= SISL_REQ_FLAGS_HOST_WRITE; | |
| 634 | − | |
| 635 | − cmd->rcb.req_flags = req_flags; | |
| 636 | − memcpy(cmd->rcb.cdb, scp->cmnd, sizeof(cmd->rcb.cdb)); | |
| 637 | − | |
| 638 | − rc = afu->send_cmd(afu, cmd); | |
| 639 | − atomic_dec(&afu->cmds_active); | |
| 640 | −out: | |
| 641 | − return rc; | |
| 642 | −} | |
| 643 | − | |
| 644 | −/** | |
| 645 | − * cxlflash_wait_for_pci_err_recovery() - wait for error recovery during probe | |
| 646 | − * @cfg: Internal structure associated with the host. | |
| 647 | − */ | |
| 648 | −static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) | |
| 649 | −{ | |
| 650 | − struct pci_dev *pdev = cfg->dev; | |
| 651 | − | |
| 652 | − if (pci_channel_offline(pdev)) | |
| 653 | − wait_event_timeout(cfg->reset_waitq, | |
| 654 | − !pci_channel_offline(pdev), | |
| 655 | − CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); | |
| 656 | −} | |
| 657 | − | |
| 658 | −/** | |
| 659 | − * free_mem() - free memory associated with the AFU | |
| 660 | − * @cfg: Internal structure associated with the host. | |
| 661 | − */ | |
| 662 | −static void free_mem(struct cxlflash_cfg *cfg) | |
| 663 | −{ | |
| 664 | − struct afu *afu = cfg->afu; | |
| 665 | − | |
| 666 | − if (cfg->afu) { | |
| 667 | − free_pages((ulong)afu, get_order(sizeof(struct afu))); | |
| 668 | − cfg->afu = NULL; | |
| 669 | − } | |
| 670 | −} | |
| 671 | − | |
| 672 | −/** | |
| 673 | − * cxlflash_reset_sync() - synchronizing point for asynchronous resets | |
| 674 | − * @cfg: Internal structure associated with the host. | |
| 675 | − */ | |
| 676 | −static void cxlflash_reset_sync(struct cxlflash_cfg *cfg) | |
| 677 | −{ | |
| 678 | − if (cfg->async_reset_cookie == 0) | |
| 679 | − return; | |
| 680 | − | |
| 681 | − /* Wait until all async calls prior to this cookie have completed */ | |
| 682 | − async_synchronize_cookie(cfg->async_reset_cookie + 1); | |
| 683 | − cfg->async_reset_cookie = 0; | |
| 684 | −} | |
| 685 | − | |
| 686 | −/** | |
| 687 | − * stop_afu() - stops the AFU command timers and unmaps the MMIO space | |
| 688 | − * @cfg: Internal structure associated with the host. | |
| 689 | − * | |
| 690 | − * Safe to call with AFU in a partially allocated/initialized state. | |
| 691 | − * | |
| 692 | − * Cancels scheduled worker threads, waits for any active internal AFU | |
| 693 | − * commands to timeout, disables IRQ polling and then unmaps the MMIO space. | |
| 694 | − */ | |
| 695 | −static void stop_afu(struct cxlflash_cfg *cfg) | |
| 696 | −{ | |
| 697 | − struct afu *afu = cfg->afu; | |
| 698 | − struct hwq *hwq; | |
| 699 | − int i; | |
| 700 | − | |
| 701 | − cancel_work_sync(&cfg->work_q); | |
| 702 | − if (!current_is_async()) | |
| 703 | − cxlflash_reset_sync(cfg); | |
| 704 | − | |
| 705 | − if (likely(afu)) { | |
| 706 | − while (atomic_read(&afu->cmds_active)) | |
| 707 | − ssleep(1); | |
| 708 | − | |
| 709 | − if (afu_is_irqpoll_enabled(afu)) { | |
| 710 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 711 | − hwq = get_hwq(afu, i); | |
| 712 | − | |
| 713 | − irq_poll_disable(&hwq->irqpoll); | |
| 714 | − } | |
| 715 | − } | |
| 716 | − | |
| 717 | − if (likely(afu->afu_map)) { | |
| 718 | − cfg->ops->psa_unmap(afu->afu_map); | |
| 719 | − afu->afu_map = NULL; | |
| 720 | − } | |
| 721 | − } | |
| 722 | −} | |
| 723 | − | |
| 724 | −/** | |
| 725 | − * term_intr() - disables all AFU interrupts | |
| 726 | − * @cfg: Internal structure associated with the host. | |
| 727 | − * @level: Depth of allocation, where to begin waterfall tear down. | |
| 728 | − * @index: Index of the hardware queue. | |
| 729 | − * | |
| 730 | − * Safe to call with AFU/MC in partially allocated/initialized state. | |
| 731 | − */ | |
| 732 | −static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level, | |
| 733 | − u32 index) | |
| 734 | −{ | |
| 735 | − struct afu *afu = cfg->afu; | |
| 736 | − struct device *dev = &cfg->dev->dev; | |
| 737 | − struct hwq *hwq; | |
| 738 | − | |
| 739 | − if (!afu) { | |
| 740 | − dev_err(dev, "%s: returning with NULL afu\n", __func__); | |
| 741 | − return; | |
| 742 | − } | |
| 743 | − | |
| 744 | − hwq = get_hwq(afu, index); | |
| 745 | − | |
| 746 | − if (!hwq->ctx_cookie) { | |
| 747 | − dev_err(dev, "%s: returning with NULL MC\n", __func__); | |
| 748 | − return; | |
| 749 | − } | |
| 750 | − | |
| 751 | − switch (level) { | |
| 752 | − case UNMAP_THREE: | |
| 753 | − /* SISL_MSI_ASYNC_ERROR is setup only for the primary HWQ */ | |
| 754 | − if (index == PRIMARY_HWQ) | |
| 755 | − cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 3, hwq); | |
| 756 | − fallthrough; | |
| 757 | − case UNMAP_TWO: | |
| 758 | − cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 2, hwq); | |
| 759 | − fallthrough; | |
| 760 | − case UNMAP_ONE: | |
| 761 | − cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 1, hwq); | |
| 762 | − fallthrough; | |
| 763 | − case FREE_IRQ: | |
| 764 | − cfg->ops->free_afu_irqs(hwq->ctx_cookie); | |
| 765 | − fallthrough; | |
| 766 | − case UNDO_NOOP: | |
| 767 | − /* No action required */ | |
| 768 | − break; | |
| 769 | − } | |
| 770 | −} | |
| 771 | − | |
| 772 | −/** | |
| 773 | − * term_mc() - terminates the master context | |
| 774 | − * @cfg: Internal structure associated with the host. | |
| 775 | − * @index: Index of the hardware queue. | |
| 776 | − * | |
| 777 | − * Safe to call with AFU/MC in partially allocated/initialized state. | |
| 778 | − */ | |
| 779 | −static void term_mc(struct cxlflash_cfg *cfg, u32 index) | |
| 780 | −{ | |
| 781 | − struct afu *afu = cfg->afu; | |
| 782 | − struct device *dev = &cfg->dev->dev; | |
| 783 | − struct hwq *hwq; | |
| 784 | − ulong lock_flags; | |
| 785 | − | |
| 786 | − if (!afu) { | |
| 787 | − dev_err(dev, "%s: returning with NULL afu\n", __func__); | |
| 788 | − return; | |
| 789 | − } | |
| 790 | − | |
| 791 | − hwq = get_hwq(afu, index); | |
| 792 | − | |
| 793 | − if (!hwq->ctx_cookie) { | |
| 794 | − dev_err(dev, "%s: returning with NULL MC\n", __func__); | |
| 795 | − return; | |
| 796 | − } | |
| 797 | − | |
| 798 | − WARN_ON(cfg->ops->stop_context(hwq->ctx_cookie)); | |
| 799 | − if (index != PRIMARY_HWQ) | |
| 800 | − WARN_ON(cfg->ops->release_context(hwq->ctx_cookie)); | |
| 801 | − hwq->ctx_cookie = NULL; | |
| 802 | − | |
| 803 | − spin_lock_irqsave(&hwq->hrrq_slock, lock_flags); | |
| 804 | − hwq->hrrq_online = false; | |
| 805 | − spin_unlock_irqrestore(&hwq->hrrq_slock, lock_flags); | |
| 806 | − | |
| 807 | − spin_lock_irqsave(&hwq->hsq_slock, lock_flags); | |
| 808 | − flush_pending_cmds(hwq); | |
| 809 | − spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); | |
| 810 | −} | |
| 811 | − | |
| 812 | −/** | |
| 813 | − * term_afu() - terminates the AFU | |
| 814 | − * @cfg: Internal structure associated with the host. | |
| 815 | − * | |
| 816 | − * Safe to call with AFU/MC in partially allocated/initialized state. | |
| 817 | − */ | |
| 818 | −static void term_afu(struct cxlflash_cfg *cfg) | |
| 819 | −{ | |
| 820 | − struct device *dev = &cfg->dev->dev; | |
| 821 | − int k; | |
| 822 | − | |
| 823 | − /* | |
| 824 | − * Tear down is carefully orchestrated to ensure | |
| 825 | − * no interrupts can come in when the problem state | |
| 826 | − * area is unmapped. | |
| 827 | − * | |
| 828 | − * 1) Disable all AFU interrupts for each master | |
| 829 | − * 2) Unmap the problem state area | |
| 830 | − * 3) Stop each master context | |
| 831 | − */ | |
| 832 | − for (k = cfg->afu->num_hwqs - 1; k >= 0; k--) | |
| 833 | − term_intr(cfg, UNMAP_THREE, k); | |
| 834 | − | |
| 835 | − stop_afu(cfg); | |
| 836 | − | |
| 837 | − for (k = cfg->afu->num_hwqs - 1; k >= 0; k--) | |
| 838 | − term_mc(cfg, k); | |
| 839 | − | |
| 840 | − dev_dbg(dev, "%s: returning\n", __func__); | |
| 841 | −} | |
| 842 | − | |
| 843 | −/** | |
| 844 | − * notify_shutdown() - notifies device of pending shutdown | |
| 845 | − * @cfg: Internal structure associated with the host. | |
| 846 | − * @wait: Whether to wait for shutdown processing to complete. | |
| 847 | − * | |
| 848 | − * This function will notify the AFU that the adapter is being shutdown | |
| 849 | − * and will wait for shutdown processing to complete if wait is true. | |
| 850 | − * This notification should flush pending I/Os to the device and halt | |
| 851 | − * further I/Os until the next AFU reset is issued and device restarted. | |
| 852 | − */ | |
| 853 | −static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) | |
| 854 | −{ | |
| 855 | − struct afu *afu = cfg->afu; | |
| 856 | − struct device *dev = &cfg->dev->dev; | |
| 857 | − struct dev_dependent_vals *ddv; | |
| 858 | − __be64 __iomem *fc_port_regs; | |
| 859 | − u64 reg, status; | |
| 860 | − int i, retry_cnt = 0; | |
| 861 | − | |
| 862 | − ddv = (struct dev_dependent_vals *)cfg->dev_id->driver_data; | |
| 863 | − if (!(ddv->flags & CXLFLASH_NOTIFY_SHUTDOWN)) | |
| 864 | − return; | |
| 865 | − | |
| 866 | − if (!afu || !afu->afu_map) { | |
| 867 | − dev_dbg(dev, "%s: Problem state area not mapped\n", __func__); | |
| 868 | − return; | |
| 869 | − } | |
| 870 | − | |
| 871 | − /* Notify AFU */ | |
| 872 | − for (i = 0; i < cfg->num_fc_ports; i++) { | |
| 873 | − fc_port_regs = get_fc_port_regs(cfg, i); | |
| 874 | − | |
| 875 | − reg = readq_be(&fc_port_regs[FC_CONFIG2 / 8]); | |
| 876 | − reg |= SISL_FC_SHUTDOWN_NORMAL; | |
| 877 | − writeq_be(reg, &fc_port_regs[FC_CONFIG2 / 8]); | |
| 878 | − } | |
| 879 | − | |
| 880 | − if (!wait) | |
| 881 | − return; | |
| 882 | − | |
| 883 | − /* Wait up to 1.5 seconds for shutdown processing to complete */ | |
| 884 | − for (i = 0; i < cfg->num_fc_ports; i++) { | |
| 885 | − fc_port_regs = get_fc_port_regs(cfg, i); | |
| 886 | − retry_cnt = 0; | |
| 887 | − | |
| 888 | − while (true) { | |
| 889 | − status = readq_be(&fc_port_regs[FC_STATUS / 8]); | |
| 890 | − if (status & SISL_STATUS_SHUTDOWN_COMPLETE) | |
| 891 | − break; | |
| 892 | − if (++retry_cnt >= MC_RETRY_CNT) { | |
| 893 | − dev_dbg(dev, "%s: port %d shutdown processing " | |
| 894 | − "not yet completed\n", __func__, i); | |
| 895 | − break; | |
| 896 | − } | |
| 897 | − msleep(100 * retry_cnt); | |
| 898 | − } | |
| 899 | − } | |
| 900 | −} | |
| 901 | − | |
| 902 | −/** | |
| 903 | − * cxlflash_get_minor() - gets the first available minor number | |
| 904 | − * | |
| 905 | − * Return: Unique minor number that can be used to create the character device. | |
| 906 | − */ | |
| 907 | −static int cxlflash_get_minor(void) | |
| 908 | −{ | |
| 909 | − int minor; | |
| 910 | − long bit; | |
| 911 | − | |
| 912 | − bit = find_first_zero_bit(cxlflash_minor, CXLFLASH_MAX_ADAPTERS); | |
| 913 | − if (bit >= CXLFLASH_MAX_ADAPTERS) | |
| 914 | − return -1; | |
| 915 | − | |
| 916 | − minor = bit & MINORMASK; | |
| 917 | − set_bit(minor, cxlflash_minor); | |
| 918 | − return minor; | |
| 919 | −} | |
| 920 | − | |
| 921 | −/** | |
| 922 | − * cxlflash_put_minor() - releases the minor number | |
| 923 | − * @minor: Minor number that is no longer needed. | |
| 924 | − */ | |
| 925 | −static void cxlflash_put_minor(int minor) | |
| 926 | −{ | |
| 927 | − clear_bit(minor, cxlflash_minor); | |
| 928 | −} | |
| 929 | − | |
| 930 | −/** | |
| 931 | − * cxlflash_release_chrdev() - release the character device for the host | |
| 932 | − * @cfg: Internal structure associated with the host. | |
| 933 | − */ | |
| 934 | −static void cxlflash_release_chrdev(struct cxlflash_cfg *cfg) | |
| 935 | −{ | |
| 936 | − device_unregister(cfg->chardev); | |
| 937 | − cfg->chardev = NULL; | |
| 938 | − cdev_del(&cfg->cdev); | |
| 939 | − cxlflash_put_minor(MINOR(cfg->cdev.dev)); | |
| 940 | −} | |
| 941 | − | |
| 942 | −/** | |
| 943 | − * cxlflash_remove() - PCI entry point to tear down host | |
| 944 | − * @pdev: PCI device associated with the host. | |
| 945 | − * | |
| 946 | − * Safe to use as a cleanup in partially allocated/initialized state. Note that | |
| 947 | − * the reset_waitq is flushed as part of the stop/termination of user contexts. | |
| 948 | − */ | |
| 949 | −static void cxlflash_remove(struct pci_dev *pdev) | |
| 950 | −{ | |
| 951 | − struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); | |
| 952 | − struct device *dev = &pdev->dev; | |
| 953 | − ulong lock_flags; | |
| 954 | − | |
| 955 | − if (!pci_is_enabled(pdev)) { | |
| 956 | − dev_dbg(dev, "%s: Device is disabled\n", __func__); | |
| 957 | − return; | |
| 958 | − } | |
| 959 | − | |
| 960 | − /* Yield to running recovery threads before continuing with remove */ | |
| 961 | − wait_event(cfg->reset_waitq, cfg->state != STATE_RESET && | |
| 962 | − cfg->state != STATE_PROBING); | |
| 963 | − spin_lock_irqsave(&cfg->tmf_slock, lock_flags); | |
| 964 | − if (cfg->tmf_active) | |
| 965 | − wait_event_interruptible_lock_irq(cfg->tmf_waitq, | |
| 966 | − !cfg->tmf_active, | |
| 967 | − cfg->tmf_slock); | |
| 968 | − spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); | |
| 969 | − | |
| 970 | − /* Notify AFU and wait for shutdown processing to complete */ | |
| 971 | − notify_shutdown(cfg, true); | |
| 972 | − | |
| 973 | − cfg->state = STATE_FAILTERM; | |
| 974 | − cxlflash_stop_term_user_contexts(cfg); | |
| 975 | − | |
| 976 | − switch (cfg->init_state) { | |
| 977 | − case INIT_STATE_CDEV: | |
| 978 | − cxlflash_release_chrdev(cfg); | |
| 979 | − fallthrough; | |
| 980 | − case INIT_STATE_SCSI: | |
| 981 | − cxlflash_term_local_luns(cfg); | |
| 982 | − scsi_remove_host(cfg->host); | |
| 983 | − fallthrough; | |
| 984 | − case INIT_STATE_AFU: | |
| 985 | − term_afu(cfg); | |
| 986 | − fallthrough; | |
| 987 | − case INIT_STATE_PCI: | |
| 988 | − cfg->ops->destroy_afu(cfg->afu_cookie); | |
| 989 | − pci_disable_device(pdev); | |
| 990 | − fallthrough; | |
| 991 | − case INIT_STATE_NONE: | |
| 992 | − free_mem(cfg); | |
| 993 | − scsi_host_put(cfg->host); | |
| 994 | − break; | |
| 995 | − } | |
| 996 | − | |
| 997 | − dev_dbg(dev, "%s: returning\n", __func__); | |
| 998 | −} | |
| 999 | − | |
| 1000 | −/** | |
| 1001 | − * alloc_mem() - allocates the AFU and its command pool | |
| 1002 | − * @cfg: Internal structure associated with the host. | |
| 1003 | − * | |
| 1004 | − * A partially allocated state remains on failure. | |
| 1005 | − * | |
| 1006 | − * Return: | |
| 1007 | − * 0 on success | |
| 1008 | − * -ENOMEM on failure to allocate memory | |
| 1009 | − */ | |
| 1010 | −static int alloc_mem(struct cxlflash_cfg *cfg) | |
| 1011 | −{ | |
| 1012 | − int rc = 0; | |
| 1013 | − struct device *dev = &cfg->dev->dev; | |
| 1014 | − | |
| 1015 | − /* AFU is ~28k, i.e. only one 64k page or up to seven 4k pages */ | |
| 1016 | − cfg->afu = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, | |
| 1017 | − get_order(sizeof(struct afu))); | |
| 1018 | − if (unlikely(!cfg->afu)) { | |
| 1019 | − dev_err(dev, "%s: cannot get %d free pages\n", | |
| 1020 | − __func__, get_order(sizeof(struct afu))); | |
| 1021 | − rc = -ENOMEM; | |
| 1022 | − goto out; | |
| 1023 | − } | |
| 1024 | − cfg->afu->parent = cfg; | |
| 1025 | − cfg->afu->desired_hwqs = CXLFLASH_DEF_HWQS; | |
| 1026 | − cfg->afu->afu_map = NULL; | |
| 1027 | −out: | |
| 1028 | − return rc; | |
| 1029 | −} | |
| 1030 | − | |
| 1031 | −/** | |
| 1032 | − * init_pci() - initializes the host as a PCI device | |
| 1033 | − * @cfg: Internal structure associated with the host. | |
| 1034 | − * | |
| 1035 | − * Return: 0 on success, -errno on failure | |
| 1036 | − */ | |
| 1037 | −static int init_pci(struct cxlflash_cfg *cfg) | |
| 1038 | −{ | |
| 1039 | − struct pci_dev *pdev = cfg->dev; | |
| 1040 | − struct device *dev = &cfg->dev->dev; | |
| 1041 | − int rc = 0; | |
| 1042 | − | |
| 1043 | − rc = pci_enable_device(pdev); | |
| 1044 | − if (rc || pci_channel_offline(pdev)) { | |
| 1045 | − if (pci_channel_offline(pdev)) { | |
| 1046 | − cxlflash_wait_for_pci_err_recovery(cfg); | |
| 1047 | − rc = pci_enable_device(pdev); | |
| 1048 | − } | |
| 1049 | − | |
| 1050 | − if (rc) { | |
| 1051 | − dev_err(dev, "%s: Cannot enable adapter\n", __func__); | |
| 1052 | − cxlflash_wait_for_pci_err_recovery(cfg); | |
| 1053 | − goto out; | |
| 1054 | − } | |
| 1055 | − } | |
| 1056 | − | |
| 1057 | −out: | |
| 1058 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 1059 | − return rc; | |
| 1060 | −} | |
| 1061 | − | |
| 1062 | −/** | |
| 1063 | − * init_scsi() - adds the host to the SCSI stack and kicks off host scan | |
| 1064 | − * @cfg: Internal structure associated with the host. | |
| 1065 | − * | |
| 1066 | − * Return: 0 on success, -errno on failure | |
| 1067 | − */ | |
| 1068 | −static int init_scsi(struct cxlflash_cfg *cfg) | |
| 1069 | −{ | |
| 1070 | − struct pci_dev *pdev = cfg->dev; | |
| 1071 | − struct device *dev = &cfg->dev->dev; | |
| 1072 | − int rc = 0; | |
| 1073 | − | |
| 1074 | − rc = scsi_add_host(cfg->host, &pdev->dev); | |
| 1075 | − if (rc) { | |
| 1076 | − dev_err(dev, "%s: scsi_add_host failed rc=%d\n", __func__, rc); | |
| 1077 | − goto out; | |
| 1078 | − } | |
| 1079 | − | |
| 1080 | − scsi_scan_host(cfg->host); | |
| 1081 | − | |
| 1082 | −out: | |
| 1083 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 1084 | − return rc; | |
| 1085 | −} | |
| 1086 | − | |
| 1087 | −/** | |
| 1088 | − * set_port_online() - transitions the specified host FC port to online state | |
| 1089 | − * @fc_regs: Top of MMIO region defined for specified port. | |
| 1090 | − * | |
| 1091 | − * The provided MMIO region must be mapped prior to call. Online state means | |
| 1092 | − * that the FC link layer has synced, completed the handshaking process, and | |
| 1093 | − * is ready for login to start. | |
| 1094 | − */ | |
| 1095 | −static void set_port_online(__be64 __iomem *fc_regs) | |
| 1096 | −{ | |
| 1097 | − u64 cmdcfg; | |
| 1098 | − | |
| 1099 | − cmdcfg = readq_be(&fc_regs[FC_MTIP_CMDCONFIG / 8]); | |
| 1100 | − cmdcfg &= (~FC_MTIP_CMDCONFIG_OFFLINE); /* clear OFF_LINE */ | |
| 1101 | − cmdcfg |= (FC_MTIP_CMDCONFIG_ONLINE); /* set ON_LINE */ | |
| 1102 | − writeq_be(cmdcfg, &fc_regs[FC_MTIP_CMDCONFIG / 8]); | |
| 1103 | −} | |
| 1104 | − | |
| 1105 | −/** | |
| 1106 | − * set_port_offline() - transitions the specified host FC port to offline state | |
| 1107 | − * @fc_regs: Top of MMIO region defined for specified port. | |
| 1108 | − * | |
| 1109 | − * The provided MMIO region must be mapped prior to call. | |
| 1110 | − */ | |
| 1111 | −static void set_port_offline(__be64 __iomem *fc_regs) | |
| 1112 | −{ | |
| 1113 | − u64 cmdcfg; | |
| 1114 | − | |
| 1115 | − cmdcfg = readq_be(&fc_regs[FC_MTIP_CMDCONFIG / 8]); | |
| 1116 | − cmdcfg &= (~FC_MTIP_CMDCONFIG_ONLINE); /* clear ON_LINE */ | |
| 1117 | − cmdcfg |= (FC_MTIP_CMDCONFIG_OFFLINE); /* set OFF_LINE */ | |
| 1118 | − writeq_be(cmdcfg, &fc_regs[FC_MTIP_CMDCONFIG / 8]); | |
| 1119 | −} | |
| 1120 | − | |
| 1121 | −/** | |
| 1122 | − * wait_port_online() - waits for the specified host FC port come online | |
| 1123 | − * @fc_regs: Top of MMIO region defined for specified port. | |
| 1124 | − * @delay_us: Number of microseconds to delay between reading port status. | |
| 1125 | − * @nretry: Number of cycles to retry reading port status. | |
| 1126 | − * | |
| 1127 | − * The provided MMIO region must be mapped prior to call. This will timeout | |
| 1128 | − * when the cable is not plugged in. | |
| 1129 | − * | |
| 1130 | − * Return: | |
| 1131 | − * TRUE (1) when the specified port is online | |
| 1132 | − * FALSE (0) when the specified port fails to come online after timeout | |
| 1133 | − */ | |
| 1134 | −static bool wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) | |
| 1135 | −{ | |
| 1136 | − u64 status; | |
| 1137 | − | |
| 1138 | − WARN_ON(delay_us < 1000); | |
| 1139 | − | |
| 1140 | − do { | |
| 1141 | − msleep(delay_us / 1000); | |
| 1142 | − status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); | |
| 1143 | − if (status == U64_MAX) | |
| 1144 | − nretry /= 2; | |
| 1145 | − } while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_ONLINE && | |
| 1146 | − nretry--); | |
| 1147 | − | |
| 1148 | − return ((status & FC_MTIP_STATUS_MASK) == FC_MTIP_STATUS_ONLINE); | |
| 1149 | −} | |
| 1150 | − | |
| 1151 | −/** | |
| 1152 | − * wait_port_offline() - waits for the specified host FC port go offline | |
| 1153 | − * @fc_regs: Top of MMIO region defined for specified port. | |
| 1154 | − * @delay_us: Number of microseconds to delay between reading port status. | |
| 1155 | − * @nretry: Number of cycles to retry reading port status. | |
| 1156 | − * | |
| 1157 | − * The provided MMIO region must be mapped prior to call. | |
| 1158 | − * | |
| 1159 | − * Return: | |
| 1160 | − * TRUE (1) when the specified port is offline | |
| 1161 | − * FALSE (0) when the specified port fails to go offline after timeout | |
| 1162 | − */ | |
| 1163 | −static bool wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) | |
| 1164 | −{ | |
| 1165 | − u64 status; | |
| 1166 | − | |
| 1167 | − WARN_ON(delay_us < 1000); | |
| 1168 | − | |
| 1169 | − do { | |
| 1170 | − msleep(delay_us / 1000); | |
| 1171 | − status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); | |
| 1172 | − if (status == U64_MAX) | |
| 1173 | − nretry /= 2; | |
| 1174 | − } while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_OFFLINE && | |
| 1175 | − nretry--); | |
| 1176 | − | |
| 1177 | − return ((status & FC_MTIP_STATUS_MASK) == FC_MTIP_STATUS_OFFLINE); | |
| 1178 | −} | |
| 1179 | − | |
| 1180 | −/** | |
| 1181 | − * afu_set_wwpn() - configures the WWPN for the specified host FC port | |
| 1182 | − * @afu: AFU associated with the host that owns the specified FC port. | |
| 1183 | − * @port: Port number being configured. | |
| 1184 | − * @fc_regs: Top of MMIO region defined for specified port. | |
| 1185 | − * @wwpn: The world-wide-port-number previously discovered for port. | |
| 1186 | − * | |
| 1187 | − * The provided MMIO region must be mapped prior to call. As part of the | |
| 1188 | − * sequence to configure the WWPN, the port is toggled offline and then back | |
| 1189 | − * online. This toggling action can cause this routine to delay up to a few | |
| 1190 | − * seconds. When configured to use the internal LUN feature of the AFU, a | |
| 1191 | − * failure to come online is overridden. | |
| 1192 | − */ | |
| 1193 | −static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs, | |
| 1194 | − u64 wwpn) | |
| 1195 | −{ | |
| 1196 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 1197 | − struct device *dev = &cfg->dev->dev; | |
| 1198 | − | |
| 1199 | − set_port_offline(fc_regs); | |
| 1200 | − if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, | |
| 1201 | − FC_PORT_STATUS_RETRY_CNT)) { | |
| 1202 | − dev_dbg(dev, "%s: wait on port %d to go offline timed out\n", | |
| 1203 | − __func__, port); | |
| 1204 | − } | |
| 1205 | − | |
| 1206 | − writeq_be(wwpn, &fc_regs[FC_PNAME / 8]); | |
| 1207 | − | |
| 1208 | − set_port_online(fc_regs); | |
| 1209 | − if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, | |
| 1210 | − FC_PORT_STATUS_RETRY_CNT)) { | |
| 1211 | − dev_dbg(dev, "%s: wait on port %d to go online timed out\n", | |
| 1212 | − __func__, port); | |
| 1213 | − } | |
| 1214 | −} | |
| 1215 | − | |
| 1216 | −/** | |
| 1217 | − * afu_link_reset() - resets the specified host FC port | |
| 1218 | − * @afu: AFU associated with the host that owns the specified FC port. | |
| 1219 | − * @port: Port number being configured. | |
| 1220 | − * @fc_regs: Top of MMIO region defined for specified port. | |
| 1221 | − * | |
| 1222 | − * The provided MMIO region must be mapped prior to call. The sequence to | |
| 1223 | − * reset the port involves toggling it offline and then back online. This | |
| 1224 | − * action can cause this routine to delay up to a few seconds. An effort | |
| 1225 | − * is made to maintain link with the device by switching to host to use | |
| 1226 | − * the alternate port exclusively while the reset takes place. | |
| 1227 | − * failure to come online is overridden. | |
| 1228 | − */ | |
| 1229 | −static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) | |
| 1230 | −{ | |
| 1231 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 1232 | − struct device *dev = &cfg->dev->dev; | |
| 1233 | − u64 port_sel; | |
| 1234 | − | |
| 1235 | − /* first switch the AFU to the other links, if any */ | |
| 1236 | − port_sel = readq_be(&afu->afu_map->global.regs.afu_port_sel); | |
| 1237 | − port_sel &= ~(1ULL << port); | |
| 1238 | − writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel); | |
| 1239 | − cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC); | |
| 1240 | − | |
| 1241 | − set_port_offline(fc_regs); | |
| 1242 | − if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, | |
| 1243 | − FC_PORT_STATUS_RETRY_CNT)) | |
| 1244 | − dev_err(dev, "%s: wait on port %d to go offline timed out\n", | |
| 1245 | − __func__, port); | |
| 1246 | − | |
| 1247 | − set_port_online(fc_regs); | |
| 1248 | − if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, | |
| 1249 | − FC_PORT_STATUS_RETRY_CNT)) | |
| 1250 | − dev_err(dev, "%s: wait on port %d to go online timed out\n", | |
| 1251 | − __func__, port); | |
| 1252 | − | |
| 1253 | − /* switch back to include this port */ | |
| 1254 | − port_sel |= (1ULL << port); | |
| 1255 | − writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel); | |
| 1256 | − cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC); | |
| 1257 | − | |
| 1258 | − dev_dbg(dev, "%s: returning port_sel=%016llx\n", __func__, port_sel); | |
| 1259 | −} | |
| 1260 | − | |
| 1261 | −/** | |
| 1262 | − * afu_err_intr_init() - clears and initializes the AFU for error interrupts | |
| 1263 | − * @afu: AFU associated with the host. | |
| 1264 | − */ | |
| 1265 | −static void afu_err_intr_init(struct afu *afu) | |
| 1266 | −{ | |
| 1267 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 1268 | − __be64 __iomem *fc_port_regs; | |
| 1269 | − int i; | |
| 1270 | − struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); | |
| 1271 | − u64 reg; | |
| 1272 | − | |
| 1273 | − /* global async interrupts: AFU clears afu_ctrl on context exit | |
| 1274 | − * if async interrupts were sent to that context. This prevents | |
| 1275 | − * the AFU form sending further async interrupts when | |
| 1276 | − * there is | |
| 1277 | − * nobody to receive them. | |
| 1278 | − */ | |
| 1279 | − | |
| 1280 | − /* mask all */ | |
| 1281 | − writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_mask); | |
| 1282 | − /* set LISN# to send and point to primary master context */ | |
| 1283 | − reg = ((u64) (((hwq->ctx_hndl << 8) | SISL_MSI_ASYNC_ERROR)) << 40); | |
| 1284 | − | |
| 1285 | − if (afu->internal_lun) | |
| 1286 | − reg |= 1; /* Bit 63 indicates local lun */ | |
| 1287 | − writeq_be(reg, &afu->afu_map->global.regs.afu_ctrl); | |
| 1288 | − /* clear all */ | |
| 1289 | − writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_clear); | |
| 1290 | − /* unmask bits that are of interest */ | |
| 1291 | − /* note: afu can send an interrupt after this step */ | |
| 1292 | − writeq_be(SISL_ASTATUS_MASK, &afu->afu_map->global.regs.aintr_mask); | |
| 1293 | − /* clear again in case a bit came on after previous clear but before */ | |
| 1294 | − /* unmask */ | |
| 1295 | − writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_clear); | |
| 1296 | − | |
| 1297 | − /* Clear/Set internal lun bits */ | |
| 1298 | − fc_port_regs = get_fc_port_regs(cfg, 0); | |
| 1299 | − reg = readq_be(&fc_port_regs[FC_CONFIG2 / 8]); | |
| 1300 | − reg &= SISL_FC_INTERNAL_MASK; | |
| 1301 | − if (afu->internal_lun) | |
| 1302 | − reg |= ((u64)(afu->internal_lun - 1) << SISL_FC_INTERNAL_SHIFT); | |
| 1303 | − writeq_be(reg, &fc_port_regs[FC_CONFIG2 / 8]); | |
| 1304 | − | |
| 1305 | − /* now clear FC errors */ | |
| 1306 | − for (i = 0; i < cfg->num_fc_ports; i++) { | |
| 1307 | − fc_port_regs = get_fc_port_regs(cfg, i); | |
| 1308 | − | |
| 1309 | − writeq_be(0xFFFFFFFFU, &fc_port_regs[FC_ERROR / 8]); | |
| 1310 | − writeq_be(0, &fc_port_regs[FC_ERRCAP / 8]); | |
| 1311 | − } | |
| 1312 | − | |
| 1313 | − /* sync interrupts for master's IOARRIN write */ | |
| 1314 | − /* note that unlike asyncs, there can be no pending sync interrupts */ | |
| 1315 | − /* at this time (this is a fresh context and master has not written */ | |
| 1316 | − /* IOARRIN yet), so there is nothing to clear. */ | |
| 1317 | − | |
| 1318 | − /* set LISN#, it is always sent to the context that wrote IOARRIN */ | |
| 1319 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 1320 | − hwq = get_hwq(afu, i); | |
| 1321 | − | |
| 1322 | − reg = readq_be(&hwq->host_map->ctx_ctrl); | |
| 1323 | − WARN_ON((reg & SISL_CTX_CTRL_LISN_MASK) != 0); | |
| 1324 | − reg |= SISL_MSI_SYNC_ERROR; | |
| 1325 | − writeq_be(reg, &hwq->host_map->ctx_ctrl); | |
| 1326 | − writeq_be(SISL_ISTATUS_MASK, &hwq->host_map->intr_mask); | |
| 1327 | − } | |
| 1328 | −} | |
| 1329 | − | |
| 1330 | −/** | |
| 1331 | − * cxlflash_sync_err_irq() - interrupt handler for synchronous errors | |
| 1332 | − * @irq: Interrupt number. | |
| 1333 | − * @data: Private data provided at interrupt registration, the AFU. | |
| 1334 | − * | |
| 1335 | − * Return: Always return IRQ_HANDLED. | |
| 1336 | − */ | |
| 1337 | −static irqreturn_t cxlflash_sync_err_irq(int irq, void *data) | |
| 1338 | −{ | |
| 1339 | − struct hwq *hwq = (struct hwq *)data; | |
| 1340 | − struct cxlflash_cfg *cfg = hwq->afu->parent; | |
| 1341 | − struct device *dev = &cfg->dev->dev; | |
| 1342 | − u64 reg; | |
| 1343 | − u64 reg_unmasked; | |
| 1344 | − | |
| 1345 | − reg = readq_be(&hwq->host_map->intr_status); | |
| 1346 | − reg_unmasked = (reg & SISL_ISTATUS_UNMASK); | |
| 1347 | − | |
| 1348 | − if (reg_unmasked == 0UL) { | |
| 1349 | − dev_err(dev, "%s: spurious interrupt, intr_status=%016llx\n", | |
| 1350 | − __func__, reg); | |
| 1351 | − goto cxlflash_sync_err_irq_exit; | |
| 1352 | − } | |
| 1353 | − | |
| 1354 | − dev_err(dev, "%s: unexpected interrupt, intr_status=%016llx\n", | |
| 1355 | − __func__, reg); | |
| 1356 | − | |
| 1357 | − writeq_be(reg_unmasked, &hwq->host_map->intr_clear); | |
| 1358 | − | |
| 1359 | −cxlflash_sync_err_irq_exit: | |
| 1360 | − return IRQ_HANDLED; | |
| 1361 | −} | |
| 1362 | − | |
| 1363 | −/** | |
| 1364 | − * process_hrrq() - process the read-response queue | |
| 1365 | − * @hwq: HWQ associated with the host. | |
| 1366 | − * @doneq: Queue of commands harvested from the RRQ. | |
| 1367 | − * @budget: Threshold of RRQ entries to process. | |
| 1368 | − * | |
| 1369 | − * This routine must be called holding the disabled RRQ spin lock. | |
| 1370 | − * | |
| 1371 | − * Return: The number of entries processed. | |
| 1372 | − */ | |
| 1373 | −static int process_hrrq(struct hwq *hwq, struct list_head *doneq, int budget) | |
| 1374 | −{ | |
| 1375 | − struct afu *afu = hwq->afu; | |
| 1376 | − struct afu_cmd *cmd; | |
| 1377 | − struct sisl_ioasa *ioasa; | |
| 1378 | − struct sisl_ioarcb *ioarcb; | |
| 1379 | − bool toggle = hwq->toggle; | |
| 1380 | − int num_hrrq = 0; | |
| 1381 | − u64 entry, | |
| 1382 | − *hrrq_start = hwq->hrrq_start, | |
| 1383 | − *hrrq_end = hwq->hrrq_end, | |
| 1384 | − *hrrq_curr = hwq->hrrq_curr; | |
| 1385 | − | |
| 1386 | − /* Process ready RRQ entries up to the specified budget (if any) */ | |
| 1387 | − while (true) { | |
| 1388 | − entry = *hrrq_curr; | |
| 1389 | − | |
| 1390 | − if ((entry & SISL_RESP_HANDLE_T_BIT) != toggle) | |
| 1391 | − break; | |
| 1392 | − | |
| 1393 | − entry &= ~SISL_RESP_HANDLE_T_BIT; | |
| 1394 | − | |
| 1395 | − if (afu_is_sq_cmd_mode(afu)) { | |
| 1396 | − ioasa = (struct sisl_ioasa *)entry; | |
| 1397 | − cmd = container_of(ioasa, struct afu_cmd, sa); | |
| 1398 | − } else { | |
| 1399 | − ioarcb = (struct sisl_ioarcb *)entry; | |
| 1400 | − cmd = container_of(ioarcb, struct afu_cmd, rcb); | |
| 1401 | − } | |
| 1402 | − | |
| 1403 | − list_add_tail(&cmd->queue, doneq); | |
| 1404 | − | |
| 1405 | − /* Advance to next entry or wrap and flip the toggle bit */ | |
| 1406 | − if (hrrq_curr < hrrq_end) | |
| 1407 | − hrrq_curr++; | |
| 1408 | − else { | |
| 1409 | − hrrq_curr = hrrq_start; | |
| 1410 | − toggle ^= SISL_RESP_HANDLE_T_BIT; | |
| 1411 | − } | |
| 1412 | − | |
| 1413 | − atomic_inc(&hwq->hsq_credits); | |
| 1414 | − num_hrrq++; | |
| 1415 | − | |
| 1416 | − if (budget > 0 && num_hrrq >= budget) | |
| 1417 | − break; | |
| 1418 | − } | |
| 1419 | − | |
| 1420 | − hwq->hrrq_curr = hrrq_curr; | |
| 1421 | − hwq->toggle = toggle; | |
| 1422 | − | |
| 1423 | − return num_hrrq; | |
| 1424 | −} | |
| 1425 | − | |
| 1426 | −/** | |
| 1427 | − * process_cmd_doneq() - process a queue of harvested RRQ commands | |
| 1428 | − * @doneq: Queue of completed commands. | |
| 1429 | − * | |
| 1430 | − * Note that upon return the queue can no longer be trusted. | |
| 1431 | − */ | |
| 1432 | −static void process_cmd_doneq(struct list_head *doneq) | |
| 1433 | −{ | |
| 1434 | − struct afu_cmd *cmd, *tmp; | |
| 1435 | − | |
| 1436 | − WARN_ON(list_empty(doneq)); | |
| 1437 | − | |
| 1438 | − list_for_each_entry_safe(cmd, tmp, doneq, queue) | |
| 1439 | − cmd_complete(cmd); | |
| 1440 | −} | |
| 1441 | − | |
| 1442 | −/** | |
| 1443 | − * cxlflash_irqpoll() - process a queue of harvested RRQ commands | |
| 1444 | − * @irqpoll: IRQ poll structure associated with queue to poll. | |
| 1445 | − * @budget: Threshold of RRQ entries to process per poll. | |
| 1446 | − * | |
| 1447 | − * Return: The number of entries processed. | |
| 1448 | − */ | |
| 1449 | −static int cxlflash_irqpoll(struct irq_poll *irqpoll, int budget) | |
| 1450 | −{ | |
| 1451 | − struct hwq *hwq = container_of(irqpoll, struct hwq, irqpoll); | |
| 1452 | − unsigned long hrrq_flags; | |
| 1453 | − LIST_HEAD(doneq); | |
| 1454 | − int num_entries = 0; | |
| 1455 | − | |
| 1456 | − spin_lock_irqsave(&hwq->hrrq_slock, hrrq_flags); | |
| 1457 | − | |
| 1458 | − num_entries = process_hrrq(hwq, &doneq, budget); | |
| 1459 | − if (num_entries < budget) | |
| 1460 | − irq_poll_complete(irqpoll); | |
| 1461 | − | |
| 1462 | − spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); | |
| 1463 | − | |
| 1464 | − process_cmd_doneq(&doneq); | |
| 1465 | − return num_entries; | |
| 1466 | −} | |
| 1467 | − | |
| 1468 | −/** | |
| 1469 | − * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path) | |
| 1470 | − * @irq: Interrupt number. | |
| 1471 | − * @data: Private data provided at interrupt registration, the AFU. | |
| 1472 | − * | |
| 1473 | − * Return: IRQ_HANDLED or IRQ_NONE when no ready entries found. | |
| 1474 | − */ | |
| 1475 | −static irqreturn_t cxlflash_rrq_irq(int irq, void *data) | |
| 1476 | −{ | |
| 1477 | − struct hwq *hwq = (struct hwq *)data; | |
| 1478 | − struct afu *afu = hwq->afu; | |
| 1479 | − unsigned long hrrq_flags; | |
| 1480 | − LIST_HEAD(doneq); | |
| 1481 | − int num_entries = 0; | |
| 1482 | − | |
| 1483 | − spin_lock_irqsave(&hwq->hrrq_slock, hrrq_flags); | |
| 1484 | − | |
| 1485 | − /* Silently drop spurious interrupts when queue is not online */ | |
| 1486 | − if (!hwq->hrrq_online) { | |
| 1487 | − spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); | |
| 1488 | − return IRQ_HANDLED; | |
| 1489 | − } | |
| 1490 | − | |
| 1491 | − if (afu_is_irqpoll_enabled(afu)) { | |
| 1492 | − irq_poll_sched(&hwq->irqpoll); | |
| 1493 | − spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); | |
| 1494 | − return IRQ_HANDLED; | |
| 1495 | − } | |
| 1496 | − | |
| 1497 | − num_entries = process_hrrq(hwq, &doneq, -1); | |
| 1498 | − spin_unlock_irqrestore(&hwq->hrrq_slock, hrrq_flags); | |
| 1499 | − | |
| 1500 | − if (num_entries == 0) | |
| 1501 | − return IRQ_NONE; | |
| 1502 | − | |
| 1503 | − process_cmd_doneq(&doneq); | |
| 1504 | − return IRQ_HANDLED; | |
| 1505 | −} | |
| 1506 | − | |
| 1507 | −/* | |
| 1508 | − * Asynchronous interrupt information table | |
| 1509 | − * | |
| 1510 | − * NOTE: | |
| 1511 | − * - Order matters here as this array is indexed by bit position. | |
| 1512 | − * | |
| 1513 | − * - The checkpatch script considers the BUILD_SISL_ASTATUS_FC_PORT macro | |
| 1514 | − * as complex and complains due to a lack of parentheses/braces. | |
| 1515 | − */ | |
| 1516 | −#define ASTATUS_FC(_a, _b, _c, _d) \ | |
| 1517 | − { SISL_ASTATUS_FC##_a##_##_b, _c, _a, (_d) } | |
| 1518 | − | |
| 1519 | −#define BUILD_SISL_ASTATUS_FC_PORT(_a) \ | |
| 1520 | − ASTATUS_FC(_a, LINK_UP, "link up", 0), \ | |
| 1521 | − ASTATUS_FC(_a, LINK_DN, "link down", 0), \ | |
| 1522 | − ASTATUS_FC(_a, LOGI_S, "login succeeded", SCAN_HOST), \ | |
| 1523 | − ASTATUS_FC(_a, LOGI_F, "login failed", CLR_FC_ERROR), \ | |
| 1524 | − ASTATUS_FC(_a, LOGI_R, "login timed out, retrying", LINK_RESET), \ | |
| 1525 | − ASTATUS_FC(_a, CRC_T, "CRC threshold exceeded", LINK_RESET), \ | |
| 1526 | − ASTATUS_FC(_a, LOGO, "target initiated LOGO", 0), \ | |
| 1527 | − ASTATUS_FC(_a, OTHER, "other error", CLR_FC_ERROR | LINK_RESET) | |
| 1528 | − | |
| 1529 | −static const struct asyc_intr_info ainfo[] = { | |
| 1530 | − BUILD_SISL_ASTATUS_FC_PORT(1), | |
| 1531 | − BUILD_SISL_ASTATUS_FC_PORT(0), | |
| 1532 | − BUILD_SISL_ASTATUS_FC_PORT(3), | |
| 1533 | − BUILD_SISL_ASTATUS_FC_PORT(2) | |
| 1534 | −}; | |
| 1535 | − | |
| 1536 | −/** | |
| 1537 | − * cxlflash_async_err_irq() - interrupt handler for asynchronous errors | |
| 1538 | − * @irq: Interrupt number. | |
| 1539 | − * @data: Private data provided at interrupt registration, the AFU. | |
| 1540 | − * | |
| 1541 | − * Return: Always return IRQ_HANDLED. | |
| 1542 | − */ | |
| 1543 | −static irqreturn_t cxlflash_async_err_irq(int irq, void *data) | |
| 1544 | −{ | |
| 1545 | − struct hwq *hwq = (struct hwq *)data; | |
| 1546 | − struct afu *afu = hwq->afu; | |
| 1547 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 1548 | − struct device *dev = &cfg->dev->dev; | |
| 1549 | − const struct asyc_intr_info *info; | |
| 1550 | − struct sisl_global_map __iomem *global = &afu->afu_map->global; | |
| 1551 | − __be64 __iomem *fc_port_regs; | |
| 1552 | − u64 reg_unmasked; | |
| 1553 | − u64 reg; | |
| 1554 | − u64 bit; | |
| 1555 | − u8 port; | |
| 1556 | − | |
| 1557 | − reg = readq_be(&global->regs.aintr_status); | |
| 1558 | − reg_unmasked = (reg & SISL_ASTATUS_UNMASK); | |
| 1559 | − | |
| 1560 | − if (unlikely(reg_unmasked == 0)) { | |
| 1561 | − dev_err(dev, "%s: spurious interrupt, aintr_status=%016llx\n", | |
| 1562 | − __func__, reg); | |
| 1563 | − goto out; | |
| 1564 | − } | |
| 1565 | − | |
| 1566 | − /* FYI, it is 'okay' to clear AFU status before FC_ERROR */ | |
| 1567 | − writeq_be(reg_unmasked, &global->regs.aintr_clear); | |
| 1568 | − | |
| 1569 | − /* Check each bit that is on */ | |
| 1570 | − for_each_set_bit(bit, (ulong *)®_unmasked, BITS_PER_LONG) { | |
| 1571 | − if (unlikely(bit >= ARRAY_SIZE(ainfo))) { | |
| 1572 | − WARN_ON_ONCE(1); | |
| 1573 | − continue; | |
| 1574 | − } | |
| 1575 | − | |
| 1576 | − info = &ainfo[bit]; | |
| 1577 | − if (unlikely(info->status != 1ULL << bit)) { | |
| 1578 | − WARN_ON_ONCE(1); | |
| 1579 | − continue; | |
| 1580 | − } | |
| 1581 | − | |
| 1582 | − port = info->port; | |
| 1583 | − fc_port_regs = get_fc_port_regs(cfg, port); | |
| 1584 | − | |
| 1585 | − dev_err(dev, "%s: FC Port %d -> %s, fc_status=%016llx\n", | |
| 1586 | − __func__, port, info->desc, | |
| 1587 | − readq_be(&fc_port_regs[FC_STATUS / 8])); | |
| 1588 | − | |
| 1589 | − /* | |
| 1590 | − * Do link reset first, some OTHER errors will set FC_ERROR | |
| 1591 | − * again if cleared before or w/o a reset | |
| 1592 | − */ | |
| 1593 | − if (info->action & LINK_RESET) { | |
| 1594 | − dev_err(dev, "%s: FC Port %d: resetting link\n", | |
| 1595 | − __func__, port); | |
| 1596 | − cfg->lr_state = LINK_RESET_REQUIRED; | |
| 1597 | − cfg->lr_port = port; | |
| 1598 | − schedule_work(&cfg->work_q); | |
| 1599 | − } | |
| 1600 | − | |
| 1601 | − if (info->action & CLR_FC_ERROR) { | |
| 1602 | − reg = readq_be(&fc_port_regs[FC_ERROR / 8]); | |
| 1603 | − | |
| 1604 | − /* | |
| 1605 | − * Since all errors are unmasked, FC_ERROR and FC_ERRCAP | |
| 1606 | − * should be the same and tracing one is sufficient. | |
| 1607 | − */ | |
| 1608 | − | |
| 1609 | − dev_err(dev, "%s: fc %d: clearing fc_error=%016llx\n", | |
| 1610 | − __func__, port, reg); | |
| 1611 | − | |
| 1612 | − writeq_be(reg, &fc_port_regs[FC_ERROR / 8]); | |
| 1613 | − writeq_be(0, &fc_port_regs[FC_ERRCAP / 8]); | |
| 1614 | − } | |
| 1615 | − | |
| 1616 | − if (info->action & SCAN_HOST) { | |
| 1617 | − atomic_inc(&cfg->scan_host_needed); | |
| 1618 | − schedule_work(&cfg->work_q); | |
| 1619 | − } | |
| 1620 | − } | |
| 1621 | − | |
| 1622 | −out: | |
| 1623 | − return IRQ_HANDLED; | |
| 1624 | −} | |
| 1625 | − | |
| 1626 | −/** | |
| 1627 | − * read_vpd() - obtains the WWPNs from VPD | |
| 1628 | − * @cfg: Internal structure associated with the host. | |
| 1629 | − * @wwpn: Array of size MAX_FC_PORTS to pass back WWPNs | |
| 1630 | − * | |
| 1631 | − * Return: 0 on success, -errno on failure | |
| 1632 | − */ | |
| 1633 | −static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) | |
| 1634 | −{ | |
| 1635 | − struct device *dev = &cfg->dev->dev; | |
| 1636 | − struct pci_dev *pdev = cfg->dev; | |
| 1637 | − int i, k, rc = 0; | |
| 1638 | − unsigned int kw_size; | |
| 1639 | − ssize_t vpd_size; | |
| 1640 | − char vpd_data[CXLFLASH_VPD_LEN]; | |
| 1641 | − char tmp_buf[WWPN_BUF_LEN] = { 0 }; | |
| 1642 | − const struct dev_dependent_vals *ddv = (struct dev_dependent_vals *) | |
| 1643 | − cfg->dev_id->driver_data; | |
| 1644 | − const bool wwpn_vpd_required = ddv->flags & CXLFLASH_WWPN_VPD_REQUIRED; | |
| 1645 | − const char *wwpn_vpd_tags[MAX_FC_PORTS] = { "V5", "V6", "V7", "V8" }; | |
| 1646 | − | |
| 1647 | − /* Get the VPD data from the device */ | |
| 1648 | − vpd_size = cfg->ops->read_adapter_vpd(pdev, vpd_data, sizeof(vpd_data)); | |
| 1649 | − if (unlikely(vpd_size <= 0)) { | |
| 1650 | − dev_err(dev, "%s: Unable to read VPD (size = %ld)\n", | |
| 1651 | − __func__, vpd_size); | |
| 1652 | − rc = -ENODEV; | |
| 1653 | − goto out; | |
| 1654 | − } | |
| 1655 | − | |
| 1656 | − /* | |
| 1657 | − * Find the offset of the WWPN tag within the read only | |
| 1658 | − * VPD data and validate the found field (partials are | |
| 1659 | − * no good to us). Convert the ASCII data to an integer | |
| 1660 | − * value. Note that we must copy to a temporary buffer | |
| 1661 | − * because the conversion service requires that the ASCII | |
| 1662 | − * string be terminated. | |
| 1663 | − * | |
| 1664 | − * Allow for WWPN not being found for all devices, setting | |
| 1665 | − * the returned WWPN to zero when not found. Notify with a | |
| 1666 | − * log error for cards that should have had WWPN keywords | |
| 1667 | − * in the VPD - cards requiring WWPN will not have their | |
| 1668 | − * ports programmed and operate in an undefined state. | |
| 1669 | − */ | |
| 1670 | − for (k = 0; k < cfg->num_fc_ports; k++) { | |
| 1671 | − i = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, | |
| 1672 | − wwpn_vpd_tags[k], &kw_size); | |
| 1673 | − if (i == -ENOENT) { | |
| 1674 | − if (wwpn_vpd_required) | |
| 1675 | − dev_err(dev, "%s: Port %d WWPN not found\n", | |
| 1676 | − __func__, k); | |
| 1677 | − wwpn[k] = 0ULL; | |
| 1678 | − continue; | |
| 1679 | − } | |
| 1680 | − | |
| 1681 | − if (i < 0 || kw_size != WWPN_LEN) { | |
| 1682 | − dev_err(dev, "%s: Port %d WWPN incomplete or bad VPD\n", | |
| 1683 | − __func__, k); | |
| 1684 | − rc = -ENODEV; | |
| 1685 | − goto out; | |
| 1686 | − } | |
| 1687 | − | |
| 1688 | − memcpy(tmp_buf, &vpd_data[i], WWPN_LEN); | |
| 1689 | − rc = kstrtoul(tmp_buf, WWPN_LEN, (ulong *)&wwpn[k]); | |
| 1690 | − if (unlikely(rc)) { | |
| 1691 | − dev_err(dev, "%s: WWPN conversion failed for port %d\n", | |
| 1692 | − __func__, k); | |
| 1693 | − rc = -ENODEV; | |
| 1694 | − goto out; | |
| 1695 | − } | |
| 1696 | − | |
| 1697 | − dev_dbg(dev, "%s: wwpn%d=%016llx\n", __func__, k, wwpn[k]); | |
| 1698 | − } | |
| 1699 | − | |
| 1700 | −out: | |
| 1701 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 1702 | − return rc; | |
| 1703 | −} | |
| 1704 | − | |
| 1705 | −/** | |
| 1706 | − * init_pcr() - initialize the provisioning and control registers | |
| 1707 | − * @cfg: Internal structure associated with the host. | |
| 1708 | − * | |
| 1709 | − * Also sets up fast access to the mapped registers and initializes AFU | |
| 1710 | − * command fields that never change. | |
| 1711 | − */ | |
| 1712 | −static void init_pcr(struct cxlflash_cfg *cfg) | |
| 1713 | −{ | |
| 1714 | − struct afu *afu = cfg->afu; | |
| 1715 | − struct sisl_ctrl_map __iomem *ctrl_map; | |
| 1716 | − struct hwq *hwq; | |
| 1717 | − void *cookie; | |
| 1718 | − int i; | |
| 1719 | − | |
| 1720 | − for (i = 0; i < MAX_CONTEXT; i++) { | |
| 1721 | − ctrl_map = &afu->afu_map->ctrls[i].ctrl; | |
| 1722 | − /* Disrupt any clients that could be running */ | |
| 1723 | − /* e.g. clients that survived a master restart */ | |
| 1724 | − writeq_be(0, &ctrl_map->rht_start); | |
| 1725 | − writeq_be(0, &ctrl_map->rht_cnt_id); | |
| 1726 | − writeq_be(0, &ctrl_map->ctx_cap); | |
| 1727 | − } | |
| 1728 | − | |
| 1729 | − /* Copy frequently used fields into hwq */ | |
| 1730 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 1731 | − hwq = get_hwq(afu, i); | |
| 1732 | − cookie = hwq->ctx_cookie; | |
| 1733 | − | |
| 1734 | − hwq->ctx_hndl = (u16) cfg->ops->process_element(cookie); | |
| 1735 | − hwq->host_map = &afu->afu_map->hosts[hwq->ctx_hndl].host; | |
| 1736 | − hwq->ctrl_map = &afu->afu_map->ctrls[hwq->ctx_hndl].ctrl; | |
| 1737 | − | |
| 1738 | − /* Program the Endian Control for the master context */ | |
| 1739 | − writeq_be(SISL_ENDIAN_CTRL, &hwq->host_map->endian_ctrl); | |
| 1740 | − } | |
| 1741 | −} | |
| 1742 | − | |
| 1743 | −/** | |
| 1744 | − * init_global() - initialize AFU global registers | |
| 1745 | − * @cfg: Internal structure associated with the host. | |
| 1746 | − */ | |
| 1747 | −static int init_global(struct cxlflash_cfg *cfg) | |
| 1748 | −{ | |
| 1749 | − struct afu *afu = cfg->afu; | |
| 1750 | − struct device *dev = &cfg->dev->dev; | |
| 1751 | − struct hwq *hwq; | |
| 1752 | − struct sisl_host_map __iomem *hmap; | |
| 1753 | − __be64 __iomem *fc_port_regs; | |
| 1754 | − u64 wwpn[MAX_FC_PORTS]; /* wwpn of AFU ports */ | |
| 1755 | − int i = 0, num_ports = 0; | |
| 1756 | − int rc = 0; | |
| 1757 | − int j; | |
| 1758 | − void *ctx; | |
| 1759 | − u64 reg; | |
| 1760 | − | |
| 1761 | − rc = read_vpd(cfg, &wwpn[0]); | |
| 1762 | − if (rc) { | |
| 1763 | − dev_err(dev, "%s: could not read vpd rc=%d\n", __func__, rc); | |
| 1764 | − goto out; | |
| 1765 | − } | |
| 1766 | − | |
| 1767 | − /* Set up RRQ and SQ in HWQ for master issued cmds */ | |
| 1768 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 1769 | − hwq = get_hwq(afu, i); | |
| 1770 | − hmap = hwq->host_map; | |
| 1771 | − | |
| 1772 | − writeq_be((u64) hwq->hrrq_start, &hmap->rrq_start); | |
| 1773 | − writeq_be((u64) hwq->hrrq_end, &hmap->rrq_end); | |
| 1774 | − hwq->hrrq_online = true; | |
| 1775 | − | |
| 1776 | − if (afu_is_sq_cmd_mode(afu)) { | |
| 1777 | − writeq_be((u64)hwq->hsq_start, &hmap->sq_start); | |
| 1778 | − writeq_be((u64)hwq->hsq_end, &hmap->sq_end); | |
| 1779 | − } | |
| 1780 | − } | |
| 1781 | − | |
| 1782 | − /* AFU configuration */ | |
| 1783 | − reg = readq_be(&afu->afu_map->global.regs.afu_config); | |
| 1784 | − reg |= SISL_AFUCONF_AR_ALL|SISL_AFUCONF_ENDIAN; | |
| 1785 | − /* enable all auto retry options and control endianness */ | |
| 1786 | − /* leave others at default: */ | |
| 1787 | − /* CTX_CAP write protected, mbox_r does not clear on read and */ | |
| 1788 | − /* checker on if dual afu */ | |
| 1789 | − writeq_be(reg, &afu->afu_map->global.regs.afu_config); | |
| 1790 | − | |
| 1791 | − /* Global port select: select either port */ | |
| 1792 | − if (afu->internal_lun) { | |
| 1793 | − /* Only use port 0 */ | |
| 1794 | − writeq_be(PORT0, &afu->afu_map->global.regs.afu_port_sel); | |
| 1795 | − num_ports = 0; | |
| 1796 | − } else { | |
| 1797 | − writeq_be(PORT_MASK(cfg->num_fc_ports), | |
| 1798 | − &afu->afu_map->global.regs.afu_port_sel); | |
| 1799 | − num_ports = cfg->num_fc_ports; | |
| 1800 | − } | |
| 1801 | − | |
| 1802 | − for (i = 0; i < num_ports; i++) { | |
| 1803 | − fc_port_regs = get_fc_port_regs(cfg, i); | |
| 1804 | − | |
| 1805 | − /* Unmask all errors (but they are still masked at AFU) */ | |
| 1806 | − writeq_be(0, &fc_port_regs[FC_ERRMSK / 8]); | |
| 1807 | − /* Clear CRC error cnt & set a threshold */ | |
| 1808 | − (void)readq_be(&fc_port_regs[FC_CNT_CRCERR / 8]); | |
| 1809 | − writeq_be(MC_CRC_THRESH, &fc_port_regs[FC_CRC_THRESH / 8]); | |
| 1810 | − | |
| 1811 | − /* Set WWPNs. If already programmed, wwpn[i] is 0 */ | |
| 1812 | − if (wwpn[i] != 0) | |
| 1813 | − afu_set_wwpn(afu, i, &fc_port_regs[0], wwpn[i]); | |
| 1814 | − /* Programming WWPN back to back causes additional | |
| 1815 | − * offline/online transitions and a PLOGI | |
| 1816 | − */ | |
| 1817 | − msleep(100); | |
| 1818 | − } | |
| 1819 | − | |
| 1820 | − if (afu_is_ocxl_lisn(afu)) { | |
| 1821 | − /* Set up the LISN effective address for each master */ | |
| 1822 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 1823 | − hwq = get_hwq(afu, i); | |
| 1824 | − ctx = hwq->ctx_cookie; | |
| 1825 | − | |
| 1826 | − for (j = 0; j < hwq->num_irqs; j++) { | |
| 1827 | − reg = cfg->ops->get_irq_objhndl(ctx, j); | |
| 1828 | − writeq_be(reg, &hwq->ctrl_map->lisn_ea[j]); | |
| 1829 | − } | |
| 1830 | − | |
| 1831 | − reg = hwq->ctx_hndl; | |
| 1832 | − writeq_be(SISL_LISN_PASID(reg, reg), | |
| 1833 | − &hwq->ctrl_map->lisn_pasid[0]); | |
| 1834 | − writeq_be(SISL_LISN_PASID(0UL, reg), | |
| 1835 | − &hwq->ctrl_map->lisn_pasid[1]); | |
| 1836 | − } | |
| 1837 | − } | |
| 1838 | − | |
| 1839 | − /* Set up master's own CTX_CAP to allow real mode, host translation */ | |
| 1840 | − /* tables, afu cmds and read/write GSCSI cmds. */ | |
| 1841 | − /* First, unlock ctx_cap write by reading mbox */ | |
| 1842 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 1843 | − hwq = get_hwq(afu, i); | |
| 1844 | − | |
| 1845 | − (void)readq_be(&hwq->ctrl_map->mbox_r); /* unlock ctx_cap */ | |
| 1846 | − writeq_be((SISL_CTX_CAP_REAL_MODE | SISL_CTX_CAP_HOST_XLATE | | |
| 1847 | − SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD | | |
| 1848 | − SISL_CTX_CAP_AFU_CMD | SISL_CTX_CAP_GSCSI_CMD), | |
| 1849 | − &hwq->ctrl_map->ctx_cap); | |
| 1850 | − } | |
| 1851 | − | |
| 1852 | − /* | |
| 1853 | − * Determine write-same unmap support for host by evaluating the unmap | |
| 1854 | − * sector support bit of the context control register associated with | |
| 1855 | − * the primary hardware queue. Note that while this status is reflected | |
| 1856 | − * in a context register, the outcome can be assumed to be host-wide. | |
| 1857 | − */ | |
| 1858 | − hwq = get_hwq(afu, PRIMARY_HWQ); | |
| 1859 | − reg = readq_be(&hwq->host_map->ctx_ctrl); | |
| 1860 | − if (reg & SISL_CTX_CTRL_UNMAP_SECTOR) | |
| 1861 | − cfg->ws_unmap = true; | |
| 1862 | − | |
| 1863 | − /* Initialize heartbeat */ | |
| 1864 | − afu->hb = readq_be(&afu->afu_map->global.regs.afu_hb); | |
| 1865 | −out: | |
| 1866 | − return rc; | |
| 1867 | −} | |
| 1868 | − | |
| 1869 | −/** | |
| 1870 | − * start_afu() - initializes and starts the AFU | |
| 1871 | − * @cfg: Internal structure associated with the host. | |
| 1872 | − */ | |
| 1873 | −static int start_afu(struct cxlflash_cfg *cfg) | |
| 1874 | −{ | |
| 1875 | − struct afu *afu = cfg->afu; | |
| 1876 | − struct device *dev = &cfg->dev->dev; | |
| 1877 | − struct hwq *hwq; | |
| 1878 | − int rc = 0; | |
| 1879 | − int i; | |
| 1880 | − | |
| 1881 | − init_pcr(cfg); | |
| 1882 | − | |
| 1883 | − /* Initialize each HWQ */ | |
| 1884 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 1885 | − hwq = get_hwq(afu, i); | |
| 1886 | − | |
| 1887 | − /* After an AFU reset, RRQ entries are stale, clear them */ | |
| 1888 | − memset(&hwq->rrq_entry, 0, sizeof(hwq->rrq_entry)); | |
| 1889 | − | |
| 1890 | − /* Initialize RRQ pointers */ | |
| 1891 | − hwq->hrrq_start = &hwq->rrq_entry[0]; | |
| 1892 | − hwq->hrrq_end = &hwq->rrq_entry[NUM_RRQ_ENTRY - 1]; | |
| 1893 | − hwq->hrrq_curr = hwq->hrrq_start; | |
| 1894 | − hwq->toggle = 1; | |
| 1895 | − | |
| 1896 | − /* Initialize spin locks */ | |
| 1897 | − spin_lock_init(&hwq->hrrq_slock); | |
| 1898 | − spin_lock_init(&hwq->hsq_slock); | |
| 1899 | − | |
| 1900 | − /* Initialize SQ */ | |
| 1901 | − if (afu_is_sq_cmd_mode(afu)) { | |
| 1902 | − memset(&hwq->sq, 0, sizeof(hwq->sq)); | |
| 1903 | − hwq->hsq_start = &hwq->sq[0]; | |
| 1904 | − hwq->hsq_end = &hwq->sq[NUM_SQ_ENTRY - 1]; | |
| 1905 | − hwq->hsq_curr = hwq->hsq_start; | |
| 1906 | − | |
| 1907 | − atomic_set(&hwq->hsq_credits, NUM_SQ_ENTRY - 1); | |
| 1908 | − } | |
| 1909 | − | |
| 1910 | − /* Initialize IRQ poll */ | |
| 1911 | − if (afu_is_irqpoll_enabled(afu)) | |
| 1912 | − irq_poll_init(&hwq->irqpoll, afu->irqpoll_weight, | |
| 1913 | − cxlflash_irqpoll); | |
| 1914 | − | |
| 1915 | − } | |
| 1916 | − | |
| 1917 | − rc = init_global(cfg); | |
| 1918 | − | |
| 1919 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 1920 | − return rc; | |
| 1921 | −} | |
| 1922 | − | |
| 1923 | −/** | |
| 1924 | − * init_intr() - setup interrupt handlers for the master context | |
| 1925 | − * @cfg: Internal structure associated with the host. | |
| 1926 | − * @hwq: Hardware queue to initialize. | |
| 1927 | − * | |
| 1928 | − * Return: 0 on success, -errno on failure | |
| 1929 | − */ | |
| 1930 | −static enum undo_level init_intr(struct cxlflash_cfg *cfg, | |
| 1931 | − struct hwq *hwq) | |
| 1932 | −{ | |
| 1933 | − struct device *dev = &cfg->dev->dev; | |
| 1934 | − void *ctx = hwq->ctx_cookie; | |
| 1935 | − int rc = 0; | |
| 1936 | − enum undo_level level = UNDO_NOOP; | |
| 1937 | − bool is_primary_hwq = (hwq->index == PRIMARY_HWQ); | |
| 1938 | − int num_irqs = hwq->num_irqs; | |
| 1939 | − | |
| 1940 | − rc = cfg->ops->allocate_afu_irqs(ctx, num_irqs); | |
| 1941 | − if (unlikely(rc)) { | |
| 1942 | − dev_err(dev, "%s: allocate_afu_irqs failed rc=%d\n", | |
| 1943 | − __func__, rc); | |
| 1944 | − level = UNDO_NOOP; | |
| 1945 | − goto out; | |
| 1946 | − } | |
| 1947 | − | |
| 1948 | − rc = cfg->ops->map_afu_irq(ctx, 1, cxlflash_sync_err_irq, hwq, | |
| 1949 | − "SISL_MSI_SYNC_ERROR"); | |
| 1950 | − if (unlikely(rc <= 0)) { | |
| 1951 | − dev_err(dev, "%s: SISL_MSI_SYNC_ERROR map failed\n", __func__); | |
| 1952 | − level = FREE_IRQ; | |
| 1953 | − goto out; | |
| 1954 | − } | |
| 1955 | − | |
| 1956 | − rc = cfg->ops->map_afu_irq(ctx, 2, cxlflash_rrq_irq, hwq, | |
| 1957 | − "SISL_MSI_RRQ_UPDATED"); | |
| 1958 | − if (unlikely(rc <= 0)) { | |
| 1959 | − dev_err(dev, "%s: SISL_MSI_RRQ_UPDATED map failed\n", __func__); | |
| 1960 | − level = UNMAP_ONE; | |
| 1961 | − goto out; | |
| 1962 | − } | |
| 1963 | − | |
| 1964 | − /* SISL_MSI_ASYNC_ERROR is setup only for the primary HWQ */ | |
| 1965 | − if (!is_primary_hwq) | |
| 1966 | − goto out; | |
| 1967 | − | |
| 1968 | − rc = cfg->ops->map_afu_irq(ctx, 3, cxlflash_async_err_irq, hwq, | |
| 1969 | − "SISL_MSI_ASYNC_ERROR"); | |
| 1970 | − if (unlikely(rc <= 0)) { | |
| 1971 | − dev_err(dev, "%s: SISL_MSI_ASYNC_ERROR map failed\n", __func__); | |
| 1972 | − level = UNMAP_TWO; | |
| 1973 | − goto out; | |
| 1974 | − } | |
| 1975 | −out: | |
| 1976 | − return level; | |
| 1977 | −} | |
| 1978 | − | |
| 1979 | −/** | |
| 1980 | − * init_mc() - create and register as the master context | |
| 1981 | − * @cfg: Internal structure associated with the host. | |
| 1982 | − * @index: HWQ Index of the master context. | |
| 1983 | − * | |
| 1984 | − * Return: 0 on success, -errno on failure | |
| 1985 | − */ | |
| 1986 | −static int init_mc(struct cxlflash_cfg *cfg, u32 index) | |
| 1987 | −{ | |
| 1988 | − void *ctx; | |
| 1989 | − struct device *dev = &cfg->dev->dev; | |
| 1990 | − struct hwq *hwq = get_hwq(cfg->afu, index); | |
| 1991 | − int rc = 0; | |
| 1992 | − int num_irqs; | |
| 1993 | − enum undo_level level; | |
| 1994 | − | |
| 1995 | − hwq->afu = cfg->afu; | |
| 1996 | − hwq->index = index; | |
| 1997 | − INIT_LIST_HEAD(&hwq->pending_cmds); | |
| 1998 | − | |
| 1999 | − if (index == PRIMARY_HWQ) { | |
| 2000 | − ctx = cfg->ops->get_context(cfg->dev, cfg->afu_cookie); | |
| 2001 | − num_irqs = 3; | |
| 2002 | − } else { | |
| 2003 | − ctx = cfg->ops->dev_context_init(cfg->dev, cfg->afu_cookie); | |
| 2004 | − num_irqs = 2; | |
| 2005 | − } | |
| 2006 | − if (IS_ERR_OR_NULL(ctx)) { | |
| 2007 | − rc = -ENOMEM; | |
| 2008 | − goto err1; | |
| 2009 | − } | |
| 2010 | − | |
| 2011 | − WARN_ON(hwq->ctx_cookie); | |
| 2012 | − hwq->ctx_cookie = ctx; | |
| 2013 | − hwq->num_irqs = num_irqs; | |
| 2014 | − | |
| 2015 | − /* Set it up as a master with the CXL */ | |
| 2016 | − cfg->ops->set_master(ctx); | |
| 2017 | − | |
| 2018 | − /* Reset AFU when initializing primary context */ | |
| 2019 | − if (index == PRIMARY_HWQ) { | |
| 2020 | − rc = cfg->ops->afu_reset(ctx); | |
| 2021 | − if (unlikely(rc)) { | |
| 2022 | − dev_err(dev, "%s: AFU reset failed rc=%d\n", | |
| 2023 | − __func__, rc); | |
| 2024 | − goto err1; | |
| 2025 | − } | |
| 2026 | − } | |
| 2027 | − | |
| 2028 | − level = init_intr(cfg, hwq); | |
| 2029 | − if (unlikely(level)) { | |
| 2030 | − dev_err(dev, "%s: interrupt init failed rc=%d\n", __func__, rc); | |
| 2031 | − goto err2; | |
| 2032 | − } | |
| 2033 | − | |
| 2034 | − /* Finally, activate the context by starting it */ | |
| 2035 | − rc = cfg->ops->start_context(hwq->ctx_cookie); | |
| 2036 | − if (unlikely(rc)) { | |
| 2037 | − dev_err(dev, "%s: start context failed rc=%d\n", __func__, rc); | |
| 2038 | − level = UNMAP_THREE; | |
| 2039 | − goto err2; | |
| 2040 | − } | |
| 2041 | − | |
| 2042 | −out: | |
| 2043 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 2044 | − return rc; | |
| 2045 | −err2: | |
| 2046 | − term_intr(cfg, level, index); | |
| 2047 | − if (index != PRIMARY_HWQ) | |
| 2048 | − cfg->ops->release_context(ctx); | |
| 2049 | −err1: | |
| 2050 | − hwq->ctx_cookie = NULL; | |
| 2051 | − goto out; | |
| 2052 | −} | |
| 2053 | − | |
| 2054 | −/** | |
| 2055 | − * get_num_afu_ports() - determines and configures the number of AFU ports | |
| 2056 | − * @cfg: Internal structure associated with the host. | |
| 2057 | − * | |
| 2058 | − * This routine determines the number of AFU ports by converting the global | |
| 2059 | − * port selection mask. The converted value is only valid following an AFU | |
| 2060 | − * reset (explicit or power-on). This routine must be invoked shortly after | |
| 2061 | − * mapping as other routines are dependent on the number of ports during the | |
| 2062 | − * initialization sequence. | |
| 2063 | − * | |
| 2064 | − * To support legacy AFUs that might not have reflected an initial global | |
| 2065 | − * port mask (value read is 0), default to the number of ports originally | |
| 2066 | − * supported by the cxlflash driver (2) before hardware with other port | |
| 2067 | − * offerings was introduced. | |
| 2068 | − */ | |
| 2069 | −static void get_num_afu_ports(struct cxlflash_cfg *cfg) | |
| 2070 | −{ | |
| 2071 | − struct afu *afu = cfg->afu; | |
| 2072 | − struct device *dev = &cfg->dev->dev; | |
| 2073 | − u64 port_mask; | |
| 2074 | − int num_fc_ports = LEGACY_FC_PORTS; | |
| 2075 | − | |
| 2076 | − port_mask = readq_be(&afu->afu_map->global.regs.afu_port_sel); | |
| 2077 | − if (port_mask != 0ULL) | |
| 2078 | − num_fc_ports = min(ilog2(port_mask) + 1, MAX_FC_PORTS); | |
| 2079 | − | |
| 2080 | − dev_dbg(dev, "%s: port_mask=%016llx num_fc_ports=%d\n", | |
| 2081 | − __func__, port_mask, num_fc_ports); | |
| 2082 | − | |
| 2083 | − cfg->num_fc_ports = num_fc_ports; | |
| 2084 | − cfg->host->max_channel = PORTNUM2CHAN(num_fc_ports); | |
| 2085 | −} | |
| 2086 | − | |
| 2087 | −/** | |
| 2088 | − * init_afu() - setup as master context and start AFU | |
| 2089 | − * @cfg: Internal structure associated with the host. | |
| 2090 | − * | |
| 2091 | − * This routine is a higher level of control for configuring the | |
| 2092 | − * AFU on probe and reset paths. | |
| 2093 | − * | |
| 2094 | − * Return: 0 on success, -errno on failure | |
| 2095 | − */ | |
| 2096 | −static int init_afu(struct cxlflash_cfg *cfg) | |
| 2097 | −{ | |
| 2098 | − u64 reg; | |
| 2099 | − int rc = 0; | |
| 2100 | − struct afu *afu = cfg->afu; | |
| 2101 | − struct device *dev = &cfg->dev->dev; | |
| 2102 | − struct hwq *hwq; | |
| 2103 | − int i; | |
| 2104 | − | |
| 2105 | − cfg->ops->perst_reloads_same_image(cfg->afu_cookie, true); | |
| 2106 | − | |
| 2107 | − mutex_init(&afu->sync_active); | |
| 2108 | − afu->num_hwqs = afu->desired_hwqs; | |
| 2109 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 2110 | − rc = init_mc(cfg, i); | |
| 2111 | − if (rc) { | |
| 2112 | − dev_err(dev, "%s: init_mc failed rc=%d index=%d\n", | |
| 2113 | − __func__, rc, i); | |
| 2114 | − goto err1; | |
| 2115 | − } | |
| 2116 | − } | |
| 2117 | − | |
| 2118 | − /* Map the entire MMIO space of the AFU using the first context */ | |
| 2119 | − hwq = get_hwq(afu, PRIMARY_HWQ); | |
| 2120 | − afu->afu_map = cfg->ops->psa_map(hwq->ctx_cookie); | |
| 2121 | − if (!afu->afu_map) { | |
| 2122 | − dev_err(dev, "%s: psa_map failed\n", __func__); | |
| 2123 | − rc = -ENOMEM; | |
| 2124 | − goto err1; | |
| 2125 | − } | |
| 2126 | − | |
| 2127 | − /* No byte reverse on reading afu_version or string will be backwards */ | |
| 2128 | − reg = readq(&afu->afu_map->global.regs.afu_version); | |
| 2129 | − memcpy(afu->version, ®, sizeof(reg)); | |
| 2130 | − afu->interface_version = | |
| 2131 | − readq_be(&afu->afu_map->global.regs.interface_version); | |
| 2132 | − if ((afu->interface_version + 1) == 0) { | |
| 2133 | − dev_err(dev, "Back level AFU, please upgrade. AFU version %s " | |
| 2134 | − "interface version %016llx\n", afu->version, | |
| 2135 | − afu->interface_version); | |
| 2136 | − rc = -EINVAL; | |
| 2137 | − goto err1; | |
| 2138 | − } | |
| 2139 | − | |
| 2140 | − if (afu_is_sq_cmd_mode(afu)) { | |
| 2141 | − afu->send_cmd = send_cmd_sq; | |
| 2142 | − afu->context_reset = context_reset_sq; | |
| 2143 | − } else { | |
| 2144 | − afu->send_cmd = send_cmd_ioarrin; | |
| 2145 | − afu->context_reset = context_reset_ioarrin; | |
| 2146 | − } | |
| 2147 | − | |
| 2148 | − dev_dbg(dev, "%s: afu_ver=%s interface_ver=%016llx\n", __func__, | |
| 2149 | − afu->version, afu->interface_version); | |
| 2150 | − | |
| 2151 | − get_num_afu_ports(cfg); | |
| 2152 | − | |
| 2153 | − rc = start_afu(cfg); | |
| 2154 | − if (rc) { | |
| 2155 | − dev_err(dev, "%s: start_afu failed, rc=%d\n", __func__, rc); | |
| 2156 | − goto err1; | |
| 2157 | − } | |
| 2158 | − | |
| 2159 | − afu_err_intr_init(cfg->afu); | |
| 2160 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 2161 | − hwq = get_hwq(afu, i); | |
| 2162 | − | |
| 2163 | − hwq->room = readq_be(&hwq->host_map->cmd_room); | |
| 2164 | − } | |
| 2165 | − | |
| 2166 | − /* Restore the LUN mappings */ | |
| 2167 | − cxlflash_restore_luntable(cfg); | |
| 2168 | −out: | |
| 2169 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 2170 | − return rc; | |
| 2171 | − | |
| 2172 | −err1: | |
| 2173 | − for (i = afu->num_hwqs - 1; i >= 0; i--) { | |
| 2174 | − term_intr(cfg, UNMAP_THREE, i); | |
| 2175 | − term_mc(cfg, i); | |
| 2176 | − } | |
| 2177 | − goto out; | |
| 2178 | −} | |
| 2179 | − | |
| 2180 | −/** | |
| 2181 | − * afu_reset() - resets the AFU | |
| 2182 | − * @cfg: Internal structure associated with the host. | |
| 2183 | − * | |
| 2184 | − * Return: 0 on success, -errno on failure | |
| 2185 | − */ | |
| 2186 | −static int afu_reset(struct cxlflash_cfg *cfg) | |
| 2187 | −{ | |
| 2188 | − struct device *dev = &cfg->dev->dev; | |
| 2189 | − int rc = 0; | |
| 2190 | − | |
| 2191 | − /* Stop the context before the reset. Since the context is | |
| 2192 | − * no longer available restart it after the reset is complete | |
| 2193 | − */ | |
| 2194 | − term_afu(cfg); | |
| 2195 | − | |
| 2196 | − rc = init_afu(cfg); | |
| 2197 | − | |
| 2198 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 2199 | − return rc; | |
| 2200 | −} | |
| 2201 | − | |
| 2202 | −/** | |
| 2203 | − * drain_ioctls() - wait until all currently executing ioctls have completed | |
| 2204 | − * @cfg: Internal structure associated with the host. | |
| 2205 | − * | |
| 2206 | − * Obtain write access to read/write semaphore that wraps ioctl | |
| 2207 | − * handling to 'drain' ioctls currently executing. | |
| 2208 | − */ | |
| 2209 | −static void drain_ioctls(struct cxlflash_cfg *cfg) | |
| 2210 | −{ | |
| 2211 | − down_write(&cfg->ioctl_rwsem); | |
| 2212 | − up_write(&cfg->ioctl_rwsem); | |
| 2213 | −} | |
| 2214 | − | |
| 2215 | −/** | |
| 2216 | − * cxlflash_async_reset_host() - asynchronous host reset handler | |
| 2217 | − * @data: Private data provided while scheduling reset. | |
| 2218 | − * @cookie: Cookie that can be used for checkpointing. | |
| 2219 | − */ | |
| 2220 | −static void cxlflash_async_reset_host(void *data, async_cookie_t cookie) | |
| 2221 | −{ | |
| 2222 | − struct cxlflash_cfg *cfg = data; | |
| 2223 | − struct device *dev = &cfg->dev->dev; | |
| 2224 | − int rc = 0; | |
| 2225 | − | |
| 2226 | − if (cfg->state != STATE_RESET) { | |
| 2227 | − dev_dbg(dev, "%s: Not performing a reset, state=%d\n", | |
| 2228 | − __func__, cfg->state); | |
| 2229 | − goto out; | |
| 2230 | − } | |
| 2231 | − | |
| 2232 | − drain_ioctls(cfg); | |
| 2233 | − cxlflash_mark_contexts_error(cfg); | |
| 2234 | − rc = afu_reset(cfg); | |
| 2235 | − if (rc) | |
| 2236 | − cfg->state = STATE_FAILTERM; | |
| 2237 | − else | |
| 2238 | − cfg->state = STATE_NORMAL; | |
| 2239 | − wake_up_all(&cfg->reset_waitq); | |
| 2240 | − | |
| 2241 | −out: | |
| 2242 | − scsi_unblock_requests(cfg->host); | |
| 2243 | −} | |
| 2244 | − | |
| 2245 | −/** | |
| 2246 | − * cxlflash_schedule_async_reset() - schedule an asynchronous host reset | |
| 2247 | − * @cfg: Internal structure associated with the host. | |
| 2248 | − */ | |
| 2249 | −static void cxlflash_schedule_async_reset(struct cxlflash_cfg *cfg) | |
| 2250 | −{ | |
| 2251 | − struct device *dev = &cfg->dev->dev; | |
| 2252 | − | |
| 2253 | − if (cfg->state != STATE_NORMAL) { | |
| 2254 | − dev_dbg(dev, "%s: Not performing reset state=%d\n", | |
| 2255 | − __func__, cfg->state); | |
| 2256 | − return; | |
| 2257 | − } | |
| 2258 | − | |
| 2259 | − cfg->state = STATE_RESET; | |
| 2260 | − scsi_block_requests(cfg->host); | |
| 2261 | − cfg->async_reset_cookie = async_schedule(cxlflash_async_reset_host, | |
| 2262 | − cfg); | |
| 2263 | −} | |
| 2264 | − | |
| 2265 | −/** | |
| 2266 | − * send_afu_cmd() - builds and sends an internal AFU command | |
| 2267 | − * @afu: AFU associated with the host. | |
| 2268 | − * @rcb: Pre-populated IOARCB describing command to send. | |
| 2269 | − * | |
| 2270 | − * The AFU can only take one internal AFU command at a time. This limitation is | |
| 2271 | − * enforced by using a mutex to provide exclusive access to the AFU during the | |
| 2272 | − * operation. This design point requires calling threads to not be on interrupt | |
| 2273 | − * context due to the possibility of sleeping during concurrent AFU operations. | |
| 2274 | − * | |
| 2275 | − * The command status is optionally passed back to the caller when the caller | |
| 2276 | − * populates the IOASA field of the IOARCB with a pointer to an IOASA structure. | |
| 2277 | − * | |
| 2278 | − * Return: | |
| 2279 | − * 0 on success, -errno on failure | |
| 2280 | − */ | |
| 2281 | −static int send_afu_cmd(struct afu *afu, struct sisl_ioarcb *rcb) | |
| 2282 | −{ | |
| 2283 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 2284 | − struct device *dev = &cfg->dev->dev; | |
| 2285 | − struct afu_cmd *cmd = NULL; | |
| 2286 | − struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); | |
| 2287 | − ulong lock_flags; | |
| 2288 | − char *buf = NULL; | |
| 2289 | − int rc = 0; | |
| 2290 | − int nretry = 0; | |
| 2291 | − | |
| 2292 | − if (cfg->state != STATE_NORMAL) { | |
| 2293 | − dev_dbg(dev, "%s: Sync not required state=%u\n", | |
| 2294 | − __func__, cfg->state); | |
| 2295 | − return 0; | |
| 2296 | − } | |
| 2297 | − | |
| 2298 | − mutex_lock(&afu->sync_active); | |
| 2299 | − atomic_inc(&afu->cmds_active); | |
| 2300 | − buf = kmalloc(sizeof(*cmd) + __alignof__(*cmd) - 1, GFP_KERNEL); | |
| 2301 | − if (unlikely(!buf)) { | |
| 2302 | − dev_err(dev, "%s: no memory for command\n", __func__); | |
| 2303 | − rc = -ENOMEM; | |
| 2304 | − goto out; | |
| 2305 | − } | |
| 2306 | − | |
| 2307 | − cmd = (struct afu_cmd *)PTR_ALIGN(buf, __alignof__(*cmd)); | |
| 2308 | − | |
| 2309 | −retry: | |
| 2310 | − memset(cmd, 0, sizeof(*cmd)); | |
| 2311 | − memcpy(&cmd->rcb, rcb, sizeof(*rcb)); | |
| 2312 | − INIT_LIST_HEAD(&cmd->queue); | |
| 2313 | − init_completion(&cmd->cevent); | |
| 2314 | − cmd->parent = afu; | |
| 2315 | − cmd->hwq_index = hwq->index; | |
| 2316 | − cmd->rcb.ctx_id = hwq->ctx_hndl; | |
| 2317 | − | |
| 2318 | − dev_dbg(dev, "%s: afu=%p cmd=%p type=%02x nretry=%d\n", | |
| 2319 | − __func__, afu, cmd, cmd->rcb.cdb[0], nretry); | |
| 2320 | − | |
| 2321 | − rc = afu->send_cmd(afu, cmd); | |
| 2322 | − if (unlikely(rc)) { | |
| 2323 | − rc = -ENOBUFS; | |
| 2324 | − goto out; | |
| 2325 | − } | |
| 2326 | − | |
| 2327 | − rc = wait_resp(afu, cmd); | |
| 2328 | − switch (rc) { | |
| 2329 | − case -ETIMEDOUT: | |
| 2330 | − rc = afu->context_reset(hwq); | |
| 2331 | − if (rc) { | |
| 2332 | − /* Delete the command from pending_cmds list */ | |
| 2333 | − spin_lock_irqsave(&hwq->hsq_slock, lock_flags); | |
| 2334 | − list_del(&cmd->list); | |
| 2335 | − spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags); | |
| 2336 | − | |
| 2337 | − cxlflash_schedule_async_reset(cfg); | |
| 2338 | − break; | |
| 2339 | − } | |
| 2340 | − fallthrough; /* to retry */ | |
| 2341 | − case -EAGAIN: | |
| 2342 | − if (++nretry < 2) | |
| 2343 | − goto retry; | |
| 2344 | − fallthrough; /* to exit */ | |
| 2345 | − default: | |
| 2346 | − break; | |
| 2347 | − } | |
| 2348 | − | |
| 2349 | − if (rcb->ioasa) | |
| 2350 | − *rcb->ioasa = cmd->sa; | |
| 2351 | −out: | |
| 2352 | − atomic_dec(&afu->cmds_active); | |
| 2353 | − mutex_unlock(&afu->sync_active); | |
| 2354 | − kfree(buf); | |
| 2355 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 2356 | − return rc; | |
| 2357 | −} | |
| 2358 | − | |
| 2359 | −/** | |
| 2360 | − * cxlflash_afu_sync() - builds and sends an AFU sync command | |
| 2361 | − * @afu: AFU associated with the host. | |
| 2362 | − * @ctx: Identifies context requesting sync. | |
| 2363 | − * @res: Identifies resource requesting sync. | |
| 2364 | − * @mode: Type of sync to issue (lightweight, heavyweight, global). | |
| 2365 | − * | |
| 2366 | − * AFU sync operations are only necessary and allowed when the device is | |
| 2367 | − * operating normally. When not operating normally, sync requests can occur as | |
| 2368 | − * part of cleaning up resources associated with an adapter prior to removal. | |
| 2369 | − * In this scenario, these requests are simply ignored (safe due to the AFU | |
| 2370 | − * going away). | |
| 2371 | − * | |
| 2372 | − * Return: | |
| 2373 | − * 0 on success, -errno on failure | |
| 2374 | − */ | |
| 2375 | −int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx, res_hndl_t res, u8 mode) | |
| 2376 | −{ | |
| 2377 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 2378 | − struct device *dev = &cfg->dev->dev; | |
| 2379 | − struct sisl_ioarcb rcb = { 0 }; | |
| 2380 | − | |
| 2381 | − dev_dbg(dev, "%s: afu=%p ctx=%u res=%u mode=%u\n", | |
| 2382 | − __func__, afu, ctx, res, mode); | |
| 2383 | − | |
| 2384 | − rcb.req_flags = SISL_REQ_FLAGS_AFU_CMD; | |
| 2385 | − rcb.msi = SISL_MSI_RRQ_UPDATED; | |
| 2386 | − rcb.timeout = MC_AFU_SYNC_TIMEOUT; | |
| 2387 | − | |
| 2388 | − rcb.cdb[0] = SISL_AFU_CMD_SYNC; | |
| 2389 | − rcb.cdb[1] = mode; | |
| 2390 | − put_unaligned_be16(ctx, &rcb.cdb[2]); | |
| 2391 | − put_unaligned_be32(res, &rcb.cdb[4]); | |
| 2392 | − | |
| 2393 | − return send_afu_cmd(afu, &rcb); | |
| 2394 | −} | |
| 2395 | − | |
| 2396 | −/** | |
| 2397 | − * cxlflash_eh_abort_handler() - abort a SCSI command | |
| 2398 | − * @scp: SCSI command to abort. | |
| 2399 | − * | |
| 2400 | − * CXL Flash devices do not support a single command abort. Reset the context | |
| 2401 | − * as per SISLite specification. Flush any pending commands in the hardware | |
| 2402 | − * queue before the reset. | |
| 2403 | − * | |
| 2404 | − * Return: SUCCESS/FAILED as defined in scsi/scsi.h | |
| 2405 | − */ | |
| 2406 | −static int cxlflash_eh_abort_handler(struct scsi_cmnd *scp) | |
| 2407 | −{ | |
| 2408 | − int rc = FAILED; | |
| 2409 | − struct Scsi_Host *host = scp->device->host; | |
| 2410 | − struct cxlflash_cfg *cfg = shost_priv(host); | |
| 2411 | − struct afu_cmd *cmd = sc_to_afuc(scp); | |
| 2412 | − struct device *dev = &cfg->dev->dev; | |
| 2413 | − struct afu *afu = cfg->afu; | |
| 2414 | − struct hwq *hwq = get_hwq(afu, cmd->hwq_index); | |
| 2415 | − | |
| 2416 | − dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu " | |
| 2417 | − "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no, | |
| 2418 | − scp->device->channel, scp->device->id, scp->device->lun, | |
| 2419 | − get_unaligned_be32(&((u32 *)scp->cmnd)[0]), | |
| 2420 | − get_unaligned_be32(&((u32 *)scp->cmnd)[1]), | |
| 2421 | − get_unaligned_be32(&((u32 *)scp->cmnd)[2]), | |
| 2422 | − get_unaligned_be32(&((u32 *)scp->cmnd)[3])); | |
| 2423 | − | |
| 2424 | − /* When the state is not normal, another reset/reload is in progress. | |
| 2425 | − * Return failed and the mid-layer will invoke host reset handler. | |
| 2426 | − */ | |
| 2427 | − if (cfg->state != STATE_NORMAL) { | |
| 2428 | − dev_dbg(dev, "%s: Invalid state for abort, state=%d\n", | |
| 2429 | − __func__, cfg->state); | |
| 2430 | − goto out; | |
| 2431 | − } | |
| 2432 | − | |
| 2433 | − rc = afu->context_reset(hwq); | |
| 2434 | − if (unlikely(rc)) | |
| 2435 | − goto out; | |
| 2436 | − | |
| 2437 | − rc = SUCCESS; | |
| 2438 | − | |
| 2439 | −out: | |
| 2440 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 2441 | − return rc; | |
| 2442 | −} | |
| 2443 | − | |
| 2444 | −/** | |
| 2445 | − * cxlflash_eh_device_reset_handler() - reset a single LUN | |
| 2446 | − * @scp: SCSI command to send. | |
| 2447 | − * | |
| 2448 | − * Return: | |
| 2449 | − * SUCCESS as defined in scsi/scsi.h | |
| 2450 | − * FAILED as defined in scsi/scsi.h | |
| 2451 | − */ | |
| 2452 | −static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) | |
| 2453 | −{ | |
| 2454 | − int rc = SUCCESS; | |
| 2455 | − struct scsi_device *sdev = scp->device; | |
| 2456 | − struct Scsi_Host *host = sdev->host; | |
| 2457 | − struct cxlflash_cfg *cfg = shost_priv(host); | |
| 2458 | − struct device *dev = &cfg->dev->dev; | |
| 2459 | − int rcr = 0; | |
| 2460 | − | |
| 2461 | − dev_dbg(dev, "%s: %d/%d/%d/%llu\n", __func__, | |
| 2462 | − host->host_no, sdev->channel, sdev->id, sdev->lun); | |
| 2463 | −retry: | |
| 2464 | − switch (cfg->state) { | |
| 2465 | − case STATE_NORMAL: | |
| 2466 | − rcr = send_tmf(cfg, sdev, TMF_LUN_RESET); | |
| 2467 | − if (unlikely(rcr)) | |
| 2468 | − rc = FAILED; | |
| 2469 | − break; | |
| 2470 | − case STATE_RESET: | |
| 2471 | − wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); | |
| 2472 | − goto retry; | |
| 2473 | − default: | |
| 2474 | − rc = FAILED; | |
| 2475 | − break; | |
| 2476 | − } | |
| 2477 | − | |
| 2478 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 2479 | − return rc; | |
| 2480 | −} | |
| 2481 | − | |
| 2482 | −/** | |
| 2483 | − * cxlflash_eh_host_reset_handler() - reset the host adapter | |
| 2484 | − * @scp: SCSI command from stack identifying host. | |
| 2485 | − * | |
| 2486 | − * Following a reset, the state is evaluated again in case an EEH occurred | |
| 2487 | − * during the reset. In such a scenario, the host reset will either yield | |
| 2488 | − * until the EEH recovery is complete or return success or failure based | |
| 2489 | − * upon the current device state. | |
| 2490 | − * | |
| 2491 | − * Return: | |
| 2492 | − * SUCCESS as defined in scsi/scsi.h | |
| 2493 | − * FAILED as defined in scsi/scsi.h | |
| 2494 | − */ | |
| 2495 | −static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) | |
| 2496 | −{ | |
| 2497 | − int rc = SUCCESS; | |
| 2498 | − int rcr = 0; | |
| 2499 | − struct Scsi_Host *host = scp->device->host; | |
| 2500 | − struct cxlflash_cfg *cfg = shost_priv(host); | |
| 2501 | − struct device *dev = &cfg->dev->dev; | |
| 2502 | − | |
| 2503 | − dev_dbg(dev, "%s: %d\n", __func__, host->host_no); | |
| 2504 | − | |
| 2505 | − switch (cfg->state) { | |
| 2506 | − case STATE_NORMAL: | |
| 2507 | − cfg->state = STATE_RESET; | |
| 2508 | − drain_ioctls(cfg); | |
| 2509 | − cxlflash_mark_contexts_error(cfg); | |
| 2510 | − rcr = afu_reset(cfg); | |
| 2511 | − if (rcr) { | |
| 2512 | − rc = FAILED; | |
| 2513 | − cfg->state = STATE_FAILTERM; | |
| 2514 | − } else | |
| 2515 | − cfg->state = STATE_NORMAL; | |
| 2516 | − wake_up_all(&cfg->reset_waitq); | |
| 2517 | − ssleep(1); | |
| 2518 | − fallthrough; | |
| 2519 | − case STATE_RESET: | |
| 2520 | − wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); | |
| 2521 | − if (cfg->state == STATE_NORMAL) | |
| 2522 | − break; | |
| 2523 | − fallthrough; | |
| 2524 | − default: | |
| 2525 | − rc = FAILED; | |
| 2526 | − break; | |
| 2527 | − } | |
| 2528 | − | |
| 2529 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 2530 | − return rc; | |
| 2531 | −} | |
| 2532 | − | |
| 2533 | −/** | |
| 2534 | − * cxlflash_change_queue_depth() - change the queue depth for the device | |
| 2535 | − * @sdev: SCSI device destined for queue depth change. | |
| 2536 | − * @qdepth: Requested queue depth value to set. | |
| 2537 | − * | |
| 2538 | − * The requested queue depth is capped to the maximum supported value. | |
| 2539 | − * | |
| 2540 | − * Return: The actual queue depth set. | |
| 2541 | − */ | |
| 2542 | −static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth) | |
| 2543 | −{ | |
| 2544 | − | |
| 2545 | − if (qdepth > CXLFLASH_MAX_CMDS_PER_LUN) | |
| 2546 | − qdepth = CXLFLASH_MAX_CMDS_PER_LUN; | |
| 2547 | − | |
| 2548 | − scsi_change_queue_depth(sdev, qdepth); | |
| 2549 | − return sdev->queue_depth; | |
| 2550 | −} | |
| 2551 | − | |
| 2552 | −/** | |
| 2553 | − * cxlflash_show_port_status() - queries and presents the current port status | |
| 2554 | − * @port: Desired port for status reporting. | |
| 2555 | − * @cfg: Internal structure associated with the host. | |
| 2556 | − * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. | |
| 2557 | − * | |
| 2558 | − * Return: The size of the ASCII string returned in @buf or -EINVAL. | |
| 2559 | − */ | |
| 2560 | −static ssize_t cxlflash_show_port_status(u32 port, | |
| 2561 | − struct cxlflash_cfg *cfg, | |
| 2562 | − char *buf) | |
| 2563 | −{ | |
| 2564 | − struct device *dev = &cfg->dev->dev; | |
| 2565 | − char *disp_status; | |
| 2566 | − u64 status; | |
| 2567 | − __be64 __iomem *fc_port_regs; | |
| 2568 | − | |
| 2569 | − WARN_ON(port >= MAX_FC_PORTS); | |
| 2570 | − | |
| 2571 | − if (port >= cfg->num_fc_ports) { | |
| 2572 | − dev_info(dev, "%s: Port %d not supported on this card.\n", | |
| 2573 | − __func__, port); | |
| 2574 | − return -EINVAL; | |
| 2575 | − } | |
| 2576 | − | |
| 2577 | − fc_port_regs = get_fc_port_regs(cfg, port); | |
| 2578 | − status = readq_be(&fc_port_regs[FC_MTIP_STATUS / 8]); | |
| 2579 | − status &= FC_MTIP_STATUS_MASK; | |
| 2580 | − | |
| 2581 | − if (status == FC_MTIP_STATUS_ONLINE) | |
| 2582 | − disp_status = "online"; | |
| 2583 | − else if (status == FC_MTIP_STATUS_OFFLINE) | |
| 2584 | − disp_status = "offline"; | |
| 2585 | − else | |
| 2586 | − disp_status = "unknown"; | |
| 2587 | − | |
| 2588 | − return scnprintf(buf, PAGE_SIZE, "%s\n", disp_status); | |
| 2589 | −} | |
| 2590 | − | |
| 2591 | −/** | |
| 2592 | − * port0_show() - queries and presents the current status of port 0 | |
| 2593 | − * @dev: Generic device associated with the host owning the port. | |
| 2594 | − * @attr: Device attribute representing the port. | |
| 2595 | − * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. | |
| 2596 | − * | |
| 2597 | − * Return: The size of the ASCII string returned in @buf. | |
| 2598 | − */ | |
| 2599 | −static ssize_t port0_show(struct device *dev, | |
| 2600 | − struct device_attribute *attr, | |
| 2601 | − char *buf) | |
| 2602 | −{ | |
| 2603 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2604 | − | |
| 2605 | − return cxlflash_show_port_status(0, cfg, buf); | |
| 2606 | −} | |
| 2607 | − | |
| 2608 | −/** | |
| 2609 | − * port1_show() - queries and presents the current status of port 1 | |
| 2610 | − * @dev: Generic device associated with the host owning the port. | |
| 2611 | − * @attr: Device attribute representing the port. | |
| 2612 | − * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. | |
| 2613 | − * | |
| 2614 | − * Return: The size of the ASCII string returned in @buf. | |
| 2615 | − */ | |
| 2616 | −static ssize_t port1_show(struct device *dev, | |
| 2617 | − struct device_attribute *attr, | |
| 2618 | − char *buf) | |
| 2619 | −{ | |
| 2620 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2621 | − | |
| 2622 | − return cxlflash_show_port_status(1, cfg, buf); | |
| 2623 | −} | |
| 2624 | − | |
| 2625 | −/** | |
| 2626 | − * port2_show() - queries and presents the current status of port 2 | |
| 2627 | − * @dev: Generic device associated with the host owning the port. | |
| 2628 | − * @attr: Device attribute representing the port. | |
| 2629 | − * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. | |
| 2630 | − * | |
| 2631 | − * Return: The size of the ASCII string returned in @buf. | |
| 2632 | − */ | |
| 2633 | −static ssize_t port2_show(struct device *dev, | |
| 2634 | − struct device_attribute *attr, | |
| 2635 | − char *buf) | |
| 2636 | −{ | |
| 2637 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2638 | − | |
| 2639 | − return cxlflash_show_port_status(2, cfg, buf); | |
| 2640 | −} | |
| 2641 | − | |
| 2642 | −/** | |
| 2643 | − * port3_show() - queries and presents the current status of port 3 | |
| 2644 | − * @dev: Generic device associated with the host owning the port. | |
| 2645 | − * @attr: Device attribute representing the port. | |
| 2646 | − * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. | |
| 2647 | − * | |
| 2648 | − * Return: The size of the ASCII string returned in @buf. | |
| 2649 | − */ | |
| 2650 | −static ssize_t port3_show(struct device *dev, | |
| 2651 | − struct device_attribute *attr, | |
| 2652 | − char *buf) | |
| 2653 | −{ | |
| 2654 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2655 | − | |
| 2656 | − return cxlflash_show_port_status(3, cfg, buf); | |
| 2657 | −} | |
| 2658 | − | |
| 2659 | −/** | |
| 2660 | − * lun_mode_show() - presents the current LUN mode of the host | |
| 2661 | − * @dev: Generic device associated with the host. | |
| 2662 | − * @attr: Device attribute representing the LUN mode. | |
| 2663 | − * @buf: Buffer of length PAGE_SIZE to report back the LUN mode in ASCII. | |
| 2664 | − * | |
| 2665 | − * Return: The size of the ASCII string returned in @buf. | |
| 2666 | − */ | |
| 2667 | −static ssize_t lun_mode_show(struct device *dev, | |
| 2668 | − struct device_attribute *attr, char *buf) | |
| 2669 | −{ | |
| 2670 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2671 | − struct afu *afu = cfg->afu; | |
| 2672 | − | |
| 2673 | − return scnprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); | |
| 2674 | −} | |
| 2675 | − | |
| 2676 | −/** | |
| 2677 | − * lun_mode_store() - sets the LUN mode of the host | |
| 2678 | − * @dev: Generic device associated with the host. | |
| 2679 | − * @attr: Device attribute representing the LUN mode. | |
| 2680 | − * @buf: Buffer of length PAGE_SIZE containing the LUN mode in ASCII. | |
| 2681 | − * @count: Length of data resizing in @buf. | |
| 2682 | − * | |
| 2683 | − * The CXL Flash AFU supports a dummy LUN mode where the external | |
| 2684 | − * links and storage are not required. Space on the FPGA is used | |
| 2685 | − * to create 1 or 2 small LUNs which are presented to the system | |
| 2686 | − * as if they were a normal storage device. This feature is useful | |
| 2687 | − * during development and also provides manufacturing with a way | |
| 2688 | − * to test the AFU without an actual device. | |
| 2689 | − * | |
| 2690 | − * 0 = external LUN[s] (default) | |
| 2691 | − * 1 = internal LUN (1 x 64K, 512B blocks, id 0) | |
| 2692 | − * 2 = internal LUN (1 x 64K, 4K blocks, id 0) | |
| 2693 | − * 3 = internal LUN (2 x 32K, 512B blocks, ids 0,1) | |
| 2694 | − * 4 = internal LUN (2 x 32K, 4K blocks, ids 0,1) | |
| 2695 | − * | |
| 2696 | − * Return: The size of the ASCII string returned in @buf. | |
| 2697 | − */ | |
| 2698 | −static ssize_t lun_mode_store(struct device *dev, | |
| 2699 | − struct device_attribute *attr, | |
| 2700 | − const char *buf, size_t count) | |
| 2701 | −{ | |
| 2702 | − struct Scsi_Host *shost = class_to_shost(dev); | |
| 2703 | − struct cxlflash_cfg *cfg = shost_priv(shost); | |
| 2704 | − struct afu *afu = cfg->afu; | |
| 2705 | − int rc; | |
| 2706 | − u32 lun_mode; | |
| 2707 | − | |
| 2708 | − rc = kstrtouint(buf, 10, &lun_mode); | |
| 2709 | − if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) { | |
| 2710 | − afu->internal_lun = lun_mode; | |
| 2711 | − | |
| 2712 | − /* | |
| 2713 | − * When configured for internal LUN, there is only one channel, | |
| 2714 | − * channel number 0, else there will be one less than the number | |
| 2715 | − * of fc ports for this card. | |
| 2716 | − */ | |
| 2717 | − if (afu->internal_lun) | |
| 2718 | − shost->max_channel = 0; | |
| 2719 | − else | |
| 2720 | − shost->max_channel = PORTNUM2CHAN(cfg->num_fc_ports); | |
| 2721 | − | |
| 2722 | − afu_reset(cfg); | |
| 2723 | − scsi_scan_host(cfg->host); | |
| 2724 | − } | |
| 2725 | − | |
| 2726 | − return count; | |
| 2727 | −} | |
| 2728 | − | |
| 2729 | −/** | |
| 2730 | − * ioctl_version_show() - presents the current ioctl version of the host | |
| 2731 | − * @dev: Generic device associated with the host. | |
| 2732 | − * @attr: Device attribute representing the ioctl version. | |
| 2733 | − * @buf: Buffer of length PAGE_SIZE to report back the ioctl version. | |
| 2734 | − * | |
| 2735 | − * Return: The size of the ASCII string returned in @buf. | |
| 2736 | − */ | |
| 2737 | −static ssize_t ioctl_version_show(struct device *dev, | |
| 2738 | − struct device_attribute *attr, char *buf) | |
| 2739 | −{ | |
| 2740 | − ssize_t bytes = 0; | |
| 2741 | − | |
| 2742 | − bytes = scnprintf(buf, PAGE_SIZE, | |
| 2743 | − "disk: %u\n", DK_CXLFLASH_VERSION_0); | |
| 2744 | − bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, | |
| 2745 | − "host: %u\n", HT_CXLFLASH_VERSION_0); | |
| 2746 | − | |
| 2747 | − return bytes; | |
| 2748 | −} | |
| 2749 | − | |
| 2750 | −/** | |
| 2751 | − * cxlflash_show_port_lun_table() - queries and presents the port LUN table | |
| 2752 | − * @port: Desired port for status reporting. | |
| 2753 | − * @cfg: Internal structure associated with the host. | |
| 2754 | − * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. | |
| 2755 | − * | |
| 2756 | − * Return: The size of the ASCII string returned in @buf or -EINVAL. | |
| 2757 | − */ | |
| 2758 | −static ssize_t cxlflash_show_port_lun_table(u32 port, | |
| 2759 | − struct cxlflash_cfg *cfg, | |
| 2760 | − char *buf) | |
| 2761 | −{ | |
| 2762 | − struct device *dev = &cfg->dev->dev; | |
| 2763 | − __be64 __iomem *fc_port_luns; | |
| 2764 | − int i; | |
| 2765 | − ssize_t bytes = 0; | |
| 2766 | − | |
| 2767 | − WARN_ON(port >= MAX_FC_PORTS); | |
| 2768 | − | |
| 2769 | − if (port >= cfg->num_fc_ports) { | |
| 2770 | − dev_info(dev, "%s: Port %d not supported on this card.\n", | |
| 2771 | − __func__, port); | |
| 2772 | − return -EINVAL; | |
| 2773 | − } | |
| 2774 | − | |
| 2775 | − fc_port_luns = get_fc_port_luns(cfg, port); | |
| 2776 | − | |
| 2777 | − for (i = 0; i < CXLFLASH_NUM_VLUNS; i++) | |
| 2778 | − bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, | |
| 2779 | − "%03d: %016llx\n", | |
| 2780 | − i, readq_be(&fc_port_luns[i])); | |
| 2781 | − return bytes; | |
| 2782 | −} | |
| 2783 | − | |
| 2784 | −/** | |
| 2785 | − * port0_lun_table_show() - presents the current LUN table of port 0 | |
| 2786 | − * @dev: Generic device associated with the host owning the port. | |
| 2787 | − * @attr: Device attribute representing the port. | |
| 2788 | − * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. | |
| 2789 | − * | |
| 2790 | − * Return: The size of the ASCII string returned in @buf. | |
| 2791 | − */ | |
| 2792 | −static ssize_t port0_lun_table_show(struct device *dev, | |
| 2793 | − struct device_attribute *attr, | |
| 2794 | − char *buf) | |
| 2795 | −{ | |
| 2796 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2797 | − | |
| 2798 | − return cxlflash_show_port_lun_table(0, cfg, buf); | |
| 2799 | −} | |
| 2800 | − | |
| 2801 | −/** | |
| 2802 | − * port1_lun_table_show() - presents the current LUN table of port 1 | |
| 2803 | − * @dev: Generic device associated with the host owning the port. | |
| 2804 | − * @attr: Device attribute representing the port. | |
| 2805 | − * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. | |
| 2806 | − * | |
| 2807 | − * Return: The size of the ASCII string returned in @buf. | |
| 2808 | − */ | |
| 2809 | −static ssize_t port1_lun_table_show(struct device *dev, | |
| 2810 | − struct device_attribute *attr, | |
| 2811 | − char *buf) | |
| 2812 | −{ | |
| 2813 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2814 | − | |
| 2815 | − return cxlflash_show_port_lun_table(1, cfg, buf); | |
| 2816 | −} | |
| 2817 | − | |
| 2818 | −/** | |
| 2819 | − * port2_lun_table_show() - presents the current LUN table of port 2 | |
| 2820 | − * @dev: Generic device associated with the host owning the port. | |
| 2821 | − * @attr: Device attribute representing the port. | |
| 2822 | − * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. | |
| 2823 | − * | |
| 2824 | − * Return: The size of the ASCII string returned in @buf. | |
| 2825 | − */ | |
| 2826 | −static ssize_t port2_lun_table_show(struct device *dev, | |
| 2827 | − struct device_attribute *attr, | |
| 2828 | − char *buf) | |
| 2829 | −{ | |
| 2830 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2831 | − | |
| 2832 | − return cxlflash_show_port_lun_table(2, cfg, buf); | |
| 2833 | −} | |
| 2834 | − | |
| 2835 | −/** | |
| 2836 | − * port3_lun_table_show() - presents the current LUN table of port 3 | |
| 2837 | − * @dev: Generic device associated with the host owning the port. | |
| 2838 | − * @attr: Device attribute representing the port. | |
| 2839 | − * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. | |
| 2840 | − * | |
| 2841 | − * Return: The size of the ASCII string returned in @buf. | |
| 2842 | − */ | |
| 2843 | −static ssize_t port3_lun_table_show(struct device *dev, | |
| 2844 | − struct device_attribute *attr, | |
| 2845 | − char *buf) | |
| 2846 | −{ | |
| 2847 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2848 | − | |
| 2849 | − return cxlflash_show_port_lun_table(3, cfg, buf); | |
| 2850 | −} | |
| 2851 | − | |
| 2852 | −/** | |
| 2853 | − * irqpoll_weight_show() - presents the current IRQ poll weight for the host | |
| 2854 | − * @dev: Generic device associated with the host. | |
| 2855 | − * @attr: Device attribute representing the IRQ poll weight. | |
| 2856 | − * @buf: Buffer of length PAGE_SIZE to report back the current IRQ poll | |
| 2857 | − * weight in ASCII. | |
| 2858 | − * | |
| 2859 | − * An IRQ poll weight of 0 indicates polling is disabled. | |
| 2860 | − * | |
| 2861 | − * Return: The size of the ASCII string returned in @buf. | |
| 2862 | − */ | |
| 2863 | −static ssize_t irqpoll_weight_show(struct device *dev, | |
| 2864 | − struct device_attribute *attr, char *buf) | |
| 2865 | −{ | |
| 2866 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2867 | − struct afu *afu = cfg->afu; | |
| 2868 | − | |
| 2869 | − return scnprintf(buf, PAGE_SIZE, "%u\n", afu->irqpoll_weight); | |
| 2870 | −} | |
| 2871 | − | |
| 2872 | −/** | |
| 2873 | − * irqpoll_weight_store() - sets the current IRQ poll weight for the host | |
| 2874 | − * @dev: Generic device associated with the host. | |
| 2875 | − * @attr: Device attribute representing the IRQ poll weight. | |
| 2876 | − * @buf: Buffer of length PAGE_SIZE containing the desired IRQ poll | |
| 2877 | − * weight in ASCII. | |
| 2878 | − * @count: Length of data resizing in @buf. | |
| 2879 | − * | |
| 2880 | − * An IRQ poll weight of 0 indicates polling is disabled. | |
| 2881 | − * | |
| 2882 | − * Return: The size of the ASCII string returned in @buf. | |
| 2883 | − */ | |
| 2884 | −static ssize_t irqpoll_weight_store(struct device *dev, | |
| 2885 | − struct device_attribute *attr, | |
| 2886 | − const char *buf, size_t count) | |
| 2887 | −{ | |
| 2888 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2889 | − struct device *cfgdev = &cfg->dev->dev; | |
| 2890 | − struct afu *afu = cfg->afu; | |
| 2891 | − struct hwq *hwq; | |
| 2892 | − u32 weight; | |
| 2893 | − int rc, i; | |
| 2894 | − | |
| 2895 | − rc = kstrtouint(buf, 10, &weight); | |
| 2896 | − if (rc) | |
| 2897 | − return -EINVAL; | |
| 2898 | − | |
| 2899 | − if (weight > 256) { | |
| 2900 | − dev_info(cfgdev, | |
| 2901 | − "Invalid IRQ poll weight. It must be 256 or less.\n"); | |
| 2902 | − return -EINVAL; | |
| 2903 | − } | |
| 2904 | − | |
| 2905 | − if (weight == afu->irqpoll_weight) { | |
| 2906 | − dev_info(cfgdev, | |
| 2907 | − "Current IRQ poll weight has the same weight.\n"); | |
| 2908 | − return -EINVAL; | |
| 2909 | − } | |
| 2910 | − | |
| 2911 | − if (afu_is_irqpoll_enabled(afu)) { | |
| 2912 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 2913 | − hwq = get_hwq(afu, i); | |
| 2914 | − | |
| 2915 | − irq_poll_disable(&hwq->irqpoll); | |
| 2916 | − } | |
| 2917 | − } | |
| 2918 | − | |
| 2919 | − afu->irqpoll_weight = weight; | |
| 2920 | − | |
| 2921 | − if (weight > 0) { | |
| 2922 | − for (i = 0; i < afu->num_hwqs; i++) { | |
| 2923 | − hwq = get_hwq(afu, i); | |
| 2924 | − | |
| 2925 | − irq_poll_init(&hwq->irqpoll, weight, cxlflash_irqpoll); | |
| 2926 | − } | |
| 2927 | − } | |
| 2928 | − | |
| 2929 | − return count; | |
| 2930 | −} | |
| 2931 | − | |
| 2932 | −/** | |
| 2933 | − * num_hwqs_show() - presents the number of hardware queues for the host | |
| 2934 | − * @dev: Generic device associated with the host. | |
| 2935 | − * @attr: Device attribute representing the number of hardware queues. | |
| 2936 | − * @buf: Buffer of length PAGE_SIZE to report back the number of hardware | |
| 2937 | − * queues in ASCII. | |
| 2938 | − * | |
| 2939 | − * Return: The size of the ASCII string returned in @buf. | |
| 2940 | − */ | |
| 2941 | −static ssize_t num_hwqs_show(struct device *dev, | |
| 2942 | − struct device_attribute *attr, char *buf) | |
| 2943 | −{ | |
| 2944 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2945 | − struct afu *afu = cfg->afu; | |
| 2946 | − | |
| 2947 | − return scnprintf(buf, PAGE_SIZE, "%u\n", afu->num_hwqs); | |
| 2948 | −} | |
| 2949 | − | |
| 2950 | −/** | |
| 2951 | − * num_hwqs_store() - sets the number of hardware queues for the host | |
| 2952 | − * @dev: Generic device associated with the host. | |
| 2953 | − * @attr: Device attribute representing the number of hardware queues. | |
| 2954 | − * @buf: Buffer of length PAGE_SIZE containing the number of hardware | |
| 2955 | − * queues in ASCII. | |
| 2956 | − * @count: Length of data resizing in @buf. | |
| 2957 | − * | |
| 2958 | − * n > 0: num_hwqs = n | |
| 2959 | − * n = 0: num_hwqs = num_online_cpus() | |
| 2960 | − * n < 0: num_online_cpus() / abs(n) | |
| 2961 | − * | |
| 2962 | − * Return: The size of the ASCII string returned in @buf. | |
| 2963 | − */ | |
| 2964 | −static ssize_t num_hwqs_store(struct device *dev, | |
| 2965 | − struct device_attribute *attr, | |
| 2966 | − const char *buf, size_t count) | |
| 2967 | −{ | |
| 2968 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 2969 | − struct afu *afu = cfg->afu; | |
| 2970 | − int rc; | |
| 2971 | − int nhwqs, num_hwqs; | |
| 2972 | − | |
| 2973 | − rc = kstrtoint(buf, 10, &nhwqs); | |
| 2974 | − if (rc) | |
| 2975 | − return -EINVAL; | |
| 2976 | − | |
| 2977 | − if (nhwqs >= 1) | |
| 2978 | − num_hwqs = nhwqs; | |
| 2979 | − else if (nhwqs == 0) | |
| 2980 | − num_hwqs = num_online_cpus(); | |
| 2981 | − else | |
| 2982 | − num_hwqs = num_online_cpus() / abs(nhwqs); | |
| 2983 | − | |
| 2984 | − afu->desired_hwqs = min(num_hwqs, CXLFLASH_MAX_HWQS); | |
| 2985 | − WARN_ON_ONCE(afu->desired_hwqs == 0); | |
| 2986 | − | |
| 2987 | −retry: | |
| 2988 | − switch (cfg->state) { | |
| 2989 | − case STATE_NORMAL: | |
| 2990 | − cfg->state = STATE_RESET; | |
| 2991 | − drain_ioctls(cfg); | |
| 2992 | − cxlflash_mark_contexts_error(cfg); | |
| 2993 | − rc = afu_reset(cfg); | |
| 2994 | − if (rc) | |
| 2995 | − cfg->state = STATE_FAILTERM; | |
| 2996 | − else | |
| 2997 | − cfg->state = STATE_NORMAL; | |
| 2998 | − wake_up_all(&cfg->reset_waitq); | |
| 2999 | − break; | |
| 3000 | − case STATE_RESET: | |
| 3001 | − wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); | |
| 3002 | − if (cfg->state == STATE_NORMAL) | |
| 3003 | − goto retry; | |
| 3004 | − fallthrough; | |
| 3005 | − default: | |
| 3006 | − /* Ideally should not happen */ | |
| 3007 | − dev_err(dev, "%s: Device is not ready, state=%d\n", | |
| 3008 | − __func__, cfg->state); | |
| 3009 | − break; | |
| 3010 | − } | |
| 3011 | − | |
| 3012 | − return count; | |
| 3013 | −} | |
| 3014 | − | |
| 3015 | −static const char *hwq_mode_name[MAX_HWQ_MODE] = { "rr", "tag", "cpu" }; | |
| 3016 | − | |
| 3017 | −/** | |
| 3018 | − * hwq_mode_show() - presents the HWQ steering mode for the host | |
| 3019 | − * @dev: Generic device associated with the host. | |
| 3020 | − * @attr: Device attribute representing the HWQ steering mode. | |
| 3021 | − * @buf: Buffer of length PAGE_SIZE to report back the HWQ steering mode | |
| 3022 | − * as a character string. | |
| 3023 | − * | |
| 3024 | − * Return: The size of the ASCII string returned in @buf. | |
| 3025 | − */ | |
| 3026 | −static ssize_t hwq_mode_show(struct device *dev, | |
| 3027 | − struct device_attribute *attr, char *buf) | |
| 3028 | −{ | |
| 3029 | − struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev)); | |
| 3030 | − struct afu *afu = cfg->afu; | |
| 3031 | − | |
| 3032 | − return scnprintf(buf, PAGE_SIZE, "%s\n", hwq_mode_name[afu->hwq_mode]); | |
| 3033 | −} | |
| 3034 | − | |
| 3035 | −/** | |
| 3036 | − * hwq_mode_store() - sets the HWQ steering mode for the host | |
| 3037 | − * @dev: Generic device associated with the host. | |
| 3038 | − * @attr: Device attribute representing the HWQ steering mode. | |
| 3039 | − * @buf: Buffer of length PAGE_SIZE containing the HWQ steering mode | |
| 3040 | − * as a character string. | |
| 3041 | − * @count: Length of data resizing in @buf. | |
| 3042 | − * | |
| 3043 | − * rr = Round-Robin | |
| 3044 | − * tag = Block MQ Tagging | |
| 3045 | − * cpu = CPU Affinity | |
| 3046 | − * | |
| 3047 | − * Return: The size of the ASCII string returned in @buf. | |
| 3048 | − */ | |
| 3049 | −static ssize_t hwq_mode_store(struct device *dev, | |
| 3050 | − struct device_attribute *attr, | |
| 3051 | − const char *buf, size_t count) | |
| 3052 | −{ | |
| 3053 | − struct Scsi_Host *shost = class_to_shost(dev); | |
| 3054 | − struct cxlflash_cfg *cfg = shost_priv(shost); | |
| 3055 | − struct device *cfgdev = &cfg->dev->dev; | |
| 3056 | − struct afu *afu = cfg->afu; | |
| 3057 | − int i; | |
| 3058 | − u32 mode = MAX_HWQ_MODE; | |
| 3059 | − | |
| 3060 | − for (i = 0; i < MAX_HWQ_MODE; i++) { | |
| 3061 | − if (!strncmp(hwq_mode_name[i], buf, strlen(hwq_mode_name[i]))) { | |
| 3062 | − mode = i; | |
| 3063 | − break; | |
| 3064 | − } | |
| 3065 | − } | |
| 3066 | − | |
| 3067 | − if (mode >= MAX_HWQ_MODE) { | |
| 3068 | − dev_info(cfgdev, "Invalid HWQ steering mode.\n"); | |
| 3069 | − return -EINVAL; | |
| 3070 | − } | |
| 3071 | − | |
| 3072 | − afu->hwq_mode = mode; | |
| 3073 | − | |
| 3074 | − return count; | |
| 3075 | −} | |
| 3076 | − | |
| 3077 | −/** | |
| 3078 | − * mode_show() - presents the current mode of the device | |
| 3079 | − * @dev: Generic device associated with the device. | |
| 3080 | − * @attr: Device attribute representing the device mode. | |
| 3081 | − * @buf: Buffer of length PAGE_SIZE to report back the dev mode in ASCII. | |
| 3082 | − * | |
| 3083 | − * Return: The size of the ASCII string returned in @buf. | |
| 3084 | − */ | |
| 3085 | −static ssize_t mode_show(struct device *dev, | |
| 3086 | − struct device_attribute *attr, char *buf) | |
| 3087 | −{ | |
| 3088 | − struct scsi_device *sdev = to_scsi_device(dev); | |
| 3089 | − | |
| 3090 | − return scnprintf(buf, PAGE_SIZE, "%s\n", | |
| 3091 | − sdev->hostdata ? "superpipe" : "legacy"); | |
| 3092 | −} | |
| 3093 | − | |
| 3094 | −/* | |
| 3095 | − * Host attributes | |
| 3096 | − */ | |
| 3097 | −static DEVICE_ATTR_RO(port0); | |
| 3098 | −static DEVICE_ATTR_RO(port1); | |
| 3099 | −static DEVICE_ATTR_RO(port2); | |
| 3100 | −static DEVICE_ATTR_RO(port3); | |
| 3101 | −static DEVICE_ATTR_RW(lun_mode); | |
| 3102 | −static DEVICE_ATTR_RO(ioctl_version); | |
| 3103 | −static DEVICE_ATTR_RO(port0_lun_table); | |
| 3104 | −static DEVICE_ATTR_RO(port1_lun_table); | |
| 3105 | −static DEVICE_ATTR_RO(port2_lun_table); | |
| 3106 | −static DEVICE_ATTR_RO(port3_lun_table); | |
| 3107 | −static DEVICE_ATTR_RW(irqpoll_weight); | |
| 3108 | −static DEVICE_ATTR_RW(num_hwqs); | |
| 3109 | −static DEVICE_ATTR_RW(hwq_mode); | |
| 3110 | − | |
| 3111 | −static struct attribute *cxlflash_host_attrs[] = { | |
| 3112 | − &dev_attr_port0.attr, | |
| 3113 | − &dev_attr_port1.attr, | |
| 3114 | − &dev_attr_port2.attr, | |
| 3115 | − &dev_attr_port3.attr, | |
| 3116 | − &dev_attr_lun_mode.attr, | |
| 3117 | − &dev_attr_ioctl_version.attr, | |
| 3118 | − &dev_attr_port0_lun_table.attr, | |
| 3119 | − &dev_attr_port1_lun_table.attr, | |
| 3120 | − &dev_attr_port2_lun_table.attr, | |
| 3121 | − &dev_attr_port3_lun_table.attr, | |
| 3122 | − &dev_attr_irqpoll_weight.attr, | |
| 3123 | − &dev_attr_num_hwqs.attr, | |
| 3124 | − &dev_attr_hwq_mode.attr, | |
| 3125 | − NULL | |
| 3126 | −}; | |
| 3127 | − | |
| 3128 | −ATTRIBUTE_GROUPS(cxlflash_host); | |
| 3129 | − | |
| 3130 | −/* | |
| 3131 | − * Device attributes | |
| 3132 | − */ | |
| 3133 | −static DEVICE_ATTR_RO(mode); | |
| 3134 | − | |
| 3135 | −static struct attribute *cxlflash_dev_attrs[] = { | |
| 3136 | − &dev_attr_mode.attr, | |
| 3137 | − NULL | |
| 3138 | −}; | |
| 3139 | − | |
| 3140 | −ATTRIBUTE_GROUPS(cxlflash_dev); | |
| 3141 | − | |
| 3142 | −/* | |
| 3143 | − * Host template | |
| 3144 | − */ | |
| 3145 | −static struct scsi_host_template driver_template = { | |
| 3146 | − .module = THIS_MODULE, | |
| 3147 | − .name = CXLFLASH_ADAPTER_NAME, | |
| 3148 | − .info = cxlflash_driver_info, | |
| 3149 | − .ioctl = cxlflash_ioctl, | |
| 3150 | − .proc_name = CXLFLASH_NAME, | |
| 3151 | − .queuecommand = cxlflash_queuecommand, | |
| 3152 | − .eh_abort_handler = cxlflash_eh_abort_handler, | |
| 3153 | − .eh_device_reset_handler = cxlflash_eh_device_reset_handler, | |
| 3154 | − .eh_host_reset_handler = cxlflash_eh_host_reset_handler, | |
| 3155 | − .change_queue_depth = cxlflash_change_queue_depth, | |
| 3156 | − .cmd_per_lun = CXLFLASH_MAX_CMDS_PER_LUN, | |
| 3157 | − .can_queue = CXLFLASH_MAX_CMDS, | |
| 3158 | − .cmd_size = sizeof(struct afu_cmd) + __alignof__(struct afu_cmd) - 1, | |
| 3159 | − .this_id = -1, | |
| 3160 | − .sg_tablesize = 1, /* No scatter gather support */ | |
| 3161 | − .max_sectors = CXLFLASH_MAX_SECTORS, | |
| 3162 | − .shost_groups = cxlflash_host_groups, | |
| 3163 | − .sdev_groups = cxlflash_dev_groups, | |
| 3164 | −}; | |
| 3165 | − | |
| 3166 | −/* | |
| 3167 | − * Device dependent values | |
| 3168 | − */ | |
| 3169 | −static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS, | |
| 3170 | − CXLFLASH_WWPN_VPD_REQUIRED }; | |
| 3171 | −static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS, | |
| 3172 | − CXLFLASH_NOTIFY_SHUTDOWN }; | |
| 3173 | −static struct dev_dependent_vals dev_briard_vals = { CXLFLASH_MAX_SECTORS, | |
| 3174 | − (CXLFLASH_NOTIFY_SHUTDOWN | | |
| 3175 | − CXLFLASH_OCXL_DEV) }; | |
| 3176 | − | |
| 3177 | −/* | |
| 3178 | − * PCI device binding table | |
| 3179 | − */ | |
| 3180 | −static const struct pci_device_id cxlflash_pci_table[] = { | |
| 3181 | − {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA, | |
| 3182 | − PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals}, | |
| 3183 | − {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_FLASH_GT, | |
| 3184 | − PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_flash_gt_vals}, | |
| 3185 | − {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_BRIARD, | |
| 3186 | − PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_briard_vals}, | |
| 3187 | − {} | |
| 3188 | −}; | |
| 3189 | − | |
| 3190 | −MODULE_DEVICE_TABLE(pci, cxlflash_pci_table); | |
| 3191 | − | |
| 3192 | −/** | |
| 3193 | − * cxlflash_worker_thread() - work thread handler for the AFU | |
| 3194 | − * @work: Work structure contained within cxlflash associated with host. | |
| 3195 | − * | |
| 3196 | − * Handles the following events: | |
| 3197 | − * - Link reset which cannot be performed on interrupt context due to | |
| 3198 | − * blocking up to a few seconds | |
| 3199 | − * - Rescan the host | |
| 3200 | − */ | |
| 3201 | −static void cxlflash_worker_thread(struct work_struct *work) | |
| 3202 | −{ | |
| 3203 | − struct cxlflash_cfg *cfg = container_of(work, struct cxlflash_cfg, | |
| 3204 | − work_q); | |
| 3205 | − struct afu *afu = cfg->afu; | |
| 3206 | − struct device *dev = &cfg->dev->dev; | |
| 3207 | − __be64 __iomem *fc_port_regs; | |
| 3208 | − int port; | |
| 3209 | − ulong lock_flags; | |
| 3210 | − | |
| 3211 | − /* Avoid MMIO if the device has failed */ | |
| 3212 | − | |
| 3213 | − if (cfg->state != STATE_NORMAL) | |
| 3214 | − return; | |
| 3215 | − | |
| 3216 | − spin_lock_irqsave(cfg->host->host_lock, lock_flags); | |
| 3217 | − | |
| 3218 | − if (cfg->lr_state == LINK_RESET_REQUIRED) { | |
| 3219 | − port = cfg->lr_port; | |
| 3220 | − if (port < 0) | |
| 3221 | − dev_err(dev, "%s: invalid port index %d\n", | |
| 3222 | − __func__, port); | |
| 3223 | − else { | |
| 3224 | − spin_unlock_irqrestore(cfg->host->host_lock, | |
| 3225 | − lock_flags); | |
| 3226 | − | |
| 3227 | − /* The reset can block... */ | |
| 3228 | − fc_port_regs = get_fc_port_regs(cfg, port); | |
| 3229 | − afu_link_reset(afu, port, fc_port_regs); | |
| 3230 | − spin_lock_irqsave(cfg->host->host_lock, lock_flags); | |
| 3231 | − } | |
| 3232 | − | |
| 3233 | − cfg->lr_state = LINK_RESET_COMPLETE; | |
| 3234 | − } | |
| 3235 | − | |
| 3236 | − spin_unlock_irqrestore(cfg->host->host_lock, lock_flags); | |
| 3237 | − | |
| 3238 | − if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0) | |
| 3239 | − scsi_scan_host(cfg->host); | |
| 3240 | −} | |
| 3241 | − | |
| 3242 | −/** | |
| 3243 | − * cxlflash_chr_open() - character device open handler | |
| 3244 | − * @inode: Device inode associated with this character device. | |
| 3245 | − * @file: File pointer for this device. | |
| 3246 | − * | |
| 3247 | − * Only users with admin privileges are allowed to open the character device. | |
| 3248 | − * | |
| 3249 | − * Return: 0 on success, -errno on failure | |
| 3250 | − */ | |
| 3251 | −static int cxlflash_chr_open(struct inode *inode, struct file *file) | |
| 3252 | −{ | |
| 3253 | − struct cxlflash_cfg *cfg; | |
| 3254 | − | |
| 3255 | − if (!capable(CAP_SYS_ADMIN)) | |
| 3256 | − return -EACCES; | |
| 3257 | − | |
| 3258 | − cfg = container_of(inode->i_cdev, struct cxlflash_cfg, cdev); | |
| 3259 | − file->private_data = cfg; | |
| 3260 | − | |
| 3261 | − return 0; | |
| 3262 | −} | |
| 3263 | − | |
| 3264 | −/** | |
| 3265 | − * decode_hioctl() - translates encoded host ioctl to easily identifiable string | |
| 3266 | − * @cmd: The host ioctl command to decode. | |
| 3267 | − * | |
| 3268 | − * Return: A string identifying the decoded host ioctl. | |
| 3269 | − */ | |
| 3270 | −static char *decode_hioctl(unsigned int cmd) | |
| 3271 | −{ | |
| 3272 | − switch (cmd) { | |
| 3273 | − case HT_CXLFLASH_LUN_PROVISION: | |
| 3274 | − return __stringify_1(HT_CXLFLASH_LUN_PROVISION); | |
| 3275 | − } | |
| 3276 | − | |
| 3277 | − return "UNKNOWN"; | |
| 3278 | −} | |
| 3279 | − | |
| 3280 | −/** | |
| 3281 | − * cxlflash_lun_provision() - host LUN provisioning handler | |
| 3282 | − * @cfg: Internal structure associated with the host. | |
| 3283 | − * @arg: Kernel copy of userspace ioctl data structure. | |
| 3284 | − * | |
| 3285 | − * Return: 0 on success, -errno on failure | |
| 3286 | − */ | |
| 3287 | −static int cxlflash_lun_provision(struct cxlflash_cfg *cfg, void *arg) | |
| 3288 | −{ | |
| 3289 | − struct ht_cxlflash_lun_provision *lunprov = arg; | |
| 3290 | − struct afu *afu = cfg->afu; | |
| 3291 | − struct device *dev = &cfg->dev->dev; | |
| 3292 | − struct sisl_ioarcb rcb; | |
| 3293 | − struct sisl_ioasa asa; | |
| 3294 | − __be64 __iomem *fc_port_regs; | |
| 3295 | − u16 port = lunprov->port; | |
| 3296 | − u16 scmd = lunprov->hdr.subcmd; | |
| 3297 | − u16 type; | |
| 3298 | − u64 reg; | |
| 3299 | − u64 size; | |
| 3300 | − u64 lun_id; | |
| 3301 | − int rc = 0; | |
| 3302 | − | |
| 3303 | − if (!afu_is_lun_provision(afu)) { | |
| 3304 | − rc = -ENOTSUPP; | |
| 3305 | − goto out; | |
| 3306 | − } | |
| 3307 | − | |
| 3308 | − if (port >= cfg->num_fc_ports) { | |
| 3309 | − rc = -EINVAL; | |
| 3310 | − goto out; | |
| 3311 | − } | |
| 3312 | − | |
| 3313 | − switch (scmd) { | |
| 3314 | − case HT_CXLFLASH_LUN_PROVISION_SUBCMD_CREATE_LUN: | |
| 3315 | − type = SISL_AFU_LUN_PROVISION_CREATE; | |
| 3316 | − size = lunprov->size; | |
| 3317 | − lun_id = 0; | |
| 3318 | − break; | |
| 3319 | − case HT_CXLFLASH_LUN_PROVISION_SUBCMD_DELETE_LUN: | |
| 3320 | − type = SISL_AFU_LUN_PROVISION_DELETE; | |
| 3321 | − size = 0; | |
| 3322 | − lun_id = lunprov->lun_id; | |
| 3323 | − break; | |
| 3324 | − case HT_CXLFLASH_LUN_PROVISION_SUBCMD_QUERY_PORT: | |
| 3325 | − fc_port_regs = get_fc_port_regs(cfg, port); | |
| 3326 | − | |
| 3327 | − reg = readq_be(&fc_port_regs[FC_MAX_NUM_LUNS / 8]); | |
| 3328 | − lunprov->max_num_luns = reg; | |
| 3329 | − reg = readq_be(&fc_port_regs[FC_CUR_NUM_LUNS / 8]); | |
| 3330 | − lunprov->cur_num_luns = reg; | |
| 3331 | − reg = readq_be(&fc_port_regs[FC_MAX_CAP_PORT / 8]); | |
| 3332 | − lunprov->max_cap_port = reg; | |
| 3333 | − reg = readq_be(&fc_port_regs[FC_CUR_CAP_PORT / 8]); | |
| 3334 | − lunprov->cur_cap_port = reg; | |
| 3335 | − | |
| 3336 | − goto out; | |
| 3337 | − default: | |
| 3338 | − rc = -EINVAL; | |
| 3339 | − goto out; | |
| 3340 | − } | |
| 3341 | − | |
| 3342 | − memset(&rcb, 0, sizeof(rcb)); | |
| 3343 | − memset(&asa, 0, sizeof(asa)); | |
| 3344 | − rcb.req_flags = SISL_REQ_FLAGS_AFU_CMD; | |
| 3345 | − rcb.lun_id = lun_id; | |
| 3346 | − rcb.msi = SISL_MSI_RRQ_UPDATED; | |
| 3347 | − rcb.timeout = MC_LUN_PROV_TIMEOUT; | |
| 3348 | − rcb.ioasa = &asa; | |
| 3349 | − | |
| 3350 | − rcb.cdb[0] = SISL_AFU_CMD_LUN_PROVISION; | |
| 3351 | − rcb.cdb[1] = type; | |
| 3352 | − rcb.cdb[2] = port; | |
| 3353 | − put_unaligned_be64(size, &rcb.cdb[8]); | |
| 3354 | − | |
| 3355 | − rc = send_afu_cmd(afu, &rcb); | |
| 3356 | − if (rc) { | |
| 3357 | − dev_err(dev, "%s: send_afu_cmd failed rc=%d asc=%08x afux=%x\n", | |
| 3358 | − __func__, rc, asa.ioasc, asa.afu_extra); | |
| 3359 | − goto out; | |
| 3360 | − } | |
| 3361 | − | |
| 3362 | − if (scmd == HT_CXLFLASH_LUN_PROVISION_SUBCMD_CREATE_LUN) { | |
| 3363 | − lunprov->lun_id = (u64)asa.lunid_hi << 32 | asa.lunid_lo; | |
| 3364 | − memcpy(lunprov->wwid, asa.wwid, sizeof(lunprov->wwid)); | |
| 3365 | − } | |
| 3366 | −out: | |
| 3367 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 3368 | − return rc; | |
| 3369 | −} | |
| 3370 | − | |
| 3371 | −/** | |
| 3372 | − * cxlflash_afu_debug() - host AFU debug handler | |
| 3373 | − * @cfg: Internal structure associated with the host. | |
| 3374 | − * @arg: Kernel copy of userspace ioctl data structure. | |
| 3375 | − * | |
| 3376 | − * For debug requests requiring a data buffer, always provide an aligned | |
| 3377 | − * (cache line) buffer to the AFU to appease any alignment requirements. | |
| 3378 | − * | |
| 3379 | − * Return: 0 on success, -errno on failure | |
| 3380 | − */ | |
| 3381 | −static int cxlflash_afu_debug(struct cxlflash_cfg *cfg, void *arg) | |
| 3382 | −{ | |
| 3383 | − struct ht_cxlflash_afu_debug *afu_dbg = arg; | |
| 3384 | − struct afu *afu = cfg->afu; | |
| 3385 | − struct device *dev = &cfg->dev->dev; | |
| 3386 | − struct sisl_ioarcb rcb; | |
| 3387 | − struct sisl_ioasa asa; | |
| 3388 | − char *buf = NULL; | |
| 3389 | − char *kbuf = NULL; | |
| 3390 | − void __user *ubuf = (__force void __user *)afu_dbg->data_ea; | |
| 3391 | − u16 req_flags = SISL_REQ_FLAGS_AFU_CMD; | |
| 3392 | − u32 ulen = afu_dbg->data_len; | |
| 3393 | − bool is_write = afu_dbg->hdr.flags & HT_CXLFLASH_HOST_WRITE; | |
| 3394 | − int rc = 0; | |
| 3395 | − | |
| 3396 | − if (!afu_is_afu_debug(afu)) { | |
| 3397 | − rc = -ENOTSUPP; | |
| 3398 | − goto out; | |
| 3399 | − } | |
| 3400 | − | |
| 3401 | − if (ulen) { | |
| 3402 | − req_flags |= SISL_REQ_FLAGS_SUP_UNDERRUN; | |
| 3403 | − | |
| 3404 | − if (ulen > HT_CXLFLASH_AFU_DEBUG_MAX_DATA_LEN) { | |
| 3405 | − rc = -EINVAL; | |
| 3406 | − goto out; | |
| 3407 | − } | |
| 3408 | − | |
| 3409 | − buf = kmalloc(ulen + cache_line_size() - 1, GFP_KERNEL); | |
| 3410 | − if (unlikely(!buf)) { | |
| 3411 | − rc = -ENOMEM; | |
| 3412 | − goto out; | |
| 3413 | − } | |
| 3414 | − | |
| 3415 | − kbuf = PTR_ALIGN(buf, cache_line_size()); | |
| 3416 | − | |
| 3417 | − if (is_write) { | |
| 3418 | − req_flags |= SISL_REQ_FLAGS_HOST_WRITE; | |
| 3419 | − | |
| 3420 | − if (copy_from_user(kbuf, ubuf, ulen)) { | |
| 3421 | − rc = -EFAULT; | |
| 3422 | − goto out; | |
| 3423 | − } | |
| 3424 | − } | |
| 3425 | − } | |
| 3426 | − | |
| 3427 | − memset(&rcb, 0, sizeof(rcb)); | |
| 3428 | − memset(&asa, 0, sizeof(asa)); | |
| 3429 | − | |
| 3430 | − rcb.req_flags = req_flags; | |
| 3431 | − rcb.msi = SISL_MSI_RRQ_UPDATED; | |
| 3432 | − rcb.timeout = MC_AFU_DEBUG_TIMEOUT; | |
| 3433 | − rcb.ioasa = &asa; | |
| 3434 | − | |
| 3435 | − if (ulen) { | |
| 3436 | − rcb.data_len = ulen; | |
| 3437 | − rcb.data_ea = (uintptr_t)kbuf; | |
| 3438 | − } | |
| 3439 | − | |
| 3440 | − rcb.cdb[0] = SISL_AFU_CMD_DEBUG; | |
| 3441 | − memcpy(&rcb.cdb[4], afu_dbg->afu_subcmd, | |
| 3442 | − HT_CXLFLASH_AFU_DEBUG_SUBCMD_LEN); | |
| 3443 | − | |
| 3444 | − rc = send_afu_cmd(afu, &rcb); | |
| 3445 | − if (rc) { | |
| 3446 | − dev_err(dev, "%s: send_afu_cmd failed rc=%d asc=%08x afux=%x\n", | |
| 3447 | − __func__, rc, asa.ioasc, asa.afu_extra); | |
| 3448 | − goto out; | |
| 3449 | − } | |
| 3450 | − | |
| 3451 | − if (ulen && !is_write) { | |
| 3452 | − if (copy_to_user(ubuf, kbuf, ulen)) | |
| 3453 | − rc = -EFAULT; | |
| 3454 | − } | |
| 3455 | −out: | |
| 3456 | − kfree(buf); | |
| 3457 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 3458 | − return rc; | |
| 3459 | −} | |
| 3460 | − | |
| 3461 | −/** | |
| 3462 | − * cxlflash_chr_ioctl() - character device IOCTL handler | |
| 3463 | − * @file: File pointer for this device. | |
| 3464 | − * @cmd: IOCTL command. | |
| 3465 | − * @arg: Userspace ioctl data structure. | |
| 3466 | − * | |
| 3467 | − * A read/write semaphore is used to implement a 'drain' of currently | |
| 3468 | − * running ioctls. The read semaphore is taken at the beginning of each | |
| 3469 | − * ioctl thread and released upon concluding execution. Additionally the | |
| 3470 | − * semaphore should be released and then reacquired in any ioctl execution | |
| 3471 | − * path which will wait for an event to occur that is outside the scope of | |
| 3472 | − * the ioctl (i.e. an adapter reset). To drain the ioctls currently running, | |
| 3473 | − * a thread simply needs to acquire the write semaphore. | |
| 3474 | − * | |
| 3475 | − * Return: 0 on success, -errno on failure | |
| 3476 | − */ | |
| 3477 | −static long cxlflash_chr_ioctl(struct file *file, unsigned int cmd, | |
| 3478 | − unsigned long arg) | |
| 3479 | −{ | |
| 3480 | − typedef int (*hioctl) (struct cxlflash_cfg *, void *); | |
| 3481 | − | |
| 3482 | − struct cxlflash_cfg *cfg = file->private_data; | |
| 3483 | − struct device *dev = &cfg->dev->dev; | |
| 3484 | − char buf[sizeof(union cxlflash_ht_ioctls)]; | |
| 3485 | − void __user *uarg = (void __user *)arg; | |
| 3486 | − struct ht_cxlflash_hdr *hdr; | |
| 3487 | − size_t size = 0; | |
| 3488 | − bool known_ioctl = false; | |
| 3489 | − int idx = 0; | |
| 3490 | − int rc = 0; | |
| 3491 | − hioctl do_ioctl = NULL; | |
| 3492 | − | |
| 3493 | − static const struct { | |
| 3494 | − size_t size; | |
| 3495 | − hioctl ioctl; | |
| 3496 | − } ioctl_tbl[] = { /* NOTE: order matters here */ | |
| 3497 | − { sizeof(struct ht_cxlflash_lun_provision), cxlflash_lun_provision }, | |
| 3498 | − { sizeof(struct ht_cxlflash_afu_debug), cxlflash_afu_debug }, | |
| 3499 | − }; | |
| 3500 | − | |
| 3501 | − /* Hold read semaphore so we can drain if needed */ | |
| 3502 | − down_read(&cfg->ioctl_rwsem); | |
| 3503 | − | |
| 3504 | − dev_dbg(dev, "%s: cmd=%u idx=%d tbl_size=%lu\n", | |
| 3505 | − __func__, cmd, idx, sizeof(ioctl_tbl)); | |
| 3506 | − | |
| 3507 | − switch (cmd) { | |
| 3508 | − case HT_CXLFLASH_LUN_PROVISION: | |
| 3509 | − case HT_CXLFLASH_AFU_DEBUG: | |
| 3510 | − known_ioctl = true; | |
| 3511 | − idx = _IOC_NR(HT_CXLFLASH_LUN_PROVISION) - _IOC_NR(cmd); | |
| 3512 | − size = ioctl_tbl[idx].size; | |
| 3513 | − do_ioctl = ioctl_tbl[idx].ioctl; | |
| 3514 | − | |
| 3515 | − if (likely(do_ioctl)) | |
| 3516 | − break; | |
| 3517 | − | |
| 3518 | − fallthrough; | |
| 3519 | − default: | |
| 3520 | − rc = -EINVAL; | |
| 3521 | − goto out; | |
| 3522 | − } | |
| 3523 | − | |
| 3524 | − if (unlikely(copy_from_user(&buf, uarg, size))) { | |
| 3525 | − dev_err(dev, "%s: copy_from_user() fail " | |
| 3526 | − "size=%lu cmd=%d (%s) uarg=%p\n", | |
| 3527 | − __func__, size, cmd, decode_hioctl(cmd), uarg); | |
| 3528 | − rc = -EFAULT; | |
| 3529 | − goto out; | |
| 3530 | − } | |
| 3531 | − | |
| 3532 | − hdr = (struct ht_cxlflash_hdr *)&buf; | |
| 3533 | − if (hdr->version != HT_CXLFLASH_VERSION_0) { | |
| 3534 | − dev_dbg(dev, "%s: Version %u not supported for %s\n", | |
| 3535 | − __func__, hdr->version, decode_hioctl(cmd)); | |
| 3536 | − rc = -EINVAL; | |
| 3537 | − goto out; | |
| 3538 | − } | |
| 3539 | − | |
| 3540 | − if (hdr->rsvd[0] || hdr->rsvd[1] || hdr->return_flags) { | |
| 3541 | − dev_dbg(dev, "%s: Reserved/rflags populated\n", __func__); | |
| 3542 | − rc = -EINVAL; | |
| 3543 | − goto out; | |
| 3544 | − } | |
| 3545 | − | |
| 3546 | − rc = do_ioctl(cfg, (void *)&buf); | |
| 3547 | − if (likely(!rc)) | |
| 3548 | − if (unlikely(copy_to_user(uarg, &buf, size))) { | |
| 3549 | − dev_err(dev, "%s: copy_to_user() fail " | |
| 3550 | − "size=%lu cmd=%d (%s) uarg=%p\n", | |
| 3551 | − __func__, size, cmd, decode_hioctl(cmd), uarg); | |
| 3552 | − rc = -EFAULT; | |
| 3553 | − } | |
| 3554 | − | |
| 3555 | − /* fall through to exit */ | |
| 3556 | − | |
| 3557 | −out: | |
| 3558 | − up_read(&cfg->ioctl_rwsem); | |
| 3559 | − if (unlikely(rc && known_ioctl)) | |
| 3560 | − dev_err(dev, "%s: ioctl %s (%08X) returned rc=%d\n", | |
| 3561 | − __func__, decode_hioctl(cmd), cmd, rc); | |
| 3562 | − else | |
| 3563 | − dev_dbg(dev, "%s: ioctl %s (%08X) returned rc=%d\n", | |
| 3564 | − __func__, decode_hioctl(cmd), cmd, rc); | |
| 3565 | − return rc; | |
| 3566 | −} | |
| 3567 | − | |
| 3568 | −/* | |
| 3569 | − * Character device file operations | |
| 3570 | − */ | |
| 3571 | −static const struct file_operations cxlflash_chr_fops = { | |
| 3572 | − .owner = THIS_MODULE, | |
| 3573 | − .open = cxlflash_chr_open, | |
| 3574 | − .unlocked_ioctl = cxlflash_chr_ioctl, | |
| 3575 | − .compat_ioctl = compat_ptr_ioctl, | |
| 3576 | −}; | |
| 3577 | − | |
| 3578 | −/** | |
| 3579 | − * init_chrdev() - initialize the character device for the host | |
| 3580 | − * @cfg: Internal structure associated with the host. | |
| 3581 | − * | |
| 3582 | − * Return: 0 on success, -errno on failure | |
| 3583 | − */ | |
| 3584 | −static int init_chrdev(struct cxlflash_cfg *cfg) | |
| 3585 | −{ | |
| 3586 | − struct device *dev = &cfg->dev->dev; | |
| 3587 | − struct device *char_dev; | |
| 3588 | − dev_t devno; | |
| 3589 | − int minor; | |
| 3590 | − int rc = 0; | |
| 3591 | − | |
| 3592 | − minor = cxlflash_get_minor(); | |
| 3593 | − if (unlikely(minor < 0)) { | |
| 3594 | − dev_err(dev, "%s: Exhausted allowed adapters\n", __func__); | |
| 3595 | − rc = -ENOSPC; | |
| 3596 | − goto out; | |
| 3597 | − } | |
| 3598 | − | |
| 3599 | − devno = MKDEV(cxlflash_major, minor); | |
| 3600 | − cdev_init(&cfg->cdev, &cxlflash_chr_fops); | |
| 3601 | − | |
| 3602 | − rc = cdev_add(&cfg->cdev, devno, 1); | |
| 3603 | − if (rc) { | |
| 3604 | − dev_err(dev, "%s: cdev_add failed rc=%d\n", __func__, rc); | |
| 3605 | − goto err1; | |
| 3606 | − } | |
| 3607 | − | |
| 3608 | − char_dev = device_create(&cxlflash_class, NULL, devno, | |
| 3609 | − NULL, "cxlflash%d", minor); | |
| 3610 | − if (IS_ERR(char_dev)) { | |
| 3611 | − rc = PTR_ERR(char_dev); | |
| 3612 | − dev_err(dev, "%s: device_create failed rc=%d\n", | |
| 3613 | − __func__, rc); | |
| 3614 | − goto err2; | |
| 3615 | − } | |
| 3616 | − | |
| 3617 | − cfg->chardev = char_dev; | |
| 3618 | −out: | |
| 3619 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 3620 | − return rc; | |
| 3621 | −err2: | |
| 3622 | − cdev_del(&cfg->cdev); | |
| 3623 | −err1: | |
| 3624 | − cxlflash_put_minor(minor); | |
| 3625 | − goto out; | |
| 3626 | −} | |
| 3627 | − | |
| 3628 | −/** | |
| 3629 | − * cxlflash_probe() - PCI entry point to add host | |
| 3630 | − * @pdev: PCI device associated with the host. | |
| 3631 | − * @dev_id: PCI device id associated with device. | |
| 3632 | − * | |
| 3633 | − * The device will initially start out in a 'probing' state and | |
| 3634 | − * transition to the 'normal' state at the end of a successful | |
| 3635 | − * probe. Should an EEH event occur during probe, the notification | |
| 3636 | − * thread (error_detected()) will wait until the probe handler | |
| 3637 | − * is nearly complete. At that time, the device will be moved to | |
| 3638 | − * a 'probed' state and the EEH thread woken up to drive the slot | |
| 3639 | − * reset and recovery (device moves to 'normal' state). Meanwhile, | |
| 3640 | − * the probe will be allowed to exit successfully. | |
| 3641 | − * | |
| 3642 | − * Return: 0 on success, -errno on failure | |
| 3643 | − */ | |
| 3644 | −static int cxlflash_probe(struct pci_dev *pdev, | |
| 3645 | − const struct pci_device_id *dev_id) | |
| 3646 | −{ | |
| 3647 | − struct Scsi_Host *host; | |
| 3648 | − struct cxlflash_cfg *cfg = NULL; | |
| 3649 | − struct device *dev = &pdev->dev; | |
| 3650 | − struct dev_dependent_vals *ddv; | |
| 3651 | − int rc = 0; | |
| 3652 | − int k; | |
| 3653 | − | |
| 3654 | − dev_err_once(&pdev->dev, "DEPRECATION: cxlflash is deprecated and will be removed in a future kernel release\n"); | |
| 3655 | − | |
| 3656 | − dev_dbg(&pdev->dev, "%s: Found CXLFLASH with IRQ: %d\n", | |
| 3657 | − __func__, pdev->irq); | |
| 3658 | − | |
| 3659 | − ddv = (struct dev_dependent_vals *)dev_id->driver_data; | |
| 3660 | − driver_template.max_sectors = ddv->max_sectors; | |
| 3661 | − | |
| 3662 | − host = scsi_host_alloc(&driver_template, sizeof(struct cxlflash_cfg)); | |
| 3663 | − if (!host) { | |
| 3664 | − dev_err(dev, "%s: scsi_host_alloc failed\n", __func__); | |
| 3665 | − rc = -ENOMEM; | |
| 3666 | − goto out; | |
| 3667 | − } | |
| 3668 | − | |
| 3669 | − host->max_id = CXLFLASH_MAX_NUM_TARGETS_PER_BUS; | |
| 3670 | − host->max_lun = CXLFLASH_MAX_NUM_LUNS_PER_TARGET; | |
| 3671 | − host->unique_id = host->host_no; | |
| 3672 | − host->max_cmd_len = CXLFLASH_MAX_CDB_LEN; | |
| 3673 | − | |
| 3674 | − cfg = shost_priv(host); | |
| 3675 | − cfg->state = STATE_PROBING; | |
| 3676 | − cfg->host = host; | |
| 3677 | − rc = alloc_mem(cfg); | |
| 3678 | − if (rc) { | |
| 3679 | − dev_err(dev, "%s: alloc_mem failed\n", __func__); | |
| 3680 | − rc = -ENOMEM; | |
| 3681 | − scsi_host_put(cfg->host); | |
| 3682 | − goto out; | |
| 3683 | − } | |
| 3684 | − | |
| 3685 | − cfg->init_state = INIT_STATE_NONE; | |
| 3686 | − cfg->dev = pdev; | |
| 3687 | − cfg->cxl_fops = cxlflash_cxl_fops; | |
| 3688 | − cfg->ops = cxlflash_assign_ops(ddv); | |
| 3689 | − WARN_ON_ONCE(!cfg->ops); | |
| 3690 | − | |
| 3691 | − /* | |
| 3692 | − * Promoted LUNs move to the top of the LUN table. The rest stay on | |
| 3693 | − * the bottom half. The bottom half grows from the end (index = 255), | |
| 3694 | − * whereas the top half grows from the beginning (index = 0). | |
| 3695 | − * | |
| 3696 | − * Initialize the last LUN index for all possible ports. | |
| 3697 | − */ | |
| 3698 | − cfg->promote_lun_index = 0; | |
| 3699 | − | |
| 3700 | − for (k = 0; k < MAX_FC_PORTS; k++) | |
| 3701 | − cfg->last_lun_index[k] = CXLFLASH_NUM_VLUNS/2 - 1; | |
| 3702 | − | |
| 3703 | − cfg->dev_id = (struct pci_device_id *)dev_id; | |
| 3704 | − | |
| 3705 | − init_waitqueue_head(&cfg->tmf_waitq); | |
| 3706 | − init_waitqueue_head(&cfg->reset_waitq); | |
| 3707 | − | |
| 3708 | − INIT_WORK(&cfg->work_q, cxlflash_worker_thread); | |
| 3709 | − cfg->lr_state = LINK_RESET_INVALID; | |
| 3710 | − cfg->lr_port = -1; | |
| 3711 | − spin_lock_init(&cfg->tmf_slock); | |
| 3712 | − mutex_init(&cfg->ctx_tbl_list_mutex); | |
| 3713 | − mutex_init(&cfg->ctx_recovery_mutex); | |
| 3714 | − init_rwsem(&cfg->ioctl_rwsem); | |
| 3715 | − INIT_LIST_HEAD(&cfg->ctx_err_recovery); | |
| 3716 | − INIT_LIST_HEAD(&cfg->lluns); | |
| 3717 | − | |
| 3718 | − pci_set_drvdata(pdev, cfg); | |
| 3719 | − | |
| 3720 | − rc = init_pci(cfg); | |
| 3721 | − if (rc) { | |
| 3722 | − dev_err(dev, "%s: init_pci failed rc=%d\n", __func__, rc); | |
| 3723 | − goto out_remove; | |
| 3724 | − } | |
| 3725 | − cfg->init_state = INIT_STATE_PCI; | |
| 3726 | − | |
| 3727 | − cfg->afu_cookie = cfg->ops->create_afu(pdev); | |
| 3728 | − if (unlikely(!cfg->afu_cookie)) { | |
| 3729 | − dev_err(dev, "%s: create_afu failed\n", __func__); | |
| 3730 | − rc = -ENOMEM; | |
| 3731 | − goto out_remove; | |
| 3732 | − } | |
| 3733 | − | |
| 3734 | − rc = init_afu(cfg); | |
| 3735 | − if (rc && !wq_has_sleeper(&cfg->reset_waitq)) { | |
| 3736 | − dev_err(dev, "%s: init_afu failed rc=%d\n", __func__, rc); | |
| 3737 | − goto out_remove; | |
| 3738 | − } | |
| 3739 | − cfg->init_state = INIT_STATE_AFU; | |
| 3740 | − | |
| 3741 | − rc = init_scsi(cfg); | |
| 3742 | − if (rc) { | |
| 3743 | − dev_err(dev, "%s: init_scsi failed rc=%d\n", __func__, rc); | |
| 3744 | − goto out_remove; | |
| 3745 | − } | |
| 3746 | − cfg->init_state = INIT_STATE_SCSI; | |
| 3747 | − | |
| 3748 | − rc = init_chrdev(cfg); | |
| 3749 | − if (rc) { | |
| 3750 | − dev_err(dev, "%s: init_chrdev failed rc=%d\n", __func__, rc); | |
| 3751 | − goto out_remove; | |
| 3752 | − } | |
| 3753 | − cfg->init_state = INIT_STATE_CDEV; | |
| 3754 | − | |
| 3755 | − if (wq_has_sleeper(&cfg->reset_waitq)) { | |
| 3756 | − cfg->state = STATE_PROBED; | |
| 3757 | − wake_up_all(&cfg->reset_waitq); | |
| 3758 | − } else | |
| 3759 | − cfg->state = STATE_NORMAL; | |
| 3760 | −out: | |
| 3761 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 3762 | − return rc; | |
| 3763 | − | |
| 3764 | −out_remove: | |
| 3765 | − cfg->state = STATE_PROBED; | |
| 3766 | − cxlflash_remove(pdev); | |
| 3767 | − goto out; | |
| 3768 | −} | |
| 3769 | − | |
| 3770 | −/** | |
| 3771 | − * cxlflash_pci_error_detected() - called when a PCI error is detected | |
| 3772 | − * @pdev: PCI device struct. | |
| 3773 | − * @state: PCI channel state. | |
| 3774 | − * | |
| 3775 | − * When an EEH occurs during an active reset, wait until the reset is | |
| 3776 | − * complete and then take action based upon the device state. | |
| 3777 | − * | |
| 3778 | − * Return: PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT | |
| 3779 | − */ | |
| 3780 | −static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, | |
| 3781 | − pci_channel_state_t state) | |
| 3782 | −{ | |
| 3783 | − int rc = 0; | |
| 3784 | − struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); | |
| 3785 | − struct device *dev = &cfg->dev->dev; | |
| 3786 | − | |
| 3787 | − dev_dbg(dev, "%s: pdev=%p state=%u\n", __func__, pdev, state); | |
| 3788 | − | |
| 3789 | − switch (state) { | |
| 3790 | − case pci_channel_io_frozen: | |
| 3791 | − wait_event(cfg->reset_waitq, cfg->state != STATE_RESET && | |
| 3792 | − cfg->state != STATE_PROBING); | |
| 3793 | − if (cfg->state == STATE_FAILTERM) | |
| 3794 | − return PCI_ERS_RESULT_DISCONNECT; | |
| 3795 | − | |
| 3796 | − cfg->state = STATE_RESET; | |
| 3797 | − scsi_block_requests(cfg->host); | |
| 3798 | − drain_ioctls(cfg); | |
| 3799 | − rc = cxlflash_mark_contexts_error(cfg); | |
| 3800 | − if (unlikely(rc)) | |
| 3801 | − dev_err(dev, "%s: Failed to mark user contexts rc=%d\n", | |
| 3802 | − __func__, rc); | |
| 3803 | − term_afu(cfg); | |
| 3804 | − return PCI_ERS_RESULT_NEED_RESET; | |
| 3805 | − case pci_channel_io_perm_failure: | |
| 3806 | − cfg->state = STATE_FAILTERM; | |
| 3807 | − wake_up_all(&cfg->reset_waitq); | |
| 3808 | − scsi_unblock_requests(cfg->host); | |
| 3809 | − return PCI_ERS_RESULT_DISCONNECT; | |
| 3810 | − default: | |
| 3811 | − break; | |
| 3812 | − } | |
| 3813 | − return PCI_ERS_RESULT_NEED_RESET; | |
| 3814 | −} | |
| 3815 | − | |
| 3816 | −/** | |
| 3817 | − * cxlflash_pci_slot_reset() - called when PCI slot has been reset | |
| 3818 | − * @pdev: PCI device struct. | |
| 3819 | − * | |
| 3820 | − * This routine is called by the pci error recovery code after the PCI | |
| 3821 | − * slot has been reset, just before we should resume normal operations. | |
| 3822 | − * | |
| 3823 | − * Return: PCI_ERS_RESULT_RECOVERED or PCI_ERS_RESULT_DISCONNECT | |
| 3824 | − */ | |
| 3825 | −static pci_ers_result_t cxlflash_pci_slot_reset(struct pci_dev *pdev) | |
| 3826 | −{ | |
| 3827 | − int rc = 0; | |
| 3828 | − struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); | |
| 3829 | − struct device *dev = &cfg->dev->dev; | |
| 3830 | − | |
| 3831 | − dev_dbg(dev, "%s: pdev=%p\n", __func__, pdev); | |
| 3832 | − | |
| 3833 | − rc = init_afu(cfg); | |
| 3834 | − if (unlikely(rc)) { | |
| 3835 | − dev_err(dev, "%s: EEH recovery failed rc=%d\n", __func__, rc); | |
| 3836 | − return PCI_ERS_RESULT_DISCONNECT; | |
| 3837 | − } | |
| 3838 | − | |
| 3839 | − return PCI_ERS_RESULT_RECOVERED; | |
| 3840 | −} | |
| 3841 | − | |
| 3842 | −/** | |
| 3843 | − * cxlflash_pci_resume() - called when normal operation can resume | |
| 3844 | − * @pdev: PCI device struct | |
| 3845 | − */ | |
| 3846 | −static void cxlflash_pci_resume(struct pci_dev *pdev) | |
| 3847 | −{ | |
| 3848 | − struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); | |
| 3849 | − struct device *dev = &cfg->dev->dev; | |
| 3850 | − | |
| 3851 | − dev_dbg(dev, "%s: pdev=%p\n", __func__, pdev); | |
| 3852 | − | |
| 3853 | − cfg->state = STATE_NORMAL; | |
| 3854 | − wake_up_all(&cfg->reset_waitq); | |
| 3855 | − scsi_unblock_requests(cfg->host); | |
| 3856 | −} | |
| 3857 | − | |
| 3858 | −/** | |
| 3859 | − * cxlflash_devnode() - provides devtmpfs for devices in the cxlflash class | |
| 3860 | − * @dev: Character device. | |
| 3861 | − * @mode: Mode that can be used to verify access. | |
| 3862 | − * | |
| 3863 | − * Return: Allocated string describing the devtmpfs structure. | |
| 3864 | − */ | |
| 3865 | −static char *cxlflash_devnode(const struct device *dev, umode_t *mode) | |
| 3866 | −{ | |
| 3867 | − return kasprintf(GFP_KERNEL, "cxlflash/%s", dev_name(dev)); | |
| 3868 | −} | |
| 3869 | − | |
| 3870 | −/** | |
| 3871 | − * cxlflash_class_init() - create character device class | |
| 3872 | − * | |
| 3873 | − * Return: 0 on success, -errno on failure | |
| 3874 | − */ | |
| 3875 | −static int cxlflash_class_init(void) | |
| 3876 | −{ | |
| 3877 | − dev_t devno; | |
| 3878 | − int rc = 0; | |
| 3879 | − | |
| 3880 | − rc = alloc_chrdev_region(&devno, 0, CXLFLASH_MAX_ADAPTERS, "cxlflash"); | |
| 3881 | − if (unlikely(rc)) { | |
| 3882 | − pr_err("%s: alloc_chrdev_region failed rc=%d\n", __func__, rc); | |
| 3883 | − goto out; | |
| 3884 | − } | |
| 3885 | − | |
| 3886 | − cxlflash_major = MAJOR(devno); | |
| 3887 | − | |
| 3888 | − rc = class_register(&cxlflash_class); | |
| 3889 | − if (rc) { | |
| 3890 | − pr_err("%s: class_create failed rc=%d\n", __func__, rc); | |
| 3891 | − goto err; | |
| 3892 | − } | |
| 3893 | − | |
| 3894 | −out: | |
| 3895 | − pr_debug("%s: returning rc=%d\n", __func__, rc); | |
| 3896 | − return rc; | |
| 3897 | −err: | |
| 3898 | − unregister_chrdev_region(devno, CXLFLASH_MAX_ADAPTERS); | |
| 3899 | − goto out; | |
| 3900 | −} | |
| 3901 | − | |
| 3902 | −/** | |
| 3903 | − * cxlflash_class_exit() - destroy character device class | |
| 3904 | − */ | |
| 3905 | −static void cxlflash_class_exit(void) | |
| 3906 | −{ | |
| 3907 | − dev_t devno = MKDEV(cxlflash_major, 0); | |
| 3908 | − | |
| 3909 | − class_unregister(&cxlflash_class); | |
| 3910 | − unregister_chrdev_region(devno, CXLFLASH_MAX_ADAPTERS); | |
| 3911 | −} | |
| 3912 | − | |
| 3913 | −static const struct pci_error_handlers cxlflash_err_handler = { | |
| 3914 | − .error_detected = cxlflash_pci_error_detected, | |
| 3915 | − .slot_reset = cxlflash_pci_slot_reset, | |
| 3916 | − .resume = cxlflash_pci_resume, | |
| 3917 | −}; | |
| 3918 | − | |
| 3919 | −/* | |
| 3920 | − * PCI device structure | |
| 3921 | − */ | |
| 3922 | −static struct pci_driver cxlflash_driver = { | |
| 3923 | − .name = CXLFLASH_NAME, | |
| 3924 | − .id_table = cxlflash_pci_table, | |
| 3925 | − .probe = cxlflash_probe, | |
| 3926 | − .remove = cxlflash_remove, | |
| 3927 | − .shutdown = cxlflash_remove, | |
| 3928 | − .err_handler = &cxlflash_err_handler, | |
| 3929 | −}; | |
| 3930 | − | |
| 3931 | −/** | |
| 3932 | − * init_cxlflash() - module entry point | |
| 3933 | − * | |
| 3934 | − * Return: 0 on success, -errno on failure | |
| 3935 | − */ | |
| 3936 | −static int __init init_cxlflash(void) | |
| 3937 | −{ | |
| 3938 | − int rc; | |
| 3939 | − | |
| 3940 | − check_sizes(); | |
| 3941 | − cxlflash_list_init(); | |
| 3942 | − rc = cxlflash_class_init(); | |
| 3943 | − if (unlikely(rc)) | |
| 3944 | − goto out; | |
| 3945 | − | |
| 3946 | − rc = pci_register_driver(&cxlflash_driver); | |
| 3947 | − if (unlikely(rc)) | |
| 3948 | − goto err; | |
| 3949 | −out: | |
| 3950 | − pr_debug("%s: returning rc=%d\n", __func__, rc); | |
| 3951 | − return rc; | |
| 3952 | −err: | |
| 3953 | − cxlflash_class_exit(); | |
| 3954 | − goto out; | |
| 3955 | −} | |
| 3956 | − | |
| 3957 | −/** | |
| 3958 | − * exit_cxlflash() - module exit point | |
| 3959 | − */ | |
| 3960 | −static void __exit exit_cxlflash(void) | |
| 3961 | −{ | |
| 3962 | − cxlflash_term_global_luns(); | |
| 3963 | − cxlflash_free_errpage(); | |
| 3964 | − | |
| 3965 | − pci_unregister_driver(&cxlflash_driver); | |
| 3966 | − cxlflash_class_exit(); | |
| 3967 | −} | |
| 3968 | − | |
| 3969 | −module_init(init_cxlflash); | |
| 3970 | −module_exit(exit_cxlflash); | |
| @@ -1,129 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2015 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#ifndef _CXLFLASH_MAIN_H | |
| 12 | −#define _CXLFLASH_MAIN_H | |
| 13 | − | |
| 14 | −#include <linux/list.h> | |
| 15 | −#include <linux/types.h> | |
| 16 | −#include <scsi/scsi.h> | |
| 17 | −#include <scsi/scsi_device.h> | |
| 18 | − | |
| 19 | −#include "backend.h" | |
| 20 | − | |
| 21 | −#define CXLFLASH_NAME "cxlflash" | |
| 22 | −#define CXLFLASH_ADAPTER_NAME "IBM POWER CXL Flash Adapter" | |
| 23 | −#define CXLFLASH_MAX_ADAPTERS 32 | |
| 24 | − | |
| 25 | −#define PCI_DEVICE_ID_IBM_CORSA 0x04F0 | |
| 26 | −#define PCI_DEVICE_ID_IBM_FLASH_GT 0x0600 | |
| 27 | −#define PCI_DEVICE_ID_IBM_BRIARD 0x0624 | |
| 28 | − | |
| 29 | −/* Since there is only one target, make it 0 */ | |
| 30 | −#define CXLFLASH_TARGET 0 | |
| 31 | −#define CXLFLASH_MAX_CDB_LEN 16 | |
| 32 | − | |
| 33 | −/* Really only one target per bus since the Texan is directly attached */ | |
| 34 | −#define CXLFLASH_MAX_NUM_TARGETS_PER_BUS 1 | |
| 35 | −#define CXLFLASH_MAX_NUM_LUNS_PER_TARGET 65536 | |
| 36 | − | |
| 37 | −#define CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT (120 * HZ) | |
| 38 | − | |
| 39 | −/* FC defines */ | |
| 40 | −#define FC_MTIP_CMDCONFIG 0x010 | |
| 41 | −#define FC_MTIP_STATUS 0x018 | |
| 42 | −#define FC_MAX_NUM_LUNS 0x080 /* Max LUNs host can provision for port */ | |
| 43 | −#define FC_CUR_NUM_LUNS 0x088 /* Cur number LUNs provisioned for port */ | |
| 44 | −#define FC_MAX_CAP_PORT 0x090 /* Max capacity all LUNs for port (4K blocks) */ | |
| 45 | −#define FC_CUR_CAP_PORT 0x098 /* Cur capacity all LUNs for port (4K blocks) */ | |
| 46 | − | |
| 47 | −#define FC_PNAME 0x300 | |
| 48 | −#define FC_CONFIG 0x320 | |
| 49 | −#define FC_CONFIG2 0x328 | |
| 50 | −#define FC_STATUS 0x330 | |
| 51 | −#define FC_ERROR 0x380 | |
| 52 | −#define FC_ERRCAP 0x388 | |
| 53 | −#define FC_ERRMSK 0x390 | |
| 54 | −#define FC_CNT_CRCERR 0x538 | |
| 55 | −#define FC_CRC_THRESH 0x580 | |
| 56 | − | |
| 57 | −#define FC_MTIP_CMDCONFIG_ONLINE 0x20ULL | |
| 58 | −#define FC_MTIP_CMDCONFIG_OFFLINE 0x40ULL | |
| 59 | − | |
| 60 | −#define FC_MTIP_STATUS_MASK 0x30ULL | |
| 61 | −#define FC_MTIP_STATUS_ONLINE 0x20ULL | |
| 62 | −#define FC_MTIP_STATUS_OFFLINE 0x10ULL | |
| 63 | − | |
| 64 | −/* TIMEOUT and RETRY definitions */ | |
| 65 | − | |
| 66 | −/* AFU command timeout values */ | |
| 67 | −#define MC_AFU_SYNC_TIMEOUT 5 /* 5 secs */ | |
| 68 | −#define MC_LUN_PROV_TIMEOUT 5 /* 5 secs */ | |
| 69 | −#define MC_AFU_DEBUG_TIMEOUT 5 /* 5 secs */ | |
| 70 | − | |
| 71 | −/* AFU command room retry limit */ | |
| 72 | −#define MC_ROOM_RETRY_CNT 10 | |
| 73 | − | |
| 74 | −/* FC CRC clear periodic timer */ | |
| 75 | −#define MC_CRC_THRESH 100 /* threshold in 5 mins */ | |
| 76 | − | |
| 77 | −#define FC_PORT_STATUS_RETRY_CNT 100 /* 100 100ms retries = 10 seconds */ | |
| 78 | −#define FC_PORT_STATUS_RETRY_INTERVAL_US 100000 /* microseconds */ | |
| 79 | − | |
| 80 | −/* VPD defines */ | |
| 81 | −#define CXLFLASH_VPD_LEN 256 | |
| 82 | −#define WWPN_LEN 16 | |
| 83 | −#define WWPN_BUF_LEN (WWPN_LEN + 1) | |
| 84 | − | |
| 85 | −enum undo_level { | |
| 86 | − UNDO_NOOP = 0, | |
| 87 | − FREE_IRQ, | |
| 88 | − UNMAP_ONE, | |
| 89 | − UNMAP_TWO, | |
| 90 | − UNMAP_THREE | |
| 91 | −}; | |
| 92 | − | |
| 93 | −struct dev_dependent_vals { | |
| 94 | − u64 max_sectors; | |
| 95 | − u64 flags; | |
| 96 | −#define CXLFLASH_NOTIFY_SHUTDOWN 0x0000000000000001ULL | |
| 97 | −#define CXLFLASH_WWPN_VPD_REQUIRED 0x0000000000000002ULL | |
| 98 | −#define CXLFLASH_OCXL_DEV 0x0000000000000004ULL | |
| 99 | −}; | |
| 100 | − | |
| 101 | −static inline const struct cxlflash_backend_ops * | |
| 102 | −cxlflash_assign_ops(struct dev_dependent_vals *ddv) | |
| 103 | −{ | |
| 104 | − const struct cxlflash_backend_ops *ops = NULL; | |
| 105 | − | |
| 106 | −#ifdef CONFIG_OCXL_BASE | |
| 107 | − if (ddv->flags & CXLFLASH_OCXL_DEV) | |
| 108 | − ops = &cxlflash_ocxl_ops; | |
| 109 | −#endif | |
| 110 | − | |
| 111 | −#ifdef CONFIG_CXL_BASE | |
| 112 | − if (!(ddv->flags & CXLFLASH_OCXL_DEV)) | |
| 113 | − ops = &cxlflash_cxl_ops; | |
| 114 | −#endif | |
| 115 | − | |
| 116 | − return ops; | |
| 117 | −} | |
| 118 | − | |
| 119 | −struct asyc_intr_info { | |
| 120 | − u64 status; | |
| 121 | − char *desc; | |
| 122 | − u8 port; | |
| 123 | − u8 action; | |
| 124 | −#define CLR_FC_ERROR 0x01 | |
| 125 | −#define LINK_RESET 0x02 | |
| 126 | −#define SCAN_HOST 0x04 | |
| 127 | −}; | |
| 128 | − | |
| 129 | −#endif /* _CXLFLASH_MAIN_H */ | |
| @@ -1,1399 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2018 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#include <linux/file.h> | |
| 12 | −#include <linux/idr.h> | |
| 13 | −#include <linux/module.h> | |
| 14 | −#include <linux/mount.h> | |
| 15 | −#include <linux/pseudo_fs.h> | |
| 16 | −#include <linux/poll.h> | |
| 17 | −#include <linux/sched/signal.h> | |
| 18 | −#include <linux/interrupt.h> | |
| 19 | −#include <linux/irqdomain.h> | |
| 20 | −#include <asm/xive.h> | |
| 21 | −#include <misc/ocxl.h> | |
| 22 | − | |
| 23 | −#include <uapi/misc/cxl.h> | |
| 24 | − | |
| 25 | −#include "backend.h" | |
| 26 | −#include "ocxl_hw.h" | |
| 27 | − | |
| 28 | −/* | |
| 29 | − * Pseudo-filesystem to allocate inodes. | |
| 30 | − */ | |
| 31 | − | |
| 32 | −#define OCXLFLASH_FS_MAGIC 0x1697698f | |
| 33 | − | |
| 34 | −static int ocxlflash_fs_cnt; | |
| 35 | −static struct vfsmount *ocxlflash_vfs_mount; | |
| 36 | − | |
| 37 | −static int ocxlflash_fs_init_fs_context(struct fs_context *fc) | |
| 38 | −{ | |
| 39 | − return init_pseudo(fc, OCXLFLASH_FS_MAGIC) ? 0 : -ENOMEM; | |
| 40 | −} | |
| 41 | − | |
| 42 | −static struct file_system_type ocxlflash_fs_type = { | |
| 43 | − .name = "ocxlflash", | |
| 44 | − .owner = THIS_MODULE, | |
| 45 | − .init_fs_context = ocxlflash_fs_init_fs_context, | |
| 46 | − .kill_sb = kill_anon_super, | |
| 47 | −}; | |
| 48 | − | |
| 49 | −/* | |
| 50 | − * ocxlflash_release_mapping() - release the memory mapping | |
| 51 | − * @ctx: Context whose mapping is to be released. | |
| 52 | − */ | |
| 53 | −static void ocxlflash_release_mapping(struct ocxlflash_context *ctx) | |
| 54 | −{ | |
| 55 | − if (ctx->mapping) | |
| 56 | − simple_release_fs(&ocxlflash_vfs_mount, &ocxlflash_fs_cnt); | |
| 57 | − ctx->mapping = NULL; | |
| 58 | −} | |
| 59 | − | |
| 60 | −/* | |
| 61 | − * ocxlflash_getfile() - allocate pseudo filesystem, inode, and the file | |
| 62 | − * @dev: Generic device of the host. | |
| 63 | − * @name: Name of the pseudo filesystem. | |
| 64 | − * @fops: File operations. | |
| 65 | − * @priv: Private data. | |
| 66 | − * @flags: Flags for the file. | |
| 67 | − * | |
| 68 | − * Return: pointer to the file on success, ERR_PTR on failure | |
| 69 | − */ | |
| 70 | −static struct file *ocxlflash_getfile(struct device *dev, const char *name, | |
| 71 | − const struct file_operations *fops, | |
| 72 | − void *priv, int flags) | |
| 73 | −{ | |
| 74 | − struct file *file; | |
| 75 | − struct inode *inode; | |
| 76 | − int rc; | |
| 77 | − | |
| 78 | − if (fops->owner && !try_module_get(fops->owner)) { | |
| 79 | − dev_err(dev, "%s: Owner does not exist\n", __func__); | |
| 80 | − rc = -ENOENT; | |
| 81 | − goto err1; | |
| 82 | − } | |
| 83 | − | |
| 84 | − rc = simple_pin_fs(&ocxlflash_fs_type, &ocxlflash_vfs_mount, | |
| 85 | − &ocxlflash_fs_cnt); | |
| 86 | − if (unlikely(rc < 0)) { | |
| 87 | − dev_err(dev, "%s: Cannot mount ocxlflash pseudofs rc=%d\n", | |
| 88 | − __func__, rc); | |
| 89 | − goto err2; | |
| 90 | − } | |
| 91 | − | |
| 92 | − inode = alloc_anon_inode(ocxlflash_vfs_mount->mnt_sb); | |
| 93 | − if (IS_ERR(inode)) { | |
| 94 | − rc = PTR_ERR(inode); | |
| 95 | − dev_err(dev, "%s: alloc_anon_inode failed rc=%d\n", | |
| 96 | − __func__, rc); | |
| 97 | − goto err3; | |
| 98 | − } | |
| 99 | − | |
| 100 | − file = alloc_file_pseudo(inode, ocxlflash_vfs_mount, name, | |
| 101 | − flags & (O_ACCMODE | O_NONBLOCK), fops); | |
| 102 | − if (IS_ERR(file)) { | |
| 103 | − rc = PTR_ERR(file); | |
| 104 | − dev_err(dev, "%s: alloc_file failed rc=%d\n", | |
| 105 | − __func__, rc); | |
| 106 | − goto err4; | |
| 107 | − } | |
| 108 | − | |
| 109 | − file->private_data = priv; | |
| 110 | −out: | |
| 111 | − return file; | |
| 112 | −err4: | |
| 113 | − iput(inode); | |
| 114 | −err3: | |
| 115 | − simple_release_fs(&ocxlflash_vfs_mount, &ocxlflash_fs_cnt); | |
| 116 | −err2: | |
| 117 | − module_put(fops->owner); | |
| 118 | −err1: | |
| 119 | − file = ERR_PTR(rc); | |
| 120 | − goto out; | |
| 121 | −} | |
| 122 | − | |
| 123 | −/** | |
| 124 | − * ocxlflash_psa_map() - map the process specific MMIO space | |
| 125 | − * @ctx_cookie: Adapter context for which the mapping needs to be done. | |
| 126 | − * | |
| 127 | − * Return: MMIO pointer of the mapped region | |
| 128 | − */ | |
| 129 | −static void __iomem *ocxlflash_psa_map(void *ctx_cookie) | |
| 130 | −{ | |
| 131 | − struct ocxlflash_context *ctx = ctx_cookie; | |
| 132 | − struct device *dev = ctx->hw_afu->dev; | |
| 133 | − | |
| 134 | − mutex_lock(&ctx->state_mutex); | |
| 135 | − if (ctx->state != STARTED) { | |
| 136 | − dev_err(dev, "%s: Context not started, state=%d\n", __func__, | |
| 137 | − ctx->state); | |
| 138 | − mutex_unlock(&ctx->state_mutex); | |
| 139 | − return NULL; | |
| 140 | − } | |
| 141 | − mutex_unlock(&ctx->state_mutex); | |
| 142 | − | |
| 143 | − return ioremap(ctx->psn_phys, ctx->psn_size); | |
| 144 | −} | |
| 145 | − | |
| 146 | −/** | |
| 147 | − * ocxlflash_psa_unmap() - unmap the process specific MMIO space | |
| 148 | − * @addr: MMIO pointer to unmap. | |
| 149 | − */ | |
| 150 | −static void ocxlflash_psa_unmap(void __iomem *addr) | |
| 151 | −{ | |
| 152 | − iounmap(addr); | |
| 153 | −} | |
| 154 | − | |
| 155 | −/** | |
| 156 | − * ocxlflash_process_element() - get process element of the adapter context | |
| 157 | − * @ctx_cookie: Adapter context associated with the process element. | |
| 158 | − * | |
| 159 | − * Return: process element of the adapter context | |
| 160 | − */ | |
| 161 | −static int ocxlflash_process_element(void *ctx_cookie) | |
| 162 | −{ | |
| 163 | − struct ocxlflash_context *ctx = ctx_cookie; | |
| 164 | − | |
| 165 | − return ctx->pe; | |
| 166 | −} | |
| 167 | − | |
| 168 | −/** | |
| 169 | − * afu_map_irq() - map the interrupt of the adapter context | |
| 170 | − * @flags: Flags. | |
| 171 | − * @ctx: Adapter context. | |
| 172 | − * @num: Per-context AFU interrupt number. | |
| 173 | − * @handler: Interrupt handler to register. | |
| 174 | − * @cookie: Interrupt handler private data. | |
| 175 | − * @name: Name of the interrupt. | |
| 176 | − * | |
| 177 | − * Return: 0 on success, -errno on failure | |
| 178 | − */ | |
| 179 | −static int afu_map_irq(u64 flags, struct ocxlflash_context *ctx, int num, | |
| 180 | − irq_handler_t handler, void *cookie, char *name) | |
| 181 | −{ | |
| 182 | − struct ocxl_hw_afu *afu = ctx->hw_afu; | |
| 183 | − struct device *dev = afu->dev; | |
| 184 | − struct ocxlflash_irqs *irq; | |
| 185 | − struct xive_irq_data *xd; | |
| 186 | − u32 virq; | |
| 187 | − int rc = 0; | |
| 188 | − | |
| 189 | − if (num < 0 || num >= ctx->num_irqs) { | |
| 190 | − dev_err(dev, "%s: Interrupt %d not allocated\n", __func__, num); | |
| 191 | − rc = -ENOENT; | |
| 192 | − goto out; | |
| 193 | − } | |
| 194 | − | |
| 195 | − irq = &ctx->irqs[num]; | |
| 196 | − virq = irq_create_mapping(NULL, irq->hwirq); | |
| 197 | − if (unlikely(!virq)) { | |
| 198 | − dev_err(dev, "%s: irq_create_mapping failed\n", __func__); | |
| 199 | − rc = -ENOMEM; | |
| 200 | − goto out; | |
| 201 | − } | |
| 202 | − | |
| 203 | − rc = request_irq(virq, handler, 0, name, cookie); | |
| 204 | − if (unlikely(rc)) { | |
| 205 | − dev_err(dev, "%s: request_irq failed rc=%d\n", __func__, rc); | |
| 206 | − goto err1; | |
| 207 | − } | |
| 208 | − | |
| 209 | − xd = irq_get_handler_data(virq); | |
| 210 | − if (unlikely(!xd)) { | |
| 211 | − dev_err(dev, "%s: Can't get interrupt data\n", __func__); | |
| 212 | − rc = -ENXIO; | |
| 213 | − goto err2; | |
| 214 | − } | |
| 215 | − | |
| 216 | − irq->virq = virq; | |
| 217 | − irq->vtrig = xd->trig_mmio; | |
| 218 | −out: | |
| 219 | − return rc; | |
| 220 | −err2: | |
| 221 | − free_irq(virq, cookie); | |
| 222 | −err1: | |
| 223 | − irq_dispose_mapping(virq); | |
| 224 | − goto out; | |
| 225 | −} | |
| 226 | − | |
| 227 | −/** | |
| 228 | − * ocxlflash_map_afu_irq() - map the interrupt of the adapter context | |
| 229 | − * @ctx_cookie: Adapter context. | |
| 230 | − * @num: Per-context AFU interrupt number. | |
| 231 | − * @handler: Interrupt handler to register. | |
| 232 | − * @cookie: Interrupt handler private data. | |
| 233 | − * @name: Name of the interrupt. | |
| 234 | − * | |
| 235 | − * Return: 0 on success, -errno on failure | |
| 236 | − */ | |
| 237 | −static int ocxlflash_map_afu_irq(void *ctx_cookie, int num, | |
| 238 | − irq_handler_t handler, void *cookie, | |
| 239 | − char *name) | |
| 240 | −{ | |
| 241 | − return afu_map_irq(0, ctx_cookie, num, handler, cookie, name); | |
| 242 | −} | |
| 243 | − | |
| 244 | −/** | |
| 245 | − * afu_unmap_irq() - unmap the interrupt | |
| 246 | − * @flags: Flags. | |
| 247 | − * @ctx: Adapter context. | |
| 248 | − * @num: Per-context AFU interrupt number. | |
| 249 | − * @cookie: Interrupt handler private data. | |
| 250 | − */ | |
| 251 | −static void afu_unmap_irq(u64 flags, struct ocxlflash_context *ctx, int num, | |
| 252 | − void *cookie) | |
| 253 | −{ | |
| 254 | − struct ocxl_hw_afu *afu = ctx->hw_afu; | |
| 255 | − struct device *dev = afu->dev; | |
| 256 | − struct ocxlflash_irqs *irq; | |
| 257 | − | |
| 258 | − if (num < 0 || num >= ctx->num_irqs) { | |
| 259 | − dev_err(dev, "%s: Interrupt %d not allocated\n", __func__, num); | |
| 260 | − return; | |
| 261 | − } | |
| 262 | − | |
| 263 | − irq = &ctx->irqs[num]; | |
| 264 | − | |
| 265 | − if (irq_find_mapping(NULL, irq->hwirq)) { | |
| 266 | − free_irq(irq->virq, cookie); | |
| 267 | − irq_dispose_mapping(irq->virq); | |
| 268 | − } | |
| 269 | − | |
| 270 | − memset(irq, 0, sizeof(*irq)); | |
| 271 | −} | |
| 272 | − | |
| 273 | −/** | |
| 274 | − * ocxlflash_unmap_afu_irq() - unmap the interrupt | |
| 275 | − * @ctx_cookie: Adapter context. | |
| 276 | − * @num: Per-context AFU interrupt number. | |
| 277 | − * @cookie: Interrupt handler private data. | |
| 278 | − */ | |
| 279 | −static void ocxlflash_unmap_afu_irq(void *ctx_cookie, int num, void *cookie) | |
| 280 | −{ | |
| 281 | − return afu_unmap_irq(0, ctx_cookie, num, cookie); | |
| 282 | −} | |
| 283 | − | |
| 284 | −/** | |
| 285 | − * ocxlflash_get_irq_objhndl() - get the object handle for an interrupt | |
| 286 | − * @ctx_cookie: Context associated with the interrupt. | |
| 287 | − * @irq: Interrupt number. | |
| 288 | − * | |
| 289 | − * Return: effective address of the mapped region | |
| 290 | − */ | |
| 291 | −static u64 ocxlflash_get_irq_objhndl(void *ctx_cookie, int irq) | |
| 292 | −{ | |
| 293 | − struct ocxlflash_context *ctx = ctx_cookie; | |
| 294 | − | |
| 295 | − if (irq < 0 || irq >= ctx->num_irqs) | |
| 296 | − return 0; | |
| 297 | − | |
| 298 | − return (__force u64)ctx->irqs[irq].vtrig; | |
| 299 | −} | |
| 300 | − | |
| 301 | −/** | |
| 302 | − * ocxlflash_xsl_fault() - callback when translation error is triggered | |
| 303 | − * @data: Private data provided at callback registration, the context. | |
| 304 | − * @addr: Address that triggered the error. | |
| 305 | − * @dsisr: Value of dsisr register. | |
| 306 | − */ | |
| 307 | −static void ocxlflash_xsl_fault(void *data, u64 addr, u64 dsisr) | |
| 308 | −{ | |
| 309 | − struct ocxlflash_context *ctx = data; | |
| 310 | − | |
| 311 | − spin_lock(&ctx->slock); | |
| 312 | − ctx->fault_addr = addr; | |
| 313 | − ctx->fault_dsisr = dsisr; | |
| 314 | − ctx->pending_fault = true; | |
| 315 | − spin_unlock(&ctx->slock); | |
| 316 | − | |
| 317 | − wake_up_all(&ctx->wq); | |
| 318 | −} | |
| 319 | − | |
| 320 | −/** | |
| 321 | − * start_context() - local routine to start a context | |
| 322 | − * @ctx: Adapter context to be started. | |
| 323 | − * | |
| 324 | − * Assign the context specific MMIO space, add and enable the PE. | |
| 325 | − * | |
| 326 | − * Return: 0 on success, -errno on failure | |
| 327 | − */ | |
| 328 | −static int start_context(struct ocxlflash_context *ctx) | |
| 329 | −{ | |
| 330 | − struct ocxl_hw_afu *afu = ctx->hw_afu; | |
| 331 | − struct ocxl_afu_config *acfg = &afu->acfg; | |
| 332 | − void *link_token = afu->link_token; | |
| 333 | − struct pci_dev *pdev = afu->pdev; | |
| 334 | − struct device *dev = afu->dev; | |
| 335 | − bool master = ctx->master; | |
| 336 | − struct mm_struct *mm; | |
| 337 | − int rc = 0; | |
| 338 | − u32 pid; | |
| 339 | − | |
| 340 | − mutex_lock(&ctx->state_mutex); | |
| 341 | − if (ctx->state != OPENED) { | |
| 342 | − dev_err(dev, "%s: Context state invalid, state=%d\n", | |
| 343 | − __func__, ctx->state); | |
| 344 | − rc = -EINVAL; | |
| 345 | − goto out; | |
| 346 | − } | |
| 347 | − | |
| 348 | − if (master) { | |
| 349 | − ctx->psn_size = acfg->global_mmio_size; | |
| 350 | − ctx->psn_phys = afu->gmmio_phys; | |
| 351 | − } else { | |
| 352 | − ctx->psn_size = acfg->pp_mmio_stride; | |
| 353 | − ctx->psn_phys = afu->ppmmio_phys + (ctx->pe * ctx->psn_size); | |
| 354 | − } | |
| 355 | − | |
| 356 | − /* pid and mm not set for master contexts */ | |
| 357 | − if (master) { | |
| 358 | − pid = 0; | |
| 359 | − mm = NULL; | |
| 360 | − } else { | |
| 361 | − pid = current->mm->context.id; | |
| 362 | − mm = current->mm; | |
| 363 | − } | |
| 364 | − | |
| 365 | − rc = ocxl_link_add_pe(link_token, ctx->pe, pid, 0, 0, | |
| 366 | − pci_dev_id(pdev), mm, ocxlflash_xsl_fault, | |
| 367 | − ctx); | |
| 368 | − if (unlikely(rc)) { | |
| 369 | − dev_err(dev, "%s: ocxl_link_add_pe failed rc=%d\n", | |
| 370 | − __func__, rc); | |
| 371 | − goto out; | |
| 372 | − } | |
| 373 | − | |
| 374 | − ctx->state = STARTED; | |
| 375 | −out: | |
| 376 | − mutex_unlock(&ctx->state_mutex); | |
| 377 | − return rc; | |
| 378 | −} | |
| 379 | − | |
| 380 | −/** | |
| 381 | − * ocxlflash_start_context() - start a kernel context | |
| 382 | − * @ctx_cookie: Adapter context to be started. | |
| 383 | − * | |
| 384 | − * Return: 0 on success, -errno on failure | |
| 385 | − */ | |
| 386 | −static int ocxlflash_start_context(void *ctx_cookie) | |
| 387 | −{ | |
| 388 | − struct ocxlflash_context *ctx = ctx_cookie; | |
| 389 | − | |
| 390 | − return start_context(ctx); | |
| 391 | −} | |
| 392 | − | |
| 393 | −/** | |
| 394 | − * ocxlflash_stop_context() - stop a context | |
| 395 | − * @ctx_cookie: Adapter context to be stopped. | |
| 396 | − * | |
| 397 | − * Return: 0 on success, -errno on failure | |
| 398 | − */ | |
| 399 | −static int ocxlflash_stop_context(void *ctx_cookie) | |
| 400 | −{ | |
| 401 | − struct ocxlflash_context *ctx = ctx_cookie; | |
| 402 | − struct ocxl_hw_afu *afu = ctx->hw_afu; | |
| 403 | − struct ocxl_afu_config *acfg = &afu->acfg; | |
| 404 | − struct pci_dev *pdev = afu->pdev; | |
| 405 | − struct device *dev = afu->dev; | |
| 406 | − enum ocxlflash_ctx_state state; | |
| 407 | − int rc = 0; | |
| 408 | − | |
| 409 | − mutex_lock(&ctx->state_mutex); | |
| 410 | − state = ctx->state; | |
| 411 | − ctx->state = CLOSED; | |
| 412 | − mutex_unlock(&ctx->state_mutex); | |
| 413 | − if (state != STARTED) | |
| 414 | − goto out; | |
| 415 | − | |
| 416 | − rc = ocxl_config_terminate_pasid(pdev, acfg->dvsec_afu_control_pos, | |
| 417 | − ctx->pe); | |
| 418 | − if (unlikely(rc)) { | |
| 419 | − dev_err(dev, "%s: ocxl_config_terminate_pasid failed rc=%d\n", | |
| 420 | − __func__, rc); | |
| 421 | − /* If EBUSY, PE could be referenced in future by the AFU */ | |
| 422 | − if (rc == -EBUSY) | |
| 423 | − goto out; | |
| 424 | − } | |
| 425 | − | |
| 426 | − rc = ocxl_link_remove_pe(afu->link_token, ctx->pe); | |
| 427 | − if (unlikely(rc)) { | |
| 428 | − dev_err(dev, "%s: ocxl_link_remove_pe failed rc=%d\n", | |
| 429 | − __func__, rc); | |
| 430 | − goto out; | |
| 431 | − } | |
| 432 | −out: | |
| 433 | − return rc; | |
| 434 | −} | |
| 435 | − | |
| 436 | −/** | |
| 437 | − * ocxlflash_afu_reset() - reset the AFU | |
| 438 | − * @ctx_cookie: Adapter context. | |
| 439 | − */ | |
| 440 | −static int ocxlflash_afu_reset(void *ctx_cookie) | |
| 441 | −{ | |
| 442 | − struct ocxlflash_context *ctx = ctx_cookie; | |
| 443 | − struct device *dev = ctx->hw_afu->dev; | |
| 444 | − | |
| 445 | − /* Pending implementation from OCXL transport services */ | |
| 446 | − dev_err_once(dev, "%s: afu_reset() fop not supported\n", __func__); | |
| 447 | − | |
| 448 | − /* Silently return success until it is implemented */ | |
| 449 | − return 0; | |
| 450 | −} | |
| 451 | − | |
| 452 | −/** | |
| 453 | − * ocxlflash_set_master() - sets the context as master | |
| 454 | − * @ctx_cookie: Adapter context to set as master. | |
| 455 | − */ | |
| 456 | −static void ocxlflash_set_master(void *ctx_cookie) | |
| 457 | −{ | |
| 458 | − struct ocxlflash_context *ctx = ctx_cookie; | |
| 459 | − | |
| 460 | − ctx->master = true; | |
| 461 | −} | |
| 462 | − | |
| 463 | −/** | |
| 464 | − * ocxlflash_get_context() - obtains the context associated with the host | |
| 465 | − * @pdev: PCI device associated with the host. | |
| 466 | − * @afu_cookie: Hardware AFU associated with the host. | |
| 467 | − * | |
| 468 | − * Return: returns the pointer to host adapter context | |
| 469 | − */ | |
| 470 | −static void *ocxlflash_get_context(struct pci_dev *pdev, void *afu_cookie) | |
| 471 | −{ | |
| 472 | − struct ocxl_hw_afu *afu = afu_cookie; | |
| 473 | − | |
| 474 | − return afu->ocxl_ctx; | |
| 475 | −} | |
| 476 | − | |
| 477 | −/** | |
| 478 | − * ocxlflash_dev_context_init() - allocate and initialize an adapter context | |
| 479 | − * @pdev: PCI device associated with the host. | |
| 480 | − * @afu_cookie: Hardware AFU associated with the host. | |
| 481 | − * | |
| 482 | − * Return: returns the adapter context on success, ERR_PTR on failure | |
| 483 | − */ | |
| 484 | −static void *ocxlflash_dev_context_init(struct pci_dev *pdev, void *afu_cookie) | |
| 485 | −{ | |
| 486 | − struct ocxl_hw_afu *afu = afu_cookie; | |
| 487 | − struct device *dev = afu->dev; | |
| 488 | − struct ocxlflash_context *ctx; | |
| 489 | − int rc; | |
| 490 | − | |
| 491 | − ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
| 492 | − if (unlikely(!ctx)) { | |
| 493 | − dev_err(dev, "%s: Context allocation failed\n", __func__); | |
| 494 | − rc = -ENOMEM; | |
| 495 | − goto err1; | |
| 496 | − } | |
| 497 | − | |
| 498 | − idr_preload(GFP_KERNEL); | |
| 499 | − rc = idr_alloc(&afu->idr, ctx, 0, afu->max_pasid, GFP_NOWAIT); | |
| 500 | − idr_preload_end(); | |
| 501 | − if (unlikely(rc < 0)) { | |
| 502 | − dev_err(dev, "%s: idr_alloc failed rc=%d\n", __func__, rc); | |
| 503 | − goto err2; | |
| 504 | − } | |
| 505 | − | |
| 506 | − spin_lock_init(&ctx->slock); | |
| 507 | − init_waitqueue_head(&ctx->wq); | |
| 508 | − mutex_init(&ctx->state_mutex); | |
| 509 | − | |
| 510 | − ctx->state = OPENED; | |
| 511 | − ctx->pe = rc; | |
| 512 | − ctx->master = false; | |
| 513 | − ctx->mapping = NULL; | |
| 514 | − ctx->hw_afu = afu; | |
| 515 | − ctx->irq_bitmap = 0; | |
| 516 | − ctx->pending_irq = false; | |
| 517 | − ctx->pending_fault = false; | |
| 518 | −out: | |
| 519 | − return ctx; | |
| 520 | −err2: | |
| 521 | − kfree(ctx); | |
| 522 | −err1: | |
| 523 | − ctx = ERR_PTR(rc); | |
| 524 | − goto out; | |
| 525 | −} | |
| 526 | − | |
| 527 | −/** | |
| 528 | − * ocxlflash_release_context() - releases an adapter context | |
| 529 | − * @ctx_cookie: Adapter context to be released. | |
| 530 | − * | |
| 531 | − * Return: 0 on success, -errno on failure | |
| 532 | − */ | |
| 533 | −static int ocxlflash_release_context(void *ctx_cookie) | |
| 534 | −{ | |
| 535 | − struct ocxlflash_context *ctx = ctx_cookie; | |
| 536 | − struct device *dev; | |
| 537 | − int rc = 0; | |
| 538 | − | |
| 539 | − if (!ctx) | |
| 540 | − goto out; | |
| 541 | − | |
| 542 | − dev = ctx->hw_afu->dev; | |
| 543 | − mutex_lock(&ctx->state_mutex); | |
| 544 | − if (ctx->state >= STARTED) { | |
| 545 | − dev_err(dev, "%s: Context in use, state=%d\n", __func__, | |
| 546 | − ctx->state); | |
| 547 | − mutex_unlock(&ctx->state_mutex); | |
| 548 | − rc = -EBUSY; | |
| 549 | − goto out; | |
| 550 | − } | |
| 551 | − mutex_unlock(&ctx->state_mutex); | |
| 552 | − | |
| 553 | − idr_remove(&ctx->hw_afu->idr, ctx->pe); | |
| 554 | − ocxlflash_release_mapping(ctx); | |
| 555 | − kfree(ctx); | |
| 556 | −out: | |
| 557 | − return rc; | |
| 558 | −} | |
| 559 | − | |
| 560 | −/** | |
| 561 | − * ocxlflash_perst_reloads_same_image() - sets the image reload policy | |
| 562 | − * @afu_cookie: Hardware AFU associated with the host. | |
| 563 | − * @image: Whether to load the same image on PERST. | |
| 564 | − */ | |
| 565 | −static void ocxlflash_perst_reloads_same_image(void *afu_cookie, bool image) | |
| 566 | −{ | |
| 567 | − struct ocxl_hw_afu *afu = afu_cookie; | |
| 568 | − | |
| 569 | − afu->perst_same_image = image; | |
| 570 | −} | |
| 571 | − | |
| 572 | −/** | |
| 573 | − * ocxlflash_read_adapter_vpd() - reads the adapter VPD | |
| 574 | − * @pdev: PCI device associated with the host. | |
| 575 | − * @buf: Buffer to get the VPD data. | |
| 576 | − * @count: Size of buffer (maximum bytes that can be read). | |
| 577 | − * | |
| 578 | − * Return: size of VPD on success, -errno on failure | |
| 579 | − */ | |
| 580 | −static ssize_t ocxlflash_read_adapter_vpd(struct pci_dev *pdev, void *buf, | |
| 581 | − size_t count) | |
| 582 | −{ | |
| 583 | − return pci_read_vpd(pdev, 0, count, buf); | |
| 584 | −} | |
| 585 | − | |
| 586 | −/** | |
| 587 | − * free_afu_irqs() - internal service to free interrupts | |
| 588 | − * @ctx: Adapter context. | |
| 589 | − */ | |
| 590 | −static void free_afu_irqs(struct ocxlflash_context *ctx) | |
| 591 | −{ | |
| 592 | − struct ocxl_hw_afu *afu = ctx->hw_afu; | |
| 593 | − struct device *dev = afu->dev; | |
| 594 | − int i; | |
| 595 | − | |
| 596 | − if (!ctx->irqs) { | |
| 597 | − dev_err(dev, "%s: Interrupts not allocated\n", __func__); | |
| 598 | − return; | |
| 599 | − } | |
| 600 | − | |
| 601 | − for (i = ctx->num_irqs; i >= 0; i--) | |
| 602 | − ocxl_link_free_irq(afu->link_token, ctx->irqs[i].hwirq); | |
| 603 | − | |
| 604 | − kfree(ctx->irqs); | |
| 605 | − ctx->irqs = NULL; | |
| 606 | −} | |
| 607 | − | |
| 608 | −/** | |
| 609 | − * alloc_afu_irqs() - internal service to allocate interrupts | |
| 610 | − * @ctx: Context associated with the request. | |
| 611 | − * @num: Number of interrupts requested. | |
| 612 | − * | |
| 613 | − * Return: 0 on success, -errno on failure | |
| 614 | − */ | |
| 615 | −static int alloc_afu_irqs(struct ocxlflash_context *ctx, int num) | |
| 616 | −{ | |
| 617 | − struct ocxl_hw_afu *afu = ctx->hw_afu; | |
| 618 | − struct device *dev = afu->dev; | |
| 619 | − struct ocxlflash_irqs *irqs; | |
| 620 | − int rc = 0; | |
| 621 | − int hwirq; | |
| 622 | − int i; | |
| 623 | − | |
| 624 | − if (ctx->irqs) { | |
| 625 | − dev_err(dev, "%s: Interrupts already allocated\n", __func__); | |
| 626 | − rc = -EEXIST; | |
| 627 | − goto out; | |
| 628 | − } | |
| 629 | − | |
| 630 | − if (num > OCXL_MAX_IRQS) { | |
| 631 | − dev_err(dev, "%s: Too many interrupts num=%d\n", __func__, num); | |
| 632 | − rc = -EINVAL; | |
| 633 | − goto out; | |
| 634 | − } | |
| 635 | − | |
| 636 | − irqs = kcalloc(num, sizeof(*irqs), GFP_KERNEL); | |
| 637 | − if (unlikely(!irqs)) { | |
| 638 | − dev_err(dev, "%s: Context irqs allocation failed\n", __func__); | |
| 639 | − rc = -ENOMEM; | |
| 640 | − goto out; | |
| 641 | − } | |
| 642 | − | |
| 643 | − for (i = 0; i < num; i++) { | |
| 644 | − rc = ocxl_link_irq_alloc(afu->link_token, &hwirq); | |
| 645 | − if (unlikely(rc)) { | |
| 646 | − dev_err(dev, "%s: ocxl_link_irq_alloc failed rc=%d\n", | |
| 647 | − __func__, rc); | |
| 648 | − goto err; | |
| 649 | − } | |
| 650 | − | |
| 651 | − irqs[i].hwirq = hwirq; | |
| 652 | − } | |
| 653 | − | |
| 654 | − ctx->irqs = irqs; | |
| 655 | − ctx->num_irqs = num; | |
| 656 | −out: | |
| 657 | − return rc; | |
| 658 | −err: | |
| 659 | − for (i = i-1; i >= 0; i--) | |
| 660 | − ocxl_link_free_irq(afu->link_token, irqs[i].hwirq); | |
| 661 | − kfree(irqs); | |
| 662 | − goto out; | |
| 663 | −} | |
| 664 | − | |
| 665 | −/** | |
| 666 | − * ocxlflash_allocate_afu_irqs() - allocates the requested number of interrupts | |
| 667 | − * @ctx_cookie: Context associated with the request. | |
| 668 | − * @num: Number of interrupts requested. | |
| 669 | − * | |
| 670 | − * Return: 0 on success, -errno on failure | |
| 671 | − */ | |
| 672 | −static int ocxlflash_allocate_afu_irqs(void *ctx_cookie, int num) | |
| 673 | −{ | |
| 674 | − return alloc_afu_irqs(ctx_cookie, num); | |
| 675 | −} | |
| 676 | − | |
| 677 | −/** | |
| 678 | − * ocxlflash_free_afu_irqs() - frees the interrupts of an adapter context | |
| 679 | − * @ctx_cookie: Adapter context. | |
| 680 | − */ | |
| 681 | −static void ocxlflash_free_afu_irqs(void *ctx_cookie) | |
| 682 | −{ | |
| 683 | − free_afu_irqs(ctx_cookie); | |
| 684 | −} | |
| 685 | − | |
| 686 | −/** | |
| 687 | − * ocxlflash_unconfig_afu() - unconfigure the AFU | |
| 688 | − * @afu: AFU associated with the host. | |
| 689 | − */ | |
| 690 | −static void ocxlflash_unconfig_afu(struct ocxl_hw_afu *afu) | |
| 691 | −{ | |
| 692 | − if (afu->gmmio_virt) { | |
| 693 | − iounmap(afu->gmmio_virt); | |
| 694 | − afu->gmmio_virt = NULL; | |
| 695 | − } | |
| 696 | −} | |
| 697 | − | |
| 698 | −/** | |
| 699 | − * ocxlflash_destroy_afu() - destroy the AFU structure | |
| 700 | − * @afu_cookie: AFU to be freed. | |
| 701 | − */ | |
| 702 | −static void ocxlflash_destroy_afu(void *afu_cookie) | |
| 703 | −{ | |
| 704 | − struct ocxl_hw_afu *afu = afu_cookie; | |
| 705 | − int pos; | |
| 706 | − | |
| 707 | − if (!afu) | |
| 708 | − return; | |
| 709 | − | |
| 710 | − ocxlflash_release_context(afu->ocxl_ctx); | |
| 711 | − idr_destroy(&afu->idr); | |
| 712 | − | |
| 713 | − /* Disable the AFU */ | |
| 714 | − pos = afu->acfg.dvsec_afu_control_pos; | |
| 715 | − ocxl_config_set_afu_state(afu->pdev, pos, 0); | |
| 716 | − | |
| 717 | − ocxlflash_unconfig_afu(afu); | |
| 718 | − kfree(afu); | |
| 719 | −} | |
| 720 | − | |
| 721 | −/** | |
| 722 | − * ocxlflash_config_fn() - configure the host function | |
| 723 | − * @pdev: PCI device associated with the host. | |
| 724 | − * @afu: AFU associated with the host. | |
| 725 | − * | |
| 726 | − * Return: 0 on success, -errno on failure | |
| 727 | − */ | |
| 728 | −static int ocxlflash_config_fn(struct pci_dev *pdev, struct ocxl_hw_afu *afu) | |
| 729 | −{ | |
| 730 | − struct ocxl_fn_config *fcfg = &afu->fcfg; | |
| 731 | − struct device *dev = &pdev->dev; | |
| 732 | − u16 base, enabled, supported; | |
| 733 | − int rc = 0; | |
| 734 | − | |
| 735 | − /* Read DVSEC config of the function */ | |
| 736 | − rc = ocxl_config_read_function(pdev, fcfg); | |
| 737 | − if (unlikely(rc)) { | |
| 738 | − dev_err(dev, "%s: ocxl_config_read_function failed rc=%d\n", | |
| 739 | − __func__, rc); | |
| 740 | − goto out; | |
| 741 | − } | |
| 742 | − | |
| 743 | − /* Check if function has AFUs defined, only 1 per function supported */ | |
| 744 | − if (fcfg->max_afu_index >= 0) { | |
| 745 | − afu->is_present = true; | |
| 746 | − if (fcfg->max_afu_index != 0) | |
| 747 | − dev_warn(dev, "%s: Unexpected AFU index value %d\n", | |
| 748 | − __func__, fcfg->max_afu_index); | |
| 749 | − } | |
| 750 | − | |
| 751 | − rc = ocxl_config_get_actag_info(pdev, &base, &enabled, &supported); | |
| 752 | − if (unlikely(rc)) { | |
| 753 | − dev_err(dev, "%s: ocxl_config_get_actag_info failed rc=%d\n", | |
| 754 | − __func__, rc); | |
| 755 | − goto out; | |
| 756 | − } | |
| 757 | − | |
| 758 | − afu->fn_actag_base = base; | |
| 759 | − afu->fn_actag_enabled = enabled; | |
| 760 | − | |
| 761 | − ocxl_config_set_actag(pdev, fcfg->dvsec_function_pos, base, enabled); | |
| 762 | − dev_dbg(dev, "%s: Function acTag range base=%u enabled=%u\n", | |
| 763 | − __func__, base, enabled); | |
| 764 | − | |
| 765 | − rc = ocxl_link_setup(pdev, 0, &afu->link_token); | |
| 766 | − if (unlikely(rc)) { | |
| 767 | − dev_err(dev, "%s: ocxl_link_setup failed rc=%d\n", | |
| 768 | − __func__, rc); | |
| 769 | − goto out; | |
| 770 | − } | |
| 771 | − | |
| 772 | − rc = ocxl_config_set_TL(pdev, fcfg->dvsec_tl_pos); | |
| 773 | − if (unlikely(rc)) { | |
| 774 | − dev_err(dev, "%s: ocxl_config_set_TL failed rc=%d\n", | |
| 775 | − __func__, rc); | |
| 776 | − goto err; | |
| 777 | − } | |
| 778 | −out: | |
| 779 | − return rc; | |
| 780 | −err: | |
| 781 | − ocxl_link_release(pdev, afu->link_token); | |
| 782 | − goto out; | |
| 783 | −} | |
| 784 | − | |
| 785 | −/** | |
| 786 | − * ocxlflash_unconfig_fn() - unconfigure the host function | |
| 787 | − * @pdev: PCI device associated with the host. | |
| 788 | − * @afu: AFU associated with the host. | |
| 789 | − */ | |
| 790 | −static void ocxlflash_unconfig_fn(struct pci_dev *pdev, struct ocxl_hw_afu *afu) | |
| 791 | −{ | |
| 792 | − ocxl_link_release(pdev, afu->link_token); | |
| 793 | −} | |
| 794 | − | |
| 795 | −/** | |
| 796 | − * ocxlflash_map_mmio() - map the AFU MMIO space | |
| 797 | − * @afu: AFU associated with the host. | |
| 798 | − * | |
| 799 | − * Return: 0 on success, -errno on failure | |
| 800 | − */ | |
| 801 | −static int ocxlflash_map_mmio(struct ocxl_hw_afu *afu) | |
| 802 | −{ | |
| 803 | − struct ocxl_afu_config *acfg = &afu->acfg; | |
| 804 | − struct pci_dev *pdev = afu->pdev; | |
| 805 | − struct device *dev = afu->dev; | |
| 806 | − phys_addr_t gmmio, ppmmio; | |
| 807 | − int rc = 0; | |
| 808 | − | |
| 809 | − rc = pci_request_region(pdev, acfg->global_mmio_bar, "ocxlflash"); | |
| 810 | − if (unlikely(rc)) { | |
| 811 | − dev_err(dev, "%s: pci_request_region for global failed rc=%d\n", | |
| 812 | − __func__, rc); | |
| 813 | − goto out; | |
| 814 | − } | |
| 815 | − gmmio = pci_resource_start(pdev, acfg->global_mmio_bar); | |
| 816 | − gmmio += acfg->global_mmio_offset; | |
| 817 | − | |
| 818 | − rc = pci_request_region(pdev, acfg->pp_mmio_bar, "ocxlflash"); | |
| 819 | − if (unlikely(rc)) { | |
| 820 | − dev_err(dev, "%s: pci_request_region for pp bar failed rc=%d\n", | |
| 821 | − __func__, rc); | |
| 822 | − goto err1; | |
| 823 | − } | |
| 824 | − ppmmio = pci_resource_start(pdev, acfg->pp_mmio_bar); | |
| 825 | − ppmmio += acfg->pp_mmio_offset; | |
| 826 | − | |
| 827 | − afu->gmmio_virt = ioremap(gmmio, acfg->global_mmio_size); | |
| 828 | − if (unlikely(!afu->gmmio_virt)) { | |
| 829 | − dev_err(dev, "%s: MMIO mapping failed\n", __func__); | |
| 830 | − rc = -ENOMEM; | |
| 831 | − goto err2; | |
| 832 | − } | |
| 833 | − | |
| 834 | − afu->gmmio_phys = gmmio; | |
| 835 | − afu->ppmmio_phys = ppmmio; | |
| 836 | −out: | |
| 837 | − return rc; | |
| 838 | −err2: | |
| 839 | − pci_release_region(pdev, acfg->pp_mmio_bar); | |
| 840 | −err1: | |
| 841 | − pci_release_region(pdev, acfg->global_mmio_bar); | |
| 842 | − goto out; | |
| 843 | −} | |
| 844 | − | |
| 845 | −/** | |
| 846 | − * ocxlflash_config_afu() - configure the host AFU | |
| 847 | − * @pdev: PCI device associated with the host. | |
| 848 | − * @afu: AFU associated with the host. | |
| 849 | − * | |
| 850 | − * Must be called _after_ host function configuration. | |
| 851 | − * | |
| 852 | − * Return: 0 on success, -errno on failure | |
| 853 | − */ | |
| 854 | −static int ocxlflash_config_afu(struct pci_dev *pdev, struct ocxl_hw_afu *afu) | |
| 855 | −{ | |
| 856 | − struct ocxl_afu_config *acfg = &afu->acfg; | |
| 857 | − struct ocxl_fn_config *fcfg = &afu->fcfg; | |
| 858 | − struct device *dev = &pdev->dev; | |
| 859 | − int count; | |
| 860 | − int base; | |
| 861 | − int pos; | |
| 862 | − int rc = 0; | |
| 863 | − | |
| 864 | − /* This HW AFU function does not have any AFUs defined */ | |
| 865 | − if (!afu->is_present) | |
| 866 | − goto out; | |
| 867 | − | |
| 868 | − /* Read AFU config at index 0 */ | |
| 869 | − rc = ocxl_config_read_afu(pdev, fcfg, acfg, 0); | |
| 870 | − if (unlikely(rc)) { | |
| 871 | − dev_err(dev, "%s: ocxl_config_read_afu failed rc=%d\n", | |
| 872 | − __func__, rc); | |
| 873 | − goto out; | |
| 874 | − } | |
| 875 | − | |
| 876 | − /* Only one AFU per function is supported, so actag_base is same */ | |
| 877 | − base = afu->fn_actag_base; | |
| 878 | − count = min_t(int, acfg->actag_supported, afu->fn_actag_enabled); | |
| 879 | − pos = acfg->dvsec_afu_control_pos; | |
| 880 | − | |
| 881 | − ocxl_config_set_afu_actag(pdev, pos, base, count); | |
| 882 | − dev_dbg(dev, "%s: acTag base=%d enabled=%d\n", __func__, base, count); | |
| 883 | − afu->afu_actag_base = base; | |
| 884 | − afu->afu_actag_enabled = count; | |
| 885 | − afu->max_pasid = 1 << acfg->pasid_supported_log; | |
| 886 | − | |
| 887 | − ocxl_config_set_afu_pasid(pdev, pos, 0, acfg->pasid_supported_log); | |
| 888 | − | |
| 889 | − rc = ocxlflash_map_mmio(afu); | |
| 890 | − if (unlikely(rc)) { | |
| 891 | − dev_err(dev, "%s: ocxlflash_map_mmio failed rc=%d\n", | |
| 892 | − __func__, rc); | |
| 893 | − goto out; | |
| 894 | − } | |
| 895 | − | |
| 896 | − /* Enable the AFU */ | |
| 897 | − ocxl_config_set_afu_state(pdev, acfg->dvsec_afu_control_pos, 1); | |
| 898 | −out: | |
| 899 | − return rc; | |
| 900 | −} | |
| 901 | − | |
| 902 | −/** | |
| 903 | − * ocxlflash_create_afu() - create the AFU for OCXL | |
| 904 | − * @pdev: PCI device associated with the host. | |
| 905 | − * | |
| 906 | − * Return: AFU on success, NULL on failure | |
| 907 | − */ | |
| 908 | −static void *ocxlflash_create_afu(struct pci_dev *pdev) | |
| 909 | −{ | |
| 910 | − struct device *dev = &pdev->dev; | |
| 911 | − struct ocxlflash_context *ctx; | |
| 912 | − struct ocxl_hw_afu *afu; | |
| 913 | − int rc; | |
| 914 | − | |
| 915 | − afu = kzalloc(sizeof(*afu), GFP_KERNEL); | |
| 916 | − if (unlikely(!afu)) { | |
| 917 | − dev_err(dev, "%s: HW AFU allocation failed\n", __func__); | |
| 918 | − goto out; | |
| 919 | − } | |
| 920 | − | |
| 921 | − afu->pdev = pdev; | |
| 922 | − afu->dev = dev; | |
| 923 | − idr_init(&afu->idr); | |
| 924 | − | |
| 925 | − rc = ocxlflash_config_fn(pdev, afu); | |
| 926 | − if (unlikely(rc)) { | |
| 927 | − dev_err(dev, "%s: Function configuration failed rc=%d\n", | |
| 928 | − __func__, rc); | |
| 929 | − goto err1; | |
| 930 | − } | |
| 931 | − | |
| 932 | − rc = ocxlflash_config_afu(pdev, afu); | |
| 933 | − if (unlikely(rc)) { | |
| 934 | − dev_err(dev, "%s: AFU configuration failed rc=%d\n", | |
| 935 | − __func__, rc); | |
| 936 | − goto err2; | |
| 937 | − } | |
| 938 | − | |
| 939 | − ctx = ocxlflash_dev_context_init(pdev, afu); | |
| 940 | − if (IS_ERR(ctx)) { | |
| 941 | − rc = PTR_ERR(ctx); | |
| 942 | − dev_err(dev, "%s: ocxlflash_dev_context_init failed rc=%d\n", | |
| 943 | − __func__, rc); | |
| 944 | − goto err3; | |
| 945 | − } | |
| 946 | − | |
| 947 | − afu->ocxl_ctx = ctx; | |
| 948 | −out: | |
| 949 | − return afu; | |
| 950 | −err3: | |
| 951 | − ocxlflash_unconfig_afu(afu); | |
| 952 | −err2: | |
| 953 | − ocxlflash_unconfig_fn(pdev, afu); | |
| 954 | −err1: | |
| 955 | − idr_destroy(&afu->idr); | |
| 956 | − kfree(afu); | |
| 957 | − afu = NULL; | |
| 958 | − goto out; | |
| 959 | −} | |
| 960 | − | |
| 961 | −/** | |
| 962 | − * ctx_event_pending() - check for any event pending on the context | |
| 963 | − * @ctx: Context to be checked. | |
| 964 | − * | |
| 965 | − * Return: true if there is an event pending, false if none pending | |
| 966 | − */ | |
| 967 | −static inline bool ctx_event_pending(struct ocxlflash_context *ctx) | |
| 968 | −{ | |
| 969 | − if (ctx->pending_irq || ctx->pending_fault) | |
| 970 | − return true; | |
| 971 | − | |
| 972 | − return false; | |
| 973 | −} | |
| 974 | − | |
| 975 | −/** | |
| 976 | − * afu_poll() - poll the AFU for events on the context | |
| 977 | − * @file: File associated with the adapter context. | |
| 978 | − * @poll: Poll structure from the user. | |
| 979 | − * | |
| 980 | − * Return: poll mask | |
| 981 | − */ | |
| 982 | −static unsigned int afu_poll(struct file *file, struct poll_table_struct *poll) | |
| 983 | −{ | |
| 984 | − struct ocxlflash_context *ctx = file->private_data; | |
| 985 | − struct device *dev = ctx->hw_afu->dev; | |
| 986 | − ulong lock_flags; | |
| 987 | − int mask = 0; | |
| 988 | − | |
| 989 | − poll_wait(file, &ctx->wq, poll); | |
| 990 | − | |
| 991 | − spin_lock_irqsave(&ctx->slock, lock_flags); | |
| 992 | − if (ctx_event_pending(ctx)) | |
| 993 | − mask |= POLLIN | POLLRDNORM; | |
| 994 | − else if (ctx->state == CLOSED) | |
| 995 | − mask |= POLLERR; | |
| 996 | − spin_unlock_irqrestore(&ctx->slock, lock_flags); | |
| 997 | − | |
| 998 | − dev_dbg(dev, "%s: Poll wait completed for pe %i mask %i\n", | |
| 999 | − __func__, ctx->pe, mask); | |
| 1000 | − | |
| 1001 | − return mask; | |
| 1002 | −} | |
| 1003 | − | |
| 1004 | −/** | |
| 1005 | − * afu_read() - perform a read on the context for any event | |
| 1006 | − * @file: File associated with the adapter context. | |
| 1007 | − * @buf: Buffer to receive the data. | |
| 1008 | − * @count: Size of buffer (maximum bytes that can be read). | |
| 1009 | − * @off: Offset. | |
| 1010 | − * | |
| 1011 | − * Return: size of the data read on success, -errno on failure | |
| 1012 | − */ | |
| 1013 | −static ssize_t afu_read(struct file *file, char __user *buf, size_t count, | |
| 1014 | − loff_t *off) | |
| 1015 | −{ | |
| 1016 | − struct ocxlflash_context *ctx = file->private_data; | |
| 1017 | − struct device *dev = ctx->hw_afu->dev; | |
| 1018 | − struct cxl_event event; | |
| 1019 | − ulong lock_flags; | |
| 1020 | − ssize_t esize; | |
| 1021 | − ssize_t rc; | |
| 1022 | − int bit; | |
| 1023 | − DEFINE_WAIT(event_wait); | |
| 1024 | − | |
| 1025 | − if (*off != 0) { | |
| 1026 | − dev_err(dev, "%s: Non-zero offset not supported, off=%lld\n", | |
| 1027 | − __func__, *off); | |
| 1028 | − rc = -EINVAL; | |
| 1029 | − goto out; | |
| 1030 | − } | |
| 1031 | − | |
| 1032 | − spin_lock_irqsave(&ctx->slock, lock_flags); | |
| 1033 | − | |
| 1034 | − for (;;) { | |
| 1035 | − prepare_to_wait(&ctx->wq, &event_wait, TASK_INTERRUPTIBLE); | |
| 1036 | − | |
| 1037 | − if (ctx_event_pending(ctx) || (ctx->state == CLOSED)) | |
| 1038 | − break; | |
| 1039 | − | |
| 1040 | − if (file->f_flags & O_NONBLOCK) { | |
| 1041 | − dev_err(dev, "%s: File cannot be blocked on I/O\n", | |
| 1042 | − __func__); | |
| 1043 | − rc = -EAGAIN; | |
| 1044 | − goto err; | |
| 1045 | − } | |
| 1046 | − | |
| 1047 | − if (signal_pending(current)) { | |
| 1048 | − dev_err(dev, "%s: Signal pending on the process\n", | |
| 1049 | − __func__); | |
| 1050 | − rc = -ERESTARTSYS; | |
| 1051 | − goto err; | |
| 1052 | − } | |
| 1053 | − | |
| 1054 | − spin_unlock_irqrestore(&ctx->slock, lock_flags); | |
| 1055 | − schedule(); | |
| 1056 | − spin_lock_irqsave(&ctx->slock, lock_flags); | |
| 1057 | − } | |
| 1058 | − | |
| 1059 | − finish_wait(&ctx->wq, &event_wait); | |
| 1060 | − | |
| 1061 | − memset(&event, 0, sizeof(event)); | |
| 1062 | − event.header.process_element = ctx->pe; | |
| 1063 | − event.header.size = sizeof(struct cxl_event_header); | |
| 1064 | − if (ctx->pending_irq) { | |
| 1065 | − esize = sizeof(struct cxl_event_afu_interrupt); | |
| 1066 | − event.header.size += esize; | |
| 1067 | − event.header.type = CXL_EVENT_AFU_INTERRUPT; | |
| 1068 | − | |
| 1069 | − bit = find_first_bit(&ctx->irq_bitmap, ctx->num_irqs); | |
| 1070 | − clear_bit(bit, &ctx->irq_bitmap); | |
| 1071 | − event.irq.irq = bit + 1; | |
| 1072 | − if (bitmap_empty(&ctx->irq_bitmap, ctx->num_irqs)) | |
| 1073 | − ctx->pending_irq = false; | |
| 1074 | − } else if (ctx->pending_fault) { | |
| 1075 | − event.header.size += sizeof(struct cxl_event_data_storage); | |
| 1076 | − event.header.type = CXL_EVENT_DATA_STORAGE; | |
| 1077 | − event.fault.addr = ctx->fault_addr; | |
| 1078 | − event.fault.dsisr = ctx->fault_dsisr; | |
| 1079 | − ctx->pending_fault = false; | |
| 1080 | − } | |
| 1081 | − | |
| 1082 | − spin_unlock_irqrestore(&ctx->slock, lock_flags); | |
| 1083 | − | |
| 1084 | − if (copy_to_user(buf, &event, event.header.size)) { | |
| 1085 | − dev_err(dev, "%s: copy_to_user failed\n", __func__); | |
| 1086 | − rc = -EFAULT; | |
| 1087 | − goto out; | |
| 1088 | − } | |
| 1089 | − | |
| 1090 | − rc = event.header.size; | |
| 1091 | −out: | |
| 1092 | − return rc; | |
| 1093 | −err: | |
| 1094 | − finish_wait(&ctx->wq, &event_wait); | |
| 1095 | − spin_unlock_irqrestore(&ctx->slock, lock_flags); | |
| 1096 | − goto out; | |
| 1097 | −} | |
| 1098 | − | |
| 1099 | −/** | |
| 1100 | − * afu_release() - release and free the context | |
| 1101 | − * @inode: File inode pointer. | |
| 1102 | − * @file: File associated with the context. | |
| 1103 | − * | |
| 1104 | − * Return: 0 on success, -errno on failure | |
| 1105 | − */ | |
| 1106 | −static int afu_release(struct inode *inode, struct file *file) | |
| 1107 | −{ | |
| 1108 | − struct ocxlflash_context *ctx = file->private_data; | |
| 1109 | − int i; | |
| 1110 | − | |
| 1111 | − /* Unmap and free the interrupts associated with the context */ | |
| 1112 | − for (i = ctx->num_irqs; i >= 0; i--) | |
| 1113 | − afu_unmap_irq(0, ctx, i, ctx); | |
| 1114 | − free_afu_irqs(ctx); | |
| 1115 | − | |
| 1116 | − return ocxlflash_release_context(ctx); | |
| 1117 | −} | |
| 1118 | − | |
| 1119 | −/** | |
| 1120 | − * ocxlflash_mmap_fault() - mmap fault handler | |
| 1121 | − * @vmf: VM fault associated with current fault. | |
| 1122 | − * | |
| 1123 | − * Return: 0 on success, -errno on failure | |
| 1124 | − */ | |
| 1125 | −static vm_fault_t ocxlflash_mmap_fault(struct vm_fault *vmf) | |
| 1126 | −{ | |
| 1127 | − struct vm_area_struct *vma = vmf->vma; | |
| 1128 | − struct ocxlflash_context *ctx = vma->vm_file->private_data; | |
| 1129 | − struct device *dev = ctx->hw_afu->dev; | |
| 1130 | − u64 mmio_area, offset; | |
| 1131 | − | |
| 1132 | − offset = vmf->pgoff << PAGE_SHIFT; | |
| 1133 | − if (offset >= ctx->psn_size) | |
| 1134 | − return VM_FAULT_SIGBUS; | |
| 1135 | − | |
| 1136 | − mutex_lock(&ctx->state_mutex); | |
| 1137 | − if (ctx->state != STARTED) { | |
| 1138 | − dev_err(dev, "%s: Context not started, state=%d\n", | |
| 1139 | − __func__, ctx->state); | |
| 1140 | − mutex_unlock(&ctx->state_mutex); | |
| 1141 | − return VM_FAULT_SIGBUS; | |
| 1142 | − } | |
| 1143 | − mutex_unlock(&ctx->state_mutex); | |
| 1144 | − | |
| 1145 | − mmio_area = ctx->psn_phys; | |
| 1146 | − mmio_area += offset; | |
| 1147 | − | |
| 1148 | − return vmf_insert_pfn(vma, vmf->address, mmio_area >> PAGE_SHIFT); | |
| 1149 | −} | |
| 1150 | − | |
| 1151 | −static const struct vm_operations_struct ocxlflash_vmops = { | |
| 1152 | − .fault = ocxlflash_mmap_fault, | |
| 1153 | −}; | |
| 1154 | − | |
| 1155 | −/** | |
| 1156 | − * afu_mmap() - map the fault handler operations | |
| 1157 | − * @file: File associated with the context. | |
| 1158 | − * @vma: VM area associated with mapping. | |
| 1159 | − * | |
| 1160 | − * Return: 0 on success, -errno on failure | |
| 1161 | − */ | |
| 1162 | −static int afu_mmap(struct file *file, struct vm_area_struct *vma) | |
| 1163 | −{ | |
| 1164 | − struct ocxlflash_context *ctx = file->private_data; | |
| 1165 | − | |
| 1166 | − if ((vma_pages(vma) + vma->vm_pgoff) > | |
| 1167 | − (ctx->psn_size >> PAGE_SHIFT)) | |
| 1168 | − return -EINVAL; | |
| 1169 | − | |
| 1170 | − vm_flags_set(vma, VM_IO | VM_PFNMAP); | |
| 1171 | − vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | |
| 1172 | − vma->vm_ops = &ocxlflash_vmops; | |
| 1173 | − return 0; | |
| 1174 | −} | |
| 1175 | − | |
| 1176 | −static const struct file_operations ocxl_afu_fops = { | |
| 1177 | − .owner = THIS_MODULE, | |
| 1178 | − .poll = afu_poll, | |
| 1179 | − .read = afu_read, | |
| 1180 | − .release = afu_release, | |
| 1181 | − .mmap = afu_mmap, | |
| 1182 | −}; | |
| 1183 | − | |
| 1184 | −#define PATCH_FOPS(NAME) \ | |
| 1185 | − do { if (!fops->NAME) fops->NAME = ocxl_afu_fops.NAME; } while (0) | |
| 1186 | − | |
| 1187 | −/** | |
| 1188 | − * ocxlflash_get_fd() - get file descriptor for an adapter context | |
| 1189 | − * @ctx_cookie: Adapter context. | |
| 1190 | − * @fops: File operations to be associated. | |
| 1191 | − * @fd: File descriptor to be returned back. | |
| 1192 | − * | |
| 1193 | − * Return: pointer to the file on success, ERR_PTR on failure | |
| 1194 | − */ | |
| 1195 | −static struct file *ocxlflash_get_fd(void *ctx_cookie, | |
| 1196 | − struct file_operations *fops, int *fd) | |
| 1197 | −{ | |
| 1198 | − struct ocxlflash_context *ctx = ctx_cookie; | |
| 1199 | − struct device *dev = ctx->hw_afu->dev; | |
| 1200 | − struct file *file; | |
| 1201 | − int flags, fdtmp; | |
| 1202 | − int rc = 0; | |
| 1203 | − char *name = NULL; | |
| 1204 | − | |
| 1205 | − /* Only allow one fd per context */ | |
| 1206 | − if (ctx->mapping) { | |
| 1207 | − dev_err(dev, "%s: Context is already mapped to an fd\n", | |
| 1208 | − __func__); | |
| 1209 | − rc = -EEXIST; | |
| 1210 | − goto err1; | |
| 1211 | − } | |
| 1212 | − | |
| 1213 | − flags = O_RDWR | O_CLOEXEC; | |
| 1214 | − | |
| 1215 | − /* This code is similar to anon_inode_getfd() */ | |
| 1216 | − rc = get_unused_fd_flags(flags); | |
| 1217 | − if (unlikely(rc < 0)) { | |
| 1218 | − dev_err(dev, "%s: get_unused_fd_flags failed rc=%d\n", | |
| 1219 | − __func__, rc); | |
| 1220 | − goto err1; | |
| 1221 | − } | |
| 1222 | − fdtmp = rc; | |
| 1223 | − | |
| 1224 | − /* Patch the file ops that are not defined */ | |
| 1225 | − if (fops) { | |
| 1226 | − PATCH_FOPS(poll); | |
| 1227 | − PATCH_FOPS(read); | |
| 1228 | − PATCH_FOPS(release); | |
| 1229 | − PATCH_FOPS(mmap); | |
| 1230 | − } else /* Use default ops */ | |
| 1231 | − fops = (struct file_operations *)&ocxl_afu_fops; | |
| 1232 | − | |
| 1233 | − name = kasprintf(GFP_KERNEL, "ocxlflash:%d", ctx->pe); | |
| 1234 | − file = ocxlflash_getfile(dev, name, fops, ctx, flags); | |
| 1235 | − kfree(name); | |
| 1236 | − if (IS_ERR(file)) { | |
| 1237 | − rc = PTR_ERR(file); | |
| 1238 | − dev_err(dev, "%s: ocxlflash_getfile failed rc=%d\n", | |
| 1239 | − __func__, rc); | |
| 1240 | − goto err2; | |
| 1241 | − } | |
| 1242 | − | |
| 1243 | − ctx->mapping = file->f_mapping; | |
| 1244 | − *fd = fdtmp; | |
| 1245 | −out: | |
| 1246 | − return file; | |
| 1247 | −err2: | |
| 1248 | − put_unused_fd(fdtmp); | |
| 1249 | −err1: | |
| 1250 | − file = ERR_PTR(rc); | |
| 1251 | − goto out; | |
| 1252 | −} | |
| 1253 | − | |
| 1254 | −/** | |
| 1255 | − * ocxlflash_fops_get_context() - get the context associated with the file | |
| 1256 | − * @file: File associated with the adapter context. | |
| 1257 | − * | |
| 1258 | − * Return: pointer to the context | |
| 1259 | − */ | |
| 1260 | −static void *ocxlflash_fops_get_context(struct file *file) | |
| 1261 | −{ | |
| 1262 | − return file->private_data; | |
| 1263 | −} | |
| 1264 | − | |
| 1265 | −/** | |
| 1266 | − * ocxlflash_afu_irq() - interrupt handler for user contexts | |
| 1267 | − * @irq: Interrupt number. | |
| 1268 | − * @data: Private data provided at interrupt registration, the context. | |
| 1269 | − * | |
| 1270 | − * Return: Always return IRQ_HANDLED. | |
| 1271 | − */ | |
| 1272 | −static irqreturn_t ocxlflash_afu_irq(int irq, void *data) | |
| 1273 | −{ | |
| 1274 | − struct ocxlflash_context *ctx = data; | |
| 1275 | − struct device *dev = ctx->hw_afu->dev; | |
| 1276 | − int i; | |
| 1277 | − | |
| 1278 | − dev_dbg(dev, "%s: Interrupt raised for pe %i virq %i\n", | |
| 1279 | − __func__, ctx->pe, irq); | |
| 1280 | − | |
| 1281 | − for (i = 0; i < ctx->num_irqs; i++) { | |
| 1282 | − if (ctx->irqs[i].virq == irq) | |
| 1283 | − break; | |
| 1284 | − } | |
| 1285 | − if (unlikely(i >= ctx->num_irqs)) { | |
| 1286 | − dev_err(dev, "%s: Received AFU IRQ out of range\n", __func__); | |
| 1287 | − goto out; | |
| 1288 | − } | |
| 1289 | − | |
| 1290 | − spin_lock(&ctx->slock); | |
| 1291 | − set_bit(i - 1, &ctx->irq_bitmap); | |
| 1292 | − ctx->pending_irq = true; | |
| 1293 | − spin_unlock(&ctx->slock); | |
| 1294 | − | |
| 1295 | − wake_up_all(&ctx->wq); | |
| 1296 | −out: | |
| 1297 | − return IRQ_HANDLED; | |
| 1298 | −} | |
| 1299 | − | |
| 1300 | −/** | |
| 1301 | − * ocxlflash_start_work() - start a user context | |
| 1302 | − * @ctx_cookie: Context to be started. | |
| 1303 | − * @num_irqs: Number of interrupts requested. | |
| 1304 | − * | |
| 1305 | − * Return: 0 on success, -errno on failure | |
| 1306 | − */ | |
| 1307 | −static int ocxlflash_start_work(void *ctx_cookie, u64 num_irqs) | |
| 1308 | −{ | |
| 1309 | − struct ocxlflash_context *ctx = ctx_cookie; | |
| 1310 | − struct ocxl_hw_afu *afu = ctx->hw_afu; | |
| 1311 | − struct device *dev = afu->dev; | |
| 1312 | − char *name; | |
| 1313 | − int rc = 0; | |
| 1314 | − int i; | |
| 1315 | − | |
| 1316 | − rc = alloc_afu_irqs(ctx, num_irqs); | |
| 1317 | − if (unlikely(rc < 0)) { | |
| 1318 | − dev_err(dev, "%s: alloc_afu_irqs failed rc=%d\n", __func__, rc); | |
| 1319 | − goto out; | |
| 1320 | − } | |
| 1321 | − | |
| 1322 | − for (i = 0; i < num_irqs; i++) { | |
| 1323 | − name = kasprintf(GFP_KERNEL, "ocxlflash-%s-pe%i-%i", | |
| 1324 | − dev_name(dev), ctx->pe, i); | |
| 1325 | − rc = afu_map_irq(0, ctx, i, ocxlflash_afu_irq, ctx, name); | |
| 1326 | − kfree(name); | |
| 1327 | − if (unlikely(rc < 0)) { | |
| 1328 | − dev_err(dev, "%s: afu_map_irq failed rc=%d\n", | |
| 1329 | − __func__, rc); | |
| 1330 | − goto err; | |
| 1331 | − } | |
| 1332 | − } | |
| 1333 | − | |
| 1334 | − rc = start_context(ctx); | |
| 1335 | − if (unlikely(rc)) { | |
| 1336 | − dev_err(dev, "%s: start_context failed rc=%d\n", __func__, rc); | |
| 1337 | − goto err; | |
| 1338 | − } | |
| 1339 | −out: | |
| 1340 | − return rc; | |
| 1341 | −err: | |
| 1342 | − for (i = i-1; i >= 0; i--) | |
| 1343 | − afu_unmap_irq(0, ctx, i, ctx); | |
| 1344 | − free_afu_irqs(ctx); | |
| 1345 | − goto out; | |
| 1346 | −}; | |
| 1347 | − | |
| 1348 | −/** | |
| 1349 | − * ocxlflash_fd_mmap() - mmap handler for adapter file descriptor | |
| 1350 | − * @file: File installed with adapter file descriptor. | |
| 1351 | − * @vma: VM area associated with mapping. | |
| 1352 | − * | |
| 1353 | − * Return: 0 on success, -errno on failure | |
| 1354 | − */ | |
| 1355 | −static int ocxlflash_fd_mmap(struct file *file, struct vm_area_struct *vma) | |
| 1356 | −{ | |
| 1357 | − return afu_mmap(file, vma); | |
| 1358 | −} | |
| 1359 | − | |
| 1360 | −/** | |
| 1361 | − * ocxlflash_fd_release() - release the context associated with the file | |
| 1362 | − * @inode: File inode pointer. | |
| 1363 | − * @file: File associated with the adapter context. | |
| 1364 | − * | |
| 1365 | − * Return: 0 on success, -errno on failure | |
| 1366 | − */ | |
| 1367 | −static int ocxlflash_fd_release(struct inode *inode, struct file *file) | |
| 1368 | −{ | |
| 1369 | − return afu_release(inode, file); | |
| 1370 | −} | |
| 1371 | − | |
| 1372 | −/* Backend ops to ocxlflash services */ | |
| 1373 | −const struct cxlflash_backend_ops cxlflash_ocxl_ops = { | |
| 1374 | − .module = THIS_MODULE, | |
| 1375 | − .psa_map = ocxlflash_psa_map, | |
| 1376 | − .psa_unmap = ocxlflash_psa_unmap, | |
| 1377 | − .process_element = ocxlflash_process_element, | |
| 1378 | − .map_afu_irq = ocxlflash_map_afu_irq, | |
| 1379 | − .unmap_afu_irq = ocxlflash_unmap_afu_irq, | |
| 1380 | − .get_irq_objhndl = ocxlflash_get_irq_objhndl, | |
| 1381 | − .start_context = ocxlflash_start_context, | |
| 1382 | − .stop_context = ocxlflash_stop_context, | |
| 1383 | − .afu_reset = ocxlflash_afu_reset, | |
| 1384 | − .set_master = ocxlflash_set_master, | |
| 1385 | − .get_context = ocxlflash_get_context, | |
| 1386 | − .dev_context_init = ocxlflash_dev_context_init, | |
| 1387 | − .release_context = ocxlflash_release_context, | |
| 1388 | − .perst_reloads_same_image = ocxlflash_perst_reloads_same_image, | |
| 1389 | − .read_adapter_vpd = ocxlflash_read_adapter_vpd, | |
| 1390 | − .allocate_afu_irqs = ocxlflash_allocate_afu_irqs, | |
| 1391 | − .free_afu_irqs = ocxlflash_free_afu_irqs, | |
| 1392 | − .create_afu = ocxlflash_create_afu, | |
| 1393 | − .destroy_afu = ocxlflash_destroy_afu, | |
| 1394 | − .get_fd = ocxlflash_get_fd, | |
| 1395 | − .fops_get_context = ocxlflash_fops_get_context, | |
| 1396 | − .start_work = ocxlflash_start_work, | |
| 1397 | − .fd_mmap = ocxlflash_fd_mmap, | |
| 1398 | − .fd_release = ocxlflash_fd_release, | |
| 1399 | −}; | |
| @@ -1,72 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2018 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#define OCXL_MAX_IRQS 4 /* Max interrupts per process */ | |
| 12 | − | |
| 13 | −struct ocxlflash_irqs { | |
| 14 | − int hwirq; | |
| 15 | − u32 virq; | |
| 16 | − void __iomem *vtrig; | |
| 17 | −}; | |
| 18 | − | |
| 19 | −/* OCXL hardware AFU associated with the host */ | |
| 20 | −struct ocxl_hw_afu { | |
| 21 | − struct ocxlflash_context *ocxl_ctx; /* Host context */ | |
| 22 | − struct pci_dev *pdev; /* PCI device */ | |
| 23 | − struct device *dev; /* Generic device */ | |
| 24 | − bool perst_same_image; /* Same image loaded on perst */ | |
| 25 | − | |
| 26 | − struct ocxl_fn_config fcfg; /* DVSEC config of the function */ | |
| 27 | − struct ocxl_afu_config acfg; /* AFU configuration data */ | |
| 28 | − | |
| 29 | − int fn_actag_base; /* Function acTag base */ | |
| 30 | − int fn_actag_enabled; /* Function acTag number enabled */ | |
| 31 | − int afu_actag_base; /* AFU acTag base */ | |
| 32 | − int afu_actag_enabled; /* AFU acTag number enabled */ | |
| 33 | − | |
| 34 | − phys_addr_t ppmmio_phys; /* Per process MMIO space */ | |
| 35 | − phys_addr_t gmmio_phys; /* Global AFU MMIO space */ | |
| 36 | − void __iomem *gmmio_virt; /* Global MMIO map */ | |
| 37 | − | |
| 38 | − void *link_token; /* Link token for the SPA */ | |
| 39 | − struct idr idr; /* IDR to manage contexts */ | |
| 40 | − int max_pasid; /* Maximum number of contexts */ | |
| 41 | − bool is_present; /* Function has AFUs defined */ | |
| 42 | −}; | |
| 43 | − | |
| 44 | −enum ocxlflash_ctx_state { | |
| 45 | − CLOSED, | |
| 46 | − OPENED, | |
| 47 | − STARTED | |
| 48 | −}; | |
| 49 | − | |
| 50 | −struct ocxlflash_context { | |
| 51 | − struct ocxl_hw_afu *hw_afu; /* HW AFU back pointer */ | |
| 52 | − struct address_space *mapping; /* Mapping for pseudo filesystem */ | |
| 53 | − bool master; /* Whether this is a master context */ | |
| 54 | − int pe; /* Process element */ | |
| 55 | − | |
| 56 | − phys_addr_t psn_phys; /* Process mapping */ | |
| 57 | − u64 psn_size; /* Process mapping size */ | |
| 58 | − | |
| 59 | − spinlock_t slock; /* Protects irq/fault/event updates */ | |
| 60 | − wait_queue_head_t wq; /* Wait queue for poll and interrupts */ | |
| 61 | − struct mutex state_mutex; /* Mutex to update context state */ | |
| 62 | − enum ocxlflash_ctx_state state; /* Context state */ | |
| 63 | − | |
| 64 | − struct ocxlflash_irqs *irqs; /* Pointer to array of structures */ | |
| 65 | − int num_irqs; /* Number of interrupts */ | |
| 66 | − bool pending_irq; /* Pending interrupt on the context */ | |
| 67 | − ulong irq_bitmap; /* Bits indicating pending irq num */ | |
| 68 | − | |
| 69 | − u64 fault_addr; /* Address that triggered the fault */ | |
| 70 | − u64 fault_dsisr; /* Value of dsisr register at fault */ | |
| 71 | − bool pending_fault; /* Pending translation fault */ | |
| 72 | −}; | |
| @@ -1,560 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2015 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#ifndef _SISLITE_H | |
| 12 | −#define _SISLITE_H | |
| 13 | − | |
| 14 | −#include <linux/types.h> | |
| 15 | − | |
| 16 | −typedef u16 ctx_hndl_t; | |
| 17 | −typedef u32 res_hndl_t; | |
| 18 | − | |
| 19 | −#define SIZE_4K 4096 | |
| 20 | −#define SIZE_64K 65536 | |
| 21 | − | |
| 22 | −/* | |
| 23 | − * IOARCB: 64 bytes, min 16 byte alignment required, host native endianness | |
| 24 | − * except for SCSI CDB which remains big endian per SCSI standards. | |
| 25 | − */ | |
| 26 | −struct sisl_ioarcb { | |
| 27 | − u16 ctx_id; /* ctx_hndl_t */ | |
| 28 | − u16 req_flags; | |
| 29 | −#define SISL_REQ_FLAGS_RES_HNDL 0x8000U /* bit 0 (MSB) */ | |
| 30 | −#define SISL_REQ_FLAGS_PORT_LUN_ID 0x0000U | |
| 31 | − | |
| 32 | −#define SISL_REQ_FLAGS_SUP_UNDERRUN 0x4000U /* bit 1 */ | |
| 33 | − | |
| 34 | −#define SISL_REQ_FLAGS_TIMEOUT_SECS 0x0000U /* bits 8,9 */ | |
| 35 | −#define SISL_REQ_FLAGS_TIMEOUT_MSECS 0x0040U | |
| 36 | −#define SISL_REQ_FLAGS_TIMEOUT_USECS 0x0080U | |
| 37 | −#define SISL_REQ_FLAGS_TIMEOUT_CYCLES 0x00C0U | |
| 38 | − | |
| 39 | −#define SISL_REQ_FLAGS_TMF_CMD 0x0004u /* bit 13 */ | |
| 40 | − | |
| 41 | −#define SISL_REQ_FLAGS_AFU_CMD 0x0002U /* bit 14 */ | |
| 42 | − | |
| 43 | −#define SISL_REQ_FLAGS_HOST_WRITE 0x0001U /* bit 15 (LSB) */ | |
| 44 | −#define SISL_REQ_FLAGS_HOST_READ 0x0000U | |
| 45 | − | |
| 46 | − union { | |
| 47 | − u32 res_hndl; /* res_hndl_t */ | |
| 48 | − u32 port_sel; /* this is a selection mask: | |
| 49 | − * 0x1 -> port#0 can be selected, | |
| 50 | − * 0x2 -> port#1 can be selected. | |
| 51 | − * Can be bitwise ORed. | |
| 52 | − */ | |
| 53 | − }; | |
| 54 | − u64 lun_id; | |
| 55 | − u32 data_len; /* 4K for read/write */ | |
| 56 | − u32 ioadl_len; | |
| 57 | − union { | |
| 58 | − u64 data_ea; /* min 16 byte aligned */ | |
| 59 | − u64 ioadl_ea; | |
| 60 | − }; | |
| 61 | − u8 msi; /* LISN to send on RRQ write */ | |
| 62 | −#define SISL_MSI_CXL_PFAULT 0 /* reserved for CXL page faults */ | |
| 63 | −#define SISL_MSI_SYNC_ERROR 1 /* recommended for AFU sync error */ | |
| 64 | −#define SISL_MSI_RRQ_UPDATED 2 /* recommended for IO completion */ | |
| 65 | −#define SISL_MSI_ASYNC_ERROR 3 /* master only - for AFU async error */ | |
| 66 | − | |
| 67 | − u8 rrq; /* 0 for a single RRQ */ | |
| 68 | − u16 timeout; /* in units specified by req_flags */ | |
| 69 | − u32 rsvd1; | |
| 70 | − u8 cdb[16]; /* must be in big endian */ | |
| 71 | −#define SISL_AFU_CMD_SYNC 0xC0 /* AFU sync command */ | |
| 72 | −#define SISL_AFU_CMD_LUN_PROVISION 0xD0 /* AFU LUN provision command */ | |
| 73 | −#define SISL_AFU_CMD_DEBUG 0xE0 /* AFU debug command */ | |
| 74 | − | |
| 75 | −#define SISL_AFU_LUN_PROVISION_CREATE 0x00 /* LUN provision create type */ | |
| 76 | −#define SISL_AFU_LUN_PROVISION_DELETE 0x01 /* LUN provision delete type */ | |
| 77 | − | |
| 78 | − union { | |
| 79 | − u64 reserved; /* Reserved for IOARRIN mode */ | |
| 80 | − struct sisl_ioasa *ioasa; /* IOASA EA for SQ Mode */ | |
| 81 | − }; | |
| 82 | −} __packed; | |
| 83 | − | |
| 84 | −struct sisl_rc { | |
| 85 | − u8 flags; | |
| 86 | −#define SISL_RC_FLAGS_SENSE_VALID 0x80U | |
| 87 | −#define SISL_RC_FLAGS_FCP_RSP_CODE_VALID 0x40U | |
| 88 | −#define SISL_RC_FLAGS_OVERRUN 0x20U | |
| 89 | −#define SISL_RC_FLAGS_UNDERRUN 0x10U | |
| 90 | − | |
| 91 | − u8 afu_rc; | |
| 92 | −#define SISL_AFU_RC_RHT_INVALID 0x01U /* user error */ | |
| 93 | −#define SISL_AFU_RC_RHT_UNALIGNED 0x02U /* should never happen */ | |
| 94 | −#define SISL_AFU_RC_RHT_OUT_OF_BOUNDS 0x03u /* user error */ | |
| 95 | −#define SISL_AFU_RC_RHT_DMA_ERR 0x04u /* see afu_extra | |
| 96 | − * may retry if afu_retry is off | |
| 97 | − * possible on master exit | |
| 98 | − */ | |
| 99 | −#define SISL_AFU_RC_RHT_RW_PERM 0x05u /* no RW perms, user error */ | |
| 100 | −#define SISL_AFU_RC_LXT_UNALIGNED 0x12U /* should never happen */ | |
| 101 | −#define SISL_AFU_RC_LXT_OUT_OF_BOUNDS 0x13u /* user error */ | |
| 102 | −#define SISL_AFU_RC_LXT_DMA_ERR 0x14u /* see afu_extra | |
| 103 | − * may retry if afu_retry is off | |
| 104 | − * possible on master exit | |
| 105 | − */ | |
| 106 | −#define SISL_AFU_RC_LXT_RW_PERM 0x15u /* no RW perms, user error */ | |
| 107 | − | |
| 108 | −#define SISL_AFU_RC_NOT_XLATE_HOST 0x1au /* possible if master exited */ | |
| 109 | − | |
| 110 | − /* NO_CHANNELS means the FC ports selected by dest_port in | |
| 111 | − * IOARCB or in the LXT entry are down when the AFU tried to select | |
| 112 | − * a FC port. If the port went down on an active IO, it will set | |
| 113 | − * fc_rc to =0x54(NOLOGI) or 0x57(LINKDOWN) instead. | |
| 114 | − */ | |
| 115 | −#define SISL_AFU_RC_NO_CHANNELS 0x20U /* see afu_extra, may retry */ | |
| 116 | −#define SISL_AFU_RC_CAP_VIOLATION 0x21U /* either user error or | |
| 117 | − * afu reset/master restart | |
| 118 | − */ | |
| 119 | −#define SISL_AFU_RC_OUT_OF_DATA_BUFS 0x30U /* always retry */ | |
| 120 | −#define SISL_AFU_RC_DATA_DMA_ERR 0x31U /* see afu_extra | |
| 121 | − * may retry if afu_retry is off | |
| 122 | − */ | |
| 123 | − | |
| 124 | − u8 scsi_rc; /* SCSI status byte, retry as appropriate */ | |
| 125 | −#define SISL_SCSI_RC_CHECK 0x02U | |
| 126 | −#define SISL_SCSI_RC_BUSY 0x08u | |
| 127 | − | |
| 128 | − u8 fc_rc; /* retry */ | |
| 129 | − /* | |
| 130 | − * We should only see fc_rc=0x57 (LINKDOWN) or 0x54(NOLOGI) for | |
| 131 | − * commands that are in flight when a link goes down or is logged out. | |
| 132 | − * If the link is down or logged out before AFU selects the port, either | |
| 133 | − * it will choose the other port or we will get afu_rc=0x20 (no_channel) | |
| 134 | − * if there is no valid port to use. | |
| 135 | − * | |
| 136 | − * ABORTPEND/ABORTOK/ABORTFAIL/TGTABORT can be retried, typically these | |
| 137 | − * would happen if a frame is dropped and something times out. | |
| 138 | − * NOLOGI or LINKDOWN can be retried if the other port is up. | |
| 139 | − * RESIDERR can be retried as well. | |
| 140 | − * | |
| 141 | − * ABORTFAIL might indicate that lots of frames are getting CRC errors. | |
| 142 | − * So it maybe retried once and reset the link if it happens again. | |
| 143 | − * The link can also be reset on the CRC error threshold interrupt. | |
| 144 | − */ | |
| 145 | −#define SISL_FC_RC_ABORTPEND 0x52 /* exchange timeout or abort request */ | |
| 146 | −#define SISL_FC_RC_WRABORTPEND 0x53 /* due to write XFER_RDY invalid */ | |
| 147 | −#define SISL_FC_RC_NOLOGI 0x54 /* port not logged in, in-flight cmds */ | |
| 148 | −#define SISL_FC_RC_NOEXP 0x55 /* FC protocol error or HW bug */ | |
| 149 | −#define SISL_FC_RC_INUSE 0x56 /* tag already in use, HW bug */ | |
| 150 | −#define SISL_FC_RC_LINKDOWN 0x57 /* link down, in-flight cmds */ | |
| 151 | −#define SISL_FC_RC_ABORTOK 0x58 /* pending abort completed w/success */ | |
| 152 | −#define SISL_FC_RC_ABORTFAIL 0x59 /* pending abort completed w/fail */ | |
| 153 | −#define SISL_FC_RC_RESID 0x5A /* ioasa underrun/overrun flags set */ | |
| 154 | −#define SISL_FC_RC_RESIDERR 0x5B /* actual data len does not match SCSI | |
| 155 | − * reported len, possibly due to dropped | |
| 156 | − * frames | |
| 157 | − */ | |
| 158 | −#define SISL_FC_RC_TGTABORT 0x5C /* command aborted by target */ | |
| 159 | −}; | |
| 160 | − | |
| 161 | −#define SISL_SENSE_DATA_LEN 20 /* Sense data length */ | |
| 162 | −#define SISL_WWID_DATA_LEN 16 /* WWID data length */ | |
| 163 | − | |
| 164 | −/* | |
| 165 | − * IOASA: 64 bytes & must follow IOARCB, min 16 byte alignment required, | |
| 166 | − * host native endianness | |
| 167 | − */ | |
| 168 | −struct sisl_ioasa { | |
| 169 | − union { | |
| 170 | − struct sisl_rc rc; | |
| 171 | − u32 ioasc; | |
| 172 | −#define SISL_IOASC_GOOD_COMPLETION 0x00000000U | |
| 173 | − }; | |
| 174 | − | |
| 175 | − union { | |
| 176 | − u32 resid; | |
| 177 | − u32 lunid_hi; | |
| 178 | − }; | |
| 179 | − | |
| 180 | − u8 port; | |
| 181 | − u8 afu_extra; | |
| 182 | − /* when afu_rc=0x04, 0x14, 0x31 (_xxx_DMA_ERR): | |
| 183 | − * afu_exta contains PSL response code. Useful codes are: | |
| 184 | − */ | |
| 185 | −#define SISL_AFU_DMA_ERR_PAGE_IN 0x0A /* AFU_retry_on_pagein Action | |
| 186 | − * Enabled N/A | |
| 187 | − * Disabled retry | |
| 188 | − */ | |
| 189 | −#define SISL_AFU_DMA_ERR_INVALID_EA 0x0B /* this is a hard error | |
| 190 | − * afu_rc Implies | |
| 191 | − * 0x04, 0x14 master exit. | |
| 192 | − * 0x31 user error. | |
| 193 | − */ | |
| 194 | − /* when afu rc=0x20 (no channels): | |
| 195 | − * afu_extra bits [4:5]: available portmask, [6:7]: requested portmask. | |
| 196 | − */ | |
| 197 | −#define SISL_AFU_NO_CLANNELS_AMASK(afu_extra) (((afu_extra) & 0x0C) >> 2) | |
| 198 | −#define SISL_AFU_NO_CLANNELS_RMASK(afu_extra) ((afu_extra) & 0x03) | |
| 199 | − | |
| 200 | − u8 scsi_extra; | |
| 201 | − u8 fc_extra; | |
| 202 | − | |
| 203 | − union { | |
| 204 | − u8 sense_data[SISL_SENSE_DATA_LEN]; | |
| 205 | − struct { | |
| 206 | − u32 lunid_lo; | |
| 207 | − u8 wwid[SISL_WWID_DATA_LEN]; | |
| 208 | − }; | |
| 209 | − }; | |
| 210 | − | |
| 211 | − /* These fields are defined by the SISlite architecture for the | |
| 212 | − * host to use as they see fit for their implementation. | |
| 213 | − */ | |
| 214 | − union { | |
| 215 | − u64 host_use[4]; | |
| 216 | − u8 host_use_b[32]; | |
| 217 | − }; | |
| 218 | −} __packed; | |
| 219 | − | |
| 220 | −#define SISL_RESP_HANDLE_T_BIT 0x1ULL /* Toggle bit */ | |
| 221 | − | |
| 222 | −/* MMIO space is required to support only 64-bit access */ | |
| 223 | − | |
| 224 | −/* | |
| 225 | − * This AFU has two mechanisms to deal with endian-ness. | |
| 226 | − * One is a global configuration (in the afu_config) register | |
| 227 | − * below that specifies the endian-ness of the host. | |
| 228 | − * The other is a per context (i.e. application) specification | |
| 229 | − * controlled by the endian_ctrl field here. Since the master | |
| 230 | − * context is one such application the master context's | |
| 231 | − * endian-ness is set to be the same as the host. | |
| 232 | − * | |
| 233 | − * As per the SISlite spec, the MMIO registers are always | |
| 234 | − * big endian. | |
| 235 | − */ | |
| 236 | −#define SISL_ENDIAN_CTRL_BE 0x8000000000000080ULL | |
| 237 | −#define SISL_ENDIAN_CTRL_LE 0x0000000000000000ULL | |
| 238 | − | |
| 239 | −#ifdef __BIG_ENDIAN | |
| 240 | −#define SISL_ENDIAN_CTRL SISL_ENDIAN_CTRL_BE | |
| 241 | −#else | |
| 242 | −#define SISL_ENDIAN_CTRL SISL_ENDIAN_CTRL_LE | |
| 243 | −#endif | |
| 244 | − | |
| 245 | −/* per context host transport MMIO */ | |
| 246 | −struct sisl_host_map { | |
| 247 | − __be64 endian_ctrl; /* Per context Endian Control. The AFU will | |
| 248 | − * operate on whatever the context is of the | |
| 249 | − * host application. | |
| 250 | − */ | |
| 251 | − | |
| 252 | − __be64 intr_status; /* this sends LISN# programmed in ctx_ctrl. | |
| 253 | − * Only recovery in a PERM_ERR is a context | |
| 254 | − * exit since there is no way to tell which | |
| 255 | − * command caused the error. | |
| 256 | − */ | |
| 257 | −#define SISL_ISTATUS_PERM_ERR_LISN_3_EA 0x0400ULL /* b53, user error */ | |
| 258 | −#define SISL_ISTATUS_PERM_ERR_LISN_2_EA 0x0200ULL /* b54, user error */ | |
| 259 | −#define SISL_ISTATUS_PERM_ERR_LISN_1_EA 0x0100ULL /* b55, user error */ | |
| 260 | −#define SISL_ISTATUS_PERM_ERR_LISN_3_PASID 0x0080ULL /* b56, user error */ | |
| 261 | −#define SISL_ISTATUS_PERM_ERR_LISN_2_PASID 0x0040ULL /* b57, user error */ | |
| 262 | −#define SISL_ISTATUS_PERM_ERR_LISN_1_PASID 0x0020ULL /* b58, user error */ | |
| 263 | −#define SISL_ISTATUS_PERM_ERR_CMDROOM 0x0010ULL /* b59, user error */ | |
| 264 | −#define SISL_ISTATUS_PERM_ERR_RCB_READ 0x0008ULL /* b60, user error */ | |
| 265 | −#define SISL_ISTATUS_PERM_ERR_SA_WRITE 0x0004ULL /* b61, user error */ | |
| 266 | −#define SISL_ISTATUS_PERM_ERR_RRQ_WRITE 0x0002ULL /* b62, user error */ | |
| 267 | − /* Page in wait accessing RCB/IOASA/RRQ is reported in b63. | |
| 268 | − * Same error in data/LXT/RHT access is reported via IOASA. | |
| 269 | − */ | |
| 270 | −#define SISL_ISTATUS_TEMP_ERR_PAGEIN 0x0001ULL /* b63, can only be | |
| 271 | − * generated when AFU | |
| 272 | − * auto retry is | |
| 273 | − * disabled. If user | |
| 274 | − * can determine the | |
| 275 | − * command that caused | |
| 276 | − * the error, it can | |
| 277 | − * be retried. | |
| 278 | − */ | |
| 279 | −#define SISL_ISTATUS_UNMASK (0x07FFULL) /* 1 means unmasked */ | |
| 280 | −#define SISL_ISTATUS_MASK ~(SISL_ISTATUS_UNMASK) /* 1 means masked */ | |
| 281 | − | |
| 282 | − __be64 intr_clear; | |
| 283 | − __be64 intr_mask; | |
| 284 | − __be64 ioarrin; /* only write what cmd_room permits */ | |
| 285 | − __be64 rrq_start; /* start & end are both inclusive */ | |
| 286 | − __be64 rrq_end; /* write sequence: start followed by end */ | |
| 287 | − __be64 cmd_room; | |
| 288 | − __be64 ctx_ctrl; /* least significant byte or b56:63 is LISN# */ | |
| 289 | −#define SISL_CTX_CTRL_UNMAP_SECTOR 0x8000000000000000ULL /* b0 */ | |
| 290 | −#define SISL_CTX_CTRL_LISN_MASK (0xFFULL) | |
| 291 | − __be64 mbox_w; /* restricted use */ | |
| 292 | − __be64 sq_start; /* Submission Queue (R/W): write sequence and */ | |
| 293 | − __be64 sq_end; /* inclusion semantics are the same as RRQ */ | |
| 294 | − __be64 sq_head; /* Submission Queue Head (R): for debugging */ | |
| 295 | − __be64 sq_tail; /* Submission Queue TAIL (R/W): next IOARCB */ | |
| 296 | − __be64 sq_ctx_reset; /* Submission Queue Context Reset (R/W) */ | |
| 297 | −}; | |
| 298 | − | |
| 299 | −/* per context provisioning & control MMIO */ | |
| 300 | −struct sisl_ctrl_map { | |
| 301 | − __be64 rht_start; | |
| 302 | − __be64 rht_cnt_id; | |
| 303 | − /* both cnt & ctx_id args must be ULL */ | |
| 304 | −#define SISL_RHT_CNT_ID(cnt, ctx_id) (((cnt) << 48) | ((ctx_id) << 32)) | |
| 305 | − | |
| 306 | − __be64 ctx_cap; /* afu_rc below is when the capability is violated */ | |
| 307 | −#define SISL_CTX_CAP_PROXY_ISSUE 0x8000000000000000ULL /* afu_rc 0x21 */ | |
| 308 | −#define SISL_CTX_CAP_REAL_MODE 0x4000000000000000ULL /* afu_rc 0x21 */ | |
| 309 | −#define SISL_CTX_CAP_HOST_XLATE 0x2000000000000000ULL /* afu_rc 0x1a */ | |
| 310 | −#define SISL_CTX_CAP_PROXY_TARGET 0x1000000000000000ULL /* afu_rc 0x21 */ | |
| 311 | −#define SISL_CTX_CAP_AFU_CMD 0x0000000000000008ULL /* afu_rc 0x21 */ | |
| 312 | −#define SISL_CTX_CAP_GSCSI_CMD 0x0000000000000004ULL /* afu_rc 0x21 */ | |
| 313 | −#define SISL_CTX_CAP_WRITE_CMD 0x0000000000000002ULL /* afu_rc 0x21 */ | |
| 314 | −#define SISL_CTX_CAP_READ_CMD 0x0000000000000001ULL /* afu_rc 0x21 */ | |
| 315 | − __be64 mbox_r; | |
| 316 | − __be64 lisn_pasid[2]; | |
| 317 | − /* pasid _a arg must be ULL */ | |
| 318 | −#define SISL_LISN_PASID(_a, _b) (((_a) << 32) | (_b)) | |
| 319 | − __be64 lisn_ea[3]; | |
| 320 | −}; | |
| 321 | − | |
| 322 | −/* single copy global regs */ | |
| 323 | −struct sisl_global_regs { | |
| 324 | − __be64 aintr_status; | |
| 325 | − /* | |
| 326 | − * In cxlflash, FC port/link are arranged in port pairs, each | |
| 327 | − * gets a byte of status: | |
| 328 | − * | |
| 329 | − * *_OTHER: other err, FC_ERRCAP[31:20] | |
| 330 | − * *_LOGO: target sent FLOGI/PLOGI/LOGO while logged in | |
| 331 | − * *_CRC_T: CRC threshold exceeded | |
| 332 | − * *_LOGI_R: login state machine timed out and retrying | |
| 333 | − * *_LOGI_F: login failed, FC_ERROR[19:0] | |
| 334 | − * *_LOGI_S: login succeeded | |
| 335 | − * *_LINK_DN: link online to offline | |
| 336 | − * *_LINK_UP: link offline to online | |
| 337 | − */ | |
| 338 | −#define SISL_ASTATUS_FC2_OTHER 0x80000000ULL /* b32 */ | |
| 339 | −#define SISL_ASTATUS_FC2_LOGO 0x40000000ULL /* b33 */ | |
| 340 | −#define SISL_ASTATUS_FC2_CRC_T 0x20000000ULL /* b34 */ | |
| 341 | −#define SISL_ASTATUS_FC2_LOGI_R 0x10000000ULL /* b35 */ | |
| 342 | −#define SISL_ASTATUS_FC2_LOGI_F 0x08000000ULL /* b36 */ | |
| 343 | −#define SISL_ASTATUS_FC2_LOGI_S 0x04000000ULL /* b37 */ | |
| 344 | −#define SISL_ASTATUS_FC2_LINK_DN 0x02000000ULL /* b38 */ | |
| 345 | −#define SISL_ASTATUS_FC2_LINK_UP 0x01000000ULL /* b39 */ | |
| 346 | − | |
| 347 | −#define SISL_ASTATUS_FC3_OTHER 0x00800000ULL /* b40 */ | |
| 348 | −#define SISL_ASTATUS_FC3_LOGO 0x00400000ULL /* b41 */ | |
| 349 | −#define SISL_ASTATUS_FC3_CRC_T 0x00200000ULL /* b42 */ | |
| 350 | −#define SISL_ASTATUS_FC3_LOGI_R 0x00100000ULL /* b43 */ | |
| 351 | −#define SISL_ASTATUS_FC3_LOGI_F 0x00080000ULL /* b44 */ | |
| 352 | −#define SISL_ASTATUS_FC3_LOGI_S 0x00040000ULL /* b45 */ | |
| 353 | −#define SISL_ASTATUS_FC3_LINK_DN 0x00020000ULL /* b46 */ | |
| 354 | −#define SISL_ASTATUS_FC3_LINK_UP 0x00010000ULL /* b47 */ | |
| 355 | − | |
| 356 | −#define SISL_ASTATUS_FC0_OTHER 0x00008000ULL /* b48 */ | |
| 357 | −#define SISL_ASTATUS_FC0_LOGO 0x00004000ULL /* b49 */ | |
| 358 | −#define SISL_ASTATUS_FC0_CRC_T 0x00002000ULL /* b50 */ | |
| 359 | −#define SISL_ASTATUS_FC0_LOGI_R 0x00001000ULL /* b51 */ | |
| 360 | −#define SISL_ASTATUS_FC0_LOGI_F 0x00000800ULL /* b52 */ | |
| 361 | −#define SISL_ASTATUS_FC0_LOGI_S 0x00000400ULL /* b53 */ | |
| 362 | −#define SISL_ASTATUS_FC0_LINK_DN 0x00000200ULL /* b54 */ | |
| 363 | −#define SISL_ASTATUS_FC0_LINK_UP 0x00000100ULL /* b55 */ | |
| 364 | − | |
| 365 | −#define SISL_ASTATUS_FC1_OTHER 0x00000080ULL /* b56 */ | |
| 366 | −#define SISL_ASTATUS_FC1_LOGO 0x00000040ULL /* b57 */ | |
| 367 | −#define SISL_ASTATUS_FC1_CRC_T 0x00000020ULL /* b58 */ | |
| 368 | −#define SISL_ASTATUS_FC1_LOGI_R 0x00000010ULL /* b59 */ | |
| 369 | −#define SISL_ASTATUS_FC1_LOGI_F 0x00000008ULL /* b60 */ | |
| 370 | −#define SISL_ASTATUS_FC1_LOGI_S 0x00000004ULL /* b61 */ | |
| 371 | −#define SISL_ASTATUS_FC1_LINK_DN 0x00000002ULL /* b62 */ | |
| 372 | −#define SISL_ASTATUS_FC1_LINK_UP 0x00000001ULL /* b63 */ | |
| 373 | − | |
| 374 | −#define SISL_FC_INTERNAL_UNMASK 0x0000000300000000ULL /* 1 means unmasked */ | |
| 375 | −#define SISL_FC_INTERNAL_MASK ~(SISL_FC_INTERNAL_UNMASK) | |
| 376 | −#define SISL_FC_INTERNAL_SHIFT 32 | |
| 377 | − | |
| 378 | −#define SISL_FC_SHUTDOWN_NORMAL 0x0000000000000010ULL | |
| 379 | −#define SISL_FC_SHUTDOWN_ABRUPT 0x0000000000000020ULL | |
| 380 | − | |
| 381 | −#define SISL_STATUS_SHUTDOWN_ACTIVE 0x0000000000000010ULL | |
| 382 | −#define SISL_STATUS_SHUTDOWN_COMPLETE 0x0000000000000020ULL | |
| 383 | − | |
| 384 | −#define SISL_ASTATUS_UNMASK 0xFFFFFFFFULL /* 1 means unmasked */ | |
| 385 | −#define SISL_ASTATUS_MASK ~(SISL_ASTATUS_UNMASK) /* 1 means masked */ | |
| 386 | − | |
| 387 | − __be64 aintr_clear; | |
| 388 | − __be64 aintr_mask; | |
| 389 | − __be64 afu_ctrl; | |
| 390 | − __be64 afu_hb; | |
| 391 | − __be64 afu_scratch_pad; | |
| 392 | − __be64 afu_port_sel; | |
| 393 | −#define SISL_AFUCONF_AR_IOARCB 0x4000ULL | |
| 394 | −#define SISL_AFUCONF_AR_LXT 0x2000ULL | |
| 395 | −#define SISL_AFUCONF_AR_RHT 0x1000ULL | |
| 396 | −#define SISL_AFUCONF_AR_DATA 0x0800ULL | |
| 397 | −#define SISL_AFUCONF_AR_RSRC 0x0400ULL | |
| 398 | −#define SISL_AFUCONF_AR_IOASA 0x0200ULL | |
| 399 | −#define SISL_AFUCONF_AR_RRQ 0x0100ULL | |
| 400 | −/* Aggregate all Auto Retry Bits */ | |
| 401 | −#define SISL_AFUCONF_AR_ALL (SISL_AFUCONF_AR_IOARCB|SISL_AFUCONF_AR_LXT| \ | |
| 402 | − SISL_AFUCONF_AR_RHT|SISL_AFUCONF_AR_DATA| \ | |
| 403 | − SISL_AFUCONF_AR_RSRC|SISL_AFUCONF_AR_IOASA| \ | |
| 404 | − SISL_AFUCONF_AR_RRQ) | |
| 405 | −#ifdef __BIG_ENDIAN | |
| 406 | −#define SISL_AFUCONF_ENDIAN 0x0000ULL | |
| 407 | −#else | |
| 408 | −#define SISL_AFUCONF_ENDIAN 0x0020ULL | |
| 409 | −#endif | |
| 410 | −#define SISL_AFUCONF_MBOX_CLR_READ 0x0010ULL | |
| 411 | − __be64 afu_config; | |
| 412 | − __be64 rsvd[0xf8]; | |
| 413 | − __le64 afu_version; | |
| 414 | − __be64 interface_version; | |
| 415 | −#define SISL_INTVER_CAP_SHIFT 16 | |
| 416 | −#define SISL_INTVER_MAJ_SHIFT 8 | |
| 417 | −#define SISL_INTVER_CAP_MASK 0xFFFFFFFF00000000ULL | |
| 418 | −#define SISL_INTVER_MAJ_MASK 0x00000000FFFF0000ULL | |
| 419 | −#define SISL_INTVER_MIN_MASK 0x000000000000FFFFULL | |
| 420 | −#define SISL_INTVER_CAP_IOARRIN_CMD_MODE 0x800000000000ULL | |
| 421 | −#define SISL_INTVER_CAP_SQ_CMD_MODE 0x400000000000ULL | |
| 422 | −#define SISL_INTVER_CAP_RESERVED_CMD_MODE_A 0x200000000000ULL | |
| 423 | −#define SISL_INTVER_CAP_RESERVED_CMD_MODE_B 0x100000000000ULL | |
| 424 | −#define SISL_INTVER_CAP_LUN_PROVISION 0x080000000000ULL | |
| 425 | −#define SISL_INTVER_CAP_AFU_DEBUG 0x040000000000ULL | |
| 426 | −#define SISL_INTVER_CAP_OCXL_LISN 0x020000000000ULL | |
| 427 | −}; | |
| 428 | − | |
| 429 | −#define CXLFLASH_NUM_FC_PORTS_PER_BANK 2 /* fixed # of ports per bank */ | |
| 430 | −#define CXLFLASH_MAX_FC_BANKS 2 /* max # of banks supported */ | |
| 431 | −#define CXLFLASH_MAX_FC_PORTS (CXLFLASH_NUM_FC_PORTS_PER_BANK * \ | |
| 432 | − CXLFLASH_MAX_FC_BANKS) | |
| 433 | −#define CXLFLASH_MAX_CONTEXT 512 /* number of contexts per AFU */ | |
| 434 | −#define CXLFLASH_NUM_VLUNS 512 /* number of vluns per AFU/port */ | |
| 435 | −#define CXLFLASH_NUM_REGS 512 /* number of registers per port */ | |
| 436 | − | |
| 437 | −struct fc_port_bank { | |
| 438 | − __be64 fc_port_regs[CXLFLASH_NUM_FC_PORTS_PER_BANK][CXLFLASH_NUM_REGS]; | |
| 439 | − __be64 fc_port_luns[CXLFLASH_NUM_FC_PORTS_PER_BANK][CXLFLASH_NUM_VLUNS]; | |
| 440 | −}; | |
| 441 | − | |
| 442 | −struct sisl_global_map { | |
| 443 | − union { | |
| 444 | − struct sisl_global_regs regs; | |
| 445 | − char page0[SIZE_4K]; /* page 0 */ | |
| 446 | − }; | |
| 447 | − | |
| 448 | − char page1[SIZE_4K]; /* page 1 */ | |
| 449 | − | |
| 450 | − struct fc_port_bank bank[CXLFLASH_MAX_FC_BANKS]; /* pages 2 - 9 */ | |
| 451 | − | |
| 452 | − /* pages 10 - 15 are reserved */ | |
| 453 | − | |
| 454 | −}; | |
| 455 | − | |
| 456 | −/* | |
| 457 | − * CXL Flash Memory Map | |
| 458 | − * | |
| 459 | − * +-------------------------------+ | |
| 460 | − * | 512 * 64 KB User MMIO | | |
| 461 | − * | (per context) | | |
| 462 | − * | User Accessible | | |
| 463 | − * +-------------------------------+ | |
| 464 | − * | 512 * 128 B per context | | |
| 465 | − * | Provisioning and Control | | |
| 466 | − * | Trusted Process accessible | | |
| 467 | − * +-------------------------------+ | |
| 468 | − * | 64 KB Global | | |
| 469 | − * | Trusted Process accessible | | |
| 470 | − * +-------------------------------+ | |
| 471 | − */ | |
| 472 | −struct cxlflash_afu_map { | |
| 473 | − union { | |
| 474 | − struct sisl_host_map host; | |
| 475 | − char harea[SIZE_64K]; /* 64KB each */ | |
| 476 | − } hosts[CXLFLASH_MAX_CONTEXT]; | |
| 477 | − | |
| 478 | − union { | |
| 479 | − struct sisl_ctrl_map ctrl; | |
| 480 | − char carea[cache_line_size()]; /* 128B each */ | |
| 481 | − } ctrls[CXLFLASH_MAX_CONTEXT]; | |
| 482 | − | |
| 483 | − union { | |
| 484 | − struct sisl_global_map global; | |
| 485 | − char garea[SIZE_64K]; /* 64KB single block */ | |
| 486 | − }; | |
| 487 | −}; | |
| 488 | − | |
| 489 | −/* | |
| 490 | − * LXT - LBA Translation Table | |
| 491 | − * LXT control blocks | |
| 492 | − */ | |
| 493 | −struct sisl_lxt_entry { | |
| 494 | − u64 rlba_base; /* bits 0:47 is base | |
| 495 | − * b48:55 is lun index | |
| 496 | − * b58:59 is write & read perms | |
| 497 | − * (if no perm, afu_rc=0x15) | |
| 498 | − * b60:63 is port_sel mask | |
| 499 | − */ | |
| 500 | −}; | |
| 501 | − | |
| 502 | −/* | |
| 503 | − * RHT - Resource Handle Table | |
| 504 | − * Per the SISlite spec, RHT entries are to be 16-byte aligned | |
| 505 | − */ | |
| 506 | −struct sisl_rht_entry { | |
| 507 | − struct sisl_lxt_entry *lxt_start; | |
| 508 | − u32 lxt_cnt; | |
| 509 | − u16 rsvd; | |
| 510 | − u8 fp; /* format & perm nibbles. | |
| 511 | − * (if no perm, afu_rc=0x05) | |
| 512 | − */ | |
| 513 | − u8 nmask; | |
| 514 | −} __packed __aligned(16); | |
| 515 | − | |
| 516 | −struct sisl_rht_entry_f1 { | |
| 517 | − u64 lun_id; | |
| 518 | − union { | |
| 519 | − struct { | |
| 520 | − u8 valid; | |
| 521 | − u8 rsvd[5]; | |
| 522 | − u8 fp; | |
| 523 | − u8 port_sel; | |
| 524 | − }; | |
| 525 | − | |
| 526 | − u64 dw; | |
| 527 | − }; | |
| 528 | −} __packed __aligned(16); | |
| 529 | − | |
| 530 | −/* make the fp byte */ | |
| 531 | −#define SISL_RHT_FP(fmt, perm) (((fmt) << 4) | (perm)) | |
| 532 | − | |
| 533 | −/* make the fp byte for a clone from a source fp and clone flags | |
| 534 | − * flags must be only 2 LSB bits. | |
| 535 | − */ | |
| 536 | −#define SISL_RHT_FP_CLONE(src_fp, cln_flags) ((src_fp) & (0xFC | (cln_flags))) | |
| 537 | − | |
| 538 | −#define RHT_PERM_READ 0x01U | |
| 539 | −#define RHT_PERM_WRITE 0x02U | |
| 540 | −#define RHT_PERM_RW (RHT_PERM_READ | RHT_PERM_WRITE) | |
| 541 | − | |
| 542 | −/* extract the perm bits from a fp */ | |
| 543 | −#define SISL_RHT_PERM(fp) ((fp) & RHT_PERM_RW) | |
| 544 | − | |
| 545 | −#define PORT0 0x01U | |
| 546 | −#define PORT1 0x02U | |
| 547 | −#define PORT2 0x04U | |
| 548 | −#define PORT3 0x08U | |
| 549 | −#define PORT_MASK(_n) ((1 << (_n)) - 1) | |
| 550 | − | |
| 551 | −/* AFU Sync Mode byte */ | |
| 552 | −#define AFU_LW_SYNC 0x0U | |
| 553 | −#define AFU_HW_SYNC 0x1U | |
| 554 | −#define AFU_GSYNC 0x2U | |
| 555 | − | |
| 556 | −/* Special Task Management Function CDB */ | |
| 557 | −#define TMF_LUN_RESET 0x1U | |
| 558 | −#define TMF_CLEAR_ACA 0x2U | |
| 559 | − | |
| 560 | −#endif /* _SISLITE_H */ | |
| @@ -1,2218 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2015 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#include <linux/delay.h> | |
| 12 | −#include <linux/file.h> | |
| 13 | −#include <linux/interrupt.h> | |
| 14 | −#include <linux/pci.h> | |
| 15 | −#include <linux/syscalls.h> | |
| 16 | −#include <linux/unaligned.h> | |
| 17 | − | |
| 18 | −#include <scsi/scsi.h> | |
| 19 | −#include <scsi/scsi_host.h> | |
| 20 | −#include <scsi/scsi_cmnd.h> | |
| 21 | −#include <scsi/scsi_eh.h> | |
| 22 | −#include <uapi/scsi/cxlflash_ioctl.h> | |
| 23 | − | |
| 24 | −#include "sislite.h" | |
| 25 | −#include "common.h" | |
| 26 | −#include "vlun.h" | |
| 27 | −#include "superpipe.h" | |
| 28 | − | |
| 29 | −struct cxlflash_global global; | |
| 30 | − | |
| 31 | −/** | |
| 32 | − * marshal_rele_to_resize() - translate release to resize structure | |
| 33 | − * @release: Source structure from which to translate/copy. | |
| 34 | − * @resize: Destination structure for the translate/copy. | |
| 35 | − */ | |
| 36 | −static void marshal_rele_to_resize(struct dk_cxlflash_release *release, | |
| 37 | − struct dk_cxlflash_resize *resize) | |
| 38 | −{ | |
| 39 | − resize->hdr = release->hdr; | |
| 40 | − resize->context_id = release->context_id; | |
| 41 | − resize->rsrc_handle = release->rsrc_handle; | |
| 42 | −} | |
| 43 | − | |
| 44 | −/** | |
| 45 | − * marshal_det_to_rele() - translate detach to release structure | |
| 46 | − * @detach: Destination structure for the translate/copy. | |
| 47 | − * @release: Source structure from which to translate/copy. | |
| 48 | − */ | |
| 49 | −static void marshal_det_to_rele(struct dk_cxlflash_detach *detach, | |
| 50 | − struct dk_cxlflash_release *release) | |
| 51 | −{ | |
| 52 | − release->hdr = detach->hdr; | |
| 53 | − release->context_id = detach->context_id; | |
| 54 | −} | |
| 55 | − | |
| 56 | −/** | |
| 57 | − * marshal_udir_to_rele() - translate udirect to release structure | |
| 58 | − * @udirect: Source structure from which to translate/copy. | |
| 59 | − * @release: Destination structure for the translate/copy. | |
| 60 | − */ | |
| 61 | −static void marshal_udir_to_rele(struct dk_cxlflash_udirect *udirect, | |
| 62 | − struct dk_cxlflash_release *release) | |
| 63 | −{ | |
| 64 | − release->hdr = udirect->hdr; | |
| 65 | − release->context_id = udirect->context_id; | |
| 66 | − release->rsrc_handle = udirect->rsrc_handle; | |
| 67 | −} | |
| 68 | − | |
| 69 | −/** | |
| 70 | − * cxlflash_free_errpage() - frees resources associated with global error page | |
| 71 | − */ | |
| 72 | −void cxlflash_free_errpage(void) | |
| 73 | −{ | |
| 74 | − | |
| 75 | − mutex_lock(&global.mutex); | |
| 76 | − if (global.err_page) { | |
| 77 | − __free_page(global.err_page); | |
| 78 | − global.err_page = NULL; | |
| 79 | − } | |
| 80 | − mutex_unlock(&global.mutex); | |
| 81 | −} | |
| 82 | − | |
| 83 | −/** | |
| 84 | − * cxlflash_stop_term_user_contexts() - stops/terminates known user contexts | |
| 85 | − * @cfg: Internal structure associated with the host. | |
| 86 | − * | |
| 87 | − * When the host needs to go down, all users must be quiesced and their | |
| 88 | − * memory freed. This is accomplished by putting the contexts in error | |
| 89 | − * state which will notify the user and let them 'drive' the tear down. | |
| 90 | − * Meanwhile, this routine camps until all user contexts have been removed. | |
| 91 | − * | |
| 92 | − * Note that the main loop in this routine will always execute at least once | |
| 93 | − * to flush the reset_waitq. | |
| 94 | − */ | |
| 95 | −void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg) | |
| 96 | −{ | |
| 97 | − struct device *dev = &cfg->dev->dev; | |
| 98 | − int i, found = true; | |
| 99 | − | |
| 100 | − cxlflash_mark_contexts_error(cfg); | |
| 101 | − | |
| 102 | − while (true) { | |
| 103 | − for (i = 0; i < MAX_CONTEXT; i++) | |
| 104 | − if (cfg->ctx_tbl[i]) { | |
| 105 | − found = true; | |
| 106 | − break; | |
| 107 | − } | |
| 108 | − | |
| 109 | − if (!found && list_empty(&cfg->ctx_err_recovery)) | |
| 110 | − return; | |
| 111 | − | |
| 112 | − dev_dbg(dev, "%s: Wait for user contexts to quiesce...\n", | |
| 113 | − __func__); | |
| 114 | − wake_up_all(&cfg->reset_waitq); | |
| 115 | − ssleep(1); | |
| 116 | − found = false; | |
| 117 | − } | |
| 118 | −} | |
| 119 | − | |
| 120 | −/** | |
| 121 | − * find_error_context() - locates a context by cookie on the error recovery list | |
| 122 | − * @cfg: Internal structure associated with the host. | |
| 123 | − * @rctxid: Desired context by id. | |
| 124 | − * @file: Desired context by file. | |
| 125 | − * | |
| 126 | − * Return: Found context on success, NULL on failure | |
| 127 | − */ | |
| 128 | −static struct ctx_info *find_error_context(struct cxlflash_cfg *cfg, u64 rctxid, | |
| 129 | − struct file *file) | |
| 130 | −{ | |
| 131 | − struct ctx_info *ctxi; | |
| 132 | − | |
| 133 | − list_for_each_entry(ctxi, &cfg->ctx_err_recovery, list) | |
| 134 | − if ((ctxi->ctxid == rctxid) || (ctxi->file == file)) | |
| 135 | − return ctxi; | |
| 136 | − | |
| 137 | − return NULL; | |
| 138 | −} | |
| 139 | − | |
| 140 | −/** | |
| 141 | − * get_context() - obtains a validated and locked context reference | |
| 142 | − * @cfg: Internal structure associated with the host. | |
| 143 | − * @rctxid: Desired context (raw, un-decoded format). | |
| 144 | − * @arg: LUN information or file associated with request. | |
| 145 | − * @ctx_ctrl: Control information to 'steer' desired lookup. | |
| 146 | − * | |
| 147 | − * NOTE: despite the name pid, in linux, current->pid actually refers | |
| 148 | − * to the lightweight process id (tid) and can change if the process is | |
| 149 | − * multi threaded. The tgid remains constant for the process and only changes | |
| 150 | − * when the process of fork. For all intents and purposes, think of tgid | |
| 151 | − * as a pid in the traditional sense. | |
| 152 | − * | |
| 153 | − * Return: Validated context on success, NULL on failure | |
| 154 | − */ | |
| 155 | −struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxid, | |
| 156 | − void *arg, enum ctx_ctrl ctx_ctrl) | |
| 157 | −{ | |
| 158 | − struct device *dev = &cfg->dev->dev; | |
| 159 | − struct ctx_info *ctxi = NULL; | |
| 160 | − struct lun_access *lun_access = NULL; | |
| 161 | − struct file *file = NULL; | |
| 162 | − struct llun_info *lli = arg; | |
| 163 | − u64 ctxid = DECODE_CTXID(rctxid); | |
| 164 | − int rc; | |
| 165 | − pid_t pid = task_tgid_nr(current), ctxpid = 0; | |
| 166 | − | |
| 167 | − if (ctx_ctrl & CTX_CTRL_FILE) { | |
| 168 | − lli = NULL; | |
| 169 | − file = (struct file *)arg; | |
| 170 | − } | |
| 171 | − | |
| 172 | − if (ctx_ctrl & CTX_CTRL_CLONE) | |
| 173 | − pid = task_ppid_nr(current); | |
| 174 | − | |
| 175 | − if (likely(ctxid < MAX_CONTEXT)) { | |
| 176 | − while (true) { | |
| 177 | − mutex_lock(&cfg->ctx_tbl_list_mutex); | |
| 178 | − ctxi = cfg->ctx_tbl[ctxid]; | |
| 179 | − if (ctxi) | |
| 180 | − if ((file && (ctxi->file != file)) || | |
| 181 | − (!file && (ctxi->ctxid != rctxid))) | |
| 182 | − ctxi = NULL; | |
| 183 | − | |
| 184 | − if ((ctx_ctrl & CTX_CTRL_ERR) || | |
| 185 | − (!ctxi && (ctx_ctrl & CTX_CTRL_ERR_FALLBACK))) | |
| 186 | − ctxi = find_error_context(cfg, rctxid, file); | |
| 187 | − if (!ctxi) { | |
| 188 | − mutex_unlock(&cfg->ctx_tbl_list_mutex); | |
| 189 | − goto out; | |
| 190 | − } | |
| 191 | − | |
| 192 | − /* | |
| 193 | − * Need to acquire ownership of the context while still | |
| 194 | − * under the table/list lock to serialize with a remove | |
| 195 | − * thread. Use the 'try' to avoid stalling the | |
| 196 | − * table/list lock for a single context. | |
| 197 | − * | |
| 198 | − * Note that the lock order is: | |
| 199 | − * | |
| 200 | − * cfg->ctx_tbl_list_mutex -> ctxi->mutex | |
| 201 | − * | |
| 202 | − * Therefore release ctx_tbl_list_mutex before retrying. | |
| 203 | − */ | |
| 204 | − rc = mutex_trylock(&ctxi->mutex); | |
| 205 | − mutex_unlock(&cfg->ctx_tbl_list_mutex); | |
| 206 | − if (rc) | |
| 207 | − break; /* got the context's lock! */ | |
| 208 | − } | |
| 209 | − | |
| 210 | − if (ctxi->unavail) | |
| 211 | − goto denied; | |
| 212 | − | |
| 213 | − ctxpid = ctxi->pid; | |
| 214 | − if (likely(!(ctx_ctrl & CTX_CTRL_NOPID))) | |
| 215 | − if (pid != ctxpid) | |
| 216 | − goto denied; | |
| 217 | − | |
| 218 | − if (lli) { | |
| 219 | − list_for_each_entry(lun_access, &ctxi->luns, list) | |
| 220 | − if (lun_access->lli == lli) | |
| 221 | − goto out; | |
| 222 | − goto denied; | |
| 223 | − } | |
| 224 | − } | |
| 225 | − | |
| 226 | −out: | |
| 227 | − dev_dbg(dev, "%s: rctxid=%016llx ctxinfo=%p ctxpid=%u pid=%u " | |
| 228 | − "ctx_ctrl=%u\n", __func__, rctxid, ctxi, ctxpid, pid, | |
| 229 | − ctx_ctrl); | |
| 230 | − | |
| 231 | − return ctxi; | |
| 232 | − | |
| 233 | −denied: | |
| 234 | − mutex_unlock(&ctxi->mutex); | |
| 235 | − ctxi = NULL; | |
| 236 | − goto out; | |
| 237 | −} | |
| 238 | − | |
| 239 | −/** | |
| 240 | − * put_context() - release a context that was retrieved from get_context() | |
| 241 | − * @ctxi: Context to release. | |
| 242 | − * | |
| 243 | − * For now, releasing the context equates to unlocking it's mutex. | |
| 244 | − */ | |
| 245 | −void put_context(struct ctx_info *ctxi) | |
| 246 | −{ | |
| 247 | − mutex_unlock(&ctxi->mutex); | |
| 248 | −} | |
| 249 | − | |
| 250 | −/** | |
| 251 | − * afu_attach() - attach a context to the AFU | |
| 252 | − * @cfg: Internal structure associated with the host. | |
| 253 | − * @ctxi: Context to attach. | |
| 254 | − * | |
| 255 | − * Upon setting the context capabilities, they must be confirmed with | |
| 256 | − * a read back operation as the context might have been closed since | |
| 257 | − * the mailbox was unlocked. When this occurs, registration is failed. | |
| 258 | − * | |
| 259 | − * Return: 0 on success, -errno on failure | |
| 260 | − */ | |
| 261 | −static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) | |
| 262 | −{ | |
| 263 | − struct device *dev = &cfg->dev->dev; | |
| 264 | − struct afu *afu = cfg->afu; | |
| 265 | − struct sisl_ctrl_map __iomem *ctrl_map = ctxi->ctrl_map; | |
| 266 | − int rc = 0; | |
| 267 | − struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); | |
| 268 | − u64 val; | |
| 269 | − int i; | |
| 270 | − | |
| 271 | − /* Unlock cap and restrict user to read/write cmds in translated mode */ | |
| 272 | − readq_be(&ctrl_map->mbox_r); | |
| 273 | − val = (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD); | |
| 274 | − writeq_be(val, &ctrl_map->ctx_cap); | |
| 275 | − val = readq_be(&ctrl_map->ctx_cap); | |
| 276 | − if (val != (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD)) { | |
| 277 | − dev_err(dev, "%s: ctx may be closed val=%016llx\n", | |
| 278 | − __func__, val); | |
| 279 | − rc = -EAGAIN; | |
| 280 | − goto out; | |
| 281 | − } | |
| 282 | − | |
| 283 | − if (afu_is_ocxl_lisn(afu)) { | |
| 284 | − /* Set up the LISN effective address for each interrupt */ | |
| 285 | − for (i = 0; i < ctxi->irqs; i++) { | |
| 286 | − val = cfg->ops->get_irq_objhndl(ctxi->ctx, i); | |
| 287 | − writeq_be(val, &ctrl_map->lisn_ea[i]); | |
| 288 | − } | |
| 289 | − | |
| 290 | − /* Use primary HWQ PASID as identifier for all interrupts */ | |
| 291 | − val = hwq->ctx_hndl; | |
| 292 | − writeq_be(SISL_LISN_PASID(val, val), &ctrl_map->lisn_pasid[0]); | |
| 293 | − writeq_be(SISL_LISN_PASID(0UL, val), &ctrl_map->lisn_pasid[1]); | |
| 294 | − } | |
| 295 | − | |
| 296 | − /* Set up MMIO registers pointing to the RHT */ | |
| 297 | − writeq_be((u64)ctxi->rht_start, &ctrl_map->rht_start); | |
| 298 | − val = SISL_RHT_CNT_ID((u64)MAX_RHT_PER_CONTEXT, (u64)(hwq->ctx_hndl)); | |
| 299 | − writeq_be(val, &ctrl_map->rht_cnt_id); | |
| 300 | −out: | |
| 301 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 302 | − return rc; | |
| 303 | −} | |
| 304 | − | |
| 305 | −/** | |
| 306 | − * read_cap16() - issues a SCSI READ_CAP16 command | |
| 307 | − * @sdev: SCSI device associated with LUN. | |
| 308 | − * @lli: LUN destined for capacity request. | |
| 309 | − * | |
| 310 | − * The READ_CAP16 can take quite a while to complete. Should an EEH occur while | |
| 311 | − * in scsi_execute_cmd(), the EEH handler will attempt to recover. As part of | |
| 312 | − * the recovery, the handler drains all currently running ioctls, waiting until | |
| 313 | − * they have completed before proceeding with a reset. As this routine is used | |
| 314 | − * on the ioctl path, this can create a condition where the EEH handler becomes | |
| 315 | − * stuck, infinitely waiting for this ioctl thread. To avoid this behavior, | |
| 316 | − * temporarily unmark this thread as an ioctl thread by releasing the ioctl | |
| 317 | − * read semaphore. This will allow the EEH handler to proceed with a recovery | |
| 318 | − * while this thread is still running. Once the scsi_execute_cmd() returns, | |
| 319 | − * reacquire the ioctl read semaphore and check the adapter state in case it | |
| 320 | − * changed while inside of scsi_execute_cmd(). The state check will wait if the | |
| 321 | − * adapter is still being recovered or return a failure if the recovery failed. | |
| 322 | − * In the event that the adapter reset failed, simply return the failure as the | |
| 323 | − * ioctl would be unable to continue. | |
| 324 | − * | |
| 325 | − * Note that the above puts a requirement on this routine to only be called on | |
| 326 | − * an ioctl thread. | |
| 327 | − * | |
| 328 | − * Return: 0 on success, -errno on failure | |
| 329 | − */ | |
| 330 | −static int read_cap16(struct scsi_device *sdev, struct llun_info *lli) | |
| 331 | −{ | |
| 332 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 333 | − struct device *dev = &cfg->dev->dev; | |
| 334 | − struct glun_info *gli = lli->parent; | |
| 335 | − struct scsi_sense_hdr sshdr; | |
| 336 | − const struct scsi_exec_args exec_args = { | |
| 337 | − .sshdr = &sshdr, | |
| 338 | − }; | |
| 339 | − u8 *cmd_buf = NULL; | |
| 340 | − u8 *scsi_cmd = NULL; | |
| 341 | − int rc = 0; | |
| 342 | − int result = 0; | |
| 343 | − int retry_cnt = 0; | |
| 344 | − u32 to = CMD_TIMEOUT * HZ; | |
| 345 | − | |
| 346 | −retry: | |
| 347 | − cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); | |
| 348 | − scsi_cmd = kzalloc(MAX_COMMAND_SIZE, GFP_KERNEL); | |
| 349 | − if (unlikely(!cmd_buf || !scsi_cmd)) { | |
| 350 | − rc = -ENOMEM; | |
| 351 | − goto out; | |
| 352 | − } | |
| 353 | − | |
| 354 | − scsi_cmd[0] = SERVICE_ACTION_IN_16; /* read cap(16) */ | |
| 355 | − scsi_cmd[1] = SAI_READ_CAPACITY_16; /* service action */ | |
| 356 | − put_unaligned_be32(CMD_BUFSIZE, &scsi_cmd[10]); | |
| 357 | − | |
| 358 | − dev_dbg(dev, "%s: %ssending cmd(%02x)\n", __func__, | |
| 359 | − retry_cnt ? "re" : "", scsi_cmd[0]); | |
| 360 | − | |
| 361 | − /* Drop the ioctl read semaphore across lengthy call */ | |
| 362 | − up_read(&cfg->ioctl_rwsem); | |
| 363 | − result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_IN, cmd_buf, | |
| 364 | − CMD_BUFSIZE, to, CMD_RETRIES, &exec_args); | |
| 365 | − down_read(&cfg->ioctl_rwsem); | |
| 366 | − rc = check_state(cfg); | |
| 367 | − if (rc) { | |
| 368 | − dev_err(dev, "%s: Failed state result=%08x\n", | |
| 369 | − __func__, result); | |
| 370 | − rc = -ENODEV; | |
| 371 | − goto out; | |
| 372 | − } | |
| 373 | − | |
| 374 | − if (result > 0 && scsi_sense_valid(&sshdr)) { | |
| 375 | − if (result & SAM_STAT_CHECK_CONDITION) { | |
| 376 | − switch (sshdr.sense_key) { | |
| 377 | − case NO_SENSE: | |
| 378 | − case RECOVERED_ERROR: | |
| 379 | − case NOT_READY: | |
| 380 | − result &= ~SAM_STAT_CHECK_CONDITION; | |
| 381 | − break; | |
| 382 | − case UNIT_ATTENTION: | |
| 383 | − switch (sshdr.asc) { | |
| 384 | − case 0x29: /* Power on Reset or Device Reset */ | |
| 385 | − fallthrough; | |
| 386 | − case 0x2A: /* Device capacity changed */ | |
| 387 | − case 0x3F: /* Report LUNs changed */ | |
| 388 | − /* Retry the command once more */ | |
| 389 | − if (retry_cnt++ < 1) { | |
| 390 | − kfree(cmd_buf); | |
| 391 | − kfree(scsi_cmd); | |
| 392 | − goto retry; | |
| 393 | − } | |
| 394 | − } | |
| 395 | − break; | |
| 396 | − default: | |
| 397 | − break; | |
| 398 | − } | |
| 399 | − } | |
| 400 | − } | |
| 401 | − | |
| 402 | − if (result) { | |
| 403 | − dev_err(dev, "%s: command failed, result=%08x\n", | |
| 404 | − __func__, result); | |
| 405 | − rc = -EIO; | |
| 406 | − goto out; | |
| 407 | − } | |
| 408 | − | |
| 409 | − /* | |
| 410 | − * Read cap was successful, grab values from the buffer; | |
| 411 | − * note that we don't need to worry about unaligned access | |
| 412 | − * as the buffer is allocated on an aligned boundary. | |
| 413 | − */ | |
| 414 | − mutex_lock(&gli->mutex); | |
| 415 | − gli->max_lba = be64_to_cpu(*((__be64 *)&cmd_buf[0])); | |
| 416 | − gli->blk_len = be32_to_cpu(*((__be32 *)&cmd_buf[8])); | |
| 417 | − mutex_unlock(&gli->mutex); | |
| 418 | − | |
| 419 | −out: | |
| 420 | − kfree(cmd_buf); | |
| 421 | − kfree(scsi_cmd); | |
| 422 | − | |
| 423 | − dev_dbg(dev, "%s: maxlba=%lld blklen=%d rc=%d\n", | |
| 424 | − __func__, gli->max_lba, gli->blk_len, rc); | |
| 425 | − return rc; | |
| 426 | −} | |
| 427 | − | |
| 428 | −/** | |
| 429 | − * get_rhte() - obtains validated resource handle table entry reference | |
| 430 | − * @ctxi: Context owning the resource handle. | |
| 431 | − * @rhndl: Resource handle associated with entry. | |
| 432 | − * @lli: LUN associated with request. | |
| 433 | − * | |
| 434 | − * Return: Validated RHTE on success, NULL on failure | |
| 435 | − */ | |
| 436 | −struct sisl_rht_entry *get_rhte(struct ctx_info *ctxi, res_hndl_t rhndl, | |
| 437 | − struct llun_info *lli) | |
| 438 | −{ | |
| 439 | − struct cxlflash_cfg *cfg = ctxi->cfg; | |
| 440 | − struct device *dev = &cfg->dev->dev; | |
| 441 | − struct sisl_rht_entry *rhte = NULL; | |
| 442 | − | |
| 443 | − if (unlikely(!ctxi->rht_start)) { | |
| 444 | − dev_dbg(dev, "%s: Context does not have allocated RHT\n", | |
| 445 | − __func__); | |
| 446 | − goto out; | |
| 447 | − } | |
| 448 | − | |
| 449 | − if (unlikely(rhndl >= MAX_RHT_PER_CONTEXT)) { | |
| 450 | − dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", | |
| 451 | − __func__, rhndl); | |
| 452 | − goto out; | |
| 453 | − } | |
| 454 | − | |
| 455 | − if (unlikely(ctxi->rht_lun[rhndl] != lli)) { | |
| 456 | − dev_dbg(dev, "%s: Bad resource handle LUN rhndl=%d\n", | |
| 457 | − __func__, rhndl); | |
| 458 | − goto out; | |
| 459 | − } | |
| 460 | − | |
| 461 | − rhte = &ctxi->rht_start[rhndl]; | |
| 462 | − if (unlikely(rhte->nmask == 0)) { | |
| 463 | − dev_dbg(dev, "%s: Unopened resource handle rhndl=%d\n", | |
| 464 | − __func__, rhndl); | |
| 465 | − rhte = NULL; | |
| 466 | − goto out; | |
| 467 | − } | |
| 468 | − | |
| 469 | −out: | |
| 470 | − return rhte; | |
| 471 | −} | |
| 472 | − | |
| 473 | −/** | |
| 474 | − * rhte_checkout() - obtains free/empty resource handle table entry | |
| 475 | − * @ctxi: Context owning the resource handle. | |
| 476 | − * @lli: LUN associated with request. | |
| 477 | − * | |
| 478 | − * Return: Free RHTE on success, NULL on failure | |
| 479 | − */ | |
| 480 | −struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, | |
| 481 | − struct llun_info *lli) | |
| 482 | −{ | |
| 483 | − struct cxlflash_cfg *cfg = ctxi->cfg; | |
| 484 | − struct device *dev = &cfg->dev->dev; | |
| 485 | − struct sisl_rht_entry *rhte = NULL; | |
| 486 | − int i; | |
| 487 | − | |
| 488 | − /* Find a free RHT entry */ | |
| 489 | − for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) | |
| 490 | − if (ctxi->rht_start[i].nmask == 0) { | |
| 491 | − rhte = &ctxi->rht_start[i]; | |
| 492 | − ctxi->rht_out++; | |
| 493 | − break; | |
| 494 | − } | |
| 495 | − | |
| 496 | − if (likely(rhte)) | |
| 497 | − ctxi->rht_lun[i] = lli; | |
| 498 | − | |
| 499 | − dev_dbg(dev, "%s: returning rhte=%p index=%d\n", __func__, rhte, i); | |
| 500 | − return rhte; | |
| 501 | −} | |
| 502 | − | |
| 503 | −/** | |
| 504 | − * rhte_checkin() - releases a resource handle table entry | |
| 505 | − * @ctxi: Context owning the resource handle. | |
| 506 | − * @rhte: RHTE to release. | |
| 507 | − */ | |
| 508 | −void rhte_checkin(struct ctx_info *ctxi, | |
| 509 | − struct sisl_rht_entry *rhte) | |
| 510 | −{ | |
| 511 | − u32 rsrc_handle = rhte - ctxi->rht_start; | |
| 512 | − | |
| 513 | − rhte->nmask = 0; | |
| 514 | − rhte->fp = 0; | |
| 515 | − ctxi->rht_out--; | |
| 516 | − ctxi->rht_lun[rsrc_handle] = NULL; | |
| 517 | − ctxi->rht_needs_ws[rsrc_handle] = false; | |
| 518 | −} | |
| 519 | − | |
| 520 | −/** | |
| 521 | − * rht_format1() - populates a RHTE for format 1 | |
| 522 | − * @rhte: RHTE to populate. | |
| 523 | − * @lun_id: LUN ID of LUN associated with RHTE. | |
| 524 | − * @perm: Desired permissions for RHTE. | |
| 525 | − * @port_sel: Port selection mask | |
| 526 | − */ | |
| 527 | −static void rht_format1(struct sisl_rht_entry *rhte, u64 lun_id, u32 perm, | |
| 528 | − u32 port_sel) | |
| 529 | −{ | |
| 530 | − /* | |
| 531 | − * Populate the Format 1 RHT entry for direct access (physical | |
| 532 | − * LUN) using the synchronization sequence defined in the | |
| 533 | − * SISLite specification. | |
| 534 | − */ | |
| 535 | − struct sisl_rht_entry_f1 dummy = { 0 }; | |
| 536 | − struct sisl_rht_entry_f1 *rhte_f1 = (struct sisl_rht_entry_f1 *)rhte; | |
| 537 | − | |
| 538 | − memset(rhte_f1, 0, sizeof(*rhte_f1)); | |
| 539 | − rhte_f1->fp = SISL_RHT_FP(1U, 0); | |
| 540 | − dma_wmb(); /* Make setting of format bit visible */ | |
| 541 | − | |
| 542 | − rhte_f1->lun_id = lun_id; | |
| 543 | − dma_wmb(); /* Make setting of LUN id visible */ | |
| 544 | − | |
| 545 | − /* | |
| 546 | − * Use a dummy RHT Format 1 entry to build the second dword | |
| 547 | − * of the entry that must be populated in a single write when | |
| 548 | − * enabled (valid bit set to TRUE). | |
| 549 | − */ | |
| 550 | − dummy.valid = 0x80; | |
| 551 | − dummy.fp = SISL_RHT_FP(1U, perm); | |
| 552 | − dummy.port_sel = port_sel; | |
| 553 | − rhte_f1->dw = dummy.dw; | |
| 554 | − | |
| 555 | − dma_wmb(); /* Make remaining RHT entry fields visible */ | |
| 556 | −} | |
| 557 | − | |
| 558 | −/** | |
| 559 | − * cxlflash_lun_attach() - attaches a user to a LUN and manages the LUN's mode | |
| 560 | − * @gli: LUN to attach. | |
| 561 | − * @mode: Desired mode of the LUN. | |
| 562 | − * @locked: Mutex status on current thread. | |
| 563 | − * | |
| 564 | − * Return: 0 on success, -errno on failure | |
| 565 | − */ | |
| 566 | −int cxlflash_lun_attach(struct glun_info *gli, enum lun_mode mode, bool locked) | |
| 567 | −{ | |
| 568 | − int rc = 0; | |
| 569 | − | |
| 570 | − if (!locked) | |
| 571 | − mutex_lock(&gli->mutex); | |
| 572 | − | |
| 573 | − if (gli->mode == MODE_NONE) | |
| 574 | − gli->mode = mode; | |
| 575 | − else if (gli->mode != mode) { | |
| 576 | − pr_debug("%s: gli_mode=%d requested_mode=%d\n", | |
| 577 | − __func__, gli->mode, mode); | |
| 578 | − rc = -EINVAL; | |
| 579 | − goto out; | |
| 580 | − } | |
| 581 | − | |
| 582 | − gli->users++; | |
| 583 | − WARN_ON(gli->users <= 0); | |
| 584 | −out: | |
| 585 | − pr_debug("%s: Returning rc=%d gli->mode=%u gli->users=%u\n", | |
| 586 | − __func__, rc, gli->mode, gli->users); | |
| 587 | − if (!locked) | |
| 588 | − mutex_unlock(&gli->mutex); | |
| 589 | − return rc; | |
| 590 | −} | |
| 591 | − | |
| 592 | −/** | |
| 593 | − * cxlflash_lun_detach() - detaches a user from a LUN and resets the LUN's mode | |
| 594 | − * @gli: LUN to detach. | |
| 595 | − * | |
| 596 | − * When resetting the mode, terminate block allocation resources as they | |
| 597 | − * are no longer required (service is safe to call even when block allocation | |
| 598 | − * resources were not present - such as when transitioning from physical mode). | |
| 599 | − * These resources will be reallocated when needed (subsequent transition to | |
| 600 | − * virtual mode). | |
| 601 | − */ | |
| 602 | −void cxlflash_lun_detach(struct glun_info *gli) | |
| 603 | −{ | |
| 604 | − mutex_lock(&gli->mutex); | |
| 605 | − WARN_ON(gli->mode == MODE_NONE); | |
| 606 | − if (--gli->users == 0) { | |
| 607 | − gli->mode = MODE_NONE; | |
| 608 | − cxlflash_ba_terminate(&gli->blka.ba_lun); | |
| 609 | − } | |
| 610 | − pr_debug("%s: gli->users=%u\n", __func__, gli->users); | |
| 611 | − WARN_ON(gli->users < 0); | |
| 612 | − mutex_unlock(&gli->mutex); | |
| 613 | −} | |
| 614 | − | |
| 615 | −/** | |
| 616 | − * _cxlflash_disk_release() - releases the specified resource entry | |
| 617 | − * @sdev: SCSI device associated with LUN. | |
| 618 | − * @ctxi: Context owning resources. | |
| 619 | − * @release: Release ioctl data structure. | |
| 620 | − * | |
| 621 | − * For LUNs in virtual mode, the virtual LUN associated with the specified | |
| 622 | − * resource handle is resized to 0 prior to releasing the RHTE. Note that the | |
| 623 | − * AFU sync should _not_ be performed when the context is sitting on the error | |
| 624 | − * recovery list. A context on the error recovery list is not known to the AFU | |
| 625 | − * due to reset. When the context is recovered, it will be reattached and made | |
| 626 | − * known again to the AFU. | |
| 627 | − * | |
| 628 | − * Return: 0 on success, -errno on failure | |
| 629 | − */ | |
| 630 | −int _cxlflash_disk_release(struct scsi_device *sdev, | |
| 631 | − struct ctx_info *ctxi, | |
| 632 | − struct dk_cxlflash_release *release) | |
| 633 | −{ | |
| 634 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 635 | − struct device *dev = &cfg->dev->dev; | |
| 636 | − struct llun_info *lli = sdev->hostdata; | |
| 637 | − struct glun_info *gli = lli->parent; | |
| 638 | − struct afu *afu = cfg->afu; | |
| 639 | − bool put_ctx = false; | |
| 640 | − | |
| 641 | − struct dk_cxlflash_resize size; | |
| 642 | − res_hndl_t rhndl = release->rsrc_handle; | |
| 643 | − | |
| 644 | − int rc = 0; | |
| 645 | − int rcr = 0; | |
| 646 | − u64 ctxid = DECODE_CTXID(release->context_id), | |
| 647 | − rctxid = release->context_id; | |
| 648 | − | |
| 649 | − struct sisl_rht_entry *rhte; | |
| 650 | − struct sisl_rht_entry_f1 *rhte_f1; | |
| 651 | − | |
| 652 | − dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu gli->mode=%u gli->users=%u\n", | |
| 653 | − __func__, ctxid, release->rsrc_handle, gli->mode, gli->users); | |
| 654 | − | |
| 655 | − if (!ctxi) { | |
| 656 | − ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); | |
| 657 | − if (unlikely(!ctxi)) { | |
| 658 | − dev_dbg(dev, "%s: Bad context ctxid=%llu\n", | |
| 659 | − __func__, ctxid); | |
| 660 | − rc = -EINVAL; | |
| 661 | − goto out; | |
| 662 | − } | |
| 663 | − | |
| 664 | − put_ctx = true; | |
| 665 | − } | |
| 666 | − | |
| 667 | − rhte = get_rhte(ctxi, rhndl, lli); | |
| 668 | − if (unlikely(!rhte)) { | |
| 669 | − dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", | |
| 670 | − __func__, rhndl); | |
| 671 | − rc = -EINVAL; | |
| 672 | − goto out; | |
| 673 | − } | |
| 674 | − | |
| 675 | − /* | |
| 676 | − * Resize to 0 for virtual LUNS by setting the size | |
| 677 | − * to 0. This will clear LXT_START and LXT_CNT fields | |
| 678 | − * in the RHT entry and properly sync with the AFU. | |
| 679 | − * | |
| 680 | − * Afterwards we clear the remaining fields. | |
| 681 | − */ | |
| 682 | − switch (gli->mode) { | |
| 683 | − case MODE_VIRTUAL: | |
| 684 | − marshal_rele_to_resize(release, &size); | |
| 685 | − size.req_size = 0; | |
| 686 | − rc = _cxlflash_vlun_resize(sdev, ctxi, &size); | |
| 687 | − if (rc) { | |
| 688 | − dev_dbg(dev, "%s: resize failed rc %d\n", __func__, rc); | |
| 689 | − goto out; | |
| 690 | − } | |
| 691 | − | |
| 692 | − break; | |
| 693 | − case MODE_PHYSICAL: | |
| 694 | − /* | |
| 695 | − * Clear the Format 1 RHT entry for direct access | |
| 696 | − * (physical LUN) using the synchronization sequence | |
| 697 | − * defined in the SISLite specification. | |
| 698 | − */ | |
| 699 | − rhte_f1 = (struct sisl_rht_entry_f1 *)rhte; | |
| 700 | − | |
| 701 | − rhte_f1->valid = 0; | |
| 702 | − dma_wmb(); /* Make revocation of RHT entry visible */ | |
| 703 | − | |
| 704 | − rhte_f1->lun_id = 0; | |
| 705 | − dma_wmb(); /* Make clearing of LUN id visible */ | |
| 706 | − | |
| 707 | − rhte_f1->dw = 0; | |
| 708 | − dma_wmb(); /* Make RHT entry bottom-half clearing visible */ | |
| 709 | − | |
| 710 | − if (!ctxi->err_recovery_active) { | |
| 711 | − rcr = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); | |
| 712 | − if (unlikely(rcr)) | |
| 713 | − dev_dbg(dev, "%s: AFU sync failed rc=%d\n", | |
| 714 | − __func__, rcr); | |
| 715 | − } | |
| 716 | − break; | |
| 717 | − default: | |
| 718 | − WARN(1, "Unsupported LUN mode!"); | |
| 719 | − goto out; | |
| 720 | − } | |
| 721 | − | |
| 722 | − rhte_checkin(ctxi, rhte); | |
| 723 | − cxlflash_lun_detach(gli); | |
| 724 | − | |
| 725 | −out: | |
| 726 | − if (put_ctx) | |
| 727 | − put_context(ctxi); | |
| 728 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 729 | − return rc; | |
| 730 | −} | |
| 731 | − | |
| 732 | −int cxlflash_disk_release(struct scsi_device *sdev, void *release) | |
| 733 | −{ | |
| 734 | − return _cxlflash_disk_release(sdev, NULL, release); | |
| 735 | −} | |
| 736 | − | |
| 737 | −/** | |
| 738 | − * destroy_context() - releases a context | |
| 739 | − * @cfg: Internal structure associated with the host. | |
| 740 | − * @ctxi: Context to release. | |
| 741 | − * | |
| 742 | − * This routine is safe to be called with a a non-initialized context. | |
| 743 | − * Also note that the routine conditionally checks for the existence | |
| 744 | − * of the context control map before clearing the RHT registers and | |
| 745 | − * context capabilities because it is possible to destroy a context | |
| 746 | − * while the context is in the error state (previous mapping was | |
| 747 | − * removed [so there is no need to worry about clearing] and context | |
| 748 | − * is waiting for a new mapping). | |
| 749 | − */ | |
| 750 | −static void destroy_context(struct cxlflash_cfg *cfg, | |
| 751 | − struct ctx_info *ctxi) | |
| 752 | −{ | |
| 753 | − struct afu *afu = cfg->afu; | |
| 754 | − | |
| 755 | − if (ctxi->initialized) { | |
| 756 | − WARN_ON(!list_empty(&ctxi->luns)); | |
| 757 | − | |
| 758 | − /* Clear RHT registers and drop all capabilities for context */ | |
| 759 | − if (afu->afu_map && ctxi->ctrl_map) { | |
| 760 | − writeq_be(0, &ctxi->ctrl_map->rht_start); | |
| 761 | − writeq_be(0, &ctxi->ctrl_map->rht_cnt_id); | |
| 762 | − writeq_be(0, &ctxi->ctrl_map->ctx_cap); | |
| 763 | − } | |
| 764 | − } | |
| 765 | − | |
| 766 | − /* Free memory associated with context */ | |
| 767 | − free_page((ulong)ctxi->rht_start); | |
| 768 | − kfree(ctxi->rht_needs_ws); | |
| 769 | − kfree(ctxi->rht_lun); | |
| 770 | − kfree(ctxi); | |
| 771 | −} | |
| 772 | − | |
| 773 | −/** | |
| 774 | − * create_context() - allocates and initializes a context | |
| 775 | − * @cfg: Internal structure associated with the host. | |
| 776 | − * | |
| 777 | − * Return: Allocated context on success, NULL on failure | |
| 778 | − */ | |
| 779 | −static struct ctx_info *create_context(struct cxlflash_cfg *cfg) | |
| 780 | −{ | |
| 781 | − struct device *dev = &cfg->dev->dev; | |
| 782 | − struct ctx_info *ctxi = NULL; | |
| 783 | − struct llun_info **lli = NULL; | |
| 784 | − u8 *ws = NULL; | |
| 785 | − struct sisl_rht_entry *rhte; | |
| 786 | − | |
| 787 | − ctxi = kzalloc(sizeof(*ctxi), GFP_KERNEL); | |
| 788 | − lli = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*lli)), GFP_KERNEL); | |
| 789 | − ws = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*ws)), GFP_KERNEL); | |
| 790 | − if (unlikely(!ctxi || !lli || !ws)) { | |
| 791 | − dev_err(dev, "%s: Unable to allocate context\n", __func__); | |
| 792 | − goto err; | |
| 793 | − } | |
| 794 | − | |
| 795 | − rhte = (struct sisl_rht_entry *)get_zeroed_page(GFP_KERNEL); | |
| 796 | − if (unlikely(!rhte)) { | |
| 797 | − dev_err(dev, "%s: Unable to allocate RHT\n", __func__); | |
| 798 | − goto err; | |
| 799 | − } | |
| 800 | − | |
| 801 | − ctxi->rht_lun = lli; | |
| 802 | − ctxi->rht_needs_ws = ws; | |
| 803 | − ctxi->rht_start = rhte; | |
| 804 | −out: | |
| 805 | − return ctxi; | |
| 806 | − | |
| 807 | −err: | |
| 808 | − kfree(ws); | |
| 809 | − kfree(lli); | |
| 810 | − kfree(ctxi); | |
| 811 | − ctxi = NULL; | |
| 812 | − goto out; | |
| 813 | −} | |
| 814 | − | |
| 815 | −/** | |
| 816 | − * init_context() - initializes a previously allocated context | |
| 817 | − * @ctxi: Previously allocated context | |
| 818 | − * @cfg: Internal structure associated with the host. | |
| 819 | − * @ctx: Previously obtained context cookie. | |
| 820 | − * @ctxid: Previously obtained process element associated with CXL context. | |
| 821 | − * @file: Previously obtained file associated with CXL context. | |
| 822 | − * @perms: User-specified permissions. | |
| 823 | − * @irqs: User-specified number of interrupts. | |
| 824 | − */ | |
| 825 | −static void init_context(struct ctx_info *ctxi, struct cxlflash_cfg *cfg, | |
| 826 | − void *ctx, int ctxid, struct file *file, u32 perms, | |
| 827 | − u64 irqs) | |
| 828 | −{ | |
| 829 | − struct afu *afu = cfg->afu; | |
| 830 | − | |
| 831 | − ctxi->rht_perms = perms; | |
| 832 | − ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl; | |
| 833 | − ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid); | |
| 834 | − ctxi->irqs = irqs; | |
| 835 | − ctxi->pid = task_tgid_nr(current); /* tgid = pid */ | |
| 836 | − ctxi->ctx = ctx; | |
| 837 | − ctxi->cfg = cfg; | |
| 838 | − ctxi->file = file; | |
| 839 | − ctxi->initialized = true; | |
| 840 | − mutex_init(&ctxi->mutex); | |
| 841 | − kref_init(&ctxi->kref); | |
| 842 | − INIT_LIST_HEAD(&ctxi->luns); | |
| 843 | − INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */ | |
| 844 | −} | |
| 845 | − | |
| 846 | −/** | |
| 847 | − * remove_context() - context kref release handler | |
| 848 | − * @kref: Kernel reference associated with context to be removed. | |
| 849 | − * | |
| 850 | − * When a context no longer has any references it can safely be removed | |
| 851 | − * from global access and destroyed. Note that it is assumed the thread | |
| 852 | − * relinquishing access to the context holds its mutex. | |
| 853 | − */ | |
| 854 | −static void remove_context(struct kref *kref) | |
| 855 | −{ | |
| 856 | − struct ctx_info *ctxi = container_of(kref, struct ctx_info, kref); | |
| 857 | − struct cxlflash_cfg *cfg = ctxi->cfg; | |
| 858 | − u64 ctxid = DECODE_CTXID(ctxi->ctxid); | |
| 859 | − | |
| 860 | − /* Remove context from table/error list */ | |
| 861 | − WARN_ON(!mutex_is_locked(&ctxi->mutex)); | |
| 862 | − ctxi->unavail = true; | |
| 863 | − mutex_unlock(&ctxi->mutex); | |
| 864 | − mutex_lock(&cfg->ctx_tbl_list_mutex); | |
| 865 | − mutex_lock(&ctxi->mutex); | |
| 866 | − | |
| 867 | − if (!list_empty(&ctxi->list)) | |
| 868 | − list_del(&ctxi->list); | |
| 869 | − cfg->ctx_tbl[ctxid] = NULL; | |
| 870 | − mutex_unlock(&cfg->ctx_tbl_list_mutex); | |
| 871 | − mutex_unlock(&ctxi->mutex); | |
| 872 | − | |
| 873 | − /* Context now completely uncoupled/unreachable */ | |
| 874 | − destroy_context(cfg, ctxi); | |
| 875 | −} | |
| 876 | − | |
| 877 | −/** | |
| 878 | − * _cxlflash_disk_detach() - detaches a LUN from a context | |
| 879 | − * @sdev: SCSI device associated with LUN. | |
| 880 | − * @ctxi: Context owning resources. | |
| 881 | − * @detach: Detach ioctl data structure. | |
| 882 | − * | |
| 883 | − * As part of the detach, all per-context resources associated with the LUN | |
| 884 | − * are cleaned up. When detaching the last LUN for a context, the context | |
| 885 | − * itself is cleaned up and released. | |
| 886 | − * | |
| 887 | − * Return: 0 on success, -errno on failure | |
| 888 | − */ | |
| 889 | −static int _cxlflash_disk_detach(struct scsi_device *sdev, | |
| 890 | − struct ctx_info *ctxi, | |
| 891 | − struct dk_cxlflash_detach *detach) | |
| 892 | −{ | |
| 893 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 894 | − struct device *dev = &cfg->dev->dev; | |
| 895 | − struct llun_info *lli = sdev->hostdata; | |
| 896 | − struct lun_access *lun_access, *t; | |
| 897 | − struct dk_cxlflash_release rel; | |
| 898 | − bool put_ctx = false; | |
| 899 | − | |
| 900 | − int i; | |
| 901 | − int rc = 0; | |
| 902 | − u64 ctxid = DECODE_CTXID(detach->context_id), | |
| 903 | − rctxid = detach->context_id; | |
| 904 | − | |
| 905 | − dev_dbg(dev, "%s: ctxid=%llu\n", __func__, ctxid); | |
| 906 | − | |
| 907 | − if (!ctxi) { | |
| 908 | − ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); | |
| 909 | − if (unlikely(!ctxi)) { | |
| 910 | − dev_dbg(dev, "%s: Bad context ctxid=%llu\n", | |
| 911 | − __func__, ctxid); | |
| 912 | − rc = -EINVAL; | |
| 913 | − goto out; | |
| 914 | − } | |
| 915 | − | |
| 916 | − put_ctx = true; | |
| 917 | − } | |
| 918 | − | |
| 919 | − /* Cleanup outstanding resources tied to this LUN */ | |
| 920 | − if (ctxi->rht_out) { | |
| 921 | − marshal_det_to_rele(detach, &rel); | |
| 922 | − for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) { | |
| 923 | − if (ctxi->rht_lun[i] == lli) { | |
| 924 | − rel.rsrc_handle = i; | |
| 925 | − _cxlflash_disk_release(sdev, ctxi, &rel); | |
| 926 | − } | |
| 927 | − | |
| 928 | − /* No need to loop further if we're done */ | |
| 929 | − if (ctxi->rht_out == 0) | |
| 930 | − break; | |
| 931 | − } | |
| 932 | − } | |
| 933 | − | |
| 934 | − /* Take our LUN out of context, free the node */ | |
| 935 | − list_for_each_entry_safe(lun_access, t, &ctxi->luns, list) | |
| 936 | − if (lun_access->lli == lli) { | |
| 937 | − list_del(&lun_access->list); | |
| 938 | − kfree(lun_access); | |
| 939 | − lun_access = NULL; | |
| 940 | − break; | |
| 941 | − } | |
| 942 | − | |
| 943 | − /* | |
| 944 | − * Release the context reference and the sdev reference that | |
| 945 | − * bound this LUN to the context. | |
| 946 | − */ | |
| 947 | − if (kref_put(&ctxi->kref, remove_context)) | |
| 948 | − put_ctx = false; | |
| 949 | − scsi_device_put(sdev); | |
| 950 | −out: | |
| 951 | − if (put_ctx) | |
| 952 | − put_context(ctxi); | |
| 953 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 954 | − return rc; | |
| 955 | −} | |
| 956 | − | |
| 957 | −static int cxlflash_disk_detach(struct scsi_device *sdev, void *detach) | |
| 958 | −{ | |
| 959 | − return _cxlflash_disk_detach(sdev, NULL, detach); | |
| 960 | −} | |
| 961 | − | |
| 962 | −/** | |
| 963 | − * cxlflash_cxl_release() - release handler for adapter file descriptor | |
| 964 | − * @inode: File-system inode associated with fd. | |
| 965 | − * @file: File installed with adapter file descriptor. | |
| 966 | − * | |
| 967 | − * This routine is the release handler for the fops registered with | |
| 968 | − * the CXL services on an initial attach for a context. It is called | |
| 969 | − * when a close (explicitly by the user or as part of a process tear | |
| 970 | − * down) is performed on the adapter file descriptor returned to the | |
| 971 | − * user. The user should be aware that explicitly performing a close | |
| 972 | − * considered catastrophic and subsequent usage of the superpipe API | |
| 973 | − * with previously saved off tokens will fail. | |
| 974 | − * | |
| 975 | − * This routine derives the context reference and calls detach for | |
| 976 | − * each LUN associated with the context.The final detach operation | |
| 977 | − * causes the context itself to be freed. With exception to when the | |
| 978 | − * CXL process element (context id) lookup fails (a case that should | |
| 979 | − * theoretically never occur), every call into this routine results | |
| 980 | − * in a complete freeing of a context. | |
| 981 | − * | |
| 982 | − * Detaching the LUN is typically an ioctl() operation and the underlying | |
| 983 | − * code assumes that ioctl_rwsem has been acquired as a reader. To support | |
| 984 | − * that design point, the semaphore is acquired and released around detach. | |
| 985 | − * | |
| 986 | − * Return: 0 on success | |
| 987 | − */ | |
| 988 | −static int cxlflash_cxl_release(struct inode *inode, struct file *file) | |
| 989 | −{ | |
| 990 | − struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, | |
| 991 | − cxl_fops); | |
| 992 | − void *ctx = cfg->ops->fops_get_context(file); | |
| 993 | − struct device *dev = &cfg->dev->dev; | |
| 994 | − struct ctx_info *ctxi = NULL; | |
| 995 | − struct dk_cxlflash_detach detach = { { 0 }, 0 }; | |
| 996 | − struct lun_access *lun_access, *t; | |
| 997 | − enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; | |
| 998 | − int ctxid; | |
| 999 | − | |
| 1000 | − ctxid = cfg->ops->process_element(ctx); | |
| 1001 | − if (unlikely(ctxid < 0)) { | |
| 1002 | − dev_err(dev, "%s: Context %p was closed ctxid=%d\n", | |
| 1003 | − __func__, ctx, ctxid); | |
| 1004 | − goto out; | |
| 1005 | − } | |
| 1006 | − | |
| 1007 | − ctxi = get_context(cfg, ctxid, file, ctrl); | |
| 1008 | − if (unlikely(!ctxi)) { | |
| 1009 | − ctxi = get_context(cfg, ctxid, file, ctrl | CTX_CTRL_CLONE); | |
| 1010 | − if (!ctxi) { | |
| 1011 | − dev_dbg(dev, "%s: ctxid=%d already free\n", | |
| 1012 | − __func__, ctxid); | |
| 1013 | − goto out_release; | |
| 1014 | − } | |
| 1015 | − | |
| 1016 | − dev_dbg(dev, "%s: Another process owns ctxid=%d\n", | |
| 1017 | − __func__, ctxid); | |
| 1018 | − put_context(ctxi); | |
| 1019 | − goto out; | |
| 1020 | − } | |
| 1021 | − | |
| 1022 | − dev_dbg(dev, "%s: close for ctxid=%d\n", __func__, ctxid); | |
| 1023 | − | |
| 1024 | − down_read(&cfg->ioctl_rwsem); | |
| 1025 | − detach.context_id = ctxi->ctxid; | |
| 1026 | − list_for_each_entry_safe(lun_access, t, &ctxi->luns, list) | |
| 1027 | − _cxlflash_disk_detach(lun_access->sdev, ctxi, &detach); | |
| 1028 | − up_read(&cfg->ioctl_rwsem); | |
| 1029 | −out_release: | |
| 1030 | − cfg->ops->fd_release(inode, file); | |
| 1031 | −out: | |
| 1032 | − dev_dbg(dev, "%s: returning\n", __func__); | |
| 1033 | − return 0; | |
| 1034 | −} | |
| 1035 | − | |
| 1036 | −/** | |
| 1037 | − * unmap_context() - clears a previously established mapping | |
| 1038 | − * @ctxi: Context owning the mapping. | |
| 1039 | − * | |
| 1040 | − * This routine is used to switch between the error notification page | |
| 1041 | − * (dummy page of all 1's) and the real mapping (established by the CXL | |
| 1042 | − * fault handler). | |
| 1043 | − */ | |
| 1044 | −static void unmap_context(struct ctx_info *ctxi) | |
| 1045 | −{ | |
| 1046 | − unmap_mapping_range(ctxi->file->f_mapping, 0, 0, 1); | |
| 1047 | −} | |
| 1048 | − | |
| 1049 | −/** | |
| 1050 | − * get_err_page() - obtains and allocates the error notification page | |
| 1051 | − * @cfg: Internal structure associated with the host. | |
| 1052 | − * | |
| 1053 | − * Return: error notification page on success, NULL on failure | |
| 1054 | − */ | |
| 1055 | −static struct page *get_err_page(struct cxlflash_cfg *cfg) | |
| 1056 | −{ | |
| 1057 | − struct page *err_page = global.err_page; | |
| 1058 | − struct device *dev = &cfg->dev->dev; | |
| 1059 | − | |
| 1060 | − if (unlikely(!err_page)) { | |
| 1061 | − err_page = alloc_page(GFP_KERNEL); | |
| 1062 | − if (unlikely(!err_page)) { | |
| 1063 | − dev_err(dev, "%s: Unable to allocate err_page\n", | |
| 1064 | − __func__); | |
| 1065 | − goto out; | |
| 1066 | − } | |
| 1067 | − | |
| 1068 | − memset(page_address(err_page), -1, PAGE_SIZE); | |
| 1069 | − | |
| 1070 | − /* Serialize update w/ other threads to avoid a leak */ | |
| 1071 | − mutex_lock(&global.mutex); | |
| 1072 | − if (likely(!global.err_page)) | |
| 1073 | − global.err_page = err_page; | |
| 1074 | − else { | |
| 1075 | − __free_page(err_page); | |
| 1076 | − err_page = global.err_page; | |
| 1077 | − } | |
| 1078 | − mutex_unlock(&global.mutex); | |
| 1079 | − } | |
| 1080 | − | |
| 1081 | −out: | |
| 1082 | − dev_dbg(dev, "%s: returning err_page=%p\n", __func__, err_page); | |
| 1083 | − return err_page; | |
| 1084 | −} | |
| 1085 | − | |
| 1086 | −/** | |
| 1087 | − * cxlflash_mmap_fault() - mmap fault handler for adapter file descriptor | |
| 1088 | − * @vmf: VM fault associated with current fault. | |
| 1089 | − * | |
| 1090 | − * To support error notification via MMIO, faults are 'caught' by this routine | |
| 1091 | − * that was inserted before passing back the adapter file descriptor on attach. | |
| 1092 | − * When a fault occurs, this routine evaluates if error recovery is active and | |
| 1093 | − * if so, installs the error page to 'notify' the user about the error state. | |
| 1094 | − * During normal operation, the fault is simply handled by the original fault | |
| 1095 | − * handler that was installed by CXL services as part of initializing the | |
| 1096 | − * adapter file descriptor. The VMA's page protection bits are toggled to | |
| 1097 | − * indicate cached/not-cached depending on the memory backing the fault. | |
| 1098 | − * | |
| 1099 | − * Return: 0 on success, VM_FAULT_SIGBUS on failure | |
| 1100 | − */ | |
| 1101 | −static vm_fault_t cxlflash_mmap_fault(struct vm_fault *vmf) | |
| 1102 | −{ | |
| 1103 | − struct vm_area_struct *vma = vmf->vma; | |
| 1104 | − struct file *file = vma->vm_file; | |
| 1105 | − struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, | |
| 1106 | − cxl_fops); | |
| 1107 | − void *ctx = cfg->ops->fops_get_context(file); | |
| 1108 | − struct device *dev = &cfg->dev->dev; | |
| 1109 | − struct ctx_info *ctxi = NULL; | |
| 1110 | − struct page *err_page = NULL; | |
| 1111 | − enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; | |
| 1112 | − vm_fault_t rc = 0; | |
| 1113 | − int ctxid; | |
| 1114 | − | |
| 1115 | − ctxid = cfg->ops->process_element(ctx); | |
| 1116 | − if (unlikely(ctxid < 0)) { | |
| 1117 | − dev_err(dev, "%s: Context %p was closed ctxid=%d\n", | |
| 1118 | − __func__, ctx, ctxid); | |
| 1119 | − goto err; | |
| 1120 | − } | |
| 1121 | − | |
| 1122 | − ctxi = get_context(cfg, ctxid, file, ctrl); | |
| 1123 | − if (unlikely(!ctxi)) { | |
| 1124 | − dev_dbg(dev, "%s: Bad context ctxid=%d\n", __func__, ctxid); | |
| 1125 | − goto err; | |
| 1126 | − } | |
| 1127 | − | |
| 1128 | − dev_dbg(dev, "%s: fault for context %d\n", __func__, ctxid); | |
| 1129 | − | |
| 1130 | − if (likely(!ctxi->err_recovery_active)) { | |
| 1131 | − vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | |
| 1132 | − rc = ctxi->cxl_mmap_vmops->fault(vmf); | |
| 1133 | − } else { | |
| 1134 | − dev_dbg(dev, "%s: err recovery active, use err_page\n", | |
| 1135 | − __func__); | |
| 1136 | − | |
| 1137 | − err_page = get_err_page(cfg); | |
| 1138 | − if (unlikely(!err_page)) { | |
| 1139 | − dev_err(dev, "%s: Could not get err_page\n", __func__); | |
| 1140 | − rc = VM_FAULT_RETRY; | |
| 1141 | − goto out; | |
| 1142 | − } | |
| 1143 | − | |
| 1144 | − get_page(err_page); | |
| 1145 | − vmf->page = err_page; | |
| 1146 | − vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); | |
| 1147 | − } | |
| 1148 | − | |
| 1149 | −out: | |
| 1150 | − if (likely(ctxi)) | |
| 1151 | − put_context(ctxi); | |
| 1152 | − dev_dbg(dev, "%s: returning rc=%x\n", __func__, rc); | |
| 1153 | − return rc; | |
| 1154 | − | |
| 1155 | −err: | |
| 1156 | − rc = VM_FAULT_SIGBUS; | |
| 1157 | − goto out; | |
| 1158 | −} | |
| 1159 | − | |
| 1160 | −/* | |
| 1161 | − * Local MMAP vmops to 'catch' faults | |
| 1162 | − */ | |
| 1163 | −static const struct vm_operations_struct cxlflash_mmap_vmops = { | |
| 1164 | − .fault = cxlflash_mmap_fault, | |
| 1165 | −}; | |
| 1166 | − | |
| 1167 | −/** | |
| 1168 | − * cxlflash_cxl_mmap() - mmap handler for adapter file descriptor | |
| 1169 | − * @file: File installed with adapter file descriptor. | |
| 1170 | − * @vma: VM area associated with mapping. | |
| 1171 | − * | |
| 1172 | − * Installs local mmap vmops to 'catch' faults for error notification support. | |
| 1173 | − * | |
| 1174 | − * Return: 0 on success, -errno on failure | |
| 1175 | − */ | |
| 1176 | −static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma) | |
| 1177 | −{ | |
| 1178 | − struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, | |
| 1179 | − cxl_fops); | |
| 1180 | − void *ctx = cfg->ops->fops_get_context(file); | |
| 1181 | − struct device *dev = &cfg->dev->dev; | |
| 1182 | − struct ctx_info *ctxi = NULL; | |
| 1183 | − enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; | |
| 1184 | − int ctxid; | |
| 1185 | − int rc = 0; | |
| 1186 | − | |
| 1187 | − ctxid = cfg->ops->process_element(ctx); | |
| 1188 | − if (unlikely(ctxid < 0)) { | |
| 1189 | − dev_err(dev, "%s: Context %p was closed ctxid=%d\n", | |
| 1190 | − __func__, ctx, ctxid); | |
| 1191 | − rc = -EIO; | |
| 1192 | − goto out; | |
| 1193 | − } | |
| 1194 | − | |
| 1195 | − ctxi = get_context(cfg, ctxid, file, ctrl); | |
| 1196 | − if (unlikely(!ctxi)) { | |
| 1197 | − dev_dbg(dev, "%s: Bad context ctxid=%d\n", __func__, ctxid); | |
| 1198 | − rc = -EIO; | |
| 1199 | − goto out; | |
| 1200 | − } | |
| 1201 | − | |
| 1202 | − dev_dbg(dev, "%s: mmap for context %d\n", __func__, ctxid); | |
| 1203 | − | |
| 1204 | − rc = cfg->ops->fd_mmap(file, vma); | |
| 1205 | − if (likely(!rc)) { | |
| 1206 | − /* Insert ourself in the mmap fault handler path */ | |
| 1207 | − ctxi->cxl_mmap_vmops = vma->vm_ops; | |
| 1208 | − vma->vm_ops = &cxlflash_mmap_vmops; | |
| 1209 | − } | |
| 1210 | − | |
| 1211 | −out: | |
| 1212 | − if (likely(ctxi)) | |
| 1213 | − put_context(ctxi); | |
| 1214 | − return rc; | |
| 1215 | −} | |
| 1216 | − | |
| 1217 | −const struct file_operations cxlflash_cxl_fops = { | |
| 1218 | − .owner = THIS_MODULE, | |
| 1219 | − .mmap = cxlflash_cxl_mmap, | |
| 1220 | − .release = cxlflash_cxl_release, | |
| 1221 | −}; | |
| 1222 | − | |
| 1223 | −/** | |
| 1224 | − * cxlflash_mark_contexts_error() - move contexts to error state and list | |
| 1225 | − * @cfg: Internal structure associated with the host. | |
| 1226 | − * | |
| 1227 | − * A context is only moved over to the error list when there are no outstanding | |
| 1228 | − * references to it. This ensures that a running operation has completed. | |
| 1229 | − * | |
| 1230 | − * Return: 0 on success, -errno on failure | |
| 1231 | − */ | |
| 1232 | −int cxlflash_mark_contexts_error(struct cxlflash_cfg *cfg) | |
| 1233 | −{ | |
| 1234 | − int i, rc = 0; | |
| 1235 | − struct ctx_info *ctxi = NULL; | |
| 1236 | − | |
| 1237 | − mutex_lock(&cfg->ctx_tbl_list_mutex); | |
| 1238 | − | |
| 1239 | − for (i = 0; i < MAX_CONTEXT; i++) { | |
| 1240 | − ctxi = cfg->ctx_tbl[i]; | |
| 1241 | − if (ctxi) { | |
| 1242 | − mutex_lock(&ctxi->mutex); | |
| 1243 | − cfg->ctx_tbl[i] = NULL; | |
| 1244 | − list_add(&ctxi->list, &cfg->ctx_err_recovery); | |
| 1245 | − ctxi->err_recovery_active = true; | |
| 1246 | − ctxi->ctrl_map = NULL; | |
| 1247 | − unmap_context(ctxi); | |
| 1248 | − mutex_unlock(&ctxi->mutex); | |
| 1249 | − } | |
| 1250 | − } | |
| 1251 | − | |
| 1252 | − mutex_unlock(&cfg->ctx_tbl_list_mutex); | |
| 1253 | − return rc; | |
| 1254 | −} | |
| 1255 | − | |
| 1256 | −/* | |
| 1257 | − * Dummy NULL fops | |
| 1258 | − */ | |
| 1259 | −static const struct file_operations null_fops = { | |
| 1260 | − .owner = THIS_MODULE, | |
| 1261 | −}; | |
| 1262 | − | |
| 1263 | −/** | |
| 1264 | − * check_state() - checks and responds to the current adapter state | |
| 1265 | − * @cfg: Internal structure associated with the host. | |
| 1266 | − * | |
| 1267 | − * This routine can block and should only be used on process context. | |
| 1268 | − * It assumes that the caller is an ioctl thread and holding the ioctl | |
| 1269 | − * read semaphore. This is temporarily let up across the wait to allow | |
| 1270 | − * for draining actively running ioctls. Also note that when waking up | |
| 1271 | − * from waiting in reset, the state is unknown and must be checked again | |
| 1272 | − * before proceeding. | |
| 1273 | − * | |
| 1274 | − * Return: 0 on success, -errno on failure | |
| 1275 | − */ | |
| 1276 | −int check_state(struct cxlflash_cfg *cfg) | |
| 1277 | −{ | |
| 1278 | − struct device *dev = &cfg->dev->dev; | |
| 1279 | − int rc = 0; | |
| 1280 | − | |
| 1281 | −retry: | |
| 1282 | − switch (cfg->state) { | |
| 1283 | − case STATE_RESET: | |
| 1284 | − dev_dbg(dev, "%s: Reset state, going to wait...\n", __func__); | |
| 1285 | − up_read(&cfg->ioctl_rwsem); | |
| 1286 | − rc = wait_event_interruptible(cfg->reset_waitq, | |
| 1287 | − cfg->state != STATE_RESET); | |
| 1288 | − down_read(&cfg->ioctl_rwsem); | |
| 1289 | − if (unlikely(rc)) | |
| 1290 | − break; | |
| 1291 | − goto retry; | |
| 1292 | − case STATE_FAILTERM: | |
| 1293 | − dev_dbg(dev, "%s: Failed/Terminating\n", __func__); | |
| 1294 | − rc = -ENODEV; | |
| 1295 | − break; | |
| 1296 | − default: | |
| 1297 | − break; | |
| 1298 | − } | |
| 1299 | − | |
| 1300 | − return rc; | |
| 1301 | −} | |
| 1302 | − | |
| 1303 | −/** | |
| 1304 | − * cxlflash_disk_attach() - attach a LUN to a context | |
| 1305 | − * @sdev: SCSI device associated with LUN. | |
| 1306 | − * @arg: Attach ioctl data structure. | |
| 1307 | − * | |
| 1308 | − * Creates a context and attaches LUN to it. A LUN can only be attached | |
| 1309 | − * one time to a context (subsequent attaches for the same context/LUN pair | |
| 1310 | − * are not supported). Additional LUNs can be attached to a context by | |
| 1311 | − * specifying the 'reuse' flag defined in the cxlflash_ioctl.h header. | |
| 1312 | − * | |
| 1313 | − * Return: 0 on success, -errno on failure | |
| 1314 | − */ | |
| 1315 | −static int cxlflash_disk_attach(struct scsi_device *sdev, void *arg) | |
| 1316 | −{ | |
| 1317 | − struct dk_cxlflash_attach *attach = arg; | |
| 1318 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 1319 | − struct device *dev = &cfg->dev->dev; | |
| 1320 | − struct afu *afu = cfg->afu; | |
| 1321 | − struct llun_info *lli = sdev->hostdata; | |
| 1322 | − struct glun_info *gli = lli->parent; | |
| 1323 | − struct ctx_info *ctxi = NULL; | |
| 1324 | − struct lun_access *lun_access = NULL; | |
| 1325 | − int rc = 0; | |
| 1326 | − u32 perms; | |
| 1327 | − int ctxid = -1; | |
| 1328 | − u64 irqs = attach->num_interrupts; | |
| 1329 | − u64 flags = 0UL; | |
| 1330 | − u64 rctxid = 0UL; | |
| 1331 | − struct file *file = NULL; | |
| 1332 | − | |
| 1333 | − void *ctx = NULL; | |
| 1334 | − | |
| 1335 | − int fd = -1; | |
| 1336 | − | |
| 1337 | − if (irqs > 4) { | |
| 1338 | − dev_dbg(dev, "%s: Cannot support this many interrupts %llu\n", | |
| 1339 | − __func__, irqs); | |
| 1340 | − rc = -EINVAL; | |
| 1341 | − goto out; | |
| 1342 | − } | |
| 1343 | − | |
| 1344 | − if (gli->max_lba == 0) { | |
| 1345 | − dev_dbg(dev, "%s: No capacity info for LUN=%016llx\n", | |
| 1346 | − __func__, lli->lun_id[sdev->channel]); | |
| 1347 | − rc = read_cap16(sdev, lli); | |
| 1348 | − if (rc) { | |
| 1349 | − dev_err(dev, "%s: Invalid device rc=%d\n", | |
| 1350 | − __func__, rc); | |
| 1351 | − rc = -ENODEV; | |
| 1352 | − goto out; | |
| 1353 | − } | |
| 1354 | − dev_dbg(dev, "%s: LBA = %016llx\n", __func__, gli->max_lba); | |
| 1355 | − dev_dbg(dev, "%s: BLK_LEN = %08x\n", __func__, gli->blk_len); | |
| 1356 | − } | |
| 1357 | − | |
| 1358 | − if (attach->hdr.flags & DK_CXLFLASH_ATTACH_REUSE_CONTEXT) { | |
| 1359 | − rctxid = attach->context_id; | |
| 1360 | − ctxi = get_context(cfg, rctxid, NULL, 0); | |
| 1361 | − if (!ctxi) { | |
| 1362 | − dev_dbg(dev, "%s: Bad context rctxid=%016llx\n", | |
| 1363 | − __func__, rctxid); | |
| 1364 | − rc = -EINVAL; | |
| 1365 | − goto out; | |
| 1366 | − } | |
| 1367 | − | |
| 1368 | − list_for_each_entry(lun_access, &ctxi->luns, list) | |
| 1369 | − if (lun_access->lli == lli) { | |
| 1370 | − dev_dbg(dev, "%s: Already attached\n", | |
| 1371 | − __func__); | |
| 1372 | − rc = -EINVAL; | |
| 1373 | − goto out; | |
| 1374 | − } | |
| 1375 | − } | |
| 1376 | − | |
| 1377 | − rc = scsi_device_get(sdev); | |
| 1378 | − if (unlikely(rc)) { | |
| 1379 | − dev_err(dev, "%s: Unable to get sdev reference\n", __func__); | |
| 1380 | − goto out; | |
| 1381 | − } | |
| 1382 | − | |
| 1383 | − lun_access = kzalloc(sizeof(*lun_access), GFP_KERNEL); | |
| 1384 | − if (unlikely(!lun_access)) { | |
| 1385 | − dev_err(dev, "%s: Unable to allocate lun_access\n", __func__); | |
| 1386 | − rc = -ENOMEM; | |
| 1387 | − goto err; | |
| 1388 | − } | |
| 1389 | − | |
| 1390 | − lun_access->lli = lli; | |
| 1391 | − lun_access->sdev = sdev; | |
| 1392 | − | |
| 1393 | − /* Non-NULL context indicates reuse (another context reference) */ | |
| 1394 | − if (ctxi) { | |
| 1395 | − dev_dbg(dev, "%s: Reusing context for LUN rctxid=%016llx\n", | |
| 1396 | − __func__, rctxid); | |
| 1397 | − kref_get(&ctxi->kref); | |
| 1398 | − list_add(&lun_access->list, &ctxi->luns); | |
| 1399 | − goto out_attach; | |
| 1400 | − } | |
| 1401 | − | |
| 1402 | − ctxi = create_context(cfg); | |
| 1403 | − if (unlikely(!ctxi)) { | |
| 1404 | − dev_err(dev, "%s: Failed to create context ctxid=%d\n", | |
| 1405 | − __func__, ctxid); | |
| 1406 | − rc = -ENOMEM; | |
| 1407 | − goto err; | |
| 1408 | − } | |
| 1409 | − | |
| 1410 | − ctx = cfg->ops->dev_context_init(cfg->dev, cfg->afu_cookie); | |
| 1411 | − if (IS_ERR_OR_NULL(ctx)) { | |
| 1412 | − dev_err(dev, "%s: Could not initialize context %p\n", | |
| 1413 | − __func__, ctx); | |
| 1414 | − rc = -ENODEV; | |
| 1415 | − goto err; | |
| 1416 | − } | |
| 1417 | − | |
| 1418 | − rc = cfg->ops->start_work(ctx, irqs); | |
| 1419 | − if (unlikely(rc)) { | |
| 1420 | − dev_dbg(dev, "%s: Could not start context rc=%d\n", | |
| 1421 | − __func__, rc); | |
| 1422 | − goto err; | |
| 1423 | − } | |
| 1424 | − | |
| 1425 | − ctxid = cfg->ops->process_element(ctx); | |
| 1426 | − if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) { | |
| 1427 | − dev_err(dev, "%s: ctxid=%d invalid\n", __func__, ctxid); | |
| 1428 | − rc = -EPERM; | |
| 1429 | − goto err; | |
| 1430 | − } | |
| 1431 | − | |
| 1432 | − file = cfg->ops->get_fd(ctx, &cfg->cxl_fops, &fd); | |
| 1433 | − if (unlikely(fd < 0)) { | |
| 1434 | − rc = -ENODEV; | |
| 1435 | − dev_err(dev, "%s: Could not get file descriptor\n", __func__); | |
| 1436 | − goto err; | |
| 1437 | − } | |
| 1438 | − | |
| 1439 | − /* Translate read/write O_* flags from fcntl.h to AFU permission bits */ | |
| 1440 | − perms = SISL_RHT_PERM(attach->hdr.flags + 1); | |
| 1441 | − | |
| 1442 | − /* Context mutex is locked upon return */ | |
| 1443 | − init_context(ctxi, cfg, ctx, ctxid, file, perms, irqs); | |
| 1444 | − | |
| 1445 | − rc = afu_attach(cfg, ctxi); | |
| 1446 | − if (unlikely(rc)) { | |
| 1447 | − dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); | |
| 1448 | − goto err; | |
| 1449 | − } | |
| 1450 | − | |
| 1451 | − /* | |
| 1452 | − * No error paths after this point. Once the fd is installed it's | |
| 1453 | − * visible to user space and can't be undone safely on this thread. | |
| 1454 | − * There is no need to worry about a deadlock here because no one | |
| 1455 | − * knows about us yet; we can be the only one holding our mutex. | |
| 1456 | − */ | |
| 1457 | − list_add(&lun_access->list, &ctxi->luns); | |
| 1458 | − mutex_lock(&cfg->ctx_tbl_list_mutex); | |
| 1459 | − mutex_lock(&ctxi->mutex); | |
| 1460 | − cfg->ctx_tbl[ctxid] = ctxi; | |
| 1461 | − mutex_unlock(&cfg->ctx_tbl_list_mutex); | |
| 1462 | − fd_install(fd, file); | |
| 1463 | − | |
| 1464 | −out_attach: | |
| 1465 | − if (fd != -1) | |
| 1466 | − flags |= DK_CXLFLASH_APP_CLOSE_ADAP_FD; | |
| 1467 | − if (afu_is_sq_cmd_mode(afu)) | |
| 1468 | − flags |= DK_CXLFLASH_CONTEXT_SQ_CMD_MODE; | |
| 1469 | − | |
| 1470 | − attach->hdr.return_flags = flags; | |
| 1471 | − attach->context_id = ctxi->ctxid; | |
| 1472 | − attach->block_size = gli->blk_len; | |
| 1473 | − attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea); | |
| 1474 | − attach->last_lba = gli->max_lba; | |
| 1475 | − attach->max_xfer = sdev->host->max_sectors * MAX_SECTOR_UNIT; | |
| 1476 | − attach->max_xfer /= gli->blk_len; | |
| 1477 | − | |
| 1478 | −out: | |
| 1479 | − attach->adap_fd = fd; | |
| 1480 | − | |
| 1481 | − if (ctxi) | |
| 1482 | − put_context(ctxi); | |
| 1483 | − | |
| 1484 | − dev_dbg(dev, "%s: returning ctxid=%d fd=%d bs=%lld rc=%d llba=%lld\n", | |
| 1485 | − __func__, ctxid, fd, attach->block_size, rc, attach->last_lba); | |
| 1486 | − return rc; | |
| 1487 | − | |
| 1488 | −err: | |
| 1489 | − /* Cleanup CXL context; okay to 'stop' even if it was not started */ | |
| 1490 | − if (!IS_ERR_OR_NULL(ctx)) { | |
| 1491 | − cfg->ops->stop_context(ctx); | |
| 1492 | − cfg->ops->release_context(ctx); | |
| 1493 | − ctx = NULL; | |
| 1494 | − } | |
| 1495 | − | |
| 1496 | − /* | |
| 1497 | − * Here, we're overriding the fops with a dummy all-NULL fops because | |
| 1498 | − * fput() calls the release fop, which will cause us to mistakenly | |
| 1499 | − * call into the CXL code. Rather than try to add yet more complexity | |
| 1500 | − * to that routine (cxlflash_cxl_release) we should try to fix the | |
| 1501 | − * issue here. | |
| 1502 | − */ | |
| 1503 | − if (fd > 0) { | |
| 1504 | − file->f_op = &null_fops; | |
| 1505 | − fput(file); | |
| 1506 | − put_unused_fd(fd); | |
| 1507 | − fd = -1; | |
| 1508 | − file = NULL; | |
| 1509 | − } | |
| 1510 | − | |
| 1511 | − /* Cleanup our context */ | |
| 1512 | − if (ctxi) { | |
| 1513 | − destroy_context(cfg, ctxi); | |
| 1514 | − ctxi = NULL; | |
| 1515 | − } | |
| 1516 | − | |
| 1517 | − kfree(lun_access); | |
| 1518 | − scsi_device_put(sdev); | |
| 1519 | − goto out; | |
| 1520 | −} | |
| 1521 | − | |
| 1522 | −/** | |
| 1523 | − * recover_context() - recovers a context in error | |
| 1524 | − * @cfg: Internal structure associated with the host. | |
| 1525 | − * @ctxi: Context to release. | |
| 1526 | − * @adap_fd: Adapter file descriptor associated with new/recovered context. | |
| 1527 | − * | |
| 1528 | − * Restablishes the state for a context-in-error. | |
| 1529 | − * | |
| 1530 | − * Return: 0 on success, -errno on failure | |
| 1531 | − */ | |
| 1532 | −static int recover_context(struct cxlflash_cfg *cfg, | |
| 1533 | − struct ctx_info *ctxi, | |
| 1534 | − int *adap_fd) | |
| 1535 | −{ | |
| 1536 | − struct device *dev = &cfg->dev->dev; | |
| 1537 | − int rc = 0; | |
| 1538 | − int fd = -1; | |
| 1539 | − int ctxid = -1; | |
| 1540 | − struct file *file; | |
| 1541 | − void *ctx; | |
| 1542 | − struct afu *afu = cfg->afu; | |
| 1543 | − | |
| 1544 | − ctx = cfg->ops->dev_context_init(cfg->dev, cfg->afu_cookie); | |
| 1545 | − if (IS_ERR_OR_NULL(ctx)) { | |
| 1546 | − dev_err(dev, "%s: Could not initialize context %p\n", | |
| 1547 | − __func__, ctx); | |
| 1548 | − rc = -ENODEV; | |
| 1549 | − goto out; | |
| 1550 | − } | |
| 1551 | − | |
| 1552 | − rc = cfg->ops->start_work(ctx, ctxi->irqs); | |
| 1553 | − if (unlikely(rc)) { | |
| 1554 | − dev_dbg(dev, "%s: Could not start context rc=%d\n", | |
| 1555 | − __func__, rc); | |
| 1556 | − goto err1; | |
| 1557 | − } | |
| 1558 | − | |
| 1559 | − ctxid = cfg->ops->process_element(ctx); | |
| 1560 | − if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) { | |
| 1561 | − dev_err(dev, "%s: ctxid=%d invalid\n", __func__, ctxid); | |
| 1562 | − rc = -EPERM; | |
| 1563 | − goto err2; | |
| 1564 | − } | |
| 1565 | − | |
| 1566 | − file = cfg->ops->get_fd(ctx, &cfg->cxl_fops, &fd); | |
| 1567 | − if (unlikely(fd < 0)) { | |
| 1568 | − rc = -ENODEV; | |
| 1569 | − dev_err(dev, "%s: Could not get file descriptor\n", __func__); | |
| 1570 | − goto err2; | |
| 1571 | − } | |
| 1572 | − | |
| 1573 | − /* Update with new MMIO area based on updated context id */ | |
| 1574 | − ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl; | |
| 1575 | − | |
| 1576 | − rc = afu_attach(cfg, ctxi); | |
| 1577 | − if (rc) { | |
| 1578 | − dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); | |
| 1579 | − goto err3; | |
| 1580 | − } | |
| 1581 | − | |
| 1582 | − /* | |
| 1583 | − * No error paths after this point. Once the fd is installed it's | |
| 1584 | − * visible to user space and can't be undone safely on this thread. | |
| 1585 | − */ | |
| 1586 | − ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid); | |
| 1587 | − ctxi->ctx = ctx; | |
| 1588 | − ctxi->file = file; | |
| 1589 | − | |
| 1590 | − /* | |
| 1591 | − * Put context back in table (note the reinit of the context list); | |
| 1592 | − * we must first drop the context's mutex and then acquire it in | |
| 1593 | − * order with the table/list mutex to avoid a deadlock - safe to do | |
| 1594 | − * here because no one can find us at this moment in time. | |
| 1595 | − */ | |
| 1596 | − mutex_unlock(&ctxi->mutex); | |
| 1597 | − mutex_lock(&cfg->ctx_tbl_list_mutex); | |
| 1598 | − mutex_lock(&ctxi->mutex); | |
| 1599 | − list_del_init(&ctxi->list); | |
| 1600 | − cfg->ctx_tbl[ctxid] = ctxi; | |
| 1601 | − mutex_unlock(&cfg->ctx_tbl_list_mutex); | |
| 1602 | − fd_install(fd, file); | |
| 1603 | − *adap_fd = fd; | |
| 1604 | −out: | |
| 1605 | − dev_dbg(dev, "%s: returning ctxid=%d fd=%d rc=%d\n", | |
| 1606 | − __func__, ctxid, fd, rc); | |
| 1607 | − return rc; | |
| 1608 | − | |
| 1609 | −err3: | |
| 1610 | − fput(file); | |
| 1611 | − put_unused_fd(fd); | |
| 1612 | −err2: | |
| 1613 | − cfg->ops->stop_context(ctx); | |
| 1614 | −err1: | |
| 1615 | − cfg->ops->release_context(ctx); | |
| 1616 | − goto out; | |
| 1617 | −} | |
| 1618 | − | |
| 1619 | −/** | |
| 1620 | − * cxlflash_afu_recover() - initiates AFU recovery | |
| 1621 | − * @sdev: SCSI device associated with LUN. | |
| 1622 | − * @arg: Recover ioctl data structure. | |
| 1623 | − * | |
| 1624 | − * Only a single recovery is allowed at a time to avoid exhausting CXL | |
| 1625 | − * resources (leading to recovery failure) in the event that we're up | |
| 1626 | − * against the maximum number of contexts limit. For similar reasons, | |
| 1627 | − * a context recovery is retried if there are multiple recoveries taking | |
| 1628 | − * place at the same time and the failure was due to CXL services being | |
| 1629 | − * unable to keep up. | |
| 1630 | − * | |
| 1631 | − * As this routine is called on ioctl context, it holds the ioctl r/w | |
| 1632 | − * semaphore that is used to drain ioctls in recovery scenarios. The | |
| 1633 | − * implementation to achieve the pacing described above (a local mutex) | |
| 1634 | − * requires that the ioctl r/w semaphore be dropped and reacquired to | |
| 1635 | − * avoid a 3-way deadlock when multiple process recoveries operate in | |
| 1636 | − * parallel. | |
| 1637 | − * | |
| 1638 | − * Because a user can detect an error condition before the kernel, it is | |
| 1639 | − * quite possible for this routine to act as the kernel's EEH detection | |
| 1640 | − * source (MMIO read of mbox_r). Because of this, there is a window of | |
| 1641 | − * time where an EEH might have been detected but not yet 'serviced' | |
| 1642 | − * (callback invoked, causing the device to enter reset state). To avoid | |
| 1643 | − * looping in this routine during that window, a 1 second sleep is in place | |
| 1644 | − * between the time the MMIO failure is detected and the time a wait on the | |
| 1645 | − * reset wait queue is attempted via check_state(). | |
| 1646 | − * | |
| 1647 | − * Return: 0 on success, -errno on failure | |
| 1648 | − */ | |
| 1649 | −static int cxlflash_afu_recover(struct scsi_device *sdev, void *arg) | |
| 1650 | −{ | |
| 1651 | − struct dk_cxlflash_recover_afu *recover = arg; | |
| 1652 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 1653 | − struct device *dev = &cfg->dev->dev; | |
| 1654 | − struct llun_info *lli = sdev->hostdata; | |
| 1655 | − struct afu *afu = cfg->afu; | |
| 1656 | − struct ctx_info *ctxi = NULL; | |
| 1657 | − struct mutex *mutex = &cfg->ctx_recovery_mutex; | |
| 1658 | − struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ); | |
| 1659 | − u64 flags; | |
| 1660 | − u64 ctxid = DECODE_CTXID(recover->context_id), | |
| 1661 | − rctxid = recover->context_id; | |
| 1662 | − long reg; | |
| 1663 | − bool locked = true; | |
| 1664 | − int lretry = 20; /* up to 2 seconds */ | |
| 1665 | − int new_adap_fd = -1; | |
| 1666 | − int rc = 0; | |
| 1667 | − | |
| 1668 | − atomic_inc(&cfg->recovery_threads); | |
| 1669 | − up_read(&cfg->ioctl_rwsem); | |
| 1670 | − rc = mutex_lock_interruptible(mutex); | |
| 1671 | − down_read(&cfg->ioctl_rwsem); | |
| 1672 | − if (rc) { | |
| 1673 | − locked = false; | |
| 1674 | − goto out; | |
| 1675 | − } | |
| 1676 | − | |
| 1677 | − rc = check_state(cfg); | |
| 1678 | − if (rc) { | |
| 1679 | − dev_err(dev, "%s: Failed state rc=%d\n", __func__, rc); | |
| 1680 | − rc = -ENODEV; | |
| 1681 | − goto out; | |
| 1682 | − } | |
| 1683 | − | |
| 1684 | − dev_dbg(dev, "%s: reason=%016llx rctxid=%016llx\n", | |
| 1685 | − __func__, recover->reason, rctxid); | |
| 1686 | − | |
| 1687 | −retry: | |
| 1688 | − /* Ensure that this process is attached to the context */ | |
| 1689 | − ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); | |
| 1690 | − if (unlikely(!ctxi)) { | |
| 1691 | − dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); | |
| 1692 | − rc = -EINVAL; | |
| 1693 | − goto out; | |
| 1694 | − } | |
| 1695 | − | |
| 1696 | − if (ctxi->err_recovery_active) { | |
| 1697 | −retry_recover: | |
| 1698 | − rc = recover_context(cfg, ctxi, &new_adap_fd); | |
| 1699 | − if (unlikely(rc)) { | |
| 1700 | − dev_err(dev, "%s: Recovery failed ctxid=%llu rc=%d\n", | |
| 1701 | − __func__, ctxid, rc); | |
| 1702 | − if ((rc == -ENODEV) && | |
| 1703 | − ((atomic_read(&cfg->recovery_threads) > 1) || | |
| 1704 | − (lretry--))) { | |
| 1705 | − dev_dbg(dev, "%s: Going to try again\n", | |
| 1706 | − __func__); | |
| 1707 | − mutex_unlock(mutex); | |
| 1708 | − msleep(100); | |
| 1709 | − rc = mutex_lock_interruptible(mutex); | |
| 1710 | − if (rc) { | |
| 1711 | − locked = false; | |
| 1712 | − goto out; | |
| 1713 | − } | |
| 1714 | − goto retry_recover; | |
| 1715 | − } | |
| 1716 | − | |
| 1717 | − goto out; | |
| 1718 | − } | |
| 1719 | − | |
| 1720 | − ctxi->err_recovery_active = false; | |
| 1721 | − | |
| 1722 | − flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD | | |
| 1723 | − DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET; | |
| 1724 | − if (afu_is_sq_cmd_mode(afu)) | |
| 1725 | − flags |= DK_CXLFLASH_CONTEXT_SQ_CMD_MODE; | |
| 1726 | − | |
| 1727 | − recover->hdr.return_flags = flags; | |
| 1728 | − recover->context_id = ctxi->ctxid; | |
| 1729 | − recover->adap_fd = new_adap_fd; | |
| 1730 | − recover->mmio_size = sizeof(afu->afu_map->hosts[0].harea); | |
| 1731 | − goto out; | |
| 1732 | − } | |
| 1733 | − | |
| 1734 | − /* Test if in error state */ | |
| 1735 | − reg = readq_be(&hwq->ctrl_map->mbox_r); | |
| 1736 | − if (reg == -1) { | |
| 1737 | − dev_dbg(dev, "%s: MMIO fail, wait for recovery.\n", __func__); | |
| 1738 | − | |
| 1739 | − /* | |
| 1740 | − * Before checking the state, put back the context obtained with | |
| 1741 | − * get_context() as it is no longer needed and sleep for a short | |
| 1742 | − * period of time (see prolog notes). | |
| 1743 | − */ | |
| 1744 | − put_context(ctxi); | |
| 1745 | − ctxi = NULL; | |
| 1746 | − ssleep(1); | |
| 1747 | − rc = check_state(cfg); | |
| 1748 | − if (unlikely(rc)) | |
| 1749 | − goto out; | |
| 1750 | − goto retry; | |
| 1751 | − } | |
| 1752 | − | |
| 1753 | − dev_dbg(dev, "%s: MMIO working, no recovery required\n", __func__); | |
| 1754 | −out: | |
| 1755 | − if (likely(ctxi)) | |
| 1756 | − put_context(ctxi); | |
| 1757 | − if (locked) | |
| 1758 | − mutex_unlock(mutex); | |
| 1759 | − atomic_dec_if_positive(&cfg->recovery_threads); | |
| 1760 | − return rc; | |
| 1761 | −} | |
| 1762 | − | |
| 1763 | −/** | |
| 1764 | − * process_sense() - evaluates and processes sense data | |
| 1765 | − * @sdev: SCSI device associated with LUN. | |
| 1766 | − * @verify: Verify ioctl data structure. | |
| 1767 | − * | |
| 1768 | − * Return: 0 on success, -errno on failure | |
| 1769 | − */ | |
| 1770 | −static int process_sense(struct scsi_device *sdev, | |
| 1771 | − struct dk_cxlflash_verify *verify) | |
| 1772 | −{ | |
| 1773 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 1774 | − struct device *dev = &cfg->dev->dev; | |
| 1775 | − struct llun_info *lli = sdev->hostdata; | |
| 1776 | − struct glun_info *gli = lli->parent; | |
| 1777 | − u64 prev_lba = gli->max_lba; | |
| 1778 | − struct scsi_sense_hdr sshdr = { 0 }; | |
| 1779 | − int rc = 0; | |
| 1780 | − | |
| 1781 | − rc = scsi_normalize_sense((const u8 *)&verify->sense_data, | |
| 1782 | − DK_CXLFLASH_VERIFY_SENSE_LEN, &sshdr); | |
| 1783 | − if (!rc) { | |
| 1784 | − dev_err(dev, "%s: Failed to normalize sense data\n", __func__); | |
| 1785 | − rc = -EINVAL; | |
| 1786 | − goto out; | |
| 1787 | − } | |
| 1788 | − | |
| 1789 | − switch (sshdr.sense_key) { | |
| 1790 | − case NO_SENSE: | |
| 1791 | − case RECOVERED_ERROR: | |
| 1792 | − case NOT_READY: | |
| 1793 | − break; | |
| 1794 | − case UNIT_ATTENTION: | |
| 1795 | − switch (sshdr.asc) { | |
| 1796 | − case 0x29: /* Power on Reset or Device Reset */ | |
| 1797 | − fallthrough; | |
| 1798 | − case 0x2A: /* Device settings/capacity changed */ | |
| 1799 | − rc = read_cap16(sdev, lli); | |
| 1800 | − if (rc) { | |
| 1801 | − rc = -ENODEV; | |
| 1802 | − break; | |
| 1803 | − } | |
| 1804 | − if (prev_lba != gli->max_lba) | |
| 1805 | − dev_dbg(dev, "%s: Capacity changed old=%lld " | |
| 1806 | − "new=%lld\n", __func__, prev_lba, | |
| 1807 | − gli->max_lba); | |
| 1808 | − break; | |
| 1809 | − case 0x3F: /* Report LUNs changed, Rescan. */ | |
| 1810 | − scsi_scan_host(cfg->host); | |
| 1811 | − break; | |
| 1812 | − default: | |
| 1813 | − rc = -EIO; | |
| 1814 | − break; | |
| 1815 | − } | |
| 1816 | − break; | |
| 1817 | − default: | |
| 1818 | − rc = -EIO; | |
| 1819 | − break; | |
| 1820 | − } | |
| 1821 | −out: | |
| 1822 | − dev_dbg(dev, "%s: sense_key %x asc %x ascq %x rc %d\n", __func__, | |
| 1823 | − sshdr.sense_key, sshdr.asc, sshdr.ascq, rc); | |
| 1824 | − return rc; | |
| 1825 | −} | |
| 1826 | − | |
| 1827 | −/** | |
| 1828 | − * cxlflash_disk_verify() - verifies a LUN is the same and handle size changes | |
| 1829 | − * @sdev: SCSI device associated with LUN. | |
| 1830 | − * @arg: Verify ioctl data structure. | |
| 1831 | − * | |
| 1832 | − * Return: 0 on success, -errno on failure | |
| 1833 | − */ | |
| 1834 | −static int cxlflash_disk_verify(struct scsi_device *sdev, void *arg) | |
| 1835 | −{ | |
| 1836 | − struct dk_cxlflash_verify *verify = arg; | |
| 1837 | − int rc = 0; | |
| 1838 | − struct ctx_info *ctxi = NULL; | |
| 1839 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 1840 | − struct device *dev = &cfg->dev->dev; | |
| 1841 | − struct llun_info *lli = sdev->hostdata; | |
| 1842 | − struct glun_info *gli = lli->parent; | |
| 1843 | − struct sisl_rht_entry *rhte = NULL; | |
| 1844 | − res_hndl_t rhndl = verify->rsrc_handle; | |
| 1845 | − u64 ctxid = DECODE_CTXID(verify->context_id), | |
| 1846 | − rctxid = verify->context_id; | |
| 1847 | − u64 last_lba = 0; | |
| 1848 | − | |
| 1849 | − dev_dbg(dev, "%s: ctxid=%llu rhndl=%016llx, hint=%016llx, " | |
| 1850 | − "flags=%016llx\n", __func__, ctxid, verify->rsrc_handle, | |
| 1851 | − verify->hint, verify->hdr.flags); | |
| 1852 | − | |
| 1853 | − ctxi = get_context(cfg, rctxid, lli, 0); | |
| 1854 | − if (unlikely(!ctxi)) { | |
| 1855 | − dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); | |
| 1856 | − rc = -EINVAL; | |
| 1857 | − goto out; | |
| 1858 | − } | |
| 1859 | − | |
| 1860 | − rhte = get_rhte(ctxi, rhndl, lli); | |
| 1861 | − if (unlikely(!rhte)) { | |
| 1862 | − dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n", | |
| 1863 | − __func__, rhndl); | |
| 1864 | − rc = -EINVAL; | |
| 1865 | − goto out; | |
| 1866 | − } | |
| 1867 | − | |
| 1868 | − /* | |
| 1869 | − * Look at the hint/sense to see if it requires us to redrive | |
| 1870 | − * inquiry (i.e. the Unit attention is due to the WWN changing). | |
| 1871 | − */ | |
| 1872 | − if (verify->hint & DK_CXLFLASH_VERIFY_HINT_SENSE) { | |
| 1873 | − /* Can't hold mutex across process_sense/read_cap16, | |
| 1874 | − * since we could have an intervening EEH event. | |
| 1875 | − */ | |
| 1876 | − ctxi->unavail = true; | |
| 1877 | − mutex_unlock(&ctxi->mutex); | |
| 1878 | − rc = process_sense(sdev, verify); | |
| 1879 | − if (unlikely(rc)) { | |
| 1880 | − dev_err(dev, "%s: Failed to validate sense data (%d)\n", | |
| 1881 | − __func__, rc); | |
| 1882 | − mutex_lock(&ctxi->mutex); | |
| 1883 | − ctxi->unavail = false; | |
| 1884 | − goto out; | |
| 1885 | − } | |
| 1886 | − mutex_lock(&ctxi->mutex); | |
| 1887 | − ctxi->unavail = false; | |
| 1888 | − } | |
| 1889 | − | |
| 1890 | − switch (gli->mode) { | |
| 1891 | − case MODE_PHYSICAL: | |
| 1892 | − last_lba = gli->max_lba; | |
| 1893 | − break; | |
| 1894 | − case MODE_VIRTUAL: | |
| 1895 | − /* Cast lxt_cnt to u64 for multiply to be treated as 64bit op */ | |
| 1896 | − last_lba = ((u64)rhte->lxt_cnt * MC_CHUNK_SIZE * gli->blk_len); | |
| 1897 | − last_lba /= CXLFLASH_BLOCK_SIZE; | |
| 1898 | − last_lba--; | |
| 1899 | − break; | |
| 1900 | − default: | |
| 1901 | − WARN(1, "Unsupported LUN mode!"); | |
| 1902 | − } | |
| 1903 | − | |
| 1904 | − verify->last_lba = last_lba; | |
| 1905 | − | |
| 1906 | −out: | |
| 1907 | − if (likely(ctxi)) | |
| 1908 | − put_context(ctxi); | |
| 1909 | − dev_dbg(dev, "%s: returning rc=%d llba=%llx\n", | |
| 1910 | − __func__, rc, verify->last_lba); | |
| 1911 | − return rc; | |
| 1912 | −} | |
| 1913 | − | |
| 1914 | −/** | |
| 1915 | − * decode_ioctl() - translates an encoded ioctl to an easily identifiable string | |
| 1916 | − * @cmd: The ioctl command to decode. | |
| 1917 | − * | |
| 1918 | − * Return: A string identifying the decoded ioctl. | |
| 1919 | − */ | |
| 1920 | −static char *decode_ioctl(unsigned int cmd) | |
| 1921 | −{ | |
| 1922 | − switch (cmd) { | |
| 1923 | − case DK_CXLFLASH_ATTACH: | |
| 1924 | − return __stringify_1(DK_CXLFLASH_ATTACH); | |
| 1925 | − case DK_CXLFLASH_USER_DIRECT: | |
| 1926 | − return __stringify_1(DK_CXLFLASH_USER_DIRECT); | |
| 1927 | − case DK_CXLFLASH_USER_VIRTUAL: | |
| 1928 | − return __stringify_1(DK_CXLFLASH_USER_VIRTUAL); | |
| 1929 | − case DK_CXLFLASH_VLUN_RESIZE: | |
| 1930 | − return __stringify_1(DK_CXLFLASH_VLUN_RESIZE); | |
| 1931 | − case DK_CXLFLASH_RELEASE: | |
| 1932 | − return __stringify_1(DK_CXLFLASH_RELEASE); | |
| 1933 | − case DK_CXLFLASH_DETACH: | |
| 1934 | − return __stringify_1(DK_CXLFLASH_DETACH); | |
| 1935 | − case DK_CXLFLASH_VERIFY: | |
| 1936 | − return __stringify_1(DK_CXLFLASH_VERIFY); | |
| 1937 | − case DK_CXLFLASH_VLUN_CLONE: | |
| 1938 | − return __stringify_1(DK_CXLFLASH_VLUN_CLONE); | |
| 1939 | − case DK_CXLFLASH_RECOVER_AFU: | |
| 1940 | − return __stringify_1(DK_CXLFLASH_RECOVER_AFU); | |
| 1941 | − case DK_CXLFLASH_MANAGE_LUN: | |
| 1942 | − return __stringify_1(DK_CXLFLASH_MANAGE_LUN); | |
| 1943 | − } | |
| 1944 | − | |
| 1945 | − return "UNKNOWN"; | |
| 1946 | −} | |
| 1947 | − | |
| 1948 | −/** | |
| 1949 | − * cxlflash_disk_direct_open() - opens a direct (physical) disk | |
| 1950 | − * @sdev: SCSI device associated with LUN. | |
| 1951 | − * @arg: UDirect ioctl data structure. | |
| 1952 | − * | |
| 1953 | − * On successful return, the user is informed of the resource handle | |
| 1954 | − * to be used to identify the direct lun and the size (in blocks) of | |
| 1955 | − * the direct lun in last LBA format. | |
| 1956 | − * | |
| 1957 | − * Return: 0 on success, -errno on failure | |
| 1958 | − */ | |
| 1959 | −static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) | |
| 1960 | −{ | |
| 1961 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 1962 | − struct device *dev = &cfg->dev->dev; | |
| 1963 | − struct afu *afu = cfg->afu; | |
| 1964 | − struct llun_info *lli = sdev->hostdata; | |
| 1965 | − struct glun_info *gli = lli->parent; | |
| 1966 | − struct dk_cxlflash_release rel = { { 0 }, 0 }; | |
| 1967 | − | |
| 1968 | − struct dk_cxlflash_udirect *pphys = (struct dk_cxlflash_udirect *)arg; | |
| 1969 | − | |
| 1970 | − u64 ctxid = DECODE_CTXID(pphys->context_id), | |
| 1971 | − rctxid = pphys->context_id; | |
| 1972 | − u64 lun_size = 0; | |
| 1973 | − u64 last_lba = 0; | |
| 1974 | − u64 rsrc_handle = -1; | |
| 1975 | − u32 port = CHAN2PORTMASK(sdev->channel); | |
| 1976 | − | |
| 1977 | − int rc = 0; | |
| 1978 | − | |
| 1979 | − struct ctx_info *ctxi = NULL; | |
| 1980 | − struct sisl_rht_entry *rhte = NULL; | |
| 1981 | − | |
| 1982 | − dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size); | |
| 1983 | − | |
| 1984 | − rc = cxlflash_lun_attach(gli, MODE_PHYSICAL, false); | |
| 1985 | − if (unlikely(rc)) { | |
| 1986 | − dev_dbg(dev, "%s: Failed attach to LUN (PHYSICAL)\n", __func__); | |
| 1987 | − goto out; | |
| 1988 | − } | |
| 1989 | − | |
| 1990 | − ctxi = get_context(cfg, rctxid, lli, 0); | |
| 1991 | − if (unlikely(!ctxi)) { | |
| 1992 | − dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); | |
| 1993 | − rc = -EINVAL; | |
| 1994 | − goto err1; | |
| 1995 | − } | |
| 1996 | − | |
| 1997 | − rhte = rhte_checkout(ctxi, lli); | |
| 1998 | − if (unlikely(!rhte)) { | |
| 1999 | − dev_dbg(dev, "%s: Too many opens ctxid=%lld\n", | |
| 2000 | − __func__, ctxid); | |
| 2001 | − rc = -EMFILE; /* too many opens */ | |
| 2002 | − goto err1; | |
| 2003 | − } | |
| 2004 | − | |
| 2005 | − rsrc_handle = (rhte - ctxi->rht_start); | |
| 2006 | − | |
| 2007 | − rht_format1(rhte, lli->lun_id[sdev->channel], ctxi->rht_perms, port); | |
| 2008 | − | |
| 2009 | − last_lba = gli->max_lba; | |
| 2010 | − pphys->hdr.return_flags = 0; | |
| 2011 | − pphys->last_lba = last_lba; | |
| 2012 | − pphys->rsrc_handle = rsrc_handle; | |
| 2013 | − | |
| 2014 | − rc = cxlflash_afu_sync(afu, ctxid, rsrc_handle, AFU_LW_SYNC); | |
| 2015 | − if (unlikely(rc)) { | |
| 2016 | − dev_dbg(dev, "%s: AFU sync failed rc=%d\n", __func__, rc); | |
| 2017 | − goto err2; | |
| 2018 | − } | |
| 2019 | − | |
| 2020 | −out: | |
| 2021 | − if (likely(ctxi)) | |
| 2022 | − put_context(ctxi); | |
| 2023 | − dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n", | |
| 2024 | − __func__, rsrc_handle, rc, last_lba); | |
| 2025 | − return rc; | |
| 2026 | − | |
| 2027 | −err2: | |
| 2028 | − marshal_udir_to_rele(pphys, &rel); | |
| 2029 | − _cxlflash_disk_release(sdev, ctxi, &rel); | |
| 2030 | − goto out; | |
| 2031 | −err1: | |
| 2032 | − cxlflash_lun_detach(gli); | |
| 2033 | − goto out; | |
| 2034 | −} | |
| 2035 | − | |
| 2036 | −/** | |
| 2037 | − * ioctl_common() - common IOCTL handler for driver | |
| 2038 | − * @sdev: SCSI device associated with LUN. | |
| 2039 | − * @cmd: IOCTL command. | |
| 2040 | − * | |
| 2041 | − * Handles common fencing operations that are valid for multiple ioctls. Always | |
| 2042 | − * allow through ioctls that are cleanup oriented in nature, even when operating | |
| 2043 | − * in a failed/terminating state. | |
| 2044 | − * | |
| 2045 | − * Return: 0 on success, -errno on failure | |
| 2046 | − */ | |
| 2047 | −static int ioctl_common(struct scsi_device *sdev, unsigned int cmd) | |
| 2048 | −{ | |
| 2049 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 2050 | − struct device *dev = &cfg->dev->dev; | |
| 2051 | − struct llun_info *lli = sdev->hostdata; | |
| 2052 | − int rc = 0; | |
| 2053 | − | |
| 2054 | − if (unlikely(!lli)) { | |
| 2055 | − dev_dbg(dev, "%s: Unknown LUN\n", __func__); | |
| 2056 | − rc = -EINVAL; | |
| 2057 | − goto out; | |
| 2058 | − } | |
| 2059 | − | |
| 2060 | − rc = check_state(cfg); | |
| 2061 | − if (unlikely(rc) && (cfg->state == STATE_FAILTERM)) { | |
| 2062 | − switch (cmd) { | |
| 2063 | − case DK_CXLFLASH_VLUN_RESIZE: | |
| 2064 | − case DK_CXLFLASH_RELEASE: | |
| 2065 | − case DK_CXLFLASH_DETACH: | |
| 2066 | − dev_dbg(dev, "%s: Command override rc=%d\n", | |
| 2067 | − __func__, rc); | |
| 2068 | − rc = 0; | |
| 2069 | − break; | |
| 2070 | − } | |
| 2071 | − } | |
| 2072 | −out: | |
| 2073 | − return rc; | |
| 2074 | −} | |
| 2075 | − | |
| 2076 | −/** | |
| 2077 | − * cxlflash_ioctl() - IOCTL handler for driver | |
| 2078 | − * @sdev: SCSI device associated with LUN. | |
| 2079 | − * @cmd: IOCTL command. | |
| 2080 | − * @arg: Userspace ioctl data structure. | |
| 2081 | − * | |
| 2082 | − * A read/write semaphore is used to implement a 'drain' of currently | |
| 2083 | − * running ioctls. The read semaphore is taken at the beginning of each | |
| 2084 | − * ioctl thread and released upon concluding execution. Additionally the | |
| 2085 | − * semaphore should be released and then reacquired in any ioctl execution | |
| 2086 | − * path which will wait for an event to occur that is outside the scope of | |
| 2087 | − * the ioctl (i.e. an adapter reset). To drain the ioctls currently running, | |
| 2088 | − * a thread simply needs to acquire the write semaphore. | |
| 2089 | − * | |
| 2090 | − * Return: 0 on success, -errno on failure | |
| 2091 | − */ | |
| 2092 | −int cxlflash_ioctl(struct scsi_device *sdev, unsigned int cmd, void __user *arg) | |
| 2093 | −{ | |
| 2094 | − typedef int (*sioctl) (struct scsi_device *, void *); | |
| 2095 | − | |
| 2096 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 2097 | − struct device *dev = &cfg->dev->dev; | |
| 2098 | − struct afu *afu = cfg->afu; | |
| 2099 | − struct dk_cxlflash_hdr *hdr; | |
| 2100 | − char buf[sizeof(union cxlflash_ioctls)]; | |
| 2101 | − size_t size = 0; | |
| 2102 | − bool known_ioctl = false; | |
| 2103 | − int idx; | |
| 2104 | − int rc = 0; | |
| 2105 | − struct Scsi_Host *shost = sdev->host; | |
| 2106 | − sioctl do_ioctl = NULL; | |
| 2107 | − | |
| 2108 | − static const struct { | |
| 2109 | − size_t size; | |
| 2110 | − sioctl ioctl; | |
| 2111 | − } ioctl_tbl[] = { /* NOTE: order matters here */ | |
| 2112 | − {sizeof(struct dk_cxlflash_attach), cxlflash_disk_attach}, | |
| 2113 | − {sizeof(struct dk_cxlflash_udirect), cxlflash_disk_direct_open}, | |
| 2114 | − {sizeof(struct dk_cxlflash_release), cxlflash_disk_release}, | |
| 2115 | − {sizeof(struct dk_cxlflash_detach), cxlflash_disk_detach}, | |
| 2116 | − {sizeof(struct dk_cxlflash_verify), cxlflash_disk_verify}, | |
| 2117 | − {sizeof(struct dk_cxlflash_recover_afu), cxlflash_afu_recover}, | |
| 2118 | − {sizeof(struct dk_cxlflash_manage_lun), cxlflash_manage_lun}, | |
| 2119 | − {sizeof(struct dk_cxlflash_uvirtual), cxlflash_disk_virtual_open}, | |
| 2120 | − {sizeof(struct dk_cxlflash_resize), cxlflash_vlun_resize}, | |
| 2121 | − {sizeof(struct dk_cxlflash_clone), cxlflash_disk_clone}, | |
| 2122 | − }; | |
| 2123 | − | |
| 2124 | − /* Hold read semaphore so we can drain if needed */ | |
| 2125 | − down_read(&cfg->ioctl_rwsem); | |
| 2126 | − | |
| 2127 | − /* Restrict command set to physical support only for internal LUN */ | |
| 2128 | − if (afu->internal_lun) | |
| 2129 | − switch (cmd) { | |
| 2130 | − case DK_CXLFLASH_RELEASE: | |
| 2131 | − case DK_CXLFLASH_USER_VIRTUAL: | |
| 2132 | − case DK_CXLFLASH_VLUN_RESIZE: | |
| 2133 | − case DK_CXLFLASH_VLUN_CLONE: | |
| 2134 | − dev_dbg(dev, "%s: %s not supported for lun_mode=%d\n", | |
| 2135 | − __func__, decode_ioctl(cmd), afu->internal_lun); | |
| 2136 | − rc = -EINVAL; | |
| 2137 | − goto cxlflash_ioctl_exit; | |
| 2138 | − } | |
| 2139 | − | |
| 2140 | − switch (cmd) { | |
| 2141 | − case DK_CXLFLASH_ATTACH: | |
| 2142 | − case DK_CXLFLASH_USER_DIRECT: | |
| 2143 | − case DK_CXLFLASH_RELEASE: | |
| 2144 | − case DK_CXLFLASH_DETACH: | |
| 2145 | − case DK_CXLFLASH_VERIFY: | |
| 2146 | − case DK_CXLFLASH_RECOVER_AFU: | |
| 2147 | − case DK_CXLFLASH_USER_VIRTUAL: | |
| 2148 | − case DK_CXLFLASH_VLUN_RESIZE: | |
| 2149 | − case DK_CXLFLASH_VLUN_CLONE: | |
| 2150 | − dev_dbg(dev, "%s: %s (%08X) on dev(%d/%d/%d/%llu)\n", | |
| 2151 | − __func__, decode_ioctl(cmd), cmd, shost->host_no, | |
| 2152 | − sdev->channel, sdev->id, sdev->lun); | |
| 2153 | − rc = ioctl_common(sdev, cmd); | |
| 2154 | − if (unlikely(rc)) | |
| 2155 | − goto cxlflash_ioctl_exit; | |
| 2156 | − | |
| 2157 | − fallthrough; | |
| 2158 | − | |
| 2159 | − case DK_CXLFLASH_MANAGE_LUN: | |
| 2160 | − known_ioctl = true; | |
| 2161 | − idx = _IOC_NR(cmd) - _IOC_NR(DK_CXLFLASH_ATTACH); | |
| 2162 | − size = ioctl_tbl[idx].size; | |
| 2163 | − do_ioctl = ioctl_tbl[idx].ioctl; | |
| 2164 | − | |
| 2165 | − if (likely(do_ioctl)) | |
| 2166 | − break; | |
| 2167 | − | |
| 2168 | − fallthrough; | |
| 2169 | − default: | |
| 2170 | − rc = -EINVAL; | |
| 2171 | − goto cxlflash_ioctl_exit; | |
| 2172 | − } | |
| 2173 | − | |
| 2174 | − if (unlikely(copy_from_user(&buf, arg, size))) { | |
| 2175 | − dev_err(dev, "%s: copy_from_user() fail size=%lu cmd=%u (%s) arg=%p\n", | |
| 2176 | − __func__, size, cmd, decode_ioctl(cmd), arg); | |
| 2177 | − rc = -EFAULT; | |
| 2178 | − goto cxlflash_ioctl_exit; | |
| 2179 | − } | |
| 2180 | − | |
| 2181 | − hdr = (struct dk_cxlflash_hdr *)&buf; | |
| 2182 | − if (hdr->version != DK_CXLFLASH_VERSION_0) { | |
| 2183 | − dev_dbg(dev, "%s: Version %u not supported for %s\n", | |
| 2184 | − __func__, hdr->version, decode_ioctl(cmd)); | |
| 2185 | − rc = -EINVAL; | |
| 2186 | − goto cxlflash_ioctl_exit; | |
| 2187 | − } | |
| 2188 | − | |
| 2189 | − if (hdr->rsvd[0] || hdr->rsvd[1] || hdr->rsvd[2] || hdr->return_flags) { | |
| 2190 | − dev_dbg(dev, "%s: Reserved/rflags populated\n", __func__); | |
| 2191 | − rc = -EINVAL; | |
| 2192 | − goto cxlflash_ioctl_exit; | |
| 2193 | − } | |
| 2194 | − | |
| 2195 | − rc = do_ioctl(sdev, (void *)&buf); | |
| 2196 | − if (likely(!rc)) | |
| 2197 | − if (unlikely(copy_to_user(arg, &buf, size))) { | |
| 2198 | − dev_err(dev, "%s: copy_to_user() fail size=%lu cmd=%u (%s) arg=%p\n", | |
| 2199 | − __func__, size, cmd, decode_ioctl(cmd), arg); | |
| 2200 | − rc = -EFAULT; | |
| 2201 | − } | |
| 2202 | − | |
| 2203 | − /* fall through to exit */ | |
| 2204 | − | |
| 2205 | −cxlflash_ioctl_exit: | |
| 2206 | − up_read(&cfg->ioctl_rwsem); | |
| 2207 | − if (unlikely(rc && known_ioctl)) | |
| 2208 | − dev_err(dev, "%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) " | |
| 2209 | − "returned rc %d\n", __func__, | |
| 2210 | − decode_ioctl(cmd), cmd, shost->host_no, | |
| 2211 | − sdev->channel, sdev->id, sdev->lun, rc); | |
| 2212 | − else | |
| 2213 | − dev_dbg(dev, "%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) " | |
| 2214 | − "returned rc %d\n", __func__, decode_ioctl(cmd), | |
| 2215 | − cmd, shost->host_no, sdev->channel, sdev->id, | |
| 2216 | − sdev->lun, rc); | |
| 2217 | − return rc; | |
| 2218 | −} | |
| @@ -1,150 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2015 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#ifndef _CXLFLASH_SUPERPIPE_H | |
| 12 | −#define _CXLFLASH_SUPERPIPE_H | |
| 13 | − | |
| 14 | −extern struct cxlflash_global global; | |
| 15 | − | |
| 16 | −/* | |
| 17 | − * Terminology: use afu (and not adapter) to refer to the HW. | |
| 18 | − * Adapter is the entire slot and includes PSL out of which | |
| 19 | − * only the AFU is visible to user space. | |
| 20 | − */ | |
| 21 | − | |
| 22 | −/* Chunk size parms: note sislite minimum chunk size is | |
| 23 | − * 0x10000 LBAs corresponding to a NMASK or 16. | |
| 24 | − */ | |
| 25 | −#define MC_CHUNK_SIZE (1 << MC_RHT_NMASK) /* in LBAs */ | |
| 26 | − | |
| 27 | −#define CMD_TIMEOUT 30 /* 30 secs */ | |
| 28 | −#define CMD_RETRIES 5 /* 5 retries for scsi_execute */ | |
| 29 | − | |
| 30 | −#define MAX_SECTOR_UNIT 512 /* max_sector is in 512 byte multiples */ | |
| 31 | − | |
| 32 | −enum lun_mode { | |
| 33 | − MODE_NONE = 0, | |
| 34 | − MODE_VIRTUAL, | |
| 35 | − MODE_PHYSICAL | |
| 36 | −}; | |
| 37 | − | |
| 38 | −/* Global (entire driver, spans adapters) lun_info structure */ | |
| 39 | −struct glun_info { | |
| 40 | − u64 max_lba; /* from read cap(16) */ | |
| 41 | − u32 blk_len; /* from read cap(16) */ | |
| 42 | − enum lun_mode mode; /* NONE, VIRTUAL, PHYSICAL */ | |
| 43 | − int users; /* Number of users w/ references to LUN */ | |
| 44 | − | |
| 45 | − u8 wwid[16]; | |
| 46 | − | |
| 47 | − struct mutex mutex; | |
| 48 | − | |
| 49 | − struct blka blka; | |
| 50 | − struct list_head list; | |
| 51 | −}; | |
| 52 | − | |
| 53 | −/* Local (per-adapter) lun_info structure */ | |
| 54 | −struct llun_info { | |
| 55 | − u64 lun_id[MAX_FC_PORTS]; /* from REPORT_LUNS */ | |
| 56 | − u32 lun_index; /* Index in the LUN table */ | |
| 57 | − u32 host_no; /* host_no from Scsi_host */ | |
| 58 | − u32 port_sel; /* What port to use for this LUN */ | |
| 59 | − bool in_table; /* Whether a LUN table entry was created */ | |
| 60 | − | |
| 61 | − u8 wwid[16]; /* Keep a duplicate copy here? */ | |
| 62 | − | |
| 63 | − struct glun_info *parent; /* Pointer to entry in global LUN structure */ | |
| 64 | − struct scsi_device *sdev; | |
| 65 | − struct list_head list; | |
| 66 | −}; | |
| 67 | − | |
| 68 | −struct lun_access { | |
| 69 | − struct llun_info *lli; | |
| 70 | − struct scsi_device *sdev; | |
| 71 | − struct list_head list; | |
| 72 | −}; | |
| 73 | − | |
| 74 | −enum ctx_ctrl { | |
| 75 | − CTX_CTRL_CLONE = (1 << 1), | |
| 76 | − CTX_CTRL_ERR = (1 << 2), | |
| 77 | − CTX_CTRL_ERR_FALLBACK = (1 << 3), | |
| 78 | − CTX_CTRL_NOPID = (1 << 4), | |
| 79 | − CTX_CTRL_FILE = (1 << 5) | |
| 80 | −}; | |
| 81 | − | |
| 82 | −#define ENCODE_CTXID(_ctx, _id) (((((u64)_ctx) & 0xFFFFFFFF0ULL) << 28) | _id) | |
| 83 | −#define DECODE_CTXID(_val) (_val & 0xFFFFFFFF) | |
| 84 | − | |
| 85 | −struct ctx_info { | |
| 86 | − struct sisl_ctrl_map __iomem *ctrl_map; /* initialized at startup */ | |
| 87 | − struct sisl_rht_entry *rht_start; /* 1 page (req'd for alignment), | |
| 88 | − * alloc/free on attach/detach | |
| 89 | − */ | |
| 90 | − u32 rht_out; /* Number of checked out RHT entries */ | |
| 91 | − u32 rht_perms; /* User-defined permissions for RHT entries */ | |
| 92 | − struct llun_info **rht_lun; /* Mapping of RHT entries to LUNs */ | |
| 93 | − u8 *rht_needs_ws; /* User-desired write-same function per RHTE */ | |
| 94 | − | |
| 95 | − u64 ctxid; | |
| 96 | − u64 irqs; /* Number of interrupts requested for context */ | |
| 97 | − pid_t pid; | |
| 98 | − bool initialized; | |
| 99 | − bool unavail; | |
| 100 | − bool err_recovery_active; | |
| 101 | − struct mutex mutex; /* Context protection */ | |
| 102 | − struct kref kref; | |
| 103 | − void *ctx; | |
| 104 | − struct cxlflash_cfg *cfg; | |
| 105 | − struct list_head luns; /* LUNs attached to this context */ | |
| 106 | − const struct vm_operations_struct *cxl_mmap_vmops; | |
| 107 | − struct file *file; | |
| 108 | − struct list_head list; /* Link contexts in error recovery */ | |
| 109 | −}; | |
| 110 | − | |
| 111 | −struct cxlflash_global { | |
| 112 | − struct mutex mutex; | |
| 113 | − struct list_head gluns;/* list of glun_info structs */ | |
| 114 | − struct page *err_page; /* One page of all 0xF for error notification */ | |
| 115 | −}; | |
| 116 | − | |
| 117 | −int cxlflash_vlun_resize(struct scsi_device *sdev, void *resize); | |
| 118 | −int _cxlflash_vlun_resize(struct scsi_device *sdev, struct ctx_info *ctxi, | |
| 119 | − struct dk_cxlflash_resize *resize); | |
| 120 | − | |
| 121 | −int cxlflash_disk_release(struct scsi_device *sdev, | |
| 122 | − void *release); | |
| 123 | −int _cxlflash_disk_release(struct scsi_device *sdev, struct ctx_info *ctxi, | |
| 124 | − struct dk_cxlflash_release *release); | |
| 125 | − | |
| 126 | −int cxlflash_disk_clone(struct scsi_device *sdev, void *arg); | |
| 127 | − | |
| 128 | −int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg); | |
| 129 | − | |
| 130 | −int cxlflash_lun_attach(struct glun_info *gli, enum lun_mode mode, bool locked); | |
| 131 | −void cxlflash_lun_detach(struct glun_info *gli); | |
| 132 | − | |
| 133 | −struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxit, void *arg, | |
| 134 | − enum ctx_ctrl ctrl); | |
| 135 | −void put_context(struct ctx_info *ctxi); | |
| 136 | − | |
| 137 | −struct sisl_rht_entry *get_rhte(struct ctx_info *ctxi, res_hndl_t rhndl, | |
| 138 | − struct llun_info *lli); | |
| 139 | − | |
| 140 | −struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, | |
| 141 | − struct llun_info *lli); | |
| 142 | −void rhte_checkin(struct ctx_info *ctxi, struct sisl_rht_entry *rhte); | |
| 143 | − | |
| 144 | −void cxlflash_ba_terminate(struct ba_lun *ba_lun); | |
| 145 | − | |
| 146 | −int cxlflash_manage_lun(struct scsi_device *sdev, void *manage); | |
| 147 | − | |
| 148 | −int check_state(struct cxlflash_cfg *cfg); | |
| 149 | − | |
| 150 | −#endif /* ifndef _CXLFLASH_SUPERPIPE_H */ | |
| @@ -1,1336 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2015 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#include <linux/interrupt.h> | |
| 12 | −#include <linux/pci.h> | |
| 13 | −#include <linux/syscalls.h> | |
| 14 | −#include <linux/unaligned.h> | |
| 15 | −#include <asm/bitsperlong.h> | |
| 16 | − | |
| 17 | −#include <scsi/scsi_cmnd.h> | |
| 18 | −#include <scsi/scsi_host.h> | |
| 19 | −#include <uapi/scsi/cxlflash_ioctl.h> | |
| 20 | − | |
| 21 | −#include "sislite.h" | |
| 22 | −#include "common.h" | |
| 23 | −#include "vlun.h" | |
| 24 | −#include "superpipe.h" | |
| 25 | − | |
| 26 | −/** | |
| 27 | − * marshal_virt_to_resize() - translate uvirtual to resize structure | |
| 28 | − * @virt: Source structure from which to translate/copy. | |
| 29 | − * @resize: Destination structure for the translate/copy. | |
| 30 | − */ | |
| 31 | −static void marshal_virt_to_resize(struct dk_cxlflash_uvirtual *virt, | |
| 32 | − struct dk_cxlflash_resize *resize) | |
| 33 | −{ | |
| 34 | − resize->hdr = virt->hdr; | |
| 35 | − resize->context_id = virt->context_id; | |
| 36 | − resize->rsrc_handle = virt->rsrc_handle; | |
| 37 | − resize->req_size = virt->lun_size; | |
| 38 | − resize->last_lba = virt->last_lba; | |
| 39 | −} | |
| 40 | − | |
| 41 | −/** | |
| 42 | − * marshal_clone_to_rele() - translate clone to release structure | |
| 43 | − * @clone: Source structure from which to translate/copy. | |
| 44 | − * @release: Destination structure for the translate/copy. | |
| 45 | − */ | |
| 46 | −static void marshal_clone_to_rele(struct dk_cxlflash_clone *clone, | |
| 47 | − struct dk_cxlflash_release *release) | |
| 48 | −{ | |
| 49 | − release->hdr = clone->hdr; | |
| 50 | − release->context_id = clone->context_id_dst; | |
| 51 | −} | |
| 52 | − | |
| 53 | −/** | |
| 54 | − * ba_init() - initializes a block allocator | |
| 55 | − * @ba_lun: Block allocator to initialize. | |
| 56 | − * | |
| 57 | − * Return: 0 on success, -errno on failure | |
| 58 | − */ | |
| 59 | −static int ba_init(struct ba_lun *ba_lun) | |
| 60 | −{ | |
| 61 | − struct ba_lun_info *bali = NULL; | |
| 62 | − int lun_size_au = 0, i = 0; | |
| 63 | − int last_word_underflow = 0; | |
| 64 | − u64 *lam; | |
| 65 | − | |
| 66 | − pr_debug("%s: Initializing LUN: lun_id=%016llx " | |
| 67 | − "ba_lun->lsize=%lx ba_lun->au_size=%lX\n", | |
| 68 | − __func__, ba_lun->lun_id, ba_lun->lsize, ba_lun->au_size); | |
| 69 | − | |
| 70 | − /* Calculate bit map size */ | |
| 71 | − lun_size_au = ba_lun->lsize / ba_lun->au_size; | |
| 72 | − if (lun_size_au == 0) { | |
| 73 | − pr_debug("%s: Requested LUN size of 0!\n", __func__); | |
| 74 | − return -EINVAL; | |
| 75 | − } | |
| 76 | − | |
| 77 | − /* Allocate lun information container */ | |
| 78 | − bali = kzalloc(sizeof(struct ba_lun_info), GFP_KERNEL); | |
| 79 | − if (unlikely(!bali)) { | |
| 80 | − pr_err("%s: Failed to allocate lun_info lun_id=%016llx\n", | |
| 81 | − __func__, ba_lun->lun_id); | |
| 82 | − return -ENOMEM; | |
| 83 | − } | |
| 84 | − | |
| 85 | − bali->total_aus = lun_size_au; | |
| 86 | − bali->lun_bmap_size = lun_size_au / BITS_PER_LONG; | |
| 87 | − | |
| 88 | − if (lun_size_au % BITS_PER_LONG) | |
| 89 | − bali->lun_bmap_size++; | |
| 90 | − | |
| 91 | − /* Allocate bitmap space */ | |
| 92 | − bali->lun_alloc_map = kzalloc((bali->lun_bmap_size * sizeof(u64)), | |
| 93 | − GFP_KERNEL); | |
| 94 | − if (unlikely(!bali->lun_alloc_map)) { | |
| 95 | − pr_err("%s: Failed to allocate lun allocation map: " | |
| 96 | − "lun_id=%016llx\n", __func__, ba_lun->lun_id); | |
| 97 | − kfree(bali); | |
| 98 | − return -ENOMEM; | |
| 99 | − } | |
| 100 | − | |
| 101 | − /* Initialize the bit map size and set all bits to '1' */ | |
| 102 | − bali->free_aun_cnt = lun_size_au; | |
| 103 | − | |
| 104 | − for (i = 0; i < bali->lun_bmap_size; i++) | |
| 105 | − bali->lun_alloc_map[i] = 0xFFFFFFFFFFFFFFFFULL; | |
| 106 | − | |
| 107 | − /* If the last word not fully utilized, mark extra bits as allocated */ | |
| 108 | − last_word_underflow = (bali->lun_bmap_size * BITS_PER_LONG); | |
| 109 | − last_word_underflow -= bali->free_aun_cnt; | |
| 110 | − if (last_word_underflow > 0) { | |
| 111 | − lam = &bali->lun_alloc_map[bali->lun_bmap_size - 1]; | |
| 112 | − for (i = (HIBIT - last_word_underflow + 1); | |
| 113 | − i < BITS_PER_LONG; | |
| 114 | − i++) | |
| 115 | − clear_bit(i, (ulong *)lam); | |
| 116 | − } | |
| 117 | − | |
| 118 | − /* Initialize high elevator index, low/curr already at 0 from kzalloc */ | |
| 119 | − bali->free_high_idx = bali->lun_bmap_size; | |
| 120 | − | |
| 121 | − /* Allocate clone map */ | |
| 122 | − bali->aun_clone_map = kzalloc((bali->total_aus * sizeof(u8)), | |
| 123 | − GFP_KERNEL); | |
| 124 | − if (unlikely(!bali->aun_clone_map)) { | |
| 125 | − pr_err("%s: Failed to allocate clone map: lun_id=%016llx\n", | |
| 126 | − __func__, ba_lun->lun_id); | |
| 127 | − kfree(bali->lun_alloc_map); | |
| 128 | − kfree(bali); | |
| 129 | − return -ENOMEM; | |
| 130 | − } | |
| 131 | − | |
| 132 | − /* Pass the allocated LUN info as a handle to the user */ | |
| 133 | − ba_lun->ba_lun_handle = bali; | |
| 134 | − | |
| 135 | − pr_debug("%s: Successfully initialized the LUN: " | |
| 136 | − "lun_id=%016llx bitmap size=%x, free_aun_cnt=%llx\n", | |
| 137 | − __func__, ba_lun->lun_id, bali->lun_bmap_size, | |
| 138 | − bali->free_aun_cnt); | |
| 139 | − return 0; | |
| 140 | −} | |
| 141 | − | |
| 142 | −/** | |
| 143 | − * find_free_range() - locates a free bit within the block allocator | |
| 144 | − * @low: First word in block allocator to start search. | |
| 145 | − * @high: Last word in block allocator to search. | |
| 146 | − * @bali: LUN information structure owning the block allocator to search. | |
| 147 | − * @bit_word: Passes back the word in the block allocator owning the free bit. | |
| 148 | − * | |
| 149 | − * Return: The bit position within the passed back word, -1 on failure | |
| 150 | − */ | |
| 151 | −static int find_free_range(u32 low, | |
| 152 | − u32 high, | |
| 153 | − struct ba_lun_info *bali, int *bit_word) | |
| 154 | −{ | |
| 155 | − int i; | |
| 156 | − u64 bit_pos = -1; | |
| 157 | − ulong *lam, num_bits; | |
| 158 | − | |
| 159 | − for (i = low; i < high; i++) | |
| 160 | − if (bali->lun_alloc_map[i] != 0) { | |
| 161 | − lam = (ulong *)&bali->lun_alloc_map[i]; | |
| 162 | − num_bits = (sizeof(*lam) * BITS_PER_BYTE); | |
| 163 | − bit_pos = find_first_bit(lam, num_bits); | |
| 164 | − | |
| 165 | − pr_devel("%s: Found free bit %llu in LUN " | |
| 166 | − "map entry %016llx at bitmap index = %d\n", | |
| 167 | − __func__, bit_pos, bali->lun_alloc_map[i], i); | |
| 168 | − | |
| 169 | − *bit_word = i; | |
| 170 | − bali->free_aun_cnt--; | |
| 171 | − clear_bit(bit_pos, lam); | |
| 172 | − break; | |
| 173 | − } | |
| 174 | − | |
| 175 | − return bit_pos; | |
| 176 | −} | |
| 177 | − | |
| 178 | −/** | |
| 179 | − * ba_alloc() - allocates a block from the block allocator | |
| 180 | − * @ba_lun: Block allocator from which to allocate a block. | |
| 181 | − * | |
| 182 | − * Return: The allocated block, -1 on failure | |
| 183 | − */ | |
| 184 | −static u64 ba_alloc(struct ba_lun *ba_lun) | |
| 185 | −{ | |
| 186 | − u64 bit_pos = -1; | |
| 187 | − int bit_word = 0; | |
| 188 | − struct ba_lun_info *bali = NULL; | |
| 189 | − | |
| 190 | − bali = ba_lun->ba_lun_handle; | |
| 191 | − | |
| 192 | − pr_debug("%s: Received block allocation request: " | |
| 193 | − "lun_id=%016llx free_aun_cnt=%llx\n", | |
| 194 | − __func__, ba_lun->lun_id, bali->free_aun_cnt); | |
| 195 | − | |
| 196 | − if (bali->free_aun_cnt == 0) { | |
| 197 | − pr_debug("%s: No space left on LUN: lun_id=%016llx\n", | |
| 198 | − __func__, ba_lun->lun_id); | |
| 199 | − return -1ULL; | |
| 200 | − } | |
| 201 | − | |
| 202 | − /* Search to find a free entry, curr->high then low->curr */ | |
| 203 | − bit_pos = find_free_range(bali->free_curr_idx, | |
| 204 | − bali->free_high_idx, bali, &bit_word); | |
| 205 | − if (bit_pos == -1) { | |
| 206 | − bit_pos = find_free_range(bali->free_low_idx, | |
| 207 | − bali->free_curr_idx, | |
| 208 | − bali, &bit_word); | |
| 209 | − if (bit_pos == -1) { | |
| 210 | − pr_debug("%s: Could not find an allocation unit on LUN:" | |
| 211 | − " lun_id=%016llx\n", __func__, ba_lun->lun_id); | |
| 212 | − return -1ULL; | |
| 213 | − } | |
| 214 | − } | |
| 215 | − | |
| 216 | − /* Update the free_curr_idx */ | |
| 217 | − if (bit_pos == HIBIT) | |
| 218 | − bali->free_curr_idx = bit_word + 1; | |
| 219 | − else | |
| 220 | − bali->free_curr_idx = bit_word; | |
| 221 | − | |
| 222 | − pr_debug("%s: Allocating AU number=%llx lun_id=%016llx " | |
| 223 | − "free_aun_cnt=%llx\n", __func__, | |
| 224 | − ((bit_word * BITS_PER_LONG) + bit_pos), ba_lun->lun_id, | |
| 225 | − bali->free_aun_cnt); | |
| 226 | − | |
| 227 | − return (u64) ((bit_word * BITS_PER_LONG) + bit_pos); | |
| 228 | −} | |
| 229 | − | |
| 230 | −/** | |
| 231 | − * validate_alloc() - validates the specified block has been allocated | |
| 232 | − * @bali: LUN info owning the block allocator. | |
| 233 | − * @aun: Block to validate. | |
| 234 | − * | |
| 235 | − * Return: 0 on success, -1 on failure | |
| 236 | − */ | |
| 237 | −static int validate_alloc(struct ba_lun_info *bali, u64 aun) | |
| 238 | −{ | |
| 239 | − int idx = 0, bit_pos = 0; | |
| 240 | − | |
| 241 | − idx = aun / BITS_PER_LONG; | |
| 242 | − bit_pos = aun % BITS_PER_LONG; | |
| 243 | − | |
| 244 | − if (test_bit(bit_pos, (ulong *)&bali->lun_alloc_map[idx])) | |
| 245 | − return -1; | |
| 246 | − | |
| 247 | − return 0; | |
| 248 | −} | |
| 249 | − | |
| 250 | −/** | |
| 251 | − * ba_free() - frees a block from the block allocator | |
| 252 | − * @ba_lun: Block allocator from which to allocate a block. | |
| 253 | − * @to_free: Block to free. | |
| 254 | − * | |
| 255 | − * Return: 0 on success, -1 on failure | |
| 256 | − */ | |
| 257 | −static int ba_free(struct ba_lun *ba_lun, u64 to_free) | |
| 258 | −{ | |
| 259 | − int idx = 0, bit_pos = 0; | |
| 260 | − struct ba_lun_info *bali = NULL; | |
| 261 | − | |
| 262 | − bali = ba_lun->ba_lun_handle; | |
| 263 | − | |
| 264 | − if (validate_alloc(bali, to_free)) { | |
| 265 | − pr_debug("%s: AUN %llx is not allocated on lun_id=%016llx\n", | |
| 266 | − __func__, to_free, ba_lun->lun_id); | |
| 267 | − return -1; | |
| 268 | − } | |
| 269 | − | |
| 270 | − pr_debug("%s: Received a request to free AU=%llx lun_id=%016llx " | |
| 271 | − "free_aun_cnt=%llx\n", __func__, to_free, ba_lun->lun_id, | |
| 272 | − bali->free_aun_cnt); | |
| 273 | − | |
| 274 | − if (bali->aun_clone_map[to_free] > 0) { | |
| 275 | − pr_debug("%s: AUN %llx lun_id=%016llx cloned. Clone count=%x\n", | |
| 276 | − __func__, to_free, ba_lun->lun_id, | |
| 277 | − bali->aun_clone_map[to_free]); | |
| 278 | − bali->aun_clone_map[to_free]--; | |
| 279 | − return 0; | |
| 280 | − } | |
| 281 | − | |
| 282 | − idx = to_free / BITS_PER_LONG; | |
| 283 | − bit_pos = to_free % BITS_PER_LONG; | |
| 284 | − | |
| 285 | − set_bit(bit_pos, (ulong *)&bali->lun_alloc_map[idx]); | |
| 286 | − bali->free_aun_cnt++; | |
| 287 | − | |
| 288 | − if (idx < bali->free_low_idx) | |
| 289 | − bali->free_low_idx = idx; | |
| 290 | − else if (idx > bali->free_high_idx) | |
| 291 | − bali->free_high_idx = idx; | |
| 292 | − | |
| 293 | − pr_debug("%s: Successfully freed AU bit_pos=%x bit map index=%x " | |
| 294 | − "lun_id=%016llx free_aun_cnt=%llx\n", __func__, bit_pos, idx, | |
| 295 | − ba_lun->lun_id, bali->free_aun_cnt); | |
| 296 | − | |
| 297 | − return 0; | |
| 298 | −} | |
| 299 | − | |
| 300 | −/** | |
| 301 | − * ba_clone() - Clone a chunk of the block allocation table | |
| 302 | − * @ba_lun: Block allocator from which to allocate a block. | |
| 303 | − * @to_clone: Block to clone. | |
| 304 | − * | |
| 305 | − * Return: 0 on success, -1 on failure | |
| 306 | − */ | |
| 307 | −static int ba_clone(struct ba_lun *ba_lun, u64 to_clone) | |
| 308 | −{ | |
| 309 | − struct ba_lun_info *bali = ba_lun->ba_lun_handle; | |
| 310 | − | |
| 311 | − if (validate_alloc(bali, to_clone)) { | |
| 312 | − pr_debug("%s: AUN=%llx not allocated on lun_id=%016llx\n", | |
| 313 | − __func__, to_clone, ba_lun->lun_id); | |
| 314 | − return -1; | |
| 315 | − } | |
| 316 | − | |
| 317 | − pr_debug("%s: Received a request to clone AUN %llx on lun_id=%016llx\n", | |
| 318 | − __func__, to_clone, ba_lun->lun_id); | |
| 319 | − | |
| 320 | − if (bali->aun_clone_map[to_clone] == MAX_AUN_CLONE_CNT) { | |
| 321 | − pr_debug("%s: AUN %llx on lun_id=%016llx hit max clones already\n", | |
| 322 | − __func__, to_clone, ba_lun->lun_id); | |
| 323 | − return -1; | |
| 324 | − } | |
| 325 | − | |
| 326 | − bali->aun_clone_map[to_clone]++; | |
| 327 | − | |
| 328 | − return 0; | |
| 329 | −} | |
| 330 | − | |
| 331 | −/** | |
| 332 | − * ba_space() - returns the amount of free space left in the block allocator | |
| 333 | − * @ba_lun: Block allocator. | |
| 334 | − * | |
| 335 | − * Return: Amount of free space in block allocator | |
| 336 | − */ | |
| 337 | −static u64 ba_space(struct ba_lun *ba_lun) | |
| 338 | −{ | |
| 339 | − struct ba_lun_info *bali = ba_lun->ba_lun_handle; | |
| 340 | − | |
| 341 | − return bali->free_aun_cnt; | |
| 342 | −} | |
| 343 | − | |
| 344 | −/** | |
| 345 | − * cxlflash_ba_terminate() - frees resources associated with the block allocator | |
| 346 | − * @ba_lun: Block allocator. | |
| 347 | − * | |
| 348 | − * Safe to call in a partially allocated state. | |
| 349 | − */ | |
| 350 | −void cxlflash_ba_terminate(struct ba_lun *ba_lun) | |
| 351 | −{ | |
| 352 | − struct ba_lun_info *bali = ba_lun->ba_lun_handle; | |
| 353 | − | |
| 354 | − if (bali) { | |
| 355 | − kfree(bali->aun_clone_map); | |
| 356 | − kfree(bali->lun_alloc_map); | |
| 357 | − kfree(bali); | |
| 358 | − ba_lun->ba_lun_handle = NULL; | |
| 359 | − } | |
| 360 | −} | |
| 361 | − | |
| 362 | −/** | |
| 363 | − * init_vlun() - initializes a LUN for virtual use | |
| 364 | − * @lli: LUN information structure that owns the block allocator. | |
| 365 | − * | |
| 366 | − * Return: 0 on success, -errno on failure | |
| 367 | − */ | |
| 368 | −static int init_vlun(struct llun_info *lli) | |
| 369 | −{ | |
| 370 | − int rc = 0; | |
| 371 | − struct glun_info *gli = lli->parent; | |
| 372 | − struct blka *blka = &gli->blka; | |
| 373 | − | |
| 374 | − memset(blka, 0, sizeof(*blka)); | |
| 375 | − mutex_init(&blka->mutex); | |
| 376 | − | |
| 377 | − /* LUN IDs are unique per port, save the index instead */ | |
| 378 | − blka->ba_lun.lun_id = lli->lun_index; | |
| 379 | − blka->ba_lun.lsize = gli->max_lba + 1; | |
| 380 | − blka->ba_lun.lba_size = gli->blk_len; | |
| 381 | − | |
| 382 | − blka->ba_lun.au_size = MC_CHUNK_SIZE; | |
| 383 | − blka->nchunk = blka->ba_lun.lsize / MC_CHUNK_SIZE; | |
| 384 | − | |
| 385 | − rc = ba_init(&blka->ba_lun); | |
| 386 | − if (unlikely(rc)) | |
| 387 | − pr_debug("%s: cannot init block_alloc, rc=%d\n", __func__, rc); | |
| 388 | − | |
| 389 | − pr_debug("%s: returning rc=%d lli=%p\n", __func__, rc, lli); | |
| 390 | − return rc; | |
| 391 | −} | |
| 392 | − | |
| 393 | −/** | |
| 394 | − * write_same16() - sends a SCSI WRITE_SAME16 (0) command to specified LUN | |
| 395 | − * @sdev: SCSI device associated with LUN. | |
| 396 | − * @lba: Logical block address to start write same. | |
| 397 | − * @nblks: Number of logical blocks to write same. | |
| 398 | − * | |
| 399 | − * The SCSI WRITE_SAME16 can take quite a while to complete. Should an EEH occur | |
| 400 | − * while in scsi_execute_cmd(), the EEH handler will attempt to recover. As | |
| 401 | − * part of the recovery, the handler drains all currently running ioctls, | |
| 402 | − * waiting until they have completed before proceeding with a reset. As this | |
| 403 | − * routine is used on the ioctl path, this can create a condition where the | |
| 404 | − * EEH handler becomes stuck, infinitely waiting for this ioctl thread. To | |
| 405 | − * avoid this behavior, temporarily unmark this thread as an ioctl thread by | |
| 406 | − * releasing the ioctl read semaphore. This will allow the EEH handler to | |
| 407 | − * proceed with a recovery while this thread is still running. Once the | |
| 408 | − * scsi_execute_cmd() returns, reacquire the ioctl read semaphore and check the | |
| 409 | − * adapter state in case it changed while inside of scsi_execute_cmd(). The | |
| 410 | − * state check will wait if the adapter is still being recovered or return a | |
| 411 | − * failure if the recovery failed. In the event that the adapter reset failed, | |
| 412 | − * simply return the failure as the ioctl would be unable to continue. | |
| 413 | − * | |
| 414 | − * Note that the above puts a requirement on this routine to only be called on | |
| 415 | − * an ioctl thread. | |
| 416 | − * | |
| 417 | − * Return: 0 on success, -errno on failure | |
| 418 | − */ | |
| 419 | −static int write_same16(struct scsi_device *sdev, | |
| 420 | − u64 lba, | |
| 421 | − u32 nblks) | |
| 422 | −{ | |
| 423 | − u8 *cmd_buf = NULL; | |
| 424 | − u8 *scsi_cmd = NULL; | |
| 425 | − int rc = 0; | |
| 426 | − int result = 0; | |
| 427 | − u64 offset = lba; | |
| 428 | − int left = nblks; | |
| 429 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 430 | − struct device *dev = &cfg->dev->dev; | |
| 431 | − const u32 s = ilog2(sdev->sector_size) - 9; | |
| 432 | − const u32 to = sdev->request_queue->rq_timeout; | |
| 433 | − const u32 ws_limit = | |
| 434 | − sdev->request_queue->limits.max_write_zeroes_sectors >> s; | |
| 435 | − | |
| 436 | − cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); | |
| 437 | − scsi_cmd = kzalloc(MAX_COMMAND_SIZE, GFP_KERNEL); | |
| 438 | − if (unlikely(!cmd_buf || !scsi_cmd)) { | |
| 439 | − rc = -ENOMEM; | |
| 440 | − goto out; | |
| 441 | − } | |
| 442 | − | |
| 443 | − while (left > 0) { | |
| 444 | − | |
| 445 | − scsi_cmd[0] = WRITE_SAME_16; | |
| 446 | − scsi_cmd[1] = cfg->ws_unmap ? 0x8 : 0; | |
| 447 | − put_unaligned_be64(offset, &scsi_cmd[2]); | |
| 448 | − put_unaligned_be32(ws_limit < left ? ws_limit : left, | |
| 449 | − &scsi_cmd[10]); | |
| 450 | − | |
| 451 | − /* Drop the ioctl read semaphore across lengthy call */ | |
| 452 | − up_read(&cfg->ioctl_rwsem); | |
| 453 | − result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_OUT, | |
| 454 | − cmd_buf, CMD_BUFSIZE, to, | |
| 455 | − CMD_RETRIES, NULL); | |
| 456 | − down_read(&cfg->ioctl_rwsem); | |
| 457 | − rc = check_state(cfg); | |
| 458 | − if (rc) { | |
| 459 | − dev_err(dev, "%s: Failed state result=%08x\n", | |
| 460 | − __func__, result); | |
| 461 | − rc = -ENODEV; | |
| 462 | − goto out; | |
| 463 | − } | |
| 464 | − | |
| 465 | − if (result) { | |
| 466 | − dev_err_ratelimited(dev, "%s: command failed for " | |
| 467 | − "offset=%lld result=%08x\n", | |
| 468 | − __func__, offset, result); | |
| 469 | − rc = -EIO; | |
| 470 | − goto out; | |
| 471 | − } | |
| 472 | − left -= ws_limit; | |
| 473 | − offset += ws_limit; | |
| 474 | − } | |
| 475 | − | |
| 476 | −out: | |
| 477 | − kfree(cmd_buf); | |
| 478 | − kfree(scsi_cmd); | |
| 479 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 480 | − return rc; | |
| 481 | −} | |
| 482 | − | |
| 483 | −/** | |
| 484 | − * grow_lxt() - expands the translation table associated with the specified RHTE | |
| 485 | − * @afu: AFU associated with the host. | |
| 486 | − * @sdev: SCSI device associated with LUN. | |
| 487 | − * @ctxid: Context ID of context owning the RHTE. | |
| 488 | − * @rhndl: Resource handle associated with the RHTE. | |
| 489 | − * @rhte: Resource handle entry (RHTE). | |
| 490 | − * @new_size: Number of translation entries associated with RHTE. | |
| 491 | − * | |
| 492 | − * By design, this routine employs a 'best attempt' allocation and will | |
| 493 | − * truncate the requested size down if there is not sufficient space in | |
| 494 | − * the block allocator to satisfy the request but there does exist some | |
| 495 | − * amount of space. The user is made aware of this by returning the size | |
| 496 | − * allocated. | |
| 497 | − * | |
| 498 | − * Return: 0 on success, -errno on failure | |
| 499 | − */ | |
| 500 | −static int grow_lxt(struct afu *afu, | |
| 501 | − struct scsi_device *sdev, | |
| 502 | − ctx_hndl_t ctxid, | |
| 503 | − res_hndl_t rhndl, | |
| 504 | − struct sisl_rht_entry *rhte, | |
| 505 | − u64 *new_size) | |
| 506 | −{ | |
| 507 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 508 | − struct device *dev = &cfg->dev->dev; | |
| 509 | − struct sisl_lxt_entry *lxt = NULL, *lxt_old = NULL; | |
| 510 | − struct llun_info *lli = sdev->hostdata; | |
| 511 | − struct glun_info *gli = lli->parent; | |
| 512 | − struct blka *blka = &gli->blka; | |
| 513 | − u32 av_size; | |
| 514 | − u32 ngrps, ngrps_old; | |
| 515 | − u64 aun; /* chunk# allocated by block allocator */ | |
| 516 | − u64 delta = *new_size - rhte->lxt_cnt; | |
| 517 | − u64 my_new_size; | |
| 518 | − int i, rc = 0; | |
| 519 | − | |
| 520 | − /* | |
| 521 | − * Check what is available in the block allocator before re-allocating | |
| 522 | − * LXT array. This is done up front under the mutex which must not be | |
| 523 | − * released until after allocation is complete. | |
| 524 | − */ | |
| 525 | − mutex_lock(&blka->mutex); | |
| 526 | − av_size = ba_space(&blka->ba_lun); | |
| 527 | − if (unlikely(av_size <= 0)) { | |
| 528 | − dev_dbg(dev, "%s: ba_space error av_size=%d\n", | |
| 529 | − __func__, av_size); | |
| 530 | − mutex_unlock(&blka->mutex); | |
| 531 | − rc = -ENOSPC; | |
| 532 | − goto out; | |
| 533 | − } | |
| 534 | − | |
| 535 | − if (av_size < delta) | |
| 536 | − delta = av_size; | |
| 537 | − | |
| 538 | − lxt_old = rhte->lxt_start; | |
| 539 | − ngrps_old = LXT_NUM_GROUPS(rhte->lxt_cnt); | |
| 540 | − ngrps = LXT_NUM_GROUPS(rhte->lxt_cnt + delta); | |
| 541 | − | |
| 542 | − if (ngrps != ngrps_old) { | |
| 543 | − /* reallocate to fit new size */ | |
| 544 | − lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), | |
| 545 | − GFP_KERNEL); | |
| 546 | − if (unlikely(!lxt)) { | |
| 547 | − mutex_unlock(&blka->mutex); | |
| 548 | − rc = -ENOMEM; | |
| 549 | − goto out; | |
| 550 | − } | |
| 551 | − | |
| 552 | − /* copy over all old entries */ | |
| 553 | − memcpy(lxt, lxt_old, (sizeof(*lxt) * rhte->lxt_cnt)); | |
| 554 | − } else | |
| 555 | − lxt = lxt_old; | |
| 556 | − | |
| 557 | − /* nothing can fail from now on */ | |
| 558 | − my_new_size = rhte->lxt_cnt + delta; | |
| 559 | − | |
| 560 | − /* add new entries to the end */ | |
| 561 | − for (i = rhte->lxt_cnt; i < my_new_size; i++) { | |
| 562 | − /* | |
| 563 | − * Due to the earlier check of available space, ba_alloc | |
| 564 | − * cannot fail here. If it did due to internal error, | |
| 565 | − * leave a rlba_base of -1u which will likely be a | |
| 566 | − * invalid LUN (too large). | |
| 567 | − */ | |
| 568 | − aun = ba_alloc(&blka->ba_lun); | |
| 569 | − if ((aun == -1ULL) || (aun >= blka->nchunk)) | |
| 570 | − dev_dbg(dev, "%s: ba_alloc error allocated chunk=%llu " | |
| 571 | − "max=%llu\n", __func__, aun, blka->nchunk - 1); | |
| 572 | − | |
| 573 | − /* select both ports, use r/w perms from RHT */ | |
| 574 | − lxt[i].rlba_base = ((aun << MC_CHUNK_SHIFT) | | |
| 575 | − (lli->lun_index << LXT_LUNIDX_SHIFT) | | |
| 576 | − (RHT_PERM_RW << LXT_PERM_SHIFT | | |
| 577 | − lli->port_sel)); | |
| 578 | − } | |
| 579 | − | |
| 580 | − mutex_unlock(&blka->mutex); | |
| 581 | − | |
| 582 | − /* | |
| 583 | − * The following sequence is prescribed in the SISlite spec | |
| 584 | − * for syncing up with the AFU when adding LXT entries. | |
| 585 | − */ | |
| 586 | − dma_wmb(); /* Make LXT updates are visible */ | |
| 587 | − | |
| 588 | − rhte->lxt_start = lxt; | |
| 589 | − dma_wmb(); /* Make RHT entry's LXT table update visible */ | |
| 590 | − | |
| 591 | − rhte->lxt_cnt = my_new_size; | |
| 592 | − dma_wmb(); /* Make RHT entry's LXT table size update visible */ | |
| 593 | − | |
| 594 | − rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); | |
| 595 | − if (unlikely(rc)) | |
| 596 | − rc = -EAGAIN; | |
| 597 | − | |
| 598 | − /* free old lxt if reallocated */ | |
| 599 | − if (lxt != lxt_old) | |
| 600 | − kfree(lxt_old); | |
| 601 | − *new_size = my_new_size; | |
| 602 | −out: | |
| 603 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 604 | − return rc; | |
| 605 | −} | |
| 606 | − | |
| 607 | −/** | |
| 608 | − * shrink_lxt() - reduces translation table associated with the specified RHTE | |
| 609 | − * @afu: AFU associated with the host. | |
| 610 | − * @sdev: SCSI device associated with LUN. | |
| 611 | − * @rhndl: Resource handle associated with the RHTE. | |
| 612 | − * @rhte: Resource handle entry (RHTE). | |
| 613 | − * @ctxi: Context owning resources. | |
| 614 | − * @new_size: Number of translation entries associated with RHTE. | |
| 615 | − * | |
| 616 | − * Return: 0 on success, -errno on failure | |
| 617 | − */ | |
| 618 | −static int shrink_lxt(struct afu *afu, | |
| 619 | − struct scsi_device *sdev, | |
| 620 | − res_hndl_t rhndl, | |
| 621 | − struct sisl_rht_entry *rhte, | |
| 622 | − struct ctx_info *ctxi, | |
| 623 | − u64 *new_size) | |
| 624 | −{ | |
| 625 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 626 | − struct device *dev = &cfg->dev->dev; | |
| 627 | − struct sisl_lxt_entry *lxt, *lxt_old; | |
| 628 | − struct llun_info *lli = sdev->hostdata; | |
| 629 | − struct glun_info *gli = lli->parent; | |
| 630 | − struct blka *blka = &gli->blka; | |
| 631 | − ctx_hndl_t ctxid = DECODE_CTXID(ctxi->ctxid); | |
| 632 | − bool needs_ws = ctxi->rht_needs_ws[rhndl]; | |
| 633 | − bool needs_sync = !ctxi->err_recovery_active; | |
| 634 | − u32 ngrps, ngrps_old; | |
| 635 | − u64 aun; /* chunk# allocated by block allocator */ | |
| 636 | − u64 delta = rhte->lxt_cnt - *new_size; | |
| 637 | − u64 my_new_size; | |
| 638 | − int i, rc = 0; | |
| 639 | − | |
| 640 | − lxt_old = rhte->lxt_start; | |
| 641 | − ngrps_old = LXT_NUM_GROUPS(rhte->lxt_cnt); | |
| 642 | − ngrps = LXT_NUM_GROUPS(rhte->lxt_cnt - delta); | |
| 643 | − | |
| 644 | − if (ngrps != ngrps_old) { | |
| 645 | − /* Reallocate to fit new size unless new size is 0 */ | |
| 646 | − if (ngrps) { | |
| 647 | − lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), | |
| 648 | − GFP_KERNEL); | |
| 649 | − if (unlikely(!lxt)) { | |
| 650 | − rc = -ENOMEM; | |
| 651 | − goto out; | |
| 652 | − } | |
| 653 | − | |
| 654 | − /* Copy over old entries that will remain */ | |
| 655 | − memcpy(lxt, lxt_old, | |
| 656 | − (sizeof(*lxt) * (rhte->lxt_cnt - delta))); | |
| 657 | − } else | |
| 658 | − lxt = NULL; | |
| 659 | − } else | |
| 660 | − lxt = lxt_old; | |
| 661 | − | |
| 662 | − /* Nothing can fail from now on */ | |
| 663 | − my_new_size = rhte->lxt_cnt - delta; | |
| 664 | − | |
| 665 | − /* | |
| 666 | − * The following sequence is prescribed in the SISlite spec | |
| 667 | − * for syncing up with the AFU when removing LXT entries. | |
| 668 | − */ | |
| 669 | − rhte->lxt_cnt = my_new_size; | |
| 670 | − dma_wmb(); /* Make RHT entry's LXT table size update visible */ | |
| 671 | − | |
| 672 | − rhte->lxt_start = lxt; | |
| 673 | − dma_wmb(); /* Make RHT entry's LXT table update visible */ | |
| 674 | − | |
| 675 | − if (needs_sync) { | |
| 676 | − rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); | |
| 677 | − if (unlikely(rc)) | |
| 678 | − rc = -EAGAIN; | |
| 679 | − } | |
| 680 | − | |
| 681 | − if (needs_ws) { | |
| 682 | − /* | |
| 683 | − * Mark the context as unavailable, so that we can release | |
| 684 | − * the mutex safely. | |
| 685 | − */ | |
| 686 | − ctxi->unavail = true; | |
| 687 | − mutex_unlock(&ctxi->mutex); | |
| 688 | − } | |
| 689 | − | |
| 690 | − /* Free LBAs allocated to freed chunks */ | |
| 691 | − mutex_lock(&blka->mutex); | |
| 692 | − for (i = delta - 1; i >= 0; i--) { | |
| 693 | − aun = lxt_old[my_new_size + i].rlba_base >> MC_CHUNK_SHIFT; | |
| 694 | − if (needs_ws) | |
| 695 | − write_same16(sdev, aun, MC_CHUNK_SIZE); | |
| 696 | − ba_free(&blka->ba_lun, aun); | |
| 697 | − } | |
| 698 | − mutex_unlock(&blka->mutex); | |
| 699 | − | |
| 700 | − if (needs_ws) { | |
| 701 | − /* Make the context visible again */ | |
| 702 | − mutex_lock(&ctxi->mutex); | |
| 703 | − ctxi->unavail = false; | |
| 704 | − } | |
| 705 | − | |
| 706 | − /* Free old lxt if reallocated */ | |
| 707 | − if (lxt != lxt_old) | |
| 708 | − kfree(lxt_old); | |
| 709 | − *new_size = my_new_size; | |
| 710 | −out: | |
| 711 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 712 | − return rc; | |
| 713 | −} | |
| 714 | − | |
| 715 | −/** | |
| 716 | − * _cxlflash_vlun_resize() - changes the size of a virtual LUN | |
| 717 | − * @sdev: SCSI device associated with LUN owning virtual LUN. | |
| 718 | − * @ctxi: Context owning resources. | |
| 719 | − * @resize: Resize ioctl data structure. | |
| 720 | − * | |
| 721 | − * On successful return, the user is informed of the new size (in blocks) | |
| 722 | − * of the virtual LUN in last LBA format. When the size of the virtual | |
| 723 | − * LUN is zero, the last LBA is reflected as -1. See comment in the | |
| 724 | − * prologue for _cxlflash_disk_release() regarding AFU syncs and contexts | |
| 725 | − * on the error recovery list. | |
| 726 | − * | |
| 727 | − * Return: 0 on success, -errno on failure | |
| 728 | − */ | |
| 729 | −int _cxlflash_vlun_resize(struct scsi_device *sdev, | |
| 730 | − struct ctx_info *ctxi, | |
| 731 | − struct dk_cxlflash_resize *resize) | |
| 732 | −{ | |
| 733 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 734 | − struct device *dev = &cfg->dev->dev; | |
| 735 | − struct llun_info *lli = sdev->hostdata; | |
| 736 | − struct glun_info *gli = lli->parent; | |
| 737 | − struct afu *afu = cfg->afu; | |
| 738 | − bool put_ctx = false; | |
| 739 | − | |
| 740 | − res_hndl_t rhndl = resize->rsrc_handle; | |
| 741 | − u64 new_size; | |
| 742 | − u64 nsectors; | |
| 743 | − u64 ctxid = DECODE_CTXID(resize->context_id), | |
| 744 | − rctxid = resize->context_id; | |
| 745 | − | |
| 746 | − struct sisl_rht_entry *rhte; | |
| 747 | − | |
| 748 | − int rc = 0; | |
| 749 | − | |
| 750 | − /* | |
| 751 | − * The requested size (req_size) is always assumed to be in 4k blocks, | |
| 752 | − * so we have to convert it here from 4k to chunk size. | |
| 753 | − */ | |
| 754 | − nsectors = (resize->req_size * CXLFLASH_BLOCK_SIZE) / gli->blk_len; | |
| 755 | − new_size = DIV_ROUND_UP(nsectors, MC_CHUNK_SIZE); | |
| 756 | − | |
| 757 | − dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu req_size=%llu new_size=%llu\n", | |
| 758 | − __func__, ctxid, resize->rsrc_handle, resize->req_size, | |
| 759 | − new_size); | |
| 760 | − | |
| 761 | − if (unlikely(gli->mode != MODE_VIRTUAL)) { | |
| 762 | − dev_dbg(dev, "%s: LUN mode does not support resize mode=%d\n", | |
| 763 | − __func__, gli->mode); | |
| 764 | − rc = -EINVAL; | |
| 765 | − goto out; | |
| 766 | − | |
| 767 | − } | |
| 768 | − | |
| 769 | − if (!ctxi) { | |
| 770 | − ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); | |
| 771 | − if (unlikely(!ctxi)) { | |
| 772 | − dev_dbg(dev, "%s: Bad context ctxid=%llu\n", | |
| 773 | − __func__, ctxid); | |
| 774 | − rc = -EINVAL; | |
| 775 | − goto out; | |
| 776 | − } | |
| 777 | − | |
| 778 | − put_ctx = true; | |
| 779 | − } | |
| 780 | − | |
| 781 | − rhte = get_rhte(ctxi, rhndl, lli); | |
| 782 | − if (unlikely(!rhte)) { | |
| 783 | − dev_dbg(dev, "%s: Bad resource handle rhndl=%u\n", | |
| 784 | − __func__, rhndl); | |
| 785 | − rc = -EINVAL; | |
| 786 | − goto out; | |
| 787 | − } | |
| 788 | − | |
| 789 | − if (new_size > rhte->lxt_cnt) | |
| 790 | − rc = grow_lxt(afu, sdev, ctxid, rhndl, rhte, &new_size); | |
| 791 | − else if (new_size < rhte->lxt_cnt) | |
| 792 | − rc = shrink_lxt(afu, sdev, rhndl, rhte, ctxi, &new_size); | |
| 793 | − else { | |
| 794 | − /* | |
| 795 | − * Rare case where there is already sufficient space, just | |
| 796 | − * need to perform a translation sync with the AFU. This | |
| 797 | − * scenario likely follows a previous sync failure during | |
| 798 | − * a resize operation. Accordingly, perform the heavyweight | |
| 799 | − * form of translation sync as it is unknown which type of | |
| 800 | − * resize failed previously. | |
| 801 | − */ | |
| 802 | − rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); | |
| 803 | − if (unlikely(rc)) { | |
| 804 | − rc = -EAGAIN; | |
| 805 | − goto out; | |
| 806 | − } | |
| 807 | − } | |
| 808 | − | |
| 809 | − resize->hdr.return_flags = 0; | |
| 810 | − resize->last_lba = (new_size * MC_CHUNK_SIZE * gli->blk_len); | |
| 811 | − resize->last_lba /= CXLFLASH_BLOCK_SIZE; | |
| 812 | − resize->last_lba--; | |
| 813 | − | |
| 814 | −out: | |
| 815 | − if (put_ctx) | |
| 816 | − put_context(ctxi); | |
| 817 | − dev_dbg(dev, "%s: resized to %llu returning rc=%d\n", | |
| 818 | − __func__, resize->last_lba, rc); | |
| 819 | − return rc; | |
| 820 | −} | |
| 821 | − | |
| 822 | −int cxlflash_vlun_resize(struct scsi_device *sdev, void *resize) | |
| 823 | −{ | |
| 824 | − return _cxlflash_vlun_resize(sdev, NULL, resize); | |
| 825 | −} | |
| 826 | − | |
| 827 | −/** | |
| 828 | − * cxlflash_restore_luntable() - Restore LUN table to prior state | |
| 829 | − * @cfg: Internal structure associated with the host. | |
| 830 | − */ | |
| 831 | −void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) | |
| 832 | −{ | |
| 833 | − struct llun_info *lli, *temp; | |
| 834 | − u32 lind; | |
| 835 | − int k; | |
| 836 | − struct device *dev = &cfg->dev->dev; | |
| 837 | − __be64 __iomem *fc_port_luns; | |
| 838 | − | |
| 839 | − mutex_lock(&global.mutex); | |
| 840 | − | |
| 841 | − list_for_each_entry_safe(lli, temp, &cfg->lluns, list) { | |
| 842 | − if (!lli->in_table) | |
| 843 | − continue; | |
| 844 | − | |
| 845 | − lind = lli->lun_index; | |
| 846 | − dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n", __func__, lind); | |
| 847 | − | |
| 848 | − for (k = 0; k < cfg->num_fc_ports; k++) | |
| 849 | − if (lli->port_sel & (1 << k)) { | |
| 850 | − fc_port_luns = get_fc_port_luns(cfg, k); | |
| 851 | − writeq_be(lli->lun_id[k], &fc_port_luns[lind]); | |
| 852 | − dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]); | |
| 853 | − } | |
| 854 | − } | |
| 855 | − | |
| 856 | − mutex_unlock(&global.mutex); | |
| 857 | −} | |
| 858 | − | |
| 859 | −/** | |
| 860 | − * get_num_ports() - compute number of ports from port selection mask | |
| 861 | − * @psm: Port selection mask. | |
| 862 | − * | |
| 863 | − * Return: Population count of port selection mask | |
| 864 | − */ | |
| 865 | −static inline u8 get_num_ports(u32 psm) | |
| 866 | −{ | |
| 867 | − static const u8 bits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, | |
| 868 | − 1, 2, 2, 3, 2, 3, 3, 4 }; | |
| 869 | − | |
| 870 | − return bits[psm & 0xf]; | |
| 871 | −} | |
| 872 | − | |
| 873 | −/** | |
| 874 | − * init_luntable() - write an entry in the LUN table | |
| 875 | − * @cfg: Internal structure associated with the host. | |
| 876 | − * @lli: Per adapter LUN information structure. | |
| 877 | − * | |
| 878 | − * On successful return, a LUN table entry is created: | |
| 879 | − * - at the top for LUNs visible on multiple ports. | |
| 880 | − * - at the bottom for LUNs visible only on one port. | |
| 881 | − * | |
| 882 | − * Return: 0 on success, -errno on failure | |
| 883 | − */ | |
| 884 | −static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) | |
| 885 | −{ | |
| 886 | − u32 chan; | |
| 887 | − u32 lind; | |
| 888 | − u32 nports; | |
| 889 | − int rc = 0; | |
| 890 | − int k; | |
| 891 | − struct device *dev = &cfg->dev->dev; | |
| 892 | − __be64 __iomem *fc_port_luns; | |
| 893 | − | |
| 894 | − mutex_lock(&global.mutex); | |
| 895 | − | |
| 896 | − if (lli->in_table) | |
| 897 | − goto out; | |
| 898 | − | |
| 899 | − nports = get_num_ports(lli->port_sel); | |
| 900 | − if (nports == 0 || nports > cfg->num_fc_ports) { | |
| 901 | − WARN(1, "Unsupported port configuration nports=%u", nports); | |
| 902 | − rc = -EIO; | |
| 903 | − goto out; | |
| 904 | − } | |
| 905 | − | |
| 906 | − if (nports > 1) { | |
| 907 | − /* | |
| 908 | − * When LUN is visible from multiple ports, we will put | |
| 909 | − * it in the top half of the LUN table. | |
| 910 | − */ | |
| 911 | − for (k = 0; k < cfg->num_fc_ports; k++) { | |
| 912 | − if (!(lli->port_sel & (1 << k))) | |
| 913 | − continue; | |
| 914 | − | |
| 915 | − if (cfg->promote_lun_index == cfg->last_lun_index[k]) { | |
| 916 | − rc = -ENOSPC; | |
| 917 | − goto out; | |
| 918 | − } | |
| 919 | − } | |
| 920 | − | |
| 921 | − lind = lli->lun_index = cfg->promote_lun_index; | |
| 922 | − dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n", __func__, lind); | |
| 923 | − | |
| 924 | − for (k = 0; k < cfg->num_fc_ports; k++) { | |
| 925 | − if (!(lli->port_sel & (1 << k))) | |
| 926 | − continue; | |
| 927 | − | |
| 928 | − fc_port_luns = get_fc_port_luns(cfg, k); | |
| 929 | − writeq_be(lli->lun_id[k], &fc_port_luns[lind]); | |
| 930 | − dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]); | |
| 931 | − } | |
| 932 | − | |
| 933 | − cfg->promote_lun_index++; | |
| 934 | − } else { | |
| 935 | − /* | |
| 936 | − * When LUN is visible only from one port, we will put | |
| 937 | − * it in the bottom half of the LUN table. | |
| 938 | − */ | |
| 939 | − chan = PORTMASK2CHAN(lli->port_sel); | |
| 940 | − if (cfg->promote_lun_index == cfg->last_lun_index[chan]) { | |
| 941 | − rc = -ENOSPC; | |
| 942 | − goto out; | |
| 943 | − } | |
| 944 | − | |
| 945 | − lind = lli->lun_index = cfg->last_lun_index[chan]; | |
| 946 | − fc_port_luns = get_fc_port_luns(cfg, chan); | |
| 947 | − writeq_be(lli->lun_id[chan], &fc_port_luns[lind]); | |
| 948 | − cfg->last_lun_index[chan]--; | |
| 949 | − dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n\t%d=%llx\n", | |
| 950 | − __func__, lind, chan, lli->lun_id[chan]); | |
| 951 | − } | |
| 952 | − | |
| 953 | − lli->in_table = true; | |
| 954 | −out: | |
| 955 | − mutex_unlock(&global.mutex); | |
| 956 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 957 | − return rc; | |
| 958 | −} | |
| 959 | − | |
| 960 | −/** | |
| 961 | − * cxlflash_disk_virtual_open() - open a virtual disk of specified size | |
| 962 | − * @sdev: SCSI device associated with LUN owning virtual LUN. | |
| 963 | − * @arg: UVirtual ioctl data structure. | |
| 964 | − * | |
| 965 | − * On successful return, the user is informed of the resource handle | |
| 966 | − * to be used to identify the virtual LUN and the size (in blocks) of | |
| 967 | − * the virtual LUN in last LBA format. When the size of the virtual LUN | |
| 968 | − * is zero, the last LBA is reflected as -1. | |
| 969 | − * | |
| 970 | − * Return: 0 on success, -errno on failure | |
| 971 | − */ | |
| 972 | −int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) | |
| 973 | −{ | |
| 974 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 975 | − struct device *dev = &cfg->dev->dev; | |
| 976 | − struct llun_info *lli = sdev->hostdata; | |
| 977 | − struct glun_info *gli = lli->parent; | |
| 978 | − | |
| 979 | − struct dk_cxlflash_uvirtual *virt = (struct dk_cxlflash_uvirtual *)arg; | |
| 980 | − struct dk_cxlflash_resize resize; | |
| 981 | − | |
| 982 | − u64 ctxid = DECODE_CTXID(virt->context_id), | |
| 983 | − rctxid = virt->context_id; | |
| 984 | − u64 lun_size = virt->lun_size; | |
| 985 | − u64 last_lba = 0; | |
| 986 | − u64 rsrc_handle = -1; | |
| 987 | − | |
| 988 | − int rc = 0; | |
| 989 | − | |
| 990 | − struct ctx_info *ctxi = NULL; | |
| 991 | − struct sisl_rht_entry *rhte = NULL; | |
| 992 | − | |
| 993 | − dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size); | |
| 994 | − | |
| 995 | − /* Setup the LUNs block allocator on first call */ | |
| 996 | − mutex_lock(&gli->mutex); | |
| 997 | − if (gli->mode == MODE_NONE) { | |
| 998 | − rc = init_vlun(lli); | |
| 999 | − if (rc) { | |
| 1000 | − dev_err(dev, "%s: init_vlun failed rc=%d\n", | |
| 1001 | − __func__, rc); | |
| 1002 | − rc = -ENOMEM; | |
| 1003 | − goto err0; | |
| 1004 | − } | |
| 1005 | − } | |
| 1006 | − | |
| 1007 | − rc = cxlflash_lun_attach(gli, MODE_VIRTUAL, true); | |
| 1008 | − if (unlikely(rc)) { | |
| 1009 | − dev_err(dev, "%s: Failed attach to LUN (VIRTUAL)\n", __func__); | |
| 1010 | − goto err0; | |
| 1011 | − } | |
| 1012 | − mutex_unlock(&gli->mutex); | |
| 1013 | − | |
| 1014 | − rc = init_luntable(cfg, lli); | |
| 1015 | − if (rc) { | |
| 1016 | − dev_err(dev, "%s: init_luntable failed rc=%d\n", __func__, rc); | |
| 1017 | − goto err1; | |
| 1018 | − } | |
| 1019 | − | |
| 1020 | − ctxi = get_context(cfg, rctxid, lli, 0); | |
| 1021 | − if (unlikely(!ctxi)) { | |
| 1022 | − dev_err(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); | |
| 1023 | − rc = -EINVAL; | |
| 1024 | − goto err1; | |
| 1025 | − } | |
| 1026 | − | |
| 1027 | − rhte = rhte_checkout(ctxi, lli); | |
| 1028 | − if (unlikely(!rhte)) { | |
| 1029 | − dev_err(dev, "%s: too many opens ctxid=%llu\n", | |
| 1030 | − __func__, ctxid); | |
| 1031 | − rc = -EMFILE; /* too many opens */ | |
| 1032 | − goto err1; | |
| 1033 | − } | |
| 1034 | − | |
| 1035 | − rsrc_handle = (rhte - ctxi->rht_start); | |
| 1036 | − | |
| 1037 | − /* Populate RHT format 0 */ | |
| 1038 | − rhte->nmask = MC_RHT_NMASK; | |
| 1039 | − rhte->fp = SISL_RHT_FP(0U, ctxi->rht_perms); | |
| 1040 | − | |
| 1041 | − /* Resize even if requested size is 0 */ | |
| 1042 | − marshal_virt_to_resize(virt, &resize); | |
| 1043 | − resize.rsrc_handle = rsrc_handle; | |
| 1044 | − rc = _cxlflash_vlun_resize(sdev, ctxi, &resize); | |
| 1045 | − if (rc) { | |
| 1046 | − dev_err(dev, "%s: resize failed rc=%d\n", __func__, rc); | |
| 1047 | − goto err2; | |
| 1048 | − } | |
| 1049 | − last_lba = resize.last_lba; | |
| 1050 | − | |
| 1051 | − if (virt->hdr.flags & DK_CXLFLASH_UVIRTUAL_NEED_WRITE_SAME) | |
| 1052 | − ctxi->rht_needs_ws[rsrc_handle] = true; | |
| 1053 | − | |
| 1054 | − virt->hdr.return_flags = 0; | |
| 1055 | − virt->last_lba = last_lba; | |
| 1056 | − virt->rsrc_handle = rsrc_handle; | |
| 1057 | − | |
| 1058 | − if (get_num_ports(lli->port_sel) > 1) | |
| 1059 | − virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE; | |
| 1060 | −out: | |
| 1061 | − if (likely(ctxi)) | |
| 1062 | − put_context(ctxi); | |
| 1063 | − dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n", | |
| 1064 | − __func__, rsrc_handle, rc, last_lba); | |
| 1065 | − return rc; | |
| 1066 | − | |
| 1067 | −err2: | |
| 1068 | − rhte_checkin(ctxi, rhte); | |
| 1069 | −err1: | |
| 1070 | − cxlflash_lun_detach(gli); | |
| 1071 | − goto out; | |
| 1072 | −err0: | |
| 1073 | − /* Special common cleanup prior to successful LUN attach */ | |
| 1074 | − cxlflash_ba_terminate(&gli->blka.ba_lun); | |
| 1075 | − mutex_unlock(&gli->mutex); | |
| 1076 | − goto out; | |
| 1077 | −} | |
| 1078 | − | |
| 1079 | −/** | |
| 1080 | − * clone_lxt() - copies translation tables from source to destination RHTE | |
| 1081 | − * @afu: AFU associated with the host. | |
| 1082 | − * @blka: Block allocator associated with LUN. | |
| 1083 | − * @ctxid: Context ID of context owning the RHTE. | |
| 1084 | − * @rhndl: Resource handle associated with the RHTE. | |
| 1085 | − * @rhte: Destination resource handle entry (RHTE). | |
| 1086 | − * @rhte_src: Source resource handle entry (RHTE). | |
| 1087 | − * | |
| 1088 | − * Return: 0 on success, -errno on failure | |
| 1089 | − */ | |
| 1090 | −static int clone_lxt(struct afu *afu, | |
| 1091 | − struct blka *blka, | |
| 1092 | − ctx_hndl_t ctxid, | |
| 1093 | − res_hndl_t rhndl, | |
| 1094 | − struct sisl_rht_entry *rhte, | |
| 1095 | − struct sisl_rht_entry *rhte_src) | |
| 1096 | −{ | |
| 1097 | − struct cxlflash_cfg *cfg = afu->parent; | |
| 1098 | − struct device *dev = &cfg->dev->dev; | |
| 1099 | − struct sisl_lxt_entry *lxt = NULL; | |
| 1100 | − bool locked = false; | |
| 1101 | − u32 ngrps; | |
| 1102 | − u64 aun; /* chunk# allocated by block allocator */ | |
| 1103 | − int j; | |
| 1104 | − int i = 0; | |
| 1105 | − int rc = 0; | |
| 1106 | − | |
| 1107 | − ngrps = LXT_NUM_GROUPS(rhte_src->lxt_cnt); | |
| 1108 | − | |
| 1109 | − if (ngrps) { | |
| 1110 | − /* allocate new LXTs for clone */ | |
| 1111 | − lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), | |
| 1112 | − GFP_KERNEL); | |
| 1113 | − if (unlikely(!lxt)) { | |
| 1114 | − rc = -ENOMEM; | |
| 1115 | − goto out; | |
| 1116 | − } | |
| 1117 | − | |
| 1118 | − /* copy over */ | |
| 1119 | − memcpy(lxt, rhte_src->lxt_start, | |
| 1120 | − (sizeof(*lxt) * rhte_src->lxt_cnt)); | |
| 1121 | − | |
| 1122 | − /* clone the LBAs in block allocator via ref_cnt, note that the | |
| 1123 | − * block allocator mutex must be held until it is established | |
| 1124 | − * that this routine will complete without the need for a | |
| 1125 | − * cleanup. | |
| 1126 | − */ | |
| 1127 | − mutex_lock(&blka->mutex); | |
| 1128 | − locked = true; | |
| 1129 | − for (i = 0; i < rhte_src->lxt_cnt; i++) { | |
| 1130 | − aun = (lxt[i].rlba_base >> MC_CHUNK_SHIFT); | |
| 1131 | − if (ba_clone(&blka->ba_lun, aun) == -1ULL) { | |
| 1132 | − rc = -EIO; | |
| 1133 | − goto err; | |
| 1134 | − } | |
| 1135 | − } | |
| 1136 | − } | |
| 1137 | − | |
| 1138 | − /* | |
| 1139 | − * The following sequence is prescribed in the SISlite spec | |
| 1140 | − * for syncing up with the AFU when adding LXT entries. | |
| 1141 | − */ | |
| 1142 | − dma_wmb(); /* Make LXT updates are visible */ | |
| 1143 | − | |
| 1144 | − rhte->lxt_start = lxt; | |
| 1145 | − dma_wmb(); /* Make RHT entry's LXT table update visible */ | |
| 1146 | − | |
| 1147 | − rhte->lxt_cnt = rhte_src->lxt_cnt; | |
| 1148 | − dma_wmb(); /* Make RHT entry's LXT table size update visible */ | |
| 1149 | − | |
| 1150 | − rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); | |
| 1151 | − if (unlikely(rc)) { | |
| 1152 | − rc = -EAGAIN; | |
| 1153 | − goto err2; | |
| 1154 | − } | |
| 1155 | − | |
| 1156 | −out: | |
| 1157 | − if (locked) | |
| 1158 | − mutex_unlock(&blka->mutex); | |
| 1159 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 1160 | − return rc; | |
| 1161 | −err2: | |
| 1162 | − /* Reset the RHTE */ | |
| 1163 | − rhte->lxt_cnt = 0; | |
| 1164 | − dma_wmb(); | |
| 1165 | − rhte->lxt_start = NULL; | |
| 1166 | − dma_wmb(); | |
| 1167 | −err: | |
| 1168 | − /* free the clones already made */ | |
| 1169 | − for (j = 0; j < i; j++) { | |
| 1170 | − aun = (lxt[j].rlba_base >> MC_CHUNK_SHIFT); | |
| 1171 | − ba_free(&blka->ba_lun, aun); | |
| 1172 | − } | |
| 1173 | − kfree(lxt); | |
| 1174 | − goto out; | |
| 1175 | −} | |
| 1176 | − | |
| 1177 | −/** | |
| 1178 | − * cxlflash_disk_clone() - clone a context by making snapshot of another | |
| 1179 | − * @sdev: SCSI device associated with LUN owning virtual LUN. | |
| 1180 | − * @arg: Clone ioctl data structure. | |
| 1181 | − * | |
| 1182 | − * This routine effectively performs cxlflash_disk_open operation for each | |
| 1183 | − * in-use virtual resource in the source context. Note that the destination | |
| 1184 | − * context must be in pristine state and cannot have any resource handles | |
| 1185 | − * open at the time of the clone. | |
| 1186 | − * | |
| 1187 | − * Return: 0 on success, -errno on failure | |
| 1188 | − */ | |
| 1189 | −int cxlflash_disk_clone(struct scsi_device *sdev, void *arg) | |
| 1190 | −{ | |
| 1191 | − struct dk_cxlflash_clone *clone = arg; | |
| 1192 | − struct cxlflash_cfg *cfg = shost_priv(sdev->host); | |
| 1193 | − struct device *dev = &cfg->dev->dev; | |
| 1194 | − struct llun_info *lli = sdev->hostdata; | |
| 1195 | − struct glun_info *gli = lli->parent; | |
| 1196 | − struct blka *blka = &gli->blka; | |
| 1197 | − struct afu *afu = cfg->afu; | |
| 1198 | − struct dk_cxlflash_release release = { { 0 }, 0 }; | |
| 1199 | − | |
| 1200 | − struct ctx_info *ctxi_src = NULL, | |
| 1201 | − *ctxi_dst = NULL; | |
| 1202 | − struct lun_access *lun_access_src, *lun_access_dst; | |
| 1203 | − u32 perms; | |
| 1204 | − u64 ctxid_src = DECODE_CTXID(clone->context_id_src), | |
| 1205 | − ctxid_dst = DECODE_CTXID(clone->context_id_dst), | |
| 1206 | − rctxid_src = clone->context_id_src, | |
| 1207 | − rctxid_dst = clone->context_id_dst; | |
| 1208 | − int i, j; | |
| 1209 | − int rc = 0; | |
| 1210 | − bool found; | |
| 1211 | − LIST_HEAD(sidecar); | |
| 1212 | − | |
| 1213 | − dev_dbg(dev, "%s: ctxid_src=%llu ctxid_dst=%llu\n", | |
| 1214 | − __func__, ctxid_src, ctxid_dst); | |
| 1215 | − | |
| 1216 | − /* Do not clone yourself */ | |
| 1217 | − if (unlikely(rctxid_src == rctxid_dst)) { | |
| 1218 | − rc = -EINVAL; | |
| 1219 | − goto out; | |
| 1220 | − } | |
| 1221 | − | |
| 1222 | − if (unlikely(gli->mode != MODE_VIRTUAL)) { | |
| 1223 | − rc = -EINVAL; | |
| 1224 | − dev_dbg(dev, "%s: Only supported on virtual LUNs mode=%u\n", | |
| 1225 | − __func__, gli->mode); | |
| 1226 | − goto out; | |
| 1227 | − } | |
| 1228 | − | |
| 1229 | − ctxi_src = get_context(cfg, rctxid_src, lli, CTX_CTRL_CLONE); | |
| 1230 | − ctxi_dst = get_context(cfg, rctxid_dst, lli, 0); | |
| 1231 | − if (unlikely(!ctxi_src || !ctxi_dst)) { | |
| 1232 | − dev_dbg(dev, "%s: Bad context ctxid_src=%llu ctxid_dst=%llu\n", | |
| 1233 | − __func__, ctxid_src, ctxid_dst); | |
| 1234 | − rc = -EINVAL; | |
| 1235 | − goto out; | |
| 1236 | − } | |
| 1237 | − | |
| 1238 | − /* Verify there is no open resource handle in the destination context */ | |
| 1239 | − for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) | |
| 1240 | − if (ctxi_dst->rht_start[i].nmask != 0) { | |
| 1241 | − rc = -EINVAL; | |
| 1242 | − goto out; | |
| 1243 | − } | |
| 1244 | − | |
| 1245 | − /* Clone LUN access list */ | |
| 1246 | − list_for_each_entry(lun_access_src, &ctxi_src->luns, list) { | |
| 1247 | − found = false; | |
| 1248 | − list_for_each_entry(lun_access_dst, &ctxi_dst->luns, list) | |
| 1249 | − if (lun_access_dst->sdev == lun_access_src->sdev) { | |
| 1250 | − found = true; | |
| 1251 | − break; | |
| 1252 | − } | |
| 1253 | − | |
| 1254 | − if (!found) { | |
| 1255 | − lun_access_dst = kzalloc(sizeof(*lun_access_dst), | |
| 1256 | − GFP_KERNEL); | |
| 1257 | − if (unlikely(!lun_access_dst)) { | |
| 1258 | − dev_err(dev, "%s: lun_access allocation fail\n", | |
| 1259 | − __func__); | |
| 1260 | − rc = -ENOMEM; | |
| 1261 | − goto out; | |
| 1262 | − } | |
| 1263 | − | |
| 1264 | − *lun_access_dst = *lun_access_src; | |
| 1265 | − list_add(&lun_access_dst->list, &sidecar); | |
| 1266 | − } | |
| 1267 | − } | |
| 1268 | − | |
| 1269 | − if (unlikely(!ctxi_src->rht_out)) { | |
| 1270 | − dev_dbg(dev, "%s: Nothing to clone\n", __func__); | |
| 1271 | − goto out_success; | |
| 1272 | − } | |
| 1273 | − | |
| 1274 | − /* User specified permission on attach */ | |
| 1275 | − perms = ctxi_dst->rht_perms; | |
| 1276 | − | |
| 1277 | − /* | |
| 1278 | − * Copy over checked-out RHT (and their associated LXT) entries by | |
| 1279 | − * hand, stopping after we've copied all outstanding entries and | |
| 1280 | − * cleaning up if the clone fails. | |
| 1281 | − * | |
| 1282 | − * Note: This loop is equivalent to performing cxlflash_disk_open and | |
| 1283 | − * cxlflash_vlun_resize. As such, LUN accounting needs to be taken into | |
| 1284 | − * account by attaching after each successful RHT entry clone. In the | |
| 1285 | − * event that a clone failure is experienced, the LUN detach is handled | |
| 1286 | − * via the cleanup performed by _cxlflash_disk_release. | |
| 1287 | − */ | |
| 1288 | − for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) { | |
| 1289 | − if (ctxi_src->rht_out == ctxi_dst->rht_out) | |
| 1290 | − break; | |
| 1291 | − if (ctxi_src->rht_start[i].nmask == 0) | |
| 1292 | − continue; | |
| 1293 | − | |
| 1294 | − /* Consume a destination RHT entry */ | |
| 1295 | − ctxi_dst->rht_out++; | |
| 1296 | − ctxi_dst->rht_start[i].nmask = ctxi_src->rht_start[i].nmask; | |
| 1297 | − ctxi_dst->rht_start[i].fp = | |
| 1298 | − SISL_RHT_FP_CLONE(ctxi_src->rht_start[i].fp, perms); | |
| 1299 | − ctxi_dst->rht_lun[i] = ctxi_src->rht_lun[i]; | |
| 1300 | − | |
| 1301 | − rc = clone_lxt(afu, blka, ctxid_dst, i, | |
| 1302 | − &ctxi_dst->rht_start[i], | |
| 1303 | − &ctxi_src->rht_start[i]); | |
| 1304 | − if (rc) { | |
| 1305 | − marshal_clone_to_rele(clone, &release); | |
| 1306 | − for (j = 0; j < i; j++) { | |
| 1307 | − release.rsrc_handle = j; | |
| 1308 | − _cxlflash_disk_release(sdev, ctxi_dst, | |
| 1309 | − &release); | |
| 1310 | − } | |
| 1311 | − | |
| 1312 | − /* Put back the one we failed on */ | |
| 1313 | − rhte_checkin(ctxi_dst, &ctxi_dst->rht_start[i]); | |
| 1314 | − goto err; | |
| 1315 | − } | |
| 1316 | − | |
| 1317 | − cxlflash_lun_attach(gli, gli->mode, false); | |
| 1318 | − } | |
| 1319 | − | |
| 1320 | −out_success: | |
| 1321 | − list_splice(&sidecar, &ctxi_dst->luns); | |
| 1322 | − | |
| 1323 | − /* fall through */ | |
| 1324 | −out: | |
| 1325 | − if (ctxi_src) | |
| 1326 | − put_context(ctxi_src); | |
| 1327 | − if (ctxi_dst) | |
| 1328 | − put_context(ctxi_dst); | |
| 1329 | − dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); | |
| 1330 | − return rc; | |
| 1331 | − | |
| 1332 | −err: | |
| 1333 | − list_for_each_entry_safe(lun_access_src, lun_access_dst, &sidecar, list) | |
| 1334 | − kfree(lun_access_src); | |
| 1335 | − goto out; | |
| 1336 | −} | |
| @@ -1,82 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2015 IBM Corporation | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#ifndef _CXLFLASH_VLUN_H | |
| 12 | −#define _CXLFLASH_VLUN_H | |
| 13 | − | |
| 14 | −/* RHT - Resource Handle Table */ | |
| 15 | −#define MC_RHT_NMASK 16 /* in bits */ | |
| 16 | −#define MC_CHUNK_SHIFT MC_RHT_NMASK /* shift to go from LBA to chunk# */ | |
| 17 | − | |
| 18 | −#define HIBIT (BITS_PER_LONG - 1) | |
| 19 | − | |
| 20 | −#define MAX_AUN_CLONE_CNT 0xFF | |
| 21 | − | |
| 22 | −/* | |
| 23 | − * LXT - LBA Translation Table | |
| 24 | − * | |
| 25 | − * +-------+-------+-------+-------+-------+-------+-------+---+---+ | |
| 26 | − * | RLBA_BASE |LUN_IDX| P |SEL| | |
| 27 | − * +-------+-------+-------+-------+-------+-------+-------+---+---+ | |
| 28 | − * | |
| 29 | − * The LXT Entry contains the physical LBA where the chunk starts (RLBA_BASE). | |
| 30 | − * AFU ORes the low order bits from the virtual LBA (offset into the chunk) | |
| 31 | − * with RLBA_BASE. The result is the physical LBA to be sent to storage. | |
| 32 | − * The LXT Entry also contains an index to a LUN TBL and a bitmask of which | |
| 33 | − * outgoing (FC) * ports can be selected. The port select bit-mask is ANDed | |
| 34 | − * with a global port select bit-mask maintained by the driver. | |
| 35 | − * In addition, it has permission bits that are ANDed with the | |
| 36 | − * RHT permissions to arrive at the final permissions for the chunk. | |
| 37 | − * | |
| 38 | − * LXT tables are allocated dynamically in groups. This is done to avoid | |
| 39 | − * a malloc/free overhead each time the LXT has to grow or shrink. | |
| 40 | − * | |
| 41 | − * Based on the current lxt_cnt (used), it is always possible to know | |
| 42 | − * how many are allocated (used+free). The number of allocated entries is | |
| 43 | − * not stored anywhere. | |
| 44 | − * | |
| 45 | − * The LXT table is re-allocated whenever it needs to cross into another group. | |
| 46 | − */ | |
| 47 | −#define LXT_GROUP_SIZE 8 | |
| 48 | −#define LXT_NUM_GROUPS(lxt_cnt) (((lxt_cnt) + 7)/8) /* alloc'ed groups */ | |
| 49 | −#define LXT_LUNIDX_SHIFT 8 /* LXT entry, shift for LUN index */ | |
| 50 | −#define LXT_PERM_SHIFT 4 /* LXT entry, shift for permission bits */ | |
| 51 | − | |
| 52 | −struct ba_lun_info { | |
| 53 | − u64 *lun_alloc_map; | |
| 54 | − u32 lun_bmap_size; | |
| 55 | − u32 total_aus; | |
| 56 | − u64 free_aun_cnt; | |
| 57 | − | |
| 58 | − /* indices to be used for elevator lookup of free map */ | |
| 59 | − u32 free_low_idx; | |
| 60 | − u32 free_curr_idx; | |
| 61 | − u32 free_high_idx; | |
| 62 | − | |
| 63 | − u8 *aun_clone_map; | |
| 64 | −}; | |
| 65 | − | |
| 66 | −struct ba_lun { | |
| 67 | − u64 lun_id; | |
| 68 | − u64 wwpn; | |
| 69 | − size_t lsize; /* LUN size in number of LBAs */ | |
| 70 | − size_t lba_size; /* LBA size in number of bytes */ | |
| 71 | − size_t au_size; /* Allocation Unit size in number of LBAs */ | |
| 72 | − struct ba_lun_info *ba_lun_handle; | |
| 73 | −}; | |
| 74 | − | |
| 75 | −/* Block Allocator */ | |
| 76 | −struct blka { | |
| 77 | − struct ba_lun ba_lun; | |
| 78 | − u64 nchunk; /* number of chunks */ | |
| 79 | − struct mutex mutex; | |
| 80 | −}; | |
| 81 | − | |
| 82 | −#endif /* ifndef _CXLFLASH_SUPERPIPE_H */ | |
| @@ -735,7 +735,7 @@ efct_pci_io_resume(struct pci_dev *pdev) · 734 unmodified lines | ||
| 735 | 735 | |
| 736 | 736 | MODULE_DEVICE_TABLE(pci, efct_pci_table); |
| 737 | 737 | |
| 738 | −static struct pci_error_handlers efct_pci_err_handler = { | |
| 738 | +static const struct pci_error_handlers efct_pci_err_handler = { | |
| 739 | 739 | .error_detected = efct_pci_io_error_detected, |
| 740 | 740 | .slot_reset = efct_pci_io_slot_reset, |
| 741 | 741 | .resume = efct_pci_io_resume, |
| @@ -308,43 +308,29 @@ void fdls_schedule_oxid_free_retry_work(struct work_struct *work) · 307 unmodified lines | ||
| 308 | 308 | struct fnic *fnic = iport->fnic; |
| 309 | 309 | struct reclaim_entry_s *reclaim_entry; |
| 310 | 310 | unsigned long delay_j = msecs_to_jiffies(OXID_RECLAIM_TOV(iport)); |
| 311 | + unsigned long flags; | |
| 311 | 312 | int idx; |
| 312 | 313 | |
| 313 | − spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); | |
| 314 | − | |
| 315 | 314 | for_each_set_bit(idx, oxid_pool->pending_schedule_free, FNIC_OXID_POOL_SZ) { |
| 316 | 315 | |
| 317 | 316 | FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, |
| 318 | 317 | "Schedule oxid free. oxid idx: %d\n", idx); |
| 319 | 318 | |
| 320 | − spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); | |
| 321 | − reclaim_entry = (struct reclaim_entry_s *) | |
| 322 | − kzalloc(sizeof(struct reclaim_entry_s), GFP_KERNEL); | |
| 323 | − spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); | |
| 324 | − | |
| 319 | + reclaim_entry = kzalloc(sizeof(*reclaim_entry), GFP_KERNEL); | |
| 325 | 320 | if (!reclaim_entry) { |
| 326 | − FNIC_FCS_DBG(KERN_WARNING, fnic->host, fnic->fnic_num, | |
| 327 | − "Failed to allocate memory for reclaim struct for oxid idx: 0x%x\n", | |
| 328 | − idx); | |
| 329 | − | |
| 330 | 321 | schedule_delayed_work(&oxid_pool->schedule_oxid_free_retry, |
| 331 | 322 | msecs_to_jiffies(SCHEDULE_OXID_FREE_RETRY_TIME)); |
| 332 | − spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); | |
| 333 | 323 | return; |
| 334 | 324 | } |
| 335 | 325 | |
| 336 | − if (test_and_clear_bit(idx, oxid_pool->pending_schedule_free)) { | |
| 337 | − reclaim_entry->oxid_idx = idx; | |
| 338 | − reclaim_entry->expires = round_jiffies(jiffies + delay_j); | |
| 339 | − list_add_tail(&reclaim_entry->links, &oxid_pool->oxid_reclaim_list); | |
| 340 | − schedule_delayed_work(&oxid_pool->oxid_reclaim_work, delay_j); | |
| 341 | − } else { | |
| 342 | − /* unlikely scenario, free the allocated memory and continue */ | |
| 343 | − kfree(reclaim_entry); | |
| 344 | − } | |
| 345 | −} | |
| 346 | − | |
| 347 | − spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); | |
| 326 | + clear_bit(idx, oxid_pool->pending_schedule_free); | |
| 327 | + reclaim_entry->oxid_idx = idx; | |
| 328 | + reclaim_entry->expires = round_jiffies(jiffies + delay_j); | |
| 329 | + spin_lock_irqsave(&fnic->fnic_lock, flags); | |
| 330 | + list_add_tail(&reclaim_entry->links, &oxid_pool->oxid_reclaim_list); | |
| 331 | + spin_unlock_irqrestore(&fnic->fnic_lock, flags); | |
| 332 | + schedule_delayed_work(&oxid_pool->oxid_reclaim_work, delay_j); | |
| 333 | + } | |
| 348 | 334 | } |
| 349 | 335 | |
| 350 | 336 | static bool fdls_is_oxid_fabric_req(uint16_t oxid) |
| @@ -1567,9 +1553,9 @@ void fdls_send_fabric_logo(struct fnic_iport_s *iport) · 1216 unmodified lines | ||
| 1567 | 1553 | |
| 1568 | 1554 | iport->fabric.flags &= ~FNIC_FDLS_FABRIC_ABORT_ISSUED; |
| 1569 | 1555 | |
| 1570 | − FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, | |
| 1571 | − "0x%x: FDLS send fabric LOGO with oxid: 0x%x", | |
| 1572 | − iport->fcid, oxid); | |
| 1556 | + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, | |
| 1557 | + "0x%x: FDLS send fabric LOGO with oxid: 0x%x", | |
| 1558 | + iport->fcid, oxid); | |
| 1573 | 1559 | |
| 1574 | 1560 | fnic_send_fcoe_frame(iport, frame, frame_size); |
| 1575 | 1561 | |
| @@ -1898,7 +1884,6 @@ static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) · 322 unmodified lines | ||
| 1898 | 1884 | if (fnic->subsys_desc_len >= FNIC_FDMI_MODEL_LEN) |
| 1899 | 1885 | fnic->subsys_desc_len = FNIC_FDMI_MODEL_LEN - 1; |
| 1900 | 1886 | strscpy_pad(data, fnic->subsys_desc, FNIC_FDMI_MODEL_LEN); |
| 1901 | − data[FNIC_FDMI_MODEL_LEN - 1] = 0; | |
| 1902 | 1887 | fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_MODEL, FNIC_FDMI_MODEL_LEN, |
| 1903 | 1888 | data, &attr_off_bytes); |
| 1904 | 1889 | |
| @@ -2061,7 +2046,6 @@ static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) · 156 unmodified lines | ||
| 2061 | 2046 | snprintf(tmp_data, FNIC_FDMI_OS_NAME_LEN - 1, "host%d", |
| 2062 | 2047 | fnic->host->host_no); |
| 2063 | 2048 | strscpy_pad(data, tmp_data, FNIC_FDMI_OS_NAME_LEN); |
| 2064 | − data[FNIC_FDMI_OS_NAME_LEN - 1] = 0; | |
| 2065 | 2049 | fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_OS_NAME, |
| 2066 | 2050 | FNIC_FDMI_OS_NAME_LEN, data, &attr_off_bytes); |
| 2067 | 2051 | |
| @@ -2071,7 +2055,6 @@ static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) · 3 unmodified lines | ||
| 2071 | 2055 | sprintf(fc_host_system_hostname(fnic->host), "%s", utsname()->nodename); |
| 2072 | 2056 | strscpy_pad(data, fc_host_system_hostname(fnic->host), |
| 2073 | 2057 | FNIC_FDMI_HN_LEN); |
| 2074 | − data[FNIC_FDMI_HN_LEN - 1] = 0; | |
| 2075 | 2058 | fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_HOST_NAME, |
| 2076 | 2059 | FNIC_FDMI_HN_LEN, data, &attr_off_bytes); |
| 2077 | 2060 | |
| @@ -4659,13 +4642,13 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, · 2581 unmodified lines | ||
| 4659 | 4642 | d_id = ntoh24(fchdr->fh_d_id); |
| 4660 | 4643 | |
| 4661 | 4644 | /* some common validation */ |
| 4662 | − if (fdls_get_state(fabric) > FDLS_STATE_FABRIC_FLOGI) { | |
| 4663 | − if ((iport->fcid != d_id) || (!FNIC_FC_FRAME_CS_CTL(fchdr))) { | |
| 4664 | − FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, | |
| 4665 | − "invalid frame received. Dropping frame"); | |
| 4666 | − return -1; | |
| 4667 | − } | |
| 4645 | + if (fdls_get_state(fabric) > FDLS_STATE_FABRIC_FLOGI) { | |
| 4646 | + if (iport->fcid != d_id || (!FNIC_FC_FRAME_CS_CTL(fchdr))) { | |
| 4647 | + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, | |
| 4648 | + "invalid frame received. Dropping frame"); | |
| 4649 | + return -1; | |
| 4668 | 4650 | } |
| 4651 | + } | |
| 4669 | 4652 | |
| 4670 | 4653 | /* BLS ABTS response */ |
| 4671 | 4654 | if ((fchdr->fh_r_ctl == FC_RCTL_BA_ACC) |
| @@ -4682,7 +4665,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, · 10 unmodified lines | ||
| 4682 | 4665 | "Received unexpected ABTS RSP(oxid:0x%x) from 0x%x. Dropping frame", |
| 4683 | 4666 | oxid, s_id); |
| 4684 | 4667 | return -1; |
| 4685 | − } | |
| 4668 | + } | |
| 4686 | 4669 | return FNIC_FABRIC_BLS_ABTS_RSP; |
| 4687 | 4670 | } else if (fdls_is_oxid_fdmi_req(oxid)) { |
| 4688 | 4671 | return FNIC_FDMI_BLS_ABTS_RSP; |
| @@ -1365,10 +1365,9 @@ static void __exit fnic_cleanup_module(void) · 1364 unmodified lines | ||
| 1365 | 1365 | if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON) |
| 1366 | 1366 | destroy_workqueue(reset_fnic_work_queue); |
| 1367 | 1367 | |
| 1368 | − if (fnic_fip_queue) { | |
| 1369 | − flush_workqueue(fnic_fip_queue); | |
| 1368 | + if (fnic_fip_queue) | |
| 1370 | 1369 | destroy_workqueue(fnic_fip_queue); |
| 1371 | − } | |
| 1370 | + | |
| 1372 | 1371 | kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); |
| 1373 | 1372 | kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); |
| 1374 | 1373 | kmem_cache_destroy(fnic_io_req_cache); |
| @@ -633,8 +633,7 @@ extern struct dentry *hisi_sas_debugfs_dir; · 632 unmodified lines | ||
| 633 | 633 | extern void hisi_sas_stop_phys(struct hisi_hba *hisi_hba); |
| 634 | 634 | extern int hisi_sas_alloc(struct hisi_hba *hisi_hba); |
| 635 | 635 | extern void hisi_sas_free(struct hisi_hba *hisi_hba); |
| 636 | −extern u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, | |
| 637 | − int direction); | |
| 636 | +extern u8 hisi_sas_get_ata_protocol(struct sas_task *task); | |
| 638 | 637 | extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port); |
| 639 | 638 | extern void hisi_sas_sata_done(struct sas_task *task, |
| 640 | 639 | struct hisi_sas_slot *slot); |
| @@ -21,8 +21,32 @@ struct hisi_sas_internal_abort_data { · 20 unmodified lines | ||
| 21 | 21 | bool rst_ha_timeout; /* reset the HA for timeout */ |
| 22 | 22 | }; |
| 23 | 23 | |
| 24 | −u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) | |
| 24 | +static u8 hisi_sas_get_ata_protocol_from_tf(struct ata_queued_cmd *qc) | |
| 25 | 25 | { |
| 26 | + if (!qc) | |
| 27 | + return HISI_SAS_SATA_PROTOCOL_PIO; | |
| 28 | + | |
| 29 | + switch (qc->tf.protocol) { | |
| 30 | + case ATA_PROT_NODATA: | |
| 31 | + return HISI_SAS_SATA_PROTOCOL_NONDATA; | |
| 32 | + case ATA_PROT_PIO: | |
| 33 | + return HISI_SAS_SATA_PROTOCOL_PIO; | |
| 34 | + case ATA_PROT_DMA: | |
| 35 | + return HISI_SAS_SATA_PROTOCOL_DMA; | |
| 36 | + case ATA_PROT_NCQ_NODATA: | |
| 37 | + case ATA_PROT_NCQ: | |
| 38 | + return HISI_SAS_SATA_PROTOCOL_FPDMA; | |
| 39 | + default: | |
| 40 | + return HISI_SAS_SATA_PROTOCOL_PIO; | |
| 41 | + } | |
| 42 | +} | |
| 43 | + | |
| 44 | +u8 hisi_sas_get_ata_protocol(struct sas_task *task) | |
| 45 | +{ | |
| 46 | + struct host_to_dev_fis *fis = &task->ata_task.fis; | |
| 47 | + struct ata_queued_cmd *qc = task->uldd_task; | |
| 48 | + int direction = task->data_dir; | |
| 49 | + | |
| 26 | 50 | switch (fis->command) { |
| 27 | 51 | case ATA_CMD_FPDMA_WRITE: |
| 28 | 52 | case ATA_CMD_FPDMA_READ: |
| @@ -93,7 +117,7 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) · 64 unmodified lines | ||
| 93 | 117 | { |
| 94 | 118 | if (direction == DMA_NONE) |
| 95 | 119 | return HISI_SAS_SATA_PROTOCOL_NONDATA; |
| 96 | − return HISI_SAS_SATA_PROTOCOL_PIO; | |
| 120 | + return hisi_sas_get_ata_protocol_from_tf(qc); | |
| 97 | 121 | } |
| 98 | 122 | } |
| 99 | 123 | } |
| @@ -1806,7 +1806,7 @@ static struct platform_driver hisi_sas_v1_driver = { · 1805 unmodified lines | ||
| 1806 | 1806 | .driver = { |
| 1807 | 1807 | .name = DRV_NAME, |
| 1808 | 1808 | .of_match_table = sas_v1_of_match, |
| 1809 | − .acpi_match_table = ACPI_PTR(sas_v1_acpi_match), | |
| 1809 | + .acpi_match_table = sas_v1_acpi_match, | |
| 1810 | 1810 | }, |
| 1811 | 1811 | }; |
| 1812 | 1812 | |
| @@ -2538,9 +2538,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, · 2537 unmodified lines | ||
| 2538 | 2538 | (task->ata_task.fis.control & ATA_SRST)) |
| 2539 | 2539 | dw1 |= 1 << CMD_HDR_RESET_OFF; |
| 2540 | 2540 | |
| 2541 | − dw1 |= (hisi_sas_get_ata_protocol( | |
| 2542 | − &task->ata_task.fis, task->data_dir)) | |
| 2543 | − << CMD_HDR_FRAME_TYPE_OFF; | |
| 2541 | + dw1 |= (hisi_sas_get_ata_protocol(task)) << CMD_HDR_FRAME_TYPE_OFF; | |
| 2544 | 2542 | dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; |
| 2545 | 2543 | hdr->dw1 = cpu_to_le32(dw1); |
| 2546 | 2544 | |
| @@ -3653,7 +3651,7 @@ static struct platform_driver hisi_sas_v2_driver = { · 1106 unmodified lines | ||
| 3653 | 3651 | .driver = { |
| 3654 | 3652 | .name = DRV_NAME, |
| 3655 | 3653 | .of_match_table = sas_v2_of_match, |
| 3656 | − .acpi_match_table = ACPI_PTR(sas_v2_acpi_match), | |
| 3654 | + .acpi_match_table = sas_v2_acpi_match, | |
| 3657 | 3655 | }, |
| 3658 | 3656 | }; |
| 3659 | 3657 | |
| @@ -1456,9 +1456,7 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, · 1455 unmodified lines | ||
| 1456 | 1456 | (task->ata_task.fis.control & ATA_SRST)) |
| 1457 | 1457 | dw1 |= 1 << CMD_HDR_RESET_OFF; |
| 1458 | 1458 | |
| 1459 | − dw1 |= (hisi_sas_get_ata_protocol( | |
| 1460 | − &task->ata_task.fis, task->data_dir)) | |
| 1461 | − << CMD_HDR_FRAME_TYPE_OFF; | |
| 1459 | + dw1 |= (hisi_sas_get_ata_protocol(task)) << CMD_HDR_FRAME_TYPE_OFF; | |
| 1462 | 1460 | dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; |
| 1463 | 1461 | |
| 1464 | 1462 | if (FIS_CMD_IS_UNCONSTRAINED(task->ata_task.fis)) |
| @@ -453,17 +453,13 @@ static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev, · 452 unmodified lines | ||
| 453 | 453 | struct device_attribute *attr, |
| 454 | 454 | const char *buf, size_t count) |
| 455 | 455 | { |
| 456 | − int status, len; | |
| 456 | + int status; | |
| 457 | 457 | struct ctlr_info *h; |
| 458 | 458 | struct Scsi_Host *shost = class_to_shost(dev); |
| 459 | − char tmpbuf[10]; | |
| 460 | 459 | |
| 461 | 460 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) |
| 462 | 461 | return -EACCES; |
| 463 | − len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; | |
| 464 | − strncpy(tmpbuf, buf, len); | |
| 465 | − tmpbuf[len] = '\0'; | |
| 466 | − if (sscanf(tmpbuf, "%d", &status) != 1) | |
| 462 | + if (kstrtoint(buf, 10, &status)) | |
| 467 | 463 | return -EINVAL; |
| 468 | 464 | h = shost_to_hba(shost); |
| 469 | 465 | h->acciopath_status = !!status; |
| @@ -477,17 +473,13 @@ static ssize_t host_store_raid_offload_debug(struct device *dev, · 7 unmodified lines | ||
| 477 | 473 | struct device_attribute *attr, |
| 478 | 474 | const char *buf, size_t count) |
| 479 | 475 | { |
| 480 | − int debug_level, len; | |
| 476 | + int debug_level; | |
| 481 | 477 | struct ctlr_info *h; |
| 482 | 478 | struct Scsi_Host *shost = class_to_shost(dev); |
| 483 | − char tmpbuf[10]; | |
| 484 | 479 | |
| 485 | 480 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) |
| 486 | 481 | return -EACCES; |
| 487 | − len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count; | |
| 488 | − strncpy(tmpbuf, buf, len); | |
| 489 | − tmpbuf[len] = '\0'; | |
| 490 | − if (sscanf(tmpbuf, "%d", &debug_level) != 1) | |
| 482 | + if (kstrtoint(buf, 10, &debug_level)) | |
| 491 | 483 | return -EINVAL; |
| 492 | 484 | if (debug_level < 0) |
| 493 | 485 | debug_level = 0; |
| @@ -7238,8 +7230,7 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, · 6744 unmodified lines | ||
| 7238 | 7230 | |
| 7239 | 7231 | static void init_driver_version(char *driver_version, int len) |
| 7240 | 7232 | { |
| 7241 | − memset(driver_version, 0, len); | |
| 7242 | − strncpy(driver_version, HPSA " " HPSA_DRIVER_VERSION, len - 1); | |
| 7233 | + strscpy_pad(driver_version, HPSA " " HPSA_DRIVER_VERSION, len); | |
| 7243 | 7234 | } |
| 7244 | 7235 | |
| 7245 | 7236 | static int write_driver_ver_to_cfgtable(struct CfgTable __iomem *cfgtable) |
| @@ -3631,8 +3631,8 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) · 3630 unmodified lines | ||
| 3631 | 3631 | |
| 3632 | 3632 | break; |
| 3633 | 3633 | |
| 3634 | − case RESERVE: | |
| 3635 | − case RELEASE: | |
| 3634 | + case RESERVE_6: | |
| 3635 | + case RELEASE_6: | |
| 3636 | 3636 | scb->scsi_cmd->result = DID_OK << 16; |
| 3637 | 3637 | break; |
| 3638 | 3638 | |
| @@ -3899,8 +3899,8 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus) · 260 unmodified lines | ||
| 3899 | 3899 | case WRITE_6: |
| 3900 | 3900 | case READ_10: |
| 3901 | 3901 | case WRITE_10: |
| 3902 | − case RESERVE: | |
| 3903 | − case RELEASE: | |
| 3902 | + case RESERVE_6: | |
| 3903 | + case RELEASE_6: | |
| 3904 | 3904 | break; |
| 3905 | 3905 | |
| 3906 | 3906 | case MODE_SENSE: |
| @@ -91,31 +91,31 @@ MODULE_DEVICE_TABLE(pci, isci_id_table); · 90 unmodified lines | ||
| 91 | 91 | |
| 92 | 92 | /* linux isci specific settings */ |
| 93 | 93 | |
| 94 | −unsigned char no_outbound_task_to = 2; | |
| 94 | +static unsigned char no_outbound_task_to = 2; | |
| 95 | 95 | module_param(no_outbound_task_to, byte, 0); |
| 96 | 96 | MODULE_PARM_DESC(no_outbound_task_to, "No Outbound Task Timeout (1us incr)"); |
| 97 | 97 | |
| 98 | −u16 ssp_max_occ_to = 20; | |
| 98 | +static u16 ssp_max_occ_to = 20; | |
| 99 | 99 | module_param(ssp_max_occ_to, ushort, 0); |
| 100 | 100 | MODULE_PARM_DESC(ssp_max_occ_to, "SSP Max occupancy timeout (100us incr)"); |
| 101 | 101 | |
| 102 | −u16 stp_max_occ_to = 5; | |
| 102 | +static u16 stp_max_occ_to = 5; | |
| 103 | 103 | module_param(stp_max_occ_to, ushort, 0); |
| 104 | 104 | MODULE_PARM_DESC(stp_max_occ_to, "STP Max occupancy timeout (100us incr)"); |
| 105 | 105 | |
| 106 | −u16 ssp_inactive_to = 5; | |
| 106 | +static u16 ssp_inactive_to = 5; | |
| 107 | 107 | module_param(ssp_inactive_to, ushort, 0); |
| 108 | 108 | MODULE_PARM_DESC(ssp_inactive_to, "SSP inactivity timeout (100us incr)"); |
| 109 | 109 | |
| 110 | −u16 stp_inactive_to = 5; | |
| 110 | +static u16 stp_inactive_to = 5; | |
| 111 | 111 | module_param(stp_inactive_to, ushort, 0); |
| 112 | 112 | MODULE_PARM_DESC(stp_inactive_to, "STP inactivity timeout (100us incr)"); |
| 113 | 113 | |
| 114 | −unsigned char phy_gen = SCIC_SDS_PARM_GEN2_SPEED; | |
| 114 | +static unsigned char phy_gen = SCIC_SDS_PARM_GEN2_SPEED; | |
| 115 | 115 | module_param(phy_gen, byte, 0); |
| 116 | 116 | MODULE_PARM_DESC(phy_gen, "PHY generation (1: 1.5Gbps 2: 3.0Gbps 3: 6.0Gbps)"); |
| 117 | 117 | |
| 118 | −unsigned char max_concurr_spinup; | |
| 118 | +static unsigned char max_concurr_spinup; | |
| 119 | 119 | module_param(max_concurr_spinup, byte, 0); |
| 120 | 120 | MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup"); |
| 121 | 121 | |
| @@ -473,13 +473,6 @@ static inline void sci_swab32_cpy(void *_dest, void *_src, ssize_t word_cnt) · 472 unmodified lines | ||
| 473 | 473 | dest[word_cnt] = swab32(src[word_cnt]); |
| 474 | 474 | } |
| 475 | 475 | |
| 476 | −extern unsigned char no_outbound_task_to; | |
| 477 | −extern u16 ssp_max_occ_to; | |
| 478 | −extern u16 stp_max_occ_to; | |
| 479 | −extern u16 ssp_inactive_to; | |
| 480 | −extern u16 stp_inactive_to; | |
| 481 | −extern unsigned char phy_gen; | |
| 482 | −extern unsigned char max_concurr_spinup; | |
| 483 | 476 | extern uint cable_selection_override; |
| 484 | 477 | |
| 485 | 478 | irqreturn_t isci_msix_isr(int vec, void *data); |
| @@ -198,7 +198,7 @@ enum sci_status sci_remote_device_reset( · 197 unmodified lines | ||
| 198 | 198 | * device. When there are no active IO for the device it is is in this |
| 199 | 199 | * state. |
| 200 | 200 | * |
| 201 | − * @SCI_STP_DEV_CMD: This is the command state for for the STP remote | |
| 201 | + * @SCI_STP_DEV_CMD: This is the command state for the STP remote | |
| 202 | 202 | * device. This state is entered when the device is processing a |
| 203 | 203 | * non-NCQ command. The device object will fail any new start IO |
| 204 | 204 | * requests until this command is complete. |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | * Zhenyu Wang |
| 18 | 18 | */ |
| 19 | 19 | |
| 20 | −#include <crypto/hash.h> | |
| 21 | 20 | #include <linux/types.h> |
| 22 | 21 | #include <linux/inet.h> |
| 23 | 22 | #include <linux/slab.h> |
| @@ -468,8 +467,7 @@ static void iscsi_sw_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, · 444 unmodified lines | ||
| 468 | 467 | * sufficient room. |
| 469 | 468 | */ |
| 470 | 469 | if (conn->hdrdgst_en) { |
| 471 | − iscsi_tcp_dgst_header(tcp_sw_conn->tx_hash, hdr, hdrlen, | |
| 472 | − hdr + hdrlen); | |
| 470 | + iscsi_tcp_dgst_header(hdr, hdrlen, hdr + hdrlen); | |
| 473 | 471 | hdrlen += ISCSI_DIGEST_SIZE; |
| 474 | 472 | } |
| 475 | 473 | |
| @@ -494,7 +492,7 @@ iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, · 18 unmodified lines | ||
| 494 | 492 | { |
| 495 | 493 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
| 496 | 494 | struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
| 497 | − struct ahash_request *tx_hash = NULL; | |
| 495 | + u32 *tx_crcp = NULL; | |
| 498 | 496 | unsigned int hdr_spec_len; |
| 499 | 497 | |
| 500 | 498 | ISCSI_SW_TCP_DBG(conn, "offset=%d, datalen=%d %s\n", offset, len, |
| @@ -507,11 +505,10 @@ iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, · 6 unmodified lines | ||
| 507 | 505 | WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); |
| 508 | 506 | |
| 509 | 507 | if (conn->datadgst_en) |
| 510 | − tx_hash = tcp_sw_conn->tx_hash; | |
| 508 | + tx_crcp = &tcp_sw_conn->tx_crc; | |
| 511 | 509 | |
| 512 | 510 | return iscsi_segment_seek_sg(&tcp_sw_conn->out.data_segment, |
| 513 | − sg, count, offset, len, | |
| 514 | − NULL, tx_hash); | |
| 511 | + sg, count, offset, len, NULL, tx_crcp); | |
| 515 | 512 | } |
| 516 | 513 | |
| 517 | 514 | static void |
| @@ -520,7 +517,7 @@ iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data, · 2 unmodified lines | ||
| 520 | 517 | { |
| 521 | 518 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
| 522 | 519 | struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
| 523 | − struct ahash_request *tx_hash = NULL; | |
| 520 | + u32 *tx_crcp = NULL; | |
| 524 | 521 | unsigned int hdr_spec_len; |
| 525 | 522 | |
| 526 | 523 | ISCSI_SW_TCP_DBG(conn, "datalen=%zd %s\n", len, conn->datadgst_en ? |
| @@ -532,10 +529,10 @@ iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data, · 5 unmodified lines | ||
| 532 | 529 | WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); |
| 533 | 530 | |
| 534 | 531 | if (conn->datadgst_en) |
| 535 | − tx_hash = tcp_sw_conn->tx_hash; | |
| 532 | + tx_crcp = &tcp_sw_conn->tx_crc; | |
| 536 | 533 | |
| 537 | 534 | iscsi_segment_init_linear(&tcp_sw_conn->out.data_segment, |
| 538 | − data, len, NULL, tx_hash); | |
| 535 | + data, len, NULL, tx_crcp); | |
| 539 | 536 | } |
| 540 | 537 | |
| 541 | 538 | static int iscsi_sw_tcp_pdu_init(struct iscsi_task *task, |
| @@ -583,7 +580,6 @@ iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session, · 41 unmodified lines | ||
| 583 | 580 | struct iscsi_cls_conn *cls_conn; |
| 584 | 581 | struct iscsi_tcp_conn *tcp_conn; |
| 585 | 582 | struct iscsi_sw_tcp_conn *tcp_sw_conn; |
| 586 | − struct crypto_ahash *tfm; | |
| 587 | 583 | |
| 588 | 584 | cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*tcp_sw_conn), |
| 589 | 585 | conn_idx); |
| @@ -596,37 +592,9 @@ iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session, · 6 unmodified lines | ||
| 596 | 592 | tcp_sw_conn->queue_recv = iscsi_recv_from_iscsi_q; |
| 597 | 593 | |
| 598 | 594 | mutex_init(&tcp_sw_conn->sock_lock); |
| 599 | − | |
| 600 | − tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC); | |
| 601 | − if (IS_ERR(tfm)) | |
| 602 | − goto free_conn; | |
| 603 | − | |
| 604 | − tcp_sw_conn->tx_hash = ahash_request_alloc(tfm, GFP_KERNEL); | |
| 605 | − if (!tcp_sw_conn->tx_hash) | |
| 606 | − goto free_tfm; | |
| 607 | − ahash_request_set_callback(tcp_sw_conn->tx_hash, 0, NULL, NULL); | |
| 608 | − | |
| 609 | − tcp_sw_conn->rx_hash = ahash_request_alloc(tfm, GFP_KERNEL); | |
| 610 | − if (!tcp_sw_conn->rx_hash) | |
| 611 | − goto free_tx_hash; | |
| 612 | − ahash_request_set_callback(tcp_sw_conn->rx_hash, 0, NULL, NULL); | |
| 613 | − | |
| 614 | − tcp_conn->rx_hash = tcp_sw_conn->rx_hash; | |
| 595 | + tcp_conn->rx_crcp = &tcp_sw_conn->rx_crc; | |
| 615 | 596 | |
| 616 | 597 | return cls_conn; |
| 617 | − | |
| 618 | −free_tx_hash: | |
| 619 | − ahash_request_free(tcp_sw_conn->tx_hash); | |
| 620 | −free_tfm: | |
| 621 | − crypto_free_ahash(tfm); | |
| 622 | −free_conn: | |
| 623 | − iscsi_conn_printk(KERN_ERR, conn, | |
| 624 | − "Could not create connection due to crc32c " | |
| 625 | − "loading error. Make sure the crc32c " | |
| 626 | − "module is built as a module or into the " | |
| 627 | − "kernel\n"); | |
| 628 | − iscsi_tcp_conn_teardown(cls_conn); | |
| 629 | − return NULL; | |
| 630 | 598 | } |
| 631 | 599 | |
| 632 | 600 | static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn) |
| @@ -664,20 +632,8 @@ static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn) · 31 unmodified lines | ||
| 664 | 632 | static void iscsi_sw_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) |
| 665 | 633 | { |
| 666 | 634 | struct iscsi_conn *conn = cls_conn->dd_data; |
| 667 | − struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | |
| 668 | − struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; | |
| 669 | 635 | |
| 670 | 636 | iscsi_sw_tcp_release_conn(conn); |
| 671 | − | |
| 672 | − ahash_request_free(tcp_sw_conn->rx_hash); | |
| 673 | − if (tcp_sw_conn->tx_hash) { | |
| 674 | − struct crypto_ahash *tfm; | |
| 675 | − | |
| 676 | − tfm = crypto_ahash_reqtfm(tcp_sw_conn->tx_hash); | |
| 677 | − ahash_request_free(tcp_sw_conn->tx_hash); | |
| 678 | − crypto_free_ahash(tfm); | |
| 679 | − } | |
| 680 | − | |
| 681 | 637 | iscsi_tcp_conn_teardown(cls_conn); |
| 682 | 638 | } |
| 683 | 639 | |
| @@ -41,8 +41,8 @@ struct iscsi_sw_tcp_conn { · 40 unmodified lines | ||
| 41 | 41 | void (*old_write_space)(struct sock *); |
| 42 | 42 | |
| 43 | 43 | /* data and header digests */ |
| 44 | − struct ahash_request *tx_hash; /* CRC32C (Tx) */ | |
| 45 | − struct ahash_request *rx_hash; /* CRC32C (Rx) */ | |
| 44 | + u32 tx_crc; /* CRC32C (Tx) */ | |
| 45 | + u32 rx_crc; /* CRC32C (Rx) */ | |
| 46 | 46 | |
| 47 | 47 | /* MIB custom statistics */ |
| 48 | 48 | uint32_t sendpage_failures_cnt; |
| @@ -15,7 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | * Zhenyu Wang |
| 16 | 16 | */ |
| 17 | 17 | |
| 18 | −#include <crypto/hash.h> | |
| 18 | +#include <linux/crc32c.h> | |
| 19 | 19 | #include <linux/types.h> |
| 20 | 20 | #include <linux/list.h> |
| 21 | 21 | #include <linux/inet.h> |
| @@ -168,7 +168,7 @@ iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest) · 146 unmodified lines | ||
| 168 | 168 | segment->size = ISCSI_DIGEST_SIZE; |
| 169 | 169 | segment->copied = 0; |
| 170 | 170 | segment->sg = NULL; |
| 171 | − segment->hash = NULL; | |
| 171 | + segment->crcp = NULL; | |
| 172 | 172 | } |
| 173 | 173 | |
| 174 | 174 | /** |
| @@ -191,29 +191,27 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, · 16 unmodified lines | ||
| 191 | 191 | struct iscsi_segment *segment, int recv, |
| 192 | 192 | unsigned copied) |
| 193 | 193 | { |
| 194 | − struct scatterlist sg; | |
| 195 | 194 | unsigned int pad; |
| 196 | 195 | |
| 197 | 196 | ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copied %u %u size %u %s\n", |
| 198 | 197 | segment->copied, copied, segment->size, |
| 199 | 198 | recv ? "recv" : "xmit"); |
| 200 | − if (segment->hash && copied) { | |
| 201 | − /* | |
| 202 | − * If a segment is kmapd we must unmap it before sending | |
| 203 | − * to the crypto layer since that will try to kmap it again. | |
| 204 | − */ | |
| 205 | − iscsi_tcp_segment_unmap(segment); | |
| 206 | − | |
| 207 | − if (!segment->data) { | |
| 208 | − sg_init_table(&sg, 1); | |
| 209 | − sg_set_page(&sg, sg_page(segment->sg), copied, | |
| 210 | − segment->copied + segment->sg_offset + | |
| 211 | − segment->sg->offset); | |
| 212 | − } else | |
| 213 | − sg_init_one(&sg, segment->data + segment->copied, | |
| 214 | − copied); | |
| 215 | − ahash_request_set_crypt(segment->hash, &sg, NULL, copied); | |
| 216 | − crypto_ahash_update(segment->hash); | |
| 199 | + if (segment->crcp && copied) { | |
| 200 | + if (segment->data) { | |
| 201 | + *segment->crcp = crc32c(*segment->crcp, | |
| 202 | + segment->data + segment->copied, | |
| 203 | + copied); | |
| 204 | + } else { | |
| 205 | + const void *data; | |
| 206 | + | |
| 207 | + data = kmap_local_page(sg_page(segment->sg)); | |
| 208 | + *segment->crcp = crc32c(*segment->crcp, | |
| 209 | + data + segment->copied + | |
| 210 | + segment->sg_offset + | |
| 211 | + segment->sg->offset, | |
| 212 | + copied); | |
| 213 | + kunmap_local(data); | |
| 214 | + } | |
| 217 | 215 | } |
| 218 | 216 | |
| 219 | 217 | segment->copied += copied; |
| @@ -258,10 +256,8 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, · 38 unmodified lines | ||
| 258 | 256 | * Set us up for transferring the data digest. hdr digest |
| 259 | 257 | * is completely handled in hdr done function. |
| 260 | 258 | */ |
| 261 | − if (segment->hash) { | |
| 262 | − ahash_request_set_crypt(segment->hash, NULL, | |
| 263 | − segment->digest, 0); | |
| 264 | − crypto_ahash_final(segment->hash); | |
| 259 | + if (segment->crcp) { | |
| 260 | + put_unaligned_le32(~*segment->crcp, segment->digest); | |
| 265 | 261 | iscsi_tcp_segment_splice_digest(segment, |
| 266 | 262 | recv ? segment->recv_digest : segment->digest); |
| 267 | 263 | return 0; |
| @@ -282,8 +278,7 @@ EXPORT_SYMBOL_GPL(iscsi_tcp_segment_done); · 14 unmodified lines | ||
| 282 | 278 | * given buffer, and returns the number of bytes |
| 283 | 279 | * consumed, which can actually be less than @len. |
| 284 | 280 | * |
| 285 | − * If hash digest is enabled, the function will update the | |
| 286 | − * hash while copying. | |
| 281 | + * If CRC is enabled, the function will update the CRC while copying. | |
| 287 | 282 | * Combining these two operations doesn't buy us a lot (yet), |
| 288 | 283 | * but in the future we could implement combined copy+crc, |
| 289 | 284 | * just way we do for network layer checksums. |
| @@ -311,14 +306,10 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn, · 21 unmodified lines | ||
| 311 | 306 | } |
| 312 | 307 | |
| 313 | 308 | inline void |
| 314 | −iscsi_tcp_dgst_header(struct ahash_request *hash, const void *hdr, | |
| 315 | − size_t hdrlen, unsigned char digest[ISCSI_DIGEST_SIZE]) | |
| 309 | +iscsi_tcp_dgst_header(const void *hdr, size_t hdrlen, | |
| 310 | + unsigned char digest[ISCSI_DIGEST_SIZE]) | |
| 316 | 311 | { |
| 317 | − struct scatterlist sg; | |
| 318 | − | |
| 319 | − sg_init_one(&sg, hdr, hdrlen); | |
| 320 | − ahash_request_set_crypt(hash, &sg, digest, hdrlen); | |
| 321 | − crypto_ahash_digest(hash); | |
| 312 | + put_unaligned_le32(~crc32c(~0, hdr, hdrlen), digest); | |
| 322 | 313 | } |
| 323 | 314 | EXPORT_SYMBOL_GPL(iscsi_tcp_dgst_header); |
| 324 | 315 | |
| @@ -343,24 +334,23 @@ iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn, · 18 unmodified lines | ||
| 343 | 334 | */ |
| 344 | 335 | static inline void |
| 345 | 336 | __iscsi_segment_init(struct iscsi_segment *segment, size_t size, |
| 346 | − iscsi_segment_done_fn_t *done, struct ahash_request *hash) | |
| 337 | + iscsi_segment_done_fn_t *done, u32 *crcp) | |
| 347 | 338 | { |
| 348 | 339 | memset(segment, 0, sizeof(*segment)); |
| 349 | 340 | segment->total_size = size; |
| 350 | 341 | segment->done = done; |
| 351 | 342 | |
| 352 | − if (hash) { | |
| 353 | − segment->hash = hash; | |
| 354 | − crypto_ahash_init(hash); | |
| 343 | + if (crcp) { | |
| 344 | + segment->crcp = crcp; | |
| 345 | + *crcp = ~0; | |
| 355 | 346 | } |
| 356 | 347 | } |
| 357 | 348 | |
| 358 | 349 | inline void |
| 359 | 350 | iscsi_segment_init_linear(struct iscsi_segment *segment, void *data, |
| 360 | − size_t size, iscsi_segment_done_fn_t *done, | |
| 361 | − struct ahash_request *hash) | |
| 351 | + size_t size, iscsi_segment_done_fn_t *done, u32 *crcp) | |
| 362 | 352 | { |
| 363 | − __iscsi_segment_init(segment, size, done, hash); | |
| 353 | + __iscsi_segment_init(segment, size, done, crcp); | |
| 364 | 354 | segment->data = data; |
| 365 | 355 | segment->size = size; |
| 366 | 356 | } |
| @@ -370,13 +360,12 @@ inline int · 3 unmodified lines | ||
| 370 | 360 | iscsi_segment_seek_sg(struct iscsi_segment *segment, |
| 371 | 361 | struct scatterlist *sg_list, unsigned int sg_count, |
| 372 | 362 | unsigned int offset, size_t size, |
| 373 | − iscsi_segment_done_fn_t *done, | |
| 374 | − struct ahash_request *hash) | |
| 363 | + iscsi_segment_done_fn_t *done, u32 *crcp) | |
| 375 | 364 | { |
| 376 | 365 | struct scatterlist *sg; |
| 377 | 366 | unsigned int i; |
| 378 | 367 | |
| 379 | − __iscsi_segment_init(segment, size, done, hash); | |
| 368 | + __iscsi_segment_init(segment, size, done, crcp); | |
| 380 | 369 | for_each_sg(sg_list, sg, sg_count, i) { |
| 381 | 370 | if (offset < sg->length) { |
| 382 | 371 | iscsi_tcp_segment_init_sg(segment, sg, offset); |
| @@ -393,7 +382,7 @@ EXPORT_SYMBOL_GPL(iscsi_segment_seek_sg); · 10 unmodified lines | ||
| 393 | 382 | * iscsi_tcp_hdr_recv_prep - prep segment for hdr reception |
| 394 | 383 | * @tcp_conn: iscsi connection to prep for |
| 395 | 384 | * |
| 396 | − * This function always passes NULL for the hash argument, because when this | |
| 385 | + * This function always passes NULL for the crcp argument, because when this | |
| 397 | 386 | * function is called we do not yet know the final size of the header and want |
| 398 | 387 | * to delay the digest processing until we know that. |
| 399 | 388 | */ |
| @@ -434,15 +423,15 @@ static void · 34 unmodified lines | ||
| 434 | 423 | iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn) |
| 435 | 424 | { |
| 436 | 425 | struct iscsi_conn *conn = tcp_conn->iscsi_conn; |
| 437 | − struct ahash_request *rx_hash = NULL; | |
| 426 | + u32 *rx_crcp = NULL; | |
| 438 | 427 | |
| 439 | 428 | if (conn->datadgst_en && |
| 440 | 429 | !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) |
| 441 | − rx_hash = tcp_conn->rx_hash; | |
| 430 | + rx_crcp = tcp_conn->rx_crcp; | |
| 442 | 431 | |
| 443 | 432 | iscsi_segment_init_linear(&tcp_conn->in.segment, |
| 444 | 433 | conn->data, tcp_conn->in.datalen, |
| 445 | − iscsi_tcp_data_recv_done, rx_hash); | |
| 434 | + iscsi_tcp_data_recv_done, rx_crcp); | |
| 446 | 435 | } |
| 447 | 436 | |
| 448 | 437 | /** |
| @@ -730,7 +719,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) · 281 unmodified lines | ||
| 730 | 719 | |
| 731 | 720 | if (tcp_conn->in.datalen) { |
| 732 | 721 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
| 733 | − struct ahash_request *rx_hash = NULL; | |
| 722 | + u32 *rx_crcp = NULL; | |
| 734 | 723 | struct scsi_data_buffer *sdb = &task->sc->sdb; |
| 735 | 724 | |
| 736 | 725 | /* |
| @@ -743,7 +732,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) · 6 unmodified lines | ||
| 743 | 732 | */ |
| 744 | 733 | if (conn->datadgst_en && |
| 745 | 734 | !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) |
| 746 | − rx_hash = tcp_conn->rx_hash; | |
| 735 | + rx_crcp = tcp_conn->rx_crcp; | |
| 747 | 736 | |
| 748 | 737 | ISCSI_DBG_TCP(conn, "iscsi_tcp_begin_data_in( " |
| 749 | 738 | "offset=%d, datalen=%d)\n", |
| @@ -756,7 +745,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) · 6 unmodified lines | ||
| 756 | 745 | tcp_task->data_offset, |
| 757 | 746 | tcp_conn->in.datalen, |
| 758 | 747 | iscsi_tcp_process_data_in, |
| 759 | − rx_hash); | |
| 748 | + rx_crcp); | |
| 760 | 749 | spin_unlock(&conn->session->back_lock); |
| 761 | 750 | return rc; |
| 762 | 751 | } |
| @@ -878,7 +867,7 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, · 115 unmodified lines | ||
| 878 | 867 | return 0; |
| 879 | 868 | } |
| 880 | 869 | |
| 881 | − iscsi_tcp_dgst_header(tcp_conn->rx_hash, hdr, | |
| 870 | + iscsi_tcp_dgst_header(hdr, | |
| 882 | 871 | segment->total_copied - ISCSI_DIGEST_SIZE, |
| 883 | 872 | segment->digest); |
| 884 | 873 | |
| @@ -74,8 +74,7 @@ struct lpfc_sli2_slim; · 73 unmodified lines | ||
| 74 | 74 | * queue depths when there are driver resource error or Firmware |
| 75 | 75 | * resource error. |
| 76 | 76 | */ |
| 77 | −/* 1 Second */ | |
| 78 | −#define QUEUE_RAMP_DOWN_INTERVAL (msecs_to_jiffies(1000 * 1)) | |
| 77 | +#define QUEUE_RAMP_DOWN_INTERVAL (secs_to_jiffies(1)) | |
| 79 | 78 | |
| 80 | 79 | /* Number of exchanges reserved for discovery to complete */ |
| 81 | 80 | #define LPFC_DISC_IOCB_BUFF_COUNT 20 |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | /******************************************************************* |
| 2 | 2 | * This file is part of the Emulex Linux Device Driver for * |
| 3 | 3 | * Fibre Channel Host Bus Adapters. * |
| 4 | − * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * | |
| 4 | + * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * | |
| 5 | 5 | * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * |
| 6 | 6 | * Copyright (C) 2004-2016 Emulex. All rights reserved. * |
| 7 | 7 | * EMULEX and SLI are trademarks of Emulex. * |
| @@ -8045,8 +8045,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, · 8037 unmodified lines | ||
| 8045 | 8045 | if (test_bit(FC_DISC_TMO, &vport->fc_flag)) { |
| 8046 | 8046 | tmo = ((phba->fc_ratov * 3) + 3); |
| 8047 | 8047 | mod_timer(&vport->fc_disctmo, |
| 8048 | − jiffies + | |
| 8049 | − msecs_to_jiffies(1000 * tmo)); | |
| 8048 | + jiffies + secs_to_jiffies(tmo)); | |
| 8050 | 8049 | } |
| 8051 | 8050 | return 0; |
| 8052 | 8051 | } |
| @@ -8081,7 +8080,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, · 28 unmodified lines | ||
| 8081 | 8080 | if (test_bit(FC_DISC_TMO, &vport->fc_flag)) { |
| 8082 | 8081 | tmo = ((phba->fc_ratov * 3) + 3); |
| 8083 | 8082 | mod_timer(&vport->fc_disctmo, |
| 8084 | − jiffies + msecs_to_jiffies(1000 * tmo)); | |
| 8083 | + jiffies + secs_to_jiffies(tmo)); | |
| 8085 | 8084 | } |
| 8086 | 8085 | if ((rscn_cnt < FC_MAX_HOLD_RSCN) && |
| 8087 | 8086 | !test_bit(FC_RSCN_DISCOVERY, &vport->fc_flag)) { |
| @@ -9511,7 +9510,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) · 1423 unmodified lines | ||
| 9511 | 9510 | if (!list_empty(&pring->txcmplq)) |
| 9512 | 9511 | if (!test_bit(FC_UNLOADING, &phba->pport->load_flag)) |
| 9513 | 9512 | mod_timer(&vport->els_tmofunc, |
| 9514 | − jiffies + msecs_to_jiffies(1000 * timeout)); | |
| 9513 | + jiffies + secs_to_jiffies(timeout)); | |
| 9515 | 9514 | } |
| 9516 | 9515 | |
| 9517 | 9516 | /** |
| @@ -9569,18 +9568,16 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) · 51 unmodified lines | ||
| 9569 | 9568 | mbx_tmo_err = test_bit(MBX_TMO_ERR, &phba->bit_flags); |
| 9570 | 9569 | /* First we need to issue aborts to outstanding cmds on txcmpl */ |
| 9571 | 9570 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { |
| 9571 | + if (piocb->vport != vport) | |
| 9572 | + continue; | |
| 9573 | + | |
| 9572 | 9574 | lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, |
| 9573 | 9575 | "2243 iotag = 0x%x cmd_flag = 0x%x " |
| 9574 | − "ulp_command = 0x%x this_vport %x " | |
| 9575 | − "sli_flag = 0x%x\n", | |
| 9576 | + "ulp_command = 0x%x sli_flag = 0x%x\n", | |
| 9576 | 9577 | piocb->iotag, piocb->cmd_flag, |
| 9577 | 9578 | get_job_cmnd(phba, piocb), |
| 9578 | − (piocb->vport == vport), | |
| 9579 | 9579 | phba->sli.sli_flag); |
| 9580 | 9580 | |
| 9581 | − if (piocb->vport != vport) | |
| 9582 | − continue; | |
| 9583 | − | |
| 9584 | 9581 | if ((phba->sli.sli_flag & LPFC_SLI_ACTIVE) && !mbx_tmo_err) { |
| 9585 | 9582 | if (piocb->cmd_flag & LPFC_IO_LIBDFC) |
| 9586 | 9583 | continue; |
| @@ -10899,7 +10896,7 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) · 1312 unmodified lines | ||
| 10899 | 10896 | "3334 Delay fc port discovery for %d secs\n", |
| 10900 | 10897 | phba->fc_ratov); |
| 10901 | 10898 | mod_timer(&vport->delayed_disc_tmo, |
| 10902 | − jiffies + msecs_to_jiffies(1000 * phba->fc_ratov)); | |
| 10899 | + jiffies + secs_to_jiffies(phba->fc_ratov)); | |
| 10903 | 10900 | return; |
| 10904 | 10901 | } |
| 10905 | 10902 | |
| @@ -11156,7 +11153,7 @@ lpfc_retry_pport_discovery(struct lpfc_hba *phba) · 250 unmodified lines | ||
| 11156 | 11153 | if (!ndlp) |
| 11157 | 11154 | return; |
| 11158 | 11155 | |
| 11159 | − mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); | |
| 11156 | + mod_timer(&ndlp->nlp_delayfunc, jiffies + secs_to_jiffies(1)); | |
| 11160 | 11157 | set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); |
| 11161 | 11158 | ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; |
| 11162 | 11159 | phba->pport->port_state = LPFC_FLOGI; |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | /******************************************************************* |
| 2 | 2 | * This file is part of the Emulex Linux Device Driver for * |
| 3 | 3 | * Fibre Channel Host Bus Adapters. * |
| 4 | − * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * | |
| 4 | + * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * | |
| 5 | 5 | * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * |
| 6 | 6 | * Copyright (C) 2004-2016 Emulex. All rights reserved. * |
| 7 | 7 | * EMULEX and SLI are trademarks of Emulex. * |
| @@ -228,10 +228,16 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) · 220 unmodified lines | ||
| 228 | 228 | if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) |
| 229 | 229 | return; |
| 230 | 230 | |
| 231 | − /* check for recovered fabric node */ | |
| 232 | − if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && | |
| 233 | − ndlp->nlp_DID == Fabric_DID) | |
| 231 | + /* Ignore callback for a mismatched (stale) rport */ | |
| 232 | + if (ndlp->rport != rport) { | |
| 233 | + lpfc_vlog_msg(vport, KERN_WARNING, LOG_NODE, | |
| 234 | + "6788 fc rport mismatch: d_id x%06x ndlp x%px " | |
| 235 | + "fc rport x%px node rport x%px state x%x " | |
| 236 | + "refcnt %u\n", | |
| 237 | + ndlp->nlp_DID, ndlp, rport, ndlp->rport, | |
| 238 | + ndlp->nlp_state, kref_read(&ndlp->kref)); | |
| 234 | 239 | return; |
| 240 | + } | |
| 235 | 241 | |
| 236 | 242 | if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn)) |
| 237 | 243 | lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, |
| @@ -3518,7 +3524,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) · 3280 unmodified lines | ||
| 3518 | 3524 | if (phba->fc_topology && |
| 3519 | 3525 | phba->fc_topology != bf_get(lpfc_mbx_read_top_topology, la)) { |
| 3520 | 3526 | lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, |
| 3521 | − "3314 Toplogy changed was 0x%x is 0x%x\n", | |
| 3527 | + "3314 Topology changed was 0x%x is 0x%x\n", | |
| 3522 | 3528 | phba->fc_topology, |
| 3523 | 3529 | bf_get(lpfc_mbx_read_top_topology, la)); |
| 3524 | 3530 | phba->fc_topology_changed = 1; |
| @@ -4973,7 +4979,7 @@ lpfc_set_disctmo(struct lpfc_vport *vport) · 1448 unmodified lines | ||
| 4973 | 4979 | tmo, vport->port_state, vport->fc_flag); |
| 4974 | 4980 | } |
| 4975 | 4981 | |
| 4976 | − mod_timer(&vport->fc_disctmo, jiffies + msecs_to_jiffies(1000 * tmo)); | |
| 4982 | + mod_timer(&vport->fc_disctmo, jiffies + secs_to_jiffies(tmo)); | |
| 4977 | 4983 | set_bit(FC_DISC_TMO, &vport->fc_flag); |
| 4978 | 4984 | |
| 4979 | 4985 | /* Start Discovery Timer state <hba_state> */ |
| @@ -5564,6 +5570,7 @@ static struct lpfc_nodelist * · 584 unmodified lines | ||
| 5564 | 5570 | __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) |
| 5565 | 5571 | { |
| 5566 | 5572 | struct lpfc_nodelist *ndlp; |
| 5573 | + struct lpfc_nodelist *np = NULL; | |
| 5567 | 5574 | uint32_t data1; |
| 5568 | 5575 | |
| 5569 | 5576 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { |
| @@ -5578,14 +5585,20 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) · 8 unmodified lines | ||
| 5578 | 5585 | ndlp, ndlp->nlp_DID, |
| 5579 | 5586 | ndlp->nlp_flag, data1, ndlp->nlp_rpi, |
| 5580 | 5587 | ndlp->active_rrqs_xri_bitmap); |
| 5581 | − return ndlp; | |
| 5588 | + | |
| 5589 | + /* Check for new or potentially stale node */ | |
| 5590 | + if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) | |
| 5591 | + return ndlp; | |
| 5592 | + np = ndlp; | |
| 5582 | 5593 | } |
| 5583 | 5594 | } |
| 5584 | 5595 | |
| 5585 | − /* FIND node did <did> NOT FOUND */ | |
| 5586 | − lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, | |
| 5587 | − "0932 FIND node did x%x NOT FOUND.\n", did); | |
| 5588 | − return NULL; | |
| 5596 | + if (!np) | |
| 5597 | + /* FIND node did <did> NOT FOUND */ | |
| 5598 | + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, | |
| 5599 | + "0932 FIND node did x%x NOT FOUND.\n", did); | |
| 5600 | + | |
| 5601 | + return np; | |
| 5589 | 5602 | } |
| 5590 | 5603 | |
| 5591 | 5604 | struct lpfc_nodelist * |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | /******************************************************************* |
| 2 | 2 | * This file is part of the Emulex Linux Device Driver for * |
| 3 | 3 | * Fibre Channel Host Bus Adapters. * |
| 4 | − * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * | |
| 4 | + * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * | |
| 5 | 5 | * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * |
| 6 | 6 | * Copyright (C) 2004-2016 Emulex. All rights reserved. * |
| 7 | 7 | * EMULEX and SLI are trademarks of Emulex. * |
| @@ -595,7 +595,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) · 587 unmodified lines | ||
| 595 | 595 | /* Set up ring-0 (ELS) timer */ |
| 596 | 596 | timeout = phba->fc_ratov * 2; |
| 597 | 597 | mod_timer(&vport->els_tmofunc, |
| 598 | − jiffies + msecs_to_jiffies(1000 * timeout)); | |
| 598 | + jiffies + secs_to_jiffies(timeout)); | |
| 599 | 599 | /* Set up heart beat (HB) timer */ |
| 600 | 600 | mod_timer(&phba->hb_tmofunc, |
| 601 | 601 | jiffies + secs_to_jiffies(LPFC_HB_MBOX_INTERVAL)); |
| @@ -604,7 +604,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) · 2 unmodified lines | ||
| 604 | 604 | phba->last_completion_time = jiffies; |
| 605 | 605 | /* Set up error attention (ERATT) polling timer */ |
| 606 | 606 | mod_timer(&phba->eratt_poll, |
| 607 | − jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); | |
| 607 | + jiffies + secs_to_jiffies(phba->eratt_poll_interval)); | |
| 608 | 608 | |
| 609 | 609 | if (test_bit(LINK_DISABLED, &phba->hba_flag)) { |
| 610 | 610 | lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, |
| @@ -3361,8 +3361,8 @@ lpfc_block_mgmt_io(struct lpfc_hba *phba, int mbx_action) · 2750 unmodified lines | ||
| 3361 | 3361 | /* Determine how long we might wait for the active mailbox |
| 3362 | 3362 | * command to be gracefully completed by firmware. |
| 3363 | 3363 | */ |
| 3364 | − timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, | |
| 3365 | − phba->sli.mbox_active) * 1000) + jiffies; | |
| 3364 | + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, | |
| 3365 | + phba->sli.mbox_active)) + jiffies; | |
| 3366 | 3366 | } |
| 3367 | 3367 | spin_unlock_irqrestore(&phba->hbalock, iflag); |
| 3368 | 3368 | |
| @@ -6909,7 +6909,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, · 3540 unmodified lines | ||
| 6909 | 6909 | * re-instantiate the Vlink using FDISC. |
| 6910 | 6910 | */ |
| 6911 | 6911 | mod_timer(&ndlp->nlp_delayfunc, |
| 6912 | − jiffies + msecs_to_jiffies(1000)); | |
| 6912 | + jiffies + secs_to_jiffies(1)); | |
| 6913 | 6913 | set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); |
| 6914 | 6914 | ndlp->nlp_last_elscmd = ELS_CMD_FDISC; |
| 6915 | 6915 | vport->port_state = LPFC_FDISC; |
| @@ -13169,6 +13169,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) · 6253 unmodified lines | ||
| 13169 | 13169 | eqhdl = lpfc_get_eq_hdl(0); |
| 13170 | 13170 | rc = pci_irq_vector(phba->pcidev, 0); |
| 13171 | 13171 | if (rc < 0) { |
| 13172 | + free_irq(phba->pcidev->irq, phba); | |
| 13172 | 13173 | pci_free_irq_vectors(phba->pcidev); |
| 13173 | 13174 | lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, |
| 13174 | 13175 | "0496 MSI pci_irq_vec failed (%d)\n", rc); |
| @@ -13249,6 +13250,7 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) · 74 unmodified lines | ||
| 13249 | 13250 | eqhdl = lpfc_get_eq_hdl(0); |
| 13250 | 13251 | retval = pci_irq_vector(phba->pcidev, 0); |
| 13251 | 13252 | if (retval < 0) { |
| 13253 | + free_irq(phba->pcidev->irq, phba); | |
| 13252 | 13254 | lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, |
| 13253 | 13255 | "0502 INTR pci_irq_vec failed (%d)\n", |
| 13254 | 13256 | retval); |
| @@ -5645,9 +5645,8 @@ wait_for_cmpl: · 5644 unmodified lines | ||
| 5645 | 5645 | * cmd_flag is set to LPFC_DRIVER_ABORTED before we wait |
| 5646 | 5646 | * for abort to complete. |
| 5647 | 5647 | */ |
| 5648 | − wait_event_timeout(waitq, | |
| 5649 | − (lpfc_cmd->pCmd != cmnd), | |
| 5650 | − msecs_to_jiffies(2*vport->cfg_devloss_tmo*1000)); | |
| 5648 | + wait_event_timeout(waitq, (lpfc_cmd->pCmd != cmnd), | |
| 5649 | + secs_to_jiffies(2*vport->cfg_devloss_tmo)); | |
| 5651 | 5650 | |
| 5652 | 5651 | spin_lock(&lpfc_cmd->buf_lock); |
| 5653 | 5652 | |
| @@ -5911,7 +5910,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct fc_rport *rport) · 257 unmodified lines | ||
| 5911 | 5910 | * If target is not in a MAPPED state, delay until |
| 5912 | 5911 | * target is rediscovered or devloss timeout expires. |
| 5913 | 5912 | */ |
| 5914 | − later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; | |
| 5913 | + later = secs_to_jiffies(2 * vport->cfg_devloss_tmo) + jiffies; | |
| 5915 | 5914 | while (time_after(later, jiffies)) { |
| 5916 | 5915 | if (!pnode) |
| 5917 | 5916 | return FAILED; |
| @@ -5957,7 +5956,7 @@ lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id, · 39 unmodified lines | ||
| 5957 | 5956 | lpfc_sli_abort_taskmgmt(vport, |
| 5958 | 5957 | &phba->sli.sli3_ring[LPFC_FCP_RING], |
| 5959 | 5958 | tgt_id, lun_id, context); |
| 5960 | − later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; | |
| 5959 | + later = secs_to_jiffies(2 * vport->cfg_devloss_tmo) + jiffies; | |
| 5961 | 5960 | while (time_after(later, jiffies) && cnt) { |
| 5962 | 5961 | schedule_timeout_uninterruptible(msecs_to_jiffies(20)); |
| 5963 | 5962 | cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); |
| @@ -6137,8 +6136,7 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) · 173 unmodified lines | ||
| 6137 | 6136 | wait_event_timeout(waitq, |
| 6138 | 6137 | !test_bit(NLP_WAIT_FOR_LOGO, |
| 6139 | 6138 | &pnode->save_flags), |
| 6140 | − msecs_to_jiffies(dev_loss_tmo * | |
| 6141 | − 1000)); | |
| 6139 | + secs_to_jiffies(dev_loss_tmo)); | |
| 6142 | 6140 | |
| 6143 | 6141 | if (test_and_clear_bit(NLP_WAIT_FOR_LOGO, |
| 6144 | 6142 | &pnode->save_flags)) |
| @@ -1025,7 +1025,7 @@ lpfc_handle_rrq_active(struct lpfc_hba *phba) · 1024 unmodified lines | ||
| 1025 | 1025 | LIST_HEAD(send_rrq); |
| 1026 | 1026 | |
| 1027 | 1027 | clear_bit(HBA_RRQ_ACTIVE, &phba->hba_flag); |
| 1028 | − next_time = jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov + 1)); | |
| 1028 | + next_time = jiffies + secs_to_jiffies(phba->fc_ratov + 1); | |
| 1029 | 1029 | spin_lock_irqsave(&phba->rrq_list_lock, iflags); |
| 1030 | 1030 | list_for_each_entry_safe(rrq, nextrrq, |
| 1031 | 1031 | &phba->active_rrq_list, list) { |
| @@ -1208,8 +1208,7 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, · 176 unmodified lines | ||
| 1208 | 1208 | else |
| 1209 | 1209 | rrq->send_rrq = 0; |
| 1210 | 1210 | rrq->xritag = xritag; |
| 1211 | − rrq->rrq_stop_time = jiffies + | |
| 1212 | − msecs_to_jiffies(1000 * (phba->fc_ratov + 1)); | |
| 1211 | + rrq->rrq_stop_time = jiffies + secs_to_jiffies(phba->fc_ratov + 1); | |
| 1213 | 1212 | rrq->nlp_DID = ndlp->nlp_DID; |
| 1214 | 1213 | rrq->vport = ndlp->vport; |
| 1215 | 1214 | rrq->rxid = rxid; |
| @@ -1736,8 +1735,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, · 520 unmodified lines | ||
| 1736 | 1735 | BUG_ON(!piocb->vport); |
| 1737 | 1736 | if (!test_bit(FC_UNLOADING, &piocb->vport->load_flag)) |
| 1738 | 1737 | mod_timer(&piocb->vport->els_tmofunc, |
| 1739 | − jiffies + | |
| 1740 | − msecs_to_jiffies(1000 * (phba->fc_ratov << 1))); | |
| 1738 | + jiffies + secs_to_jiffies(phba->fc_ratov << 1)); | |
| 1741 | 1739 | } |
| 1742 | 1740 | |
| 1743 | 1741 | return 0; |
| @@ -2923,6 +2921,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) · 1179 unmodified lines | ||
| 2923 | 2921 | clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); |
| 2924 | 2922 | ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; |
| 2925 | 2923 | lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); |
| 2924 | + } else { | |
| 2925 | + clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); | |
| 2926 | 2926 | } |
| 2927 | 2927 | |
| 2928 | 2928 | /* The unreg_login mailbox is complete and had a |
| @@ -3956,8 +3956,7 @@ void lpfc_poll_eratt(struct timer_list *t) · 1027 unmodified lines | ||
| 3956 | 3956 | else |
| 3957 | 3957 | /* Restart the timer for next eratt poll */ |
| 3958 | 3958 | mod_timer(&phba->eratt_poll, |
| 3959 | − jiffies + | |
| 3960 | − msecs_to_jiffies(1000 * phba->eratt_poll_interval)); | |
| 3959 | + jiffies + secs_to_jiffies(phba->eratt_poll_interval)); | |
| 3961 | 3960 | return; |
| 3962 | 3961 | } |
| 3963 | 3962 | |
| @@ -9008,7 +9007,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) · 5044 unmodified lines | ||
| 9008 | 9007 | |
| 9009 | 9008 | /* Start the ELS watchdog timer */ |
| 9010 | 9009 | mod_timer(&vport->els_tmofunc, |
| 9011 | − jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov * 2))); | |
| 9010 | + jiffies + secs_to_jiffies(phba->fc_ratov * 2)); | |
| 9012 | 9011 | |
| 9013 | 9012 | /* Start heart beat timer */ |
| 9014 | 9013 | mod_timer(&phba->hb_tmofunc, |
| @@ -9027,7 +9026,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) · 12 unmodified lines | ||
| 9027 | 9026 | |
| 9028 | 9027 | /* Start error attention (ERATT) polling timer */ |
| 9029 | 9028 | mod_timer(&phba->eratt_poll, |
| 9030 | − jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); | |
| 9029 | + jiffies + secs_to_jiffies(phba->eratt_poll_interval)); | |
| 9031 | 9030 | |
| 9032 | 9031 | /* |
| 9033 | 9032 | * The port is ready, set the host's link state to LINK_DOWN |
| @@ -9504,8 +9503,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, · 470 unmodified lines | ||
| 9504 | 9503 | goto out_not_finished; |
| 9505 | 9504 | } |
| 9506 | 9505 | /* timeout active mbox command */ |
| 9507 | − timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox) * | |
| 9508 | − 1000); | |
| 9506 | + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox)); | |
| 9509 | 9507 | mod_timer(&psli->mbox_tmo, jiffies + timeout); |
| 9510 | 9508 | } |
| 9511 | 9509 | |
| @@ -9629,8 +9627,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, · 117 unmodified lines | ||
| 9629 | 9627 | drvr_flag); |
| 9630 | 9628 | goto out_not_finished; |
| 9631 | 9629 | } |
| 9632 | − timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox) * | |
| 9633 | − 1000) + jiffies; | |
| 9630 | + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox)) + jiffies; | |
| 9634 | 9631 | i = 0; |
| 9635 | 9632 | /* Wait for command to complete */ |
| 9636 | 9633 | while (((word0 & OWN_CHIP) == OWN_CHIP) || |
| @@ -9756,9 +9753,8 @@ lpfc_sli4_async_mbox_block(struct lpfc_hba *phba) · 119 unmodified lines | ||
| 9756 | 9753 | * command to be gracefully completed by firmware. |
| 9757 | 9754 | */ |
| 9758 | 9755 | if (phba->sli.mbox_active) |
| 9759 | − timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, | |
| 9760 | − phba->sli.mbox_active) * | |
| 9761 | − 1000) + jiffies; | |
| 9756 | + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, | |
| 9757 | + phba->sli.mbox_active)) + jiffies; | |
| 9762 | 9758 | spin_unlock_irq(&phba->hbalock); |
| 9763 | 9759 | |
| 9764 | 9760 | /* Make sure the mailbox is really active */ |
| @@ -9881,8 +9877,7 @@ lpfc_sli4_wait_bmbx_ready(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) · 116 unmodified lines | ||
| 9881 | 9877 | } |
| 9882 | 9878 | } |
| 9883 | 9879 | |
| 9884 | − timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq) | |
| 9885 | − * 1000) + jiffies; | |
| 9880 | + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq)) + jiffies; | |
| 9886 | 9881 | |
| 9887 | 9882 | do { |
| 9888 | 9883 | bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); |
| @@ -10230,7 +10225,7 @@ lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) · 341 unmodified lines | ||
| 10230 | 10225 | |
| 10231 | 10226 | /* Start timer for the mbox_tmo and log some mailbox post messages */ |
| 10232 | 10227 | mod_timer(&psli->mbox_tmo, (jiffies + |
| 10233 | − msecs_to_jiffies(1000 * lpfc_mbox_tmo_val(phba, mboxq)))); | |
| 10228 | + secs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq)))); | |
| 10234 | 10229 | |
| 10235 | 10230 | lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, |
| 10236 | 10231 | "(%d):0355 Mailbox cmd x%x (x%x/x%x) issue Data: " |
| @@ -13159,7 +13154,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, · 2922 unmodified lines | ||
| 13159 | 13154 | retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, |
| 13160 | 13155 | SLI_IOCB_RET_IOCB); |
| 13161 | 13156 | if (retval == IOCB_SUCCESS) { |
| 13162 | − timeout_req = msecs_to_jiffies(timeout * 1000); | |
| 13157 | + timeout_req = secs_to_jiffies(timeout); | |
| 13163 | 13158 | timeleft = wait_event_timeout(done_q, |
| 13164 | 13159 | lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE), |
| 13165 | 13160 | timeout_req); |
| @@ -13275,8 +13270,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, · 109 unmodified lines | ||
| 13275 | 13270 | /* now issue the command */ |
| 13276 | 13271 | retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); |
| 13277 | 13272 | if (retval == MBX_BUSY || retval == MBX_SUCCESS) { |
| 13278 | − wait_for_completion_timeout(&mbox_done, | |
| 13279 | − msecs_to_jiffies(timeout * 1000)); | |
| 13273 | + wait_for_completion_timeout(&mbox_done, secs_to_jiffies(timeout)); | |
| 13280 | 13274 | |
| 13281 | 13275 | spin_lock_irqsave(&phba->hbalock, flag); |
| 13282 | 13276 | pmboxq->ctx_u.mbox_wait = NULL; |
| @@ -13336,9 +13330,8 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action) · 53 unmodified lines | ||
| 13336 | 13330 | * command to be gracefully completed by firmware. |
| 13337 | 13331 | */ |
| 13338 | 13332 | if (phba->sli.mbox_active) |
| 13339 | − timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, | |
| 13340 | − phba->sli.mbox_active) * | |
| 13341 | − 1000) + jiffies; | |
| 13333 | + timeout = secs_to_jiffies(lpfc_mbox_tmo_val(phba, | |
| 13334 | + phba->sli.mbox_active)) + jiffies; | |
| 13342 | 13335 | spin_unlock_irq(&phba->hbalock); |
| 13343 | 13336 | |
| 13344 | 13337 | /* Enable softirqs again, done with phba->hbalock */ |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | /******************************************************************* |
| 2 | 2 | * This file is part of the Emulex Linux Device Driver for * |
| 3 | 3 | * Fibre Channel Host Bus Adapters. * |
| 4 | − * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * | |
| 4 | + * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * | |
| 5 | 5 | * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * |
| 6 | 6 | * Copyright (C) 2004-2016 Emulex. All rights reserved. * |
| 7 | 7 | * EMULEX and SLI are trademarks of Emulex. * |
| @@ -20,7 +20,7 @@ · 12 unmodified lines | ||
| 20 | 20 | * included with this package. * |
| 21 | 21 | *******************************************************************/ |
| 22 | 22 | |
| 23 | −#define LPFC_DRIVER_VERSION "14.4.0.7" | |
| 23 | +#define LPFC_DRIVER_VERSION "14.4.0.8" | |
| 24 | 24 | #define LPFC_DRIVER_NAME "lpfc" |
| 25 | 25 | |
| 26 | 26 | /* Used for SLI 2/3 */ |
| @@ -32,6 +32,6 @@ · 5 unmodified lines | ||
| 32 | 32 | |
| 33 | 33 | #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ |
| 34 | 34 | LPFC_DRIVER_VERSION |
| 35 | −#define LPFC_COPYRIGHT "Copyright (C) 2017-2024 Broadcom. All Rights " \ | |
| 35 | +#define LPFC_COPYRIGHT "Copyright (C) 2017-2025 Broadcom. All Rights " \ | |
| 36 | 36 | "Reserved. The term \"Broadcom\" refers to Broadcom Inc. " \ |
| 37 | 37 | "and/or its subsidiaries." |
| @@ -246,7 +246,7 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport) · 245 unmodified lines | ||
| 246 | 246 | * fabric RA_TOV value and dev_loss tmo. The driver's |
| 247 | 247 | * devloss_tmo is 10 giving this loop a 3x multiplier minimally. |
| 248 | 248 | */ |
| 249 | − wait_time_max = msecs_to_jiffies(((phba->fc_ratov * 3) + 3) * 1000); | |
| 249 | + wait_time_max = secs_to_jiffies((phba->fc_ratov * 3) + 3); | |
| 250 | 250 | wait_time_max += jiffies; |
| 251 | 251 | start_time = jiffies; |
| 252 | 252 | while (time_before(jiffies, wait_time_max)) { |
| @@ -855,8 +855,8 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) · 854 unmodified lines | ||
| 855 | 855 | return scb; |
| 856 | 856 | |
| 857 | 857 | #if MEGA_HAVE_CLUSTERING |
| 858 | − case RESERVE: | |
| 859 | − case RELEASE: | |
| 858 | + case RESERVE_6: | |
| 859 | + case RELEASE_6: | |
| 860 | 860 | |
| 861 | 861 | /* |
| 862 | 862 | * Do we support clustering and is the support enabled |
| @@ -875,7 +875,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) · 12 unmodified lines | ||
| 875 | 875 | } |
| 876 | 876 | |
| 877 | 877 | scb->raw_mbox[0] = MEGA_CLUSTER_CMD; |
| 878 | − scb->raw_mbox[2] = ( *cmd->cmnd == RESERVE ) ? | |
| 878 | + scb->raw_mbox[2] = *cmd->cmnd == RESERVE_6 ? | |
| 879 | 879 | MEGA_RESERVE_LD : MEGA_RELEASE_LD; |
| 880 | 880 | |
| 881 | 881 | scb->raw_mbox[3] = ldrv_num; |
| @@ -1618,8 +1618,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) · 736 unmodified lines | ||
| 1618 | 1618 | * failed or the input parameter is invalid |
| 1619 | 1619 | */ |
| 1620 | 1620 | if( status == 1 && |
| 1621 | − (cmd->cmnd[0] == RESERVE || | |
| 1622 | − cmd->cmnd[0] == RELEASE) ) { | |
| 1621 | + (cmd->cmnd[0] == RESERVE_6 || | |
| 1622 | + cmd->cmnd[0] == RELEASE_6) ) { | |
| 1623 | 1623 | |
| 1624 | 1624 | cmd->result |= (DID_ERROR << 16) | |
| 1625 | 1625 | SAM_STAT_RESERVATION_CONFLICT; |
| @@ -1725,8 +1725,8 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) · 1724 unmodified lines | ||
| 1725 | 1725 | |
| 1726 | 1726 | return scb; |
| 1727 | 1727 | |
| 1728 | − case RESERVE: | |
| 1729 | − case RELEASE: | |
| 1728 | + case RESERVE_6: | |
| 1729 | + case RELEASE_6: | |
| 1730 | 1730 | /* |
| 1731 | 1731 | * Do we support clustering and is the support enabled |
| 1732 | 1732 | */ |
| @@ -1748,7 +1748,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) · 15 unmodified lines | ||
| 1748 | 1748 | scb->dev_channel = 0xFF; |
| 1749 | 1749 | scb->dev_target = target; |
| 1750 | 1750 | ccb->raw_mbox[0] = CLUSTER_CMD; |
| 1751 | − ccb->raw_mbox[2] = (scp->cmnd[0] == RESERVE) ? | |
| 1751 | + ccb->raw_mbox[2] = scp->cmnd[0] == RESERVE_6 ? | |
| 1752 | 1752 | RESERVE_LD : RELEASE_LD; |
| 1753 | 1753 | |
| 1754 | 1754 | ccb->raw_mbox[3] = target; |
| @@ -2334,8 +2334,8 @@ megaraid_mbox_dpc(unsigned long devp) · 579 unmodified lines | ||
| 2334 | 2334 | * Error code returned is 1 if Reserve or Release |
| 2335 | 2335 | * failed or the input parameter is invalid |
| 2336 | 2336 | */ |
| 2337 | − if (status == 1 && (scp->cmnd[0] == RESERVE || | |
| 2338 | − scp->cmnd[0] == RELEASE)) { | |
| 2337 | + if (status == 1 && (scp->cmnd[0] == RESERVE_6 || | |
| 2338 | + scp->cmnd[0] == RELEASE_6)) { | |
| 2339 | 2339 | |
| 2340 | 2340 | scp->result = DID_ERROR << 16 | |
| 2341 | 2341 | SAM_STAT_RESERVATION_CONFLICT; |
| @@ -93,7 +93,7 @@ static unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT; · 92 unmodified lines | ||
| 93 | 93 | module_param(scmd_timeout, int, 0444); |
| 94 | 94 | MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer."); |
| 95 | 95 | |
| 96 | −int perf_mode = -1; | |
| 96 | +static int perf_mode = -1; | |
| 97 | 97 | module_param(perf_mode, int, 0444); |
| 98 | 98 | MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t" |
| 99 | 99 | "0 - balanced: High iops and low latency queues are allocated &\n\t\t" |
| @@ -105,15 +105,15 @@ MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options: · 5 unmodified lines | ||
| 105 | 105 | "default mode is 'balanced'" |
| 106 | 106 | ); |
| 107 | 107 | |
| 108 | −int event_log_level = MFI_EVT_CLASS_CRITICAL; | |
| 108 | +static int event_log_level = MFI_EVT_CLASS_CRITICAL; | |
| 109 | 109 | module_param(event_log_level, int, 0644); |
| 110 | 110 | MODULE_PARM_DESC(event_log_level, "Asynchronous event logging level- range is: -2(CLASS_DEBUG) to 4(CLASS_DEAD), Default: 2(CLASS_CRITICAL)"); |
| 111 | 111 | |
| 112 | −unsigned int enable_sdev_max_qd; | |
| 112 | +static unsigned int enable_sdev_max_qd; | |
| 113 | 113 | module_param(enable_sdev_max_qd, int, 0444); |
| 114 | 114 | MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue. Default: 0"); |
| 115 | 115 | |
| 116 | −int poll_queues; | |
| 116 | +static int poll_queues; | |
| 117 | 117 | module_param(poll_queues, int, 0444); |
| 118 | 118 | MODULE_PARM_DESC(poll_queues, "Number of queues to be use for io_uring poll mode.\n\t\t" |
| 119 | 119 | "This parameter is effective only if host_tagset_enable=1 &\n\t\t" |
| @@ -122,7 +122,7 @@ MODULE_PARM_DESC(poll_queues, "Number of queues to be use for io_uring poll mode · 2 unmodified lines | ||
| 122 | 122 | "High iops queues are not allocated &\n\t\t" |
| 123 | 123 | ); |
| 124 | 124 | |
| 125 | −int host_tagset_enable = 1; | |
| 125 | +static int host_tagset_enable = 1; | |
| 126 | 126 | module_param(host_tagset_enable, int, 0444); |
| 127 | 127 | MODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: enable(1)"); |
| 128 | 128 | |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | #define MPI3_CONFIG_PAGETYPE_PCIE_SWITCH (0x31) |
| 20 | 20 | #define MPI3_CONFIG_PAGETYPE_PCIE_LINK (0x33) |
| 21 | 21 | #define MPI3_CONFIG_PAGEATTR_MASK (0xf0) |
| 22 | +#define MPI3_CONFIG_PAGEATTR_SHIFT (4) | |
| 22 | 23 | #define MPI3_CONFIG_PAGEATTR_READ_ONLY (0x00) |
| 23 | 24 | #define MPI3_CONFIG_PAGEATTR_CHANGEABLE (0x10) |
| 24 | 25 | #define MPI3_CONFIG_PAGEATTR_PERSISTENT (0x20) |
| @@ -29,10 +30,13 @@ · 4 unmodified lines | ||
| 29 | 30 | #define MPI3_CONFIG_ACTION_READ_PERSISTENT (0x04) |
| 30 | 31 | #define MPI3_CONFIG_ACTION_WRITE_PERSISTENT (0x05) |
| 31 | 32 | #define MPI3_DEVICE_PGAD_FORM_MASK (0xf0000000) |
| 33 | +#define MPI3_DEVICE_PGAD_FORM_SHIFT (28) | |
| 32 | 34 | #define MPI3_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) |
| 33 | 35 | #define MPI3_DEVICE_PGAD_FORM_HANDLE (0x20000000) |
| 34 | 36 | #define MPI3_DEVICE_PGAD_HANDLE_MASK (0x0000ffff) |
| 37 | +#define MPI3_DEVICE_PGAD_HANDLE_SHIFT (0) | |
| 35 | 38 | #define MPI3_SAS_EXPAND_PGAD_FORM_MASK (0xf0000000) |
| 39 | +#define MPI3_SAS_EXPAND_PGAD_FORM_SHIFT (28) | |
| 36 | 40 | #define MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) |
| 37 | 41 | #define MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM (0x10000000) |
| 38 | 42 | #define MPI3_SAS_EXPAND_PGAD_FORM_HANDLE (0x20000000) |
| @@ -66,7 +66,12 @@ struct mpi3_component_image_header { · 65 unmodified lines | ||
| 66 | 66 | #define MPI3_IMAGE_HEADER_SIGNATURE1_SMM (0x204d4d53) |
| 67 | 67 | #define MPI3_IMAGE_HEADER_SIGNATURE1_PSW (0x20575350) |
| 68 | 68 | #define MPI3_IMAGE_HEADER_SIGNATURE2_VALUE (0x50584546) |
| 69 | +#define MPI3_IMAGE_HEADER_FLAGS_SIGNED_UEFI_MASK (0x00000300) | |
| 70 | +#define MPI3_IMAGE_HEADER_FLAGS_SIGNED_UEFI_SHIFT (8) | |
| 71 | +#define MPI3_IMAGE_HEADER_FLAGS_CERT_CHAIN_FORMAT_MASK (0x000000c0) | |
| 72 | +#define MPI3_IMAGE_HEADER_FLAGS_CERT_CHAIN_FORMAT_SHIFT (6) | |
| 69 | 73 | #define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_MASK (0x00000030) |
| 74 | +#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_SHIFT (4) | |
| 70 | 75 | #define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_CDI (0x00000000) |
| 71 | 76 | #define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_DI (0x00000010) |
| 72 | 77 | #define MPI3_IMAGE_HEADER_FLAGS_SIGNED_NVDATA (0x00000008) |
| @@ -214,11 +219,13 @@ struct mpi3_encrypted_hash_entry { · 141 unmodified lines | ||
| 214 | 219 | #define MPI3_HASH_IMAGE_TYPE_KEY_WITH_HASH_1_OF_2 (0x04) |
| 215 | 220 | #define MPI3_HASH_IMAGE_TYPE_KEY_WITH_HASH_2_OF_2 (0x05) |
| 216 | 221 | #define MPI3_HASH_ALGORITHM_VERSION_MASK (0xe0) |
| 222 | +#define MPI3_HASH_ALGORITHM_VERSION_SHIFT (5) | |
| 217 | 223 | #define MPI3_HASH_ALGORITHM_VERSION_NONE (0x00) |
| 218 | 224 | #define MPI3_HASH_ALGORITHM_VERSION_SHA1 (0x20) |
| 219 | 225 | #define MPI3_HASH_ALGORITHM_VERSION_SHA2 (0x40) |
| 220 | 226 | #define MPI3_HASH_ALGORITHM_VERSION_SHA3 (0x60) |
| 221 | 227 | #define MPI3_HASH_ALGORITHM_SIZE_MASK (0x1f) |
| 228 | +#define MPI3_HASH_ALGORITHM_SIZE_SHIFT (0) | |
| 222 | 229 | #define MPI3_HASH_ALGORITHM_SIZE_UNUSED (0x00) |
| 223 | 230 | #define MPI3_HASH_ALGORITHM_SIZE_SHA256 (0x01) |
| 224 | 231 | #define MPI3_HASH_ALGORITHM_SIZE_SHA512 (0x02) |
| @@ -236,6 +243,7 @@ struct mpi3_encrypted_hash_entry { · 11 unmodified lines | ||
| 236 | 243 | #define MPI3_ENCRYPTION_ALGORITHM_ML_DSA_65 (0x0c) |
| 237 | 244 | #define MPI3_ENCRYPTION_ALGORITHM_ML_DSA_44 (0x0d) |
| 238 | 245 | #define MPI3_ENCRYPTED_HASH_ENTRY_FLAGS_PAIRED_KEY_MASK (0x0f) |
| 246 | +#define MPI3_ENCRYPTED_HASH_ENTRY_FLAGS_PAIRED_KEY_SHIFT (0) | |
| 239 | 247 | |
| 240 | 248 | #ifndef MPI3_ENCRYPTED_HASH_ENTRY_MAX |
| 241 | 249 | #define MPI3_ENCRYPTED_HASH_ENTRY_MAX (1) |
| @@ -38,23 +38,31 @@ struct mpi3_scsi_io_request { · 37 unmodified lines | ||
| 38 | 38 | #define MPI3_SCSIIO_MSGFLAGS_METASGL_VALID (0x80) |
| 39 | 39 | #define MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE (0x40) |
| 40 | 40 | #define MPI3_SCSIIO_FLAGS_LARGE_CDB (0x60000000) |
| 41 | +#define MPI3_SCSIIO_FLAGS_LARGE_CDB_MASK (0x60000000) | |
| 42 | +#define MPI3_SCSIIO_FLAGS_LARGE_CDB_SHIFT (29) | |
| 43 | +#define MPI3_SCSIIO_FLAGS_IOC_USE_ONLY_27_MASK (0x18000000) | |
| 44 | +#define MPI3_SCSIIO_FLAGS_IOC_USE_ONLY_27_SHIFT (27) | |
| 41 | 45 | #define MPI3_SCSIIO_FLAGS_CDB_16_OR_LESS (0x00000000) |
| 42 | 46 | #define MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16 (0x20000000) |
| 43 | 47 | #define MPI3_SCSIIO_FLAGS_CDB_IN_SEPARATE_BUFFER (0x40000000) |
| 44 | 48 | #define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_MASK (0x07000000) |
| 49 | +#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SHIFT (24) | |
| 50 | +#define MPI3_SCSIIO_FLAGS_DATADIRECTION_MASK (0x000c0000) | |
| 51 | +#define MPI3_SCSIIO_FLAGS_DATADIRECTION_SHIFT (18) | |
| 45 | 52 | #define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ (0x00000000) |
| 46 | 53 | #define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_HEADOFQ (0x01000000) |
| 47 | 54 | #define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ORDEREDQ (0x02000000) |
| 48 | 55 | #define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ACAQ (0x04000000) |
| 49 | 56 | #define MPI3_SCSIIO_FLAGS_CMDPRI_MASK (0x00f00000) |
| 50 | 57 | #define MPI3_SCSIIO_FLAGS_CMDPRI_SHIFT (20) |
| 51 | −#define MPI3_SCSIIO_FLAGS_DATADIRECTION_MASK (0x000c0000) | |
| 52 | 58 | #define MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER (0x00000000) |
| 53 | 59 | #define MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE (0x00040000) |
| 54 | 60 | #define MPI3_SCSIIO_FLAGS_DATADIRECTION_READ (0x00080000) |
| 55 | 61 | #define MPI3_SCSIIO_FLAGS_DMAOPERATION_MASK (0x00030000) |
| 62 | +#define MPI3_SCSIIO_FLAGS_DMAOPERATION_SHIFT (16) | |
| 56 | 63 | #define MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI (0x00010000) |
| 57 | 64 | #define MPI3_SCSIIO_FLAGS_DIVERT_REASON_MASK (0x000000f0) |
| 65 | +#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_SHIFT (4) | |
| 58 | 66 | #define MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING (0x00000010) |
| 59 | 67 | #define MPI3_SCSIIO_FLAGS_DIVERT_REASON_WRITE_SAME_TOO_LARGE (0x00000020) |
| 60 | 68 | #define MPI3_SCSIIO_FLAGS_DIVERT_REASON_PROD_SPECIFIC (0x00000080) |
| @@ -99,6 +107,7 @@ struct mpi3_scsi_io_reply { · 38 unmodified lines | ||
| 99 | 107 | #define MPI3_SCSI_STATUS_ACA_ACTIVE (0x30) |
| 100 | 108 | #define MPI3_SCSI_STATUS_TASK_ABORTED (0x40) |
| 101 | 109 | #define MPI3_SCSI_STATE_SENSE_MASK (0x03) |
| 110 | +#define MPI3_SCSI_STATE_SENSE_SHIFT (0) | |
| 102 | 111 | #define MPI3_SCSI_STATE_SENSE_VALID (0x00) |
| 103 | 112 | #define MPI3_SCSI_STATE_SENSE_FAILED (0x01) |
| 104 | 113 | #define MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY (0x02) |
| @@ -30,6 +30,7 @@ struct mpi3_ioc_init_request { · 29 unmodified lines | ||
| 30 | 30 | #define MPI3_IOCINIT_MSGFLAGS_WRITESAMEDIVERT_SUPPORTED (0x08) |
| 31 | 31 | #define MPI3_IOCINIT_MSGFLAGS_SCSIIOSTATUSREPLY_SUPPORTED (0x04) |
| 32 | 32 | #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_MASK (0x03) |
| 33 | +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_SHIFT (0) | |
| 33 | 34 | #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_NOT_USED (0x00) |
| 34 | 35 | #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_SEPARATED (0x01) |
| 35 | 36 | #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_INLINE (0x02) |
| @@ -40,6 +41,7 @@ struct mpi3_ioc_init_request { · 4 unmodified lines | ||
| 40 | 41 | #define MPI3_WHOINIT_MANUFACTURER (0x04) |
| 41 | 42 | |
| 42 | 43 | #define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_MASK (0x00000003) |
| 44 | +#define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_SHIFT (0) | |
| 43 | 45 | #define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_NO_GUIDANCE (0x00000000) |
| 44 | 46 | #define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_NO_SPECIAL (0x00000001) |
| 45 | 47 | #define MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_REPORT_AS_HDD (0x00000002) |
| @@ -111,9 +113,11 @@ struct mpi3_ioc_facts_data { · 65 unmodified lines | ||
| 111 | 113 | __le32 diag_tty_size; |
| 112 | 114 | }; |
| 113 | 115 | #define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_MASK (0x80000000) |
| 116 | +#define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_SHIFT (31) | |
| 114 | 117 | #define MPI3_IOCFACTS_CAPABILITY_SUPERVISOR_IOC (0x00000000) |
| 115 | 118 | #define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC (0x80000000) |
| 116 | 119 | #define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_MASK (0x00000600) |
| 120 | +#define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_SHIFT (9) | |
| 117 | 121 | #define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_FIXED_THRESHOLD (0x00000000) |
| 118 | 122 | #define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_OUTSTANDING_IO (0x00000200) |
| 119 | 123 | #define MPI3_IOCFACTS_CAPABILITY_COMPLETE_RESET_SUPPORTED (0x00000100) |
| @@ -134,6 +138,7 @@ struct mpi3_ioc_facts_data { · 14 unmodified lines | ||
| 134 | 138 | #define MPI3_IOCFACTS_EXCEPT_SAS_DISABLED (0x1000) |
| 135 | 139 | #define MPI3_IOCFACTS_EXCEPT_SAFE_MODE (0x0800) |
| 136 | 140 | #define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_MASK (0x0700) |
| 141 | +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_SHIFT (8) | |
| 137 | 142 | #define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_NONE (0x0000) |
| 138 | 143 | #define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_MGMT (0x0100) |
| 139 | 144 | #define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_MGMT (0x0200) |
| @@ -149,6 +154,7 @@ struct mpi3_ioc_facts_data { · 9 unmodified lines | ||
| 149 | 154 | #define MPI3_IOCFACTS_EXCEPT_BLOCKING_BOOT_EVENT (0x0004) |
| 150 | 155 | #define MPI3_IOCFACTS_EXCEPT_SECURITY_SELFTEST_FAILURE (0x0002) |
| 151 | 156 | #define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x0001) |
| 157 | +#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_SHIFT (0) | |
| 152 | 158 | #define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_PRIMARY (0x0000) |
| 153 | 159 | #define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_SECONDARY (0x0001) |
| 154 | 160 | #define MPI3_IOCFACTS_PROTOCOL_SAS (0x0010) |
| @@ -161,10 +167,12 @@ struct mpi3_ioc_facts_data { · 6 unmodified lines | ||
| 161 | 167 | #define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK (0x0000ff00) |
| 162 | 168 | #define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT (8) |
| 163 | 169 | #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK (0x00000030) |
| 170 | +#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_SHIFT (4) | |
| 164 | 171 | #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_NOT_STARTED (0x00000000) |
| 165 | 172 | #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_IN_PROGRESS (0x00000010) |
| 166 | 173 | #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_COMPLETE (0x00000020) |
| 167 | 174 | #define MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK (0x0000000f) |
| 175 | +#define MPI3_IOCFACTS_FLAGS_PERSONALITY_SHIFT (0) | |
| 168 | 176 | #define MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA (0x00000000) |
| 169 | 177 | #define MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR (0x00000002) |
| 170 | 178 | #define MPI3_IOCFACTS_IO_THROTTLE_DATA_LENGTH_NOT_REQUIRED (0x0000) |
| @@ -204,6 +212,7 @@ struct mpi3_create_request_queue_request { · 33 unmodified lines | ||
| 204 | 212 | }; |
| 205 | 213 | |
| 206 | 214 | #define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_MASK (0x80) |
| 215 | +#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SHIFT (7) | |
| 207 | 216 | #define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80) |
| 208 | 217 | #define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00) |
| 209 | 218 | #define MPI3_CREATE_REQUEST_QUEUE_SIZE_MINIMUM (2) |
| @@ -237,10 +246,12 @@ struct mpi3_create_reply_queue_request { · 27 unmodified lines | ||
| 237 | 246 | }; |
| 238 | 247 | |
| 239 | 248 | #define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_MASK (0x80) |
| 249 | +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_SHIFT (7) | |
| 240 | 250 | #define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80) |
| 241 | 251 | #define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00) |
| 242 | 252 | #define MPI3_CREATE_REPLY_QUEUE_FLAGS_COALESCE_DISABLE (0x02) |
| 243 | 253 | #define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_MASK (0x01) |
| 254 | +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_SHIFT (0) | |
| 244 | 255 | #define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_DISABLE (0x00) |
| 245 | 256 | #define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE (0x01) |
| 246 | 257 | #define MPI3_CREATE_REPLY_QUEUE_SIZE_MINIMUM (2) |
| @@ -326,9 +337,11 @@ struct mpi3_event_notification_reply { · 79 unmodified lines | ||
| 326 | 337 | }; |
| 327 | 338 | |
| 328 | 339 | #define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK (0x01) |
| 340 | +#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_SHIFT (0) | |
| 329 | 341 | #define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED (0x01) |
| 330 | 342 | #define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_NOT_REQUIRED (0x00) |
| 331 | 343 | #define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_MASK (0x02) |
| 344 | +#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_SHIFT (1) | |
| 332 | 345 | #define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_ORIGINAL (0x00) |
| 333 | 346 | #define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_REPLAY (0x02) |
| 334 | 347 | struct mpi3_event_data_gpio_interrupt { |
| @@ -487,6 +500,7 @@ struct mpi3_event_sas_topo_phy_entry { · 152 unmodified lines | ||
| 487 | 500 | #define MPI3_EVENT_SAS_TOPO_PHY_STATUS_NO_EXIST (0x40) |
| 488 | 501 | #define MPI3_EVENT_SAS_TOPO_PHY_STATUS_VACANT (0x80) |
| 489 | 502 | #define MPI3_EVENT_SAS_TOPO_PHY_RC_MASK (0x0f) |
| 503 | +#define MPI3_EVENT_SAS_TOPO_PHY_RC_SHIFT (0) | |
| 490 | 504 | #define MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING (0x02) |
| 491 | 505 | #define MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED (0x03) |
| 492 | 506 | #define MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE (0x04) |
| @@ -566,6 +580,7 @@ struct mpi3_event_pcie_topo_port_entry { · 73 unmodified lines | ||
| 566 | 580 | #define MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING (0x05) |
| 567 | 581 | #define MPI3_EVENT_PCIE_TOPO_PS_RESPONDING (0x06) |
| 568 | 582 | #define MPI3_EVENT_PCIE_TOPO_PI_LANES_MASK (0xf0) |
| 583 | +#define MPI3_EVENT_PCIE_TOPO_PI_LANES_SHIFT (4) | |
| 569 | 584 | #define MPI3_EVENT_PCIE_TOPO_PI_LANES_UNKNOWN (0x00) |
| 570 | 585 | #define MPI3_EVENT_PCIE_TOPO_PI_LANES_1 (0x10) |
| 571 | 586 | #define MPI3_EVENT_PCIE_TOPO_PI_LANES_2 (0x20) |
| @@ -573,6 +588,7 @@ struct mpi3_event_pcie_topo_port_entry { · 1 unmodified line | ||
| 573 | 588 | #define MPI3_EVENT_PCIE_TOPO_PI_LANES_8 (0x40) |
| 574 | 589 | #define MPI3_EVENT_PCIE_TOPO_PI_LANES_16 (0x50) |
| 575 | 590 | #define MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK (0x0f) |
| 591 | +#define MPI3_EVENT_PCIE_TOPO_PI_RATE_SHIFT (0) | |
| 576 | 592 | #define MPI3_EVENT_PCIE_TOPO_PI_RATE_UNKNOWN (0x00) |
| 577 | 593 | #define MPI3_EVENT_PCIE_TOPO_PI_RATE_DISABLED (0x01) |
| 578 | 594 | #define MPI3_EVENT_PCIE_TOPO_PI_RATE_2_5 (0x02) |
| @@ -881,6 +897,7 @@ struct mpi3_pel_req_action_acknowledge { · 302 unmodified lines | ||
| 881 | 897 | }; |
| 882 | 898 | |
| 883 | 899 | #define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_MASK (0x03) |
| 900 | +#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_SHIFT (0) | |
| 884 | 901 | #define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_NO_GUIDANCE (0x00) |
| 885 | 902 | #define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_CONTINUE_OP (0x01) |
| 886 | 903 | #define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_TRANSITION_TO_FAULT (0x02) |
| @@ -924,6 +941,7 @@ struct mpi3_ci_download_request { · 37 unmodified lines | ||
| 924 | 941 | #define MPI3_CI_DOWNLOAD_MSGFLAGS_FORCE_FMC_ENABLE (0x40) |
| 925 | 942 | #define MPI3_CI_DOWNLOAD_MSGFLAGS_SIGNED_NVDATA (0x20) |
| 926 | 943 | #define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_MASK (0x03) |
| 944 | +#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_SHIFT (0) | |
| 927 | 945 | #define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_FAST (0x00) |
| 928 | 946 | #define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_MEDIUM (0x01) |
| 929 | 947 | #define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_SLOW (0x02) |
| @@ -953,6 +971,7 @@ struct mpi3_ci_download_reply { · 23 unmodified lines | ||
| 953 | 971 | #define MPI3_CI_DOWNLOAD_FLAGS_OFFLINE_ACTIVATION_REQUIRED (0x20) |
| 954 | 972 | #define MPI3_CI_DOWNLOAD_FLAGS_KEY_UPDATE_PENDING (0x10) |
| 955 | 973 | #define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_MASK (0x0e) |
| 974 | +#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_SHIFT (1) | |
| 956 | 975 | #define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_NOT_NEEDED (0x00) |
| 957 | 976 | #define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_AWAITING (0x02) |
| 958 | 977 | #define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_ONLINE_PENDING (0x04) |
| @@ -976,9 +995,11 @@ struct mpi3_ci_upload_request { · 17 unmodified lines | ||
| 976 | 995 | }; |
| 977 | 996 | |
| 978 | 997 | #define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_MASK (0x01) |
| 998 | +#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_SHIFT (0) | |
| 979 | 999 | #define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY (0x00) |
| 980 | 1000 | #define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_SECONDARY (0x01) |
| 981 | 1001 | #define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_MASK (0x02) |
| 1002 | +#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_SHIFT (1) | |
| 982 | 1003 | #define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_FLASH (0x00) |
| 983 | 1004 | #define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_EXECUTABLE (0x02) |
| 984 | 1005 | #define MPI3_CTRL_OP_FORCE_FULL_DISCOVERY (0x01) |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #define MPI3_DIAG_BUFFER_TYPE_FW (0x02) |
| 10 | 10 | #define MPI3_DIAG_BUFFER_ACTION_RELEASE (0x01) |
| 11 | 11 | |
| 12 | +#define MPI3_DIAG_BUFFER_POST_MSGFLAGS_SEGMENTED (0x01) | |
| 12 | 13 | struct mpi3_diag_buffer_post_request { |
| 13 | 14 | __le16 host_tag; |
| 14 | 15 | u8 ioc_use_only02; |
| @@ -18,7 +18,7 @@ union mpi3_version_union { · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | #define MPI3_VERSION_MAJOR (3) |
| 20 | 20 | #define MPI3_VERSION_MINOR (0) |
| 21 | −#define MPI3_VERSION_UNIT (34) | |
| 21 | +#define MPI3_VERSION_UNIT (35) | |
| 22 | 22 | #define MPI3_VERSION_DEV (0) |
| 23 | 23 | #define MPI3_DEVHANDLE_INVALID (0xffff) |
| 24 | 24 | struct mpi3_sysif_oper_queue_indexes { |
| @@ -80,6 +80,7 @@ struct mpi3_sysif_registers { · 55 unmodified lines | ||
| 80 | 80 | #define MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT (20) |
| 81 | 81 | #define MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ (0x000f0000) |
| 82 | 82 | #define MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT (16) |
| 83 | +#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_SHIFT (14) | |
| 83 | 84 | #define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_MASK (0x0000c000) |
| 84 | 85 | #define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NO (0x00000000) |
| 85 | 86 | #define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL (0x00004000) |
| @@ -97,6 +98,7 @@ struct mpi3_sysif_registers { · 11 unmodified lines | ||
| 97 | 98 | #define MPI3_SYSIF_IOC_STATUS_READY (0x00000001) |
| 98 | 99 | #define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_OFFSET (0x00000024) |
| 99 | 100 | #define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REQ_MASK (0x0fff) |
| 101 | +#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REQ_SHIFT (0) | |
| 100 | 102 | #define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_OFFSET (0x00000026) |
| 101 | 103 | #define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_MASK (0x0fff0000) |
| 102 | 104 | #define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_SHIFT (16) |
| @@ -106,6 +108,7 @@ struct mpi3_sysif_registers { · 3 unmodified lines | ||
| 106 | 108 | #define MPI3_SYSIF_ADMIN_REPLY_Q_ADDR_HIGH_OFFSET (0x00000034) |
| 107 | 109 | #define MPI3_SYSIF_COALESCE_CONTROL_OFFSET (0x00000040) |
| 108 | 110 | #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_MASK (0xc0000000) |
| 111 | +#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_SHIFT (30) | |
| 109 | 112 | #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_NO_CHANGE (0x00000000) |
| 110 | 113 | #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_DISABLE (0x40000000) |
| 111 | 114 | #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_ENABLE (0xc0000000) |
| @@ -124,6 +127,7 @@ struct mpi3_sysif_registers { · 12 unmodified lines | ||
| 124 | 127 | #define MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(N) (MPI3_SYSIF_OPER_REPLY_Q_CI_OFFSET + (((N) - 1) * 8)) |
| 125 | 128 | #define MPI3_SYSIF_WRITE_SEQUENCE_OFFSET (0x00001c04) |
| 126 | 129 | #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_MASK (0x0000000f) |
| 130 | +#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_SHIFT (0) | |
| 127 | 131 | #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH (0x0) |
| 128 | 132 | #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST (0xf) |
| 129 | 133 | #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND (0x4) |
| @@ -133,6 +137,7 @@ struct mpi3_sysif_registers { · 3 unmodified lines | ||
| 133 | 137 | #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH (0xd) |
| 134 | 138 | #define MPI3_SYSIF_HOST_DIAG_OFFSET (0x00001c08) |
| 135 | 139 | #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_MASK (0x00000700) |
| 140 | +#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SHIFT (8) | |
| 136 | 141 | #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_NO_RESET (0x00000000) |
| 137 | 142 | #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET (0x00000100) |
| 138 | 143 | #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_HOST_CONTROL_BOOT_RESET (0x00000200) |
| @@ -151,6 +156,7 @@ struct mpi3_sysif_registers { · 12 unmodified lines | ||
| 151 | 156 | #define MPI3_SYSIF_FAULT_FUNC_AREA_SHIFT (24) |
| 152 | 157 | #define MPI3_SYSIF_FAULT_FUNC_AREA_MPI_DEFINED (0x00000000) |
| 153 | 158 | #define MPI3_SYSIF_FAULT_CODE_MASK (0x0000ffff) |
| 159 | +#define MPI3_SYSIF_FAULT_CODE_SHIFT (0) | |
| 154 | 160 | #define MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET (0x0000f000) |
| 155 | 161 | #define MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET (0x0000f001) |
| 156 | 162 | #define MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS (0x0000f002) |
| @@ -176,17 +182,20 @@ struct mpi3_sysif_registers { · 19 unmodified lines | ||
| 176 | 182 | #define MPI3_SYSIF_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00001c5c) |
| 177 | 183 | #define MPI3_SYSIF_DIAG_RW_CONTROL_OFFSET (0x00001c60) |
| 178 | 184 | #define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_MASK (0x00000030) |
| 185 | +#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_SHIFT (4) | |
| 179 | 186 | #define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_1BYTE (0x00000000) |
| 180 | 187 | #define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_2BYTES (0x00000010) |
| 181 | 188 | #define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_4BYTES (0x00000020) |
| 182 | 189 | #define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_8BYTES (0x00000030) |
| 183 | 190 | #define MPI3_SYSIF_DIAG_RW_CONTROL_RESET (0x00000004) |
| 184 | 191 | #define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_MASK (0x00000002) |
| 192 | +#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_SHIFT (1) | |
| 185 | 193 | #define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_READ (0x00000000) |
| 186 | 194 | #define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_WRITE (0x00000002) |
| 187 | 195 | #define MPI3_SYSIF_DIAG_RW_CONTROL_START (0x00000001) |
| 188 | 196 | #define MPI3_SYSIF_DIAG_RW_STATUS_OFFSET (0x00001c62) |
| 189 | 197 | #define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_MASK (0x0000000e) |
| 198 | +#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_SHIFT (1) | |
| 190 | 199 | #define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_SUCCESS (0x00000000) |
| 191 | 200 | #define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_INV_ADDR (0x00000002) |
| 192 | 201 | #define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_ACC_ERR (0x00000004) |
| @@ -207,7 +216,9 @@ struct mpi3_default_reply_descriptor { · 14 unmodified lines | ||
| 207 | 216 | }; |
| 208 | 217 | |
| 209 | 218 | #define MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK (0x0001) |
| 219 | +#define MPI3_REPLY_DESCRIPT_FLAGS_PHASE_SHIFT (0) | |
| 210 | 220 | #define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK (0xf000) |
| 221 | +#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SHIFT (12) | |
| 211 | 222 | #define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY (0x0000) |
| 212 | 223 | #define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS (0x1000) |
| 213 | 224 | #define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_TARGET_COMMAND_BUFFER (0x2000) |
| @@ -301,6 +312,7 @@ union mpi3_sge_union { · 87 unmodified lines | ||
| 301 | 312 | }; |
| 302 | 313 | |
| 303 | 314 | #define MPI3_SGE_FLAGS_ELEMENT_TYPE_MASK (0xf0) |
| 315 | +#define MPI3_SGE_FLAGS_ELEMENT_TYPE_SHIFT (4) | |
| 304 | 316 | #define MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE (0x00) |
| 305 | 317 | #define MPI3_SGE_FLAGS_ELEMENT_TYPE_BIT_BUCKET (0x10) |
| 306 | 318 | #define MPI3_SGE_FLAGS_ELEMENT_TYPE_CHAIN (0x20) |
| @@ -309,6 +321,7 @@ union mpi3_sge_union { · 2 unmodified lines | ||
| 309 | 321 | #define MPI3_SGE_FLAGS_END_OF_LIST (0x08) |
| 310 | 322 | #define MPI3_SGE_FLAGS_END_OF_BUFFER (0x04) |
| 311 | 323 | #define MPI3_SGE_FLAGS_DLAS_MASK (0x03) |
| 324 | +#define MPI3_SGE_FLAGS_DLAS_SHIFT (0) | |
| 312 | 325 | #define MPI3_SGE_FLAGS_DLAS_SYSTEM (0x00) |
| 313 | 326 | #define MPI3_SGE_FLAGS_DLAS_IOC_UDP (0x01) |
| 314 | 327 | #define MPI3_SGE_FLAGS_DLAS_IOC_CTL (0x02) |
| @@ -322,15 +335,18 @@ union mpi3_sge_union { · 7 unmodified lines | ||
| 322 | 335 | #define MPI3_EEDPFLAGS_CHK_APP_TAG (0x0200) |
| 323 | 336 | #define MPI3_EEDPFLAGS_CHK_GUARD (0x0100) |
| 324 | 337 | #define MPI3_EEDPFLAGS_ESC_MODE_MASK (0x00c0) |
| 338 | +#define MPI3_EEDPFLAGS_ESC_MODE_SHIFT (6) | |
| 325 | 339 | #define MPI3_EEDPFLAGS_ESC_MODE_DO_NOT_DISABLE (0x0040) |
| 326 | 340 | #define MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE (0x0080) |
| 327 | 341 | #define MPI3_EEDPFLAGS_ESC_MODE_APPTAG_REFTAG_DISABLE (0x00c0) |
| 328 | 342 | #define MPI3_EEDPFLAGS_HOST_GUARD_MASK (0x0030) |
| 343 | +#define MPI3_EEDPFLAGS_HOST_GUARD_SHIFT (4) | |
| 329 | 344 | #define MPI3_EEDPFLAGS_HOST_GUARD_T10_CRC (0x0000) |
| 330 | 345 | #define MPI3_EEDPFLAGS_HOST_GUARD_IP_CHKSUM (0x0010) |
| 331 | 346 | #define MPI3_EEDPFLAGS_HOST_GUARD_OEM_SPECIFIC (0x0020) |
| 332 | 347 | #define MPI3_EEDPFLAGS_PT_REF_TAG (0x0008) |
| 333 | 348 | #define MPI3_EEDPFLAGS_EEDP_OP_MASK (0x0007) |
| 349 | +#define MPI3_EEDPFLAGS_EEDP_OP_SHIFT (0) | |
| 334 | 350 | #define MPI3_EEDPFLAGS_EEDP_OP_CHECK (0x0001) |
| 335 | 351 | #define MPI3_EEDPFLAGS_EEDP_OP_STRIP (0x0002) |
| 336 | 352 | #define MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE (0x0003) |
| @@ -403,6 +419,7 @@ struct mpi3_default_reply { · 66 unmodified lines | ||
| 403 | 419 | #define MPI3_IOCSTATUS_LOG_INFO_AVAIL_MASK (0x8000) |
| 404 | 420 | #define MPI3_IOCSTATUS_LOG_INFO_AVAILABLE (0x8000) |
| 405 | 421 | #define MPI3_IOCSTATUS_STATUS_MASK (0x7fff) |
| 422 | +#define MPI3_IOCSTATUS_STATUS_SHIFT (0) | |
| 406 | 423 | #define MPI3_IOCSTATUS_SUCCESS (0x0000) |
| 407 | 424 | #define MPI3_IOCSTATUS_INVALID_FUNCTION (0x0001) |
| 408 | 425 | #define MPI3_IOCSTATUS_BUSY (0x0002) |
| @@ -469,4 +486,5 @@ struct mpi3_default_reply { · 60 unmodified lines | ||
| 469 | 486 | #define MPI3_IOCLOGINFO_TYPE_NONE (0x0) |
| 470 | 487 | #define MPI3_IOCLOGINFO_TYPE_SAS (0x3) |
| 471 | 488 | #define MPI3_IOCLOGINFO_LOG_DATA_MASK (0x0fffffff) |
| 489 | +#define MPI3_IOCLOGINFO_LOG_DATA_SHIFT (0) | |
| 472 | 490 | #endif |
| @@ -56,8 +56,8 @@ extern struct list_head mrioc_list; · 55 unmodified lines | ||
| 56 | 56 | extern int prot_mask; |
| 57 | 57 | extern atomic64_t event_counter; |
| 58 | 58 | |
| 59 | −#define MPI3MR_DRIVER_VERSION "8.12.0.3.50" | |
| 60 | −#define MPI3MR_DRIVER_RELDATE "11-November-2024" | |
| 59 | +#define MPI3MR_DRIVER_VERSION "8.13.0.5.50" | |
| 60 | +#define MPI3MR_DRIVER_RELDATE "20-February-2025" | |
| 61 | 61 | |
| 62 | 62 | #define MPI3MR_DRIVER_NAME "mpi3mr" |
| 63 | 63 | #define MPI3MR_DRIVER_LICENSE "GPL" |
| @@ -80,13 +80,14 @@ extern atomic64_t event_counter; · 16 unmodified lines | ||
| 80 | 80 | |
| 81 | 81 | /* Admin queue management definitions */ |
| 82 | 82 | #define MPI3MR_ADMIN_REQ_Q_SIZE (2 * MPI3MR_PAGE_SIZE_4K) |
| 83 | −#define MPI3MR_ADMIN_REPLY_Q_SIZE (4 * MPI3MR_PAGE_SIZE_4K) | |
| 83 | +#define MPI3MR_ADMIN_REPLY_Q_SIZE (8 * MPI3MR_PAGE_SIZE_4K) | |
| 84 | 84 | #define MPI3MR_ADMIN_REQ_FRAME_SZ 128 |
| 85 | 85 | #define MPI3MR_ADMIN_REPLY_FRAME_SZ 16 |
| 86 | 86 | |
| 87 | 87 | /* Operational queue management definitions */ |
| 88 | 88 | #define MPI3MR_OP_REQ_Q_QD 512 |
| 89 | 89 | #define MPI3MR_OP_REP_Q_QD 1024 |
| 90 | +#define MPI3MR_OP_REP_Q_QD2K 2048 | |
| 90 | 91 | #define MPI3MR_OP_REP_Q_QD4K 4096 |
| 91 | 92 | #define MPI3MR_OP_REQ_Q_SEG_SIZE 4096 |
| 92 | 93 | #define MPI3MR_OP_REP_Q_SEG_SIZE 4096 |
| @@ -328,6 +329,7 @@ enum mpi3mr_reset_reason { · 235 unmodified lines | ||
| 328 | 329 | #define MPI3MR_RESET_REASON_OSTYPE_SHIFT 28 |
| 329 | 330 | #define MPI3MR_RESET_REASON_IOCNUM_SHIFT 20 |
| 330 | 331 | |
| 332 | + | |
| 331 | 333 | /* Queue type definitions */ |
| 332 | 334 | enum queue_type { |
| 333 | 335 | MPI3MR_DEFAULT_QUEUE = 0, |
| @@ -387,6 +389,7 @@ struct mpi3mr_ioc_facts { · 53 unmodified lines | ||
| 387 | 389 | u16 max_msix_vectors; |
| 388 | 390 | u8 personality; |
| 389 | 391 | u8 dma_mask; |
| 392 | + bool max_req_limit; | |
| 390 | 393 | u8 protocol_flags; |
| 391 | 394 | u8 sge_mod_mask; |
| 392 | 395 | u8 sge_mod_value; |
| @@ -456,6 +459,8 @@ struct op_req_qinfo { · 63 unmodified lines | ||
| 456 | 459 | * @enable_irq_poll: Flag to indicate polling is enabled |
| 457 | 460 | * @in_use: Queue is handled by poll/ISR |
| 458 | 461 | * @qtype: Type of queue (types defined in enum queue_type) |
| 462 | + * @qfull_watermark: Watermark defined in reply queue to avoid | |
| 463 | + * reply queue full | |
| 459 | 464 | */ |
| 460 | 465 | struct op_reply_qinfo { |
| 461 | 466 | u16 ci; |
| @@ -471,6 +476,7 @@ struct op_reply_qinfo { · 9 unmodified lines | ||
| 471 | 476 | bool enable_irq_poll; |
| 472 | 477 | atomic_t in_use; |
| 473 | 478 | enum queue_type qtype; |
| 479 | + u16 qfull_watermark; | |
| 474 | 480 | }; |
| 475 | 481 | |
| 476 | 482 | /** |
| @@ -928,6 +934,8 @@ struct trigger_event_data { · 451 unmodified lines | ||
| 928 | 934 | * @size: Buffer size |
| 929 | 935 | * @addr: Virtual address |
| 930 | 936 | * @dma_addr: Buffer DMA address |
| 937 | + * @is_segmented: The buffer is segmented or not | |
| 938 | + * @disabled_after_reset: The buffer is disabled after reset | |
| 931 | 939 | */ |
| 932 | 940 | struct diag_buffer_desc { |
| 933 | 941 | u8 type; |
| @@ -937,6 +945,8 @@ struct diag_buffer_desc { · 3 unmodified lines | ||
| 937 | 945 | u32 size; |
| 938 | 946 | void *addr; |
| 939 | 947 | dma_addr_t dma_addr; |
| 948 | + bool is_segmented; | |
| 949 | + bool disabled_after_reset; | |
| 940 | 950 | }; |
| 941 | 951 | |
| 942 | 952 | /** |
| @@ -1022,6 +1032,8 @@ struct scmd_priv { · 79 unmodified lines | ||
| 1022 | 1032 | * @admin_reply_base: Admin reply queue base virtual address |
| 1023 | 1033 | * @admin_reply_dma: Admin reply queue base dma address |
| 1024 | 1034 | * @admin_reply_q_in_use: Queue is handled by poll/ISR |
| 1035 | + * @admin_pend_isr: Count of unprocessed admin ISR/poll calls | |
| 1036 | + * due to another thread processing replies | |
| 1025 | 1037 | * @ready_timeout: Controller ready timeout |
| 1026 | 1038 | * @intr_info: Interrupt cookie pointer |
| 1027 | 1039 | * @intr_info_count: Number of interrupt cookies |
| @@ -1090,6 +1102,7 @@ struct scmd_priv { · 62 unmodified lines | ||
| 1090 | 1102 | * @ts_update_interval: Timestamp update interval |
| 1091 | 1103 | * @reset_in_progress: Reset in progress flag |
| 1092 | 1104 | * @unrecoverable: Controller unrecoverable flag |
| 1105 | + * @io_admin_reset_sync: Manage state of I/O ops during an admin reset process | |
| 1093 | 1106 | * @prev_reset_result: Result of previous reset |
| 1094 | 1107 | * @reset_mutex: Controller reset mutex |
| 1095 | 1108 | * @reset_waitq: Controller reset wait queue |
| @@ -1153,6 +1166,12 @@ struct scmd_priv { · 57 unmodified lines | ||
| 1153 | 1166 | * @snapdump_trigger_active: Snapdump trigger active flag |
| 1154 | 1167 | * @pci_err_recovery: PCI error recovery in progress |
| 1155 | 1168 | * @block_on_pci_err: Block IO during PCI error recovery |
| 1169 | + * @reply_qfull_count: Occurences of reply queue full avoidance kicking-in | |
| 1170 | + * @prevent_reply_qfull: Enable reply queue prevention | |
| 1171 | + * @seg_tb_support: Segmented trace buffer support | |
| 1172 | + * @num_tb_segs: Number of Segments in Trace buffer | |
| 1173 | + * @trace_buf_pool: DMA pool for Segmented trace buffer segments | |
| 1174 | + * @trace_buf: Trace buffer segments memory descriptor | |
| 1156 | 1175 | */ |
| 1157 | 1176 | struct mpi3mr_ioc { |
| 1158 | 1177 | struct list_head list; |
| @@ -1189,6 +1208,7 @@ struct mpi3mr_ioc { · 30 unmodified lines | ||
| 1189 | 1208 | void *admin_reply_base; |
| 1190 | 1209 | dma_addr_t admin_reply_dma; |
| 1191 | 1210 | atomic_t admin_reply_q_in_use; |
| 1211 | + atomic_t admin_pend_isr; | |
| 1192 | 1212 | |
| 1193 | 1213 | u32 ready_timeout; |
| 1194 | 1214 | |
| @@ -1276,6 +1296,7 @@ struct mpi3mr_ioc { · 81 unmodified lines | ||
| 1276 | 1296 | u16 ts_update_interval; |
| 1277 | 1297 | u8 reset_in_progress; |
| 1278 | 1298 | u8 unrecoverable; |
| 1299 | + u8 io_admin_reset_sync; | |
| 1279 | 1300 | int prev_reset_result; |
| 1280 | 1301 | struct mutex reset_mutex; |
| 1281 | 1302 | wait_queue_head_t reset_waitq; |
| @@ -1351,6 +1372,13 @@ struct mpi3mr_ioc { · 69 unmodified lines | ||
| 1351 | 1372 | bool fw_release_trigger_active; |
| 1352 | 1373 | bool pci_err_recovery; |
| 1353 | 1374 | bool block_on_pci_err; |
| 1375 | + atomic_t reply_qfull_count; | |
| 1376 | + bool prevent_reply_qfull; | |
| 1377 | + bool seg_tb_support; | |
| 1378 | + u32 num_tb_segs; | |
| 1379 | + struct dma_pool *trace_buf_pool; | |
| 1380 | + struct segments *trace_buf; | |
| 1381 | + | |
| 1354 | 1382 | }; |
| 1355 | 1383 | |
| 1356 | 1384 | /** |
| @@ -12,23 +12,98 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <uapi/scsi/scsi_bsg_mpi3mr.h> |
| 13 | 13 | |
| 14 | 14 | /** |
| 15 | − * mpi3mr_alloc_trace_buffer: Allocate trace buffer | |
| 15 | + * mpi3mr_alloc_trace_buffer: Allocate segmented trace buffer | |
| 16 | 16 | * @mrioc: Adapter instance reference |
| 17 | 17 | * @trace_size: Trace buffer size |
| 18 | 18 | * |
| 19 | − * Allocate trace buffer | |
| 19 | + * Allocate either segmented memory pools or contiguous buffer | |
| 20 | + * based on the controller capability for the host trace | |
| 21 | + * buffer. | |
| 22 | + * | |
| 20 | 23 | * Return: 0 on success, non-zero on failure. |
| 21 | 24 | */ |
| 22 | 25 | static int mpi3mr_alloc_trace_buffer(struct mpi3mr_ioc *mrioc, u32 trace_size) |
| 23 | 26 | { |
| 24 | 27 | struct diag_buffer_desc *diag_buffer = &mrioc->diag_buffers[0]; |
| 28 | + int i, sz; | |
| 29 | + u64 *diag_buffer_list = NULL; | |
| 30 | + dma_addr_t diag_buffer_list_dma; | |
| 31 | + u32 seg_count; | |
| 32 | + | |
| 33 | + if (mrioc->seg_tb_support) { | |
| 34 | + seg_count = (trace_size) / MPI3MR_PAGE_SIZE_4K; | |
| 35 | + trace_size = seg_count * MPI3MR_PAGE_SIZE_4K; | |
| 36 | + | |
| 37 | + diag_buffer_list = dma_alloc_coherent(&mrioc->pdev->dev, | |
| 38 | + sizeof(u64) * seg_count, | |
| 39 | + &diag_buffer_list_dma, GFP_KERNEL); | |
| 40 | + if (!diag_buffer_list) | |
| 41 | + return -1; | |
| 42 | + | |
| 43 | + mrioc->num_tb_segs = seg_count; | |
| 44 | + | |
| 45 | + sz = sizeof(struct segments) * seg_count; | |
| 46 | + mrioc->trace_buf = kzalloc(sz, GFP_KERNEL); | |
| 47 | + if (!mrioc->trace_buf) | |
| 48 | + goto trace_buf_failed; | |
| 49 | + | |
| 50 | + mrioc->trace_buf_pool = dma_pool_create("trace_buf pool", | |
| 51 | + &mrioc->pdev->dev, MPI3MR_PAGE_SIZE_4K, MPI3MR_PAGE_SIZE_4K, | |
| 52 | + 0); | |
| 53 | + if (!mrioc->trace_buf_pool) { | |
| 54 | + ioc_err(mrioc, "trace buf pool: dma_pool_create failed\n"); | |
| 55 | + goto trace_buf_pool_failed; | |
| 56 | + } | |
| 25 | 57 | |
| 26 | − diag_buffer->addr = dma_alloc_coherent(&mrioc->pdev->dev, | |
| 27 | − trace_size, &diag_buffer->dma_addr, GFP_KERNEL); | |
| 28 | − if (diag_buffer->addr) { | |
| 29 | − dprint_init(mrioc, "trace diag buffer is allocated successfully\n"); | |
| 58 | + for (i = 0; i < seg_count; i++) { | |
| 59 | + mrioc->trace_buf[i].segment = | |
| 60 | + dma_pool_zalloc(mrioc->trace_buf_pool, GFP_KERNEL, | |
| 61 | + &mrioc->trace_buf[i].segment_dma); | |
| 62 | + diag_buffer_list[i] = | |
| 63 | + (u64) mrioc->trace_buf[i].segment_dma; | |
| 64 | + if (!diag_buffer_list[i]) | |
| 65 | + goto tb_seg_alloc_failed; | |
| 66 | + } | |
| 67 | + | |
| 68 | + diag_buffer->addr = diag_buffer_list; | |
| 69 | + diag_buffer->dma_addr = diag_buffer_list_dma; | |
| 70 | + diag_buffer->is_segmented = true; | |
| 71 | + | |
| 72 | + dprint_init(mrioc, "segmented trace diag buffer\n" | |
| 73 | + "is allocated successfully seg_count:%d\n", seg_count); | |
| 30 | 74 | return 0; |
| 75 | + } else { | |
| 76 | + diag_buffer->addr = dma_alloc_coherent(&mrioc->pdev->dev, | |
| 77 | + trace_size, &diag_buffer->dma_addr, GFP_KERNEL); | |
| 78 | + if (diag_buffer->addr) { | |
| 79 | + dprint_init(mrioc, "trace diag buffer is allocated successfully\n"); | |
| 80 | + return 0; | |
| 81 | + } | |
| 82 | + return -1; | |
| 31 | 83 | } |
| 84 | + | |
| 85 | +tb_seg_alloc_failed: | |
| 86 | + if (mrioc->trace_buf_pool) { | |
| 87 | + for (i = 0; i < mrioc->num_tb_segs; i++) { | |
| 88 | + if (mrioc->trace_buf[i].segment) { | |
| 89 | + dma_pool_free(mrioc->trace_buf_pool, | |
| 90 | + mrioc->trace_buf[i].segment, | |
| 91 | + mrioc->trace_buf[i].segment_dma); | |
| 92 | + mrioc->trace_buf[i].segment = NULL; | |
| 93 | + } | |
| 94 | + mrioc->trace_buf[i].segment = NULL; | |
| 95 | + } | |
| 96 | + dma_pool_destroy(mrioc->trace_buf_pool); | |
| 97 | + mrioc->trace_buf_pool = NULL; | |
| 98 | + } | |
| 99 | +trace_buf_pool_failed: | |
| 100 | + kfree(mrioc->trace_buf); | |
| 101 | + mrioc->trace_buf = NULL; | |
| 102 | +trace_buf_failed: | |
| 103 | + if (diag_buffer_list) | |
| 104 | + dma_free_coherent(&mrioc->pdev->dev, | |
| 105 | + sizeof(u64) * mrioc->num_tb_segs, | |
| 106 | + diag_buffer_list, diag_buffer_list_dma); | |
| 32 | 107 | return -1; |
| 33 | 108 | } |
| 34 | 109 | |
| @@ -100,8 +175,9 @@ retry_trace: · 65 unmodified lines | ||
| 100 | 175 | dprint_init(mrioc, |
| 101 | 176 | "trying to allocate trace diag buffer of size = %dKB\n", |
| 102 | 177 | trace_size / 1024); |
| 103 | − if (get_order(trace_size) > MAX_PAGE_ORDER || | |
| 178 | + if ((!mrioc->seg_tb_support && (get_order(trace_size) > MAX_PAGE_ORDER)) || | |
| 104 | 179 | mpi3mr_alloc_trace_buffer(mrioc, trace_size)) { |
| 180 | + | |
| 105 | 181 | retry = true; |
| 106 | 182 | trace_size -= trace_dec_size; |
| 107 | 183 | dprint_init(mrioc, "trace diag buffer allocation failed\n" |
| @@ -161,6 +237,12 @@ int mpi3mr_issue_diag_buf_post(struct mpi3mr_ioc *mrioc, · 53 unmodified lines | ||
| 161 | 237 | u8 prev_status; |
| 162 | 238 | int retval = 0; |
| 163 | 239 | |
| 240 | + if (diag_buffer->disabled_after_reset) { | |
| 241 | + dprint_bsg_err(mrioc, "%s: skipping diag buffer posting\n" | |
| 242 | + "as it is disabled after reset\n", __func__); | |
| 243 | + return -1; | |
| 244 | + } | |
| 245 | + | |
| 164 | 246 | memset(&diag_buf_post_req, 0, sizeof(diag_buf_post_req)); |
| 165 | 247 | mutex_lock(&mrioc->init_cmds.mutex); |
| 166 | 248 | if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { |
| @@ -177,8 +259,12 @@ int mpi3mr_issue_diag_buf_post(struct mpi3mr_ioc *mrioc, · 10 unmodified lines | ||
| 177 | 259 | diag_buf_post_req.address = le64_to_cpu(diag_buffer->dma_addr); |
| 178 | 260 | diag_buf_post_req.length = le32_to_cpu(diag_buffer->size); |
| 179 | 261 | |
| 180 | − dprint_bsg_info(mrioc, "%s: posting diag buffer type %d\n", __func__, | |
| 181 | − diag_buffer->type); | |
| 262 | + if (diag_buffer->is_segmented) | |
| 263 | + diag_buf_post_req.msg_flags |= MPI3_DIAG_BUFFER_POST_MSGFLAGS_SEGMENTED; | |
| 264 | + | |
| 265 | + dprint_bsg_info(mrioc, "%s: posting diag buffer type %d segmented:%d\n", __func__, | |
| 266 | + diag_buffer->type, diag_buffer->is_segmented); | |
| 267 | + | |
| 182 | 268 | prev_status = diag_buffer->status; |
| 183 | 269 | diag_buffer->status = MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED; |
| 184 | 270 | init_completion(&mrioc->init_cmds.done); |
| @@ -2339,6 +2425,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) · 2154 unmodified lines | ||
| 2339 | 2425 | } |
| 2340 | 2426 | |
| 2341 | 2427 | if (!mrioc->ioctl_sges_allocated) { |
| 2428 | + mutex_unlock(&mrioc->bsg_cmds.mutex); | |
| 2342 | 2429 | dprint_bsg_err(mrioc, "%s: DMA memory was not allocated\n", |
| 2343 | 2430 | __func__); |
| 2344 | 2431 | return -ENOMEM; |
| @@ -3060,6 +3147,29 @@ reply_queue_count_show(struct device *dev, struct device_attribute *attr, · 715 unmodified lines | ||
| 3060 | 3147 | |
| 3061 | 3148 | static DEVICE_ATTR_RO(reply_queue_count); |
| 3062 | 3149 | |
| 3150 | +/** | |
| 3151 | + * reply_qfull_count_show - Show reply qfull count | |
| 3152 | + * @dev: class device | |
| 3153 | + * @attr: Device attributes | |
| 3154 | + * @buf: Buffer to copy | |
| 3155 | + * | |
| 3156 | + * Retrieves the current value of the reply_qfull_count from the mrioc structure and | |
| 3157 | + * formats it as a string for display. | |
| 3158 | + * | |
| 3159 | + * Return: sysfs_emit() return | |
| 3160 | + */ | |
| 3161 | +static ssize_t | |
| 3162 | +reply_qfull_count_show(struct device *dev, struct device_attribute *attr, | |
| 3163 | + char *buf) | |
| 3164 | +{ | |
| 3165 | + struct Scsi_Host *shost = class_to_shost(dev); | |
| 3166 | + struct mpi3mr_ioc *mrioc = shost_priv(shost); | |
| 3167 | + | |
| 3168 | + return sysfs_emit(buf, "%u\n", atomic_read(&mrioc->reply_qfull_count)); | |
| 3169 | +} | |
| 3170 | + | |
| 3171 | +static DEVICE_ATTR_RO(reply_qfull_count); | |
| 3172 | + | |
| 3063 | 3173 | /** |
| 3064 | 3174 | * logging_level_show - Show controller debug level |
| 3065 | 3175 | * @dev: class device |
| @@ -3152,6 +3262,7 @@ static struct attribute *mpi3mr_host_attrs[] = { · 86 unmodified lines | ||
| 3152 | 3262 | &dev_attr_fw_queue_depth.attr, |
| 3153 | 3263 | &dev_attr_op_req_q_count.attr, |
| 3154 | 3264 | &dev_attr_reply_queue_count.attr, |
| 3265 | + &dev_attr_reply_qfull_count.attr, | |
| 3155 | 3266 | &dev_attr_logging_level.attr, |
| 3156 | 3267 | &dev_attr_adp_state.attr, |
| 3157 | 3268 | NULL, |
| @@ -17,7 +17,7 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, · 16 unmodified lines | ||
| 17 | 17 | struct mpi3_ioc_facts_data *facts_data); |
| 18 | 18 | static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc, |
| 19 | 19 | struct mpi3mr_drv_cmd *drv_cmd); |
| 20 | − | |
| 20 | +static int mpi3mr_check_op_admin_proc(struct mpi3mr_ioc *mrioc); | |
| 21 | 21 | static int poll_queues; |
| 22 | 22 | module_param(poll_queues, int, 0444); |
| 23 | 23 | MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)"); |
| @@ -446,8 +446,10 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) · 422 unmodified lines | ||
| 446 | 446 | u16 threshold_comps = 0; |
| 447 | 447 | struct mpi3_default_reply_descriptor *reply_desc; |
| 448 | 448 | |
| 449 | − if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1)) | |
| 449 | + if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1)) { | |
| 450 | + atomic_inc(&mrioc->admin_pend_isr); | |
| 450 | 451 | return 0; |
| 452 | + } | |
| 451 | 453 | |
| 452 | 454 | reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base + |
| 453 | 455 | admin_reply_ci; |
| @@ -459,7 +461,7 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) · 5 unmodified lines | ||
| 459 | 461 | } |
| 460 | 462 | |
| 461 | 463 | do { |
| 462 | − if (mrioc->unrecoverable) | |
| 464 | + if (mrioc->unrecoverable || mrioc->io_admin_reset_sync) | |
| 463 | 465 | break; |
| 464 | 466 | |
| 465 | 467 | mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci); |
| @@ -554,7 +556,7 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, · 88 unmodified lines | ||
| 554 | 556 | } |
| 555 | 557 | |
| 556 | 558 | do { |
| 557 | − if (mrioc->unrecoverable) | |
| 559 | + if (mrioc->unrecoverable || mrioc->io_admin_reset_sync) | |
| 558 | 560 | break; |
| 559 | 561 | |
| 560 | 562 | req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1; |
| @@ -1302,7 +1304,7 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, · 741 unmodified lines | ||
| 1302 | 1304 | (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) |
| 1303 | 1305 | retval = 0; |
| 1304 | 1306 | |
| 1305 | − ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n", | |
| 1307 | + ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%08x)/(0x%08x)\n", | |
| 1306 | 1308 | (!retval) ? "successful" : "failed", ioc_status, ioc_config); |
| 1307 | 1309 | return retval; |
| 1308 | 1310 | } |
| @@ -1355,6 +1357,19 @@ mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc) · 46 unmodified lines | ||
| 1355 | 1357 | "\tcontroller while sas transport support is enabled at the\n" |
| 1356 | 1358 | "\tdriver, please reboot the system or reload the driver\n"); |
| 1357 | 1359 | |
| 1360 | + if (mrioc->seg_tb_support) { | |
| 1361 | + if (!(mrioc->facts.ioc_capabilities & | |
| 1362 | + MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_SUPPORTED)) { | |
| 1363 | + ioc_err(mrioc, | |
| 1364 | + "critical error: previously enabled segmented trace\n" | |
| 1365 | + " buffer capability is disabled after reset. Please\n" | |
| 1366 | + " update the firmware or reboot the system or\n" | |
| 1367 | + " reload the driver to enable trace diag buffer\n"); | |
| 1368 | + mrioc->diag_buffers[0].disabled_after_reset = true; | |
| 1369 | + } else | |
| 1370 | + mrioc->diag_buffers[0].disabled_after_reset = false; | |
| 1371 | + } | |
| 1372 | + | |
| 1358 | 1373 | if (mrioc->facts.max_devhandle > mrioc->dev_handle_bitmap_bits) { |
| 1359 | 1374 | removepend_bitmap = bitmap_zalloc(mrioc->facts.max_devhandle, |
| 1360 | 1375 | GFP_KERNEL); |
| @@ -1717,7 +1732,7 @@ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, · 356 unmodified lines | ||
| 1717 | 1732 | ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); |
| 1718 | 1733 | ioc_status = readl(&mrioc->sysif_regs->ioc_status); |
| 1719 | 1734 | ioc_info(mrioc, |
| 1720 | − "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n", | |
| 1735 | + "ioc_status/ioc_config after %s reset is (0x%08x)/(0x%08x)\n", | |
| 1721 | 1736 | (!retval)?"successful":"failed", ioc_status, |
| 1722 | 1737 | ioc_config); |
| 1723 | 1738 | if (retval) |
| @@ -2104,15 +2119,22 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) · 380 unmodified lines | ||
| 2104 | 2119 | } |
| 2105 | 2120 | |
| 2106 | 2121 | reply_qid = qidx + 1; |
| 2107 | − op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; | |
| 2108 | − if ((mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) && | |
| 2109 | − !mrioc->pdev->revision) | |
| 2110 | − op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K; | |
| 2122 | + | |
| 2123 | + if (mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) { | |
| 2124 | + if (mrioc->pdev->revision) | |
| 2125 | + op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; | |
| 2126 | + else | |
| 2127 | + op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K; | |
| 2128 | + } else | |
| 2129 | + op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD2K; | |
| 2130 | + | |
| 2111 | 2131 | op_reply_q->ci = 0; |
| 2112 | 2132 | op_reply_q->ephase = 1; |
| 2113 | 2133 | atomic_set(&op_reply_q->pend_ios, 0); |
| 2114 | 2134 | atomic_set(&op_reply_q->in_use, 0); |
| 2115 | 2135 | op_reply_q->enable_irq_poll = false; |
| 2136 | + op_reply_q->qfull_watermark = | |
| 2137 | + op_reply_q->num_replies - (MPI3MR_THRESHOLD_REPLY_COUNT * 2); | |
| 2116 | 2138 | |
| 2117 | 2139 | if (!op_reply_q->q_segments) { |
| 2118 | 2140 | retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx); |
| @@ -2416,8 +2438,10 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, · 297 unmodified lines | ||
| 2416 | 2438 | void *segment_base_addr; |
| 2417 | 2439 | u16 req_sz = mrioc->facts.op_req_sz; |
| 2418 | 2440 | struct segments *segments = op_req_q->q_segments; |
| 2441 | + struct op_reply_qinfo *op_reply_q = NULL; | |
| 2419 | 2442 | |
| 2420 | 2443 | reply_qidx = op_req_q->reply_qid - 1; |
| 2444 | + op_reply_q = mrioc->op_reply_qinfo + reply_qidx; | |
| 2421 | 2445 | |
| 2422 | 2446 | if (mrioc->unrecoverable) |
| 2423 | 2447 | return -EFAULT; |
| @@ -2448,6 +2472,15 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, · 24 unmodified lines | ||
| 2448 | 2472 | goto out; |
| 2449 | 2473 | } |
| 2450 | 2474 | |
| 2475 | + /* Reply queue is nearing to get full, push back IOs to SML */ | |
| 2476 | + if ((mrioc->prevent_reply_qfull == true) && | |
| 2477 | + (atomic_read(&op_reply_q->pend_ios) > | |
| 2478 | + (op_reply_q->qfull_watermark))) { | |
| 2479 | + atomic_inc(&mrioc->reply_qfull_count); | |
| 2480 | + retval = -EAGAIN; | |
| 2481 | + goto out; | |
| 2482 | + } | |
| 2483 | + | |
| 2451 | 2484 | segment_base_addr = segments[pi / op_req_q->segment_qd].segment; |
| 2452 | 2485 | req_entry = (u8 *)segment_base_addr + |
| 2453 | 2486 | ((pi % op_req_q->segment_qd) * req_sz); |
| @@ -2726,7 +2759,16 @@ static void mpi3mr_watchdog_work(struct work_struct *work) · 272 unmodified lines | ||
| 2726 | 2759 | return; |
| 2727 | 2760 | } |
| 2728 | 2761 | |
| 2729 | − if (mrioc->ts_update_counter++ >= mrioc->ts_update_interval) { | |
| 2762 | + if (atomic_read(&mrioc->admin_pend_isr)) { | |
| 2763 | + ioc_err(mrioc, "Unprocessed admin ISR instance found\n" | |
| 2764 | + "flush admin replies\n"); | |
| 2765 | + mpi3mr_process_admin_reply_q(mrioc); | |
| 2766 | + } | |
| 2767 | + | |
| 2768 | + if (!(mrioc->facts.ioc_capabilities & | |
| 2769 | + MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC) && | |
| 2770 | + (mrioc->ts_update_counter++ >= mrioc->ts_update_interval)) { | |
| 2771 | + | |
| 2730 | 2772 | mrioc->ts_update_counter = 0; |
| 2731 | 2773 | mpi3mr_sync_timestamp(mrioc); |
| 2732 | 2774 | } |
| @@ -3091,6 +3133,9 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, · 358 unmodified lines | ||
| 3091 | 3133 | mrioc->facts.dma_mask = (facts_flags & |
| 3092 | 3134 | MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> |
| 3093 | 3135 | MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; |
| 3136 | + mrioc->facts.dma_mask = (facts_flags & | |
| 3137 | + MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> | |
| 3138 | + MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; | |
| 3094 | 3139 | mrioc->facts.protocol_flags = facts_data->protocol_flags; |
| 3095 | 3140 | mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word); |
| 3096 | 3141 | mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_requests); |
| @@ -4214,6 +4259,13 @@ retry_init: · 1117 unmodified lines | ||
| 4214 | 4259 | mrioc->shost->transportt = mpi3mr_transport_template; |
| 4215 | 4260 | } |
| 4216 | 4261 | |
| 4262 | + if (mrioc->facts.max_req_limit) | |
| 4263 | + mrioc->prevent_reply_qfull = true; | |
| 4264 | + | |
| 4265 | + if (mrioc->facts.ioc_capabilities & | |
| 4266 | + MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_SUPPORTED) | |
| 4267 | + mrioc->seg_tb_support = true; | |
| 4268 | + | |
| 4217 | 4269 | mrioc->reply_sz = mrioc->facts.reply_sz; |
| 4218 | 4270 | |
| 4219 | 4271 | retval = mpi3mr_check_reset_dma_mask(mrioc); |
| @@ -4370,6 +4422,7 @@ retry_init: · 150 unmodified lines | ||
| 4370 | 4422 | goto out_failed_noretry; |
| 4371 | 4423 | } |
| 4372 | 4424 | |
| 4425 | + mrioc->io_admin_reset_sync = 0; | |
| 4373 | 4426 | if (is_resume || mrioc->block_on_pci_err) { |
| 4374 | 4427 | dprint_reset(mrioc, "setting up single ISR\n"); |
| 4375 | 4428 | retval = mpi3mr_setup_isr(mrioc, 1); |
| @@ -4671,7 +4724,7 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) · 295 unmodified lines | ||
| 4671 | 4724 | */ |
| 4672 | 4725 | void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) |
| 4673 | 4726 | { |
| 4674 | − u16 i; | |
| 4727 | + u16 i, j; | |
| 4675 | 4728 | struct mpi3mr_intr_info *intr_info; |
| 4676 | 4729 | struct diag_buffer_desc *diag_buffer; |
| 4677 | 4730 | |
| @@ -4806,6 +4859,26 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) · 128 unmodified lines | ||
| 4806 | 4859 | |
| 4807 | 4860 | for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) { |
| 4808 | 4861 | diag_buffer = &mrioc->diag_buffers[i]; |
| 4862 | + if ((i == 0) && mrioc->seg_tb_support) { | |
| 4863 | + if (mrioc->trace_buf_pool) { | |
| 4864 | + for (j = 0; j < mrioc->num_tb_segs; j++) { | |
| 4865 | + if (mrioc->trace_buf[j].segment) { | |
| 4866 | + dma_pool_free(mrioc->trace_buf_pool, | |
| 4867 | + mrioc->trace_buf[j].segment, | |
| 4868 | + mrioc->trace_buf[j].segment_dma); | |
| 4869 | + mrioc->trace_buf[j].segment = NULL; | |
| 4870 | + } | |
| 4871 | + | |
| 4872 | + mrioc->trace_buf[j].segment = NULL; | |
| 4873 | + } | |
| 4874 | + dma_pool_destroy(mrioc->trace_buf_pool); | |
| 4875 | + mrioc->trace_buf_pool = NULL; | |
| 4876 | + } | |
| 4877 | + | |
| 4878 | + kfree(mrioc->trace_buf); | |
| 4879 | + mrioc->trace_buf = NULL; | |
| 4880 | + diag_buffer->size = sizeof(u64) * mrioc->num_tb_segs; | |
| 4881 | + } | |
| 4809 | 4882 | if (diag_buffer->addr) { |
| 4810 | 4883 | dma_free_coherent(&mrioc->pdev->dev, |
| 4811 | 4884 | diag_buffer->size, diag_buffer->addr, |
| @@ -4883,7 +4956,7 @@ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) · 71 unmodified lines | ||
| 4883 | 4956 | } |
| 4884 | 4957 | |
| 4885 | 4958 | ioc_info(mrioc, |
| 4886 | − "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n", | |
| 4959 | + "Base IOC Sts/Config after %s shutdown is (0x%08x)/(0x%08x)\n", | |
| 4887 | 4960 | (!retval) ? "successful" : "failed", ioc_status, |
| 4888 | 4961 | ioc_config); |
| 4889 | 4962 | } |
| @@ -5228,6 +5301,55 @@ cleanup_drv_cmd: · 338 unmodified lines | ||
| 5228 | 5301 | drv_cmd->retry_count = 0; |
| 5229 | 5302 | } |
| 5230 | 5303 | |
| 5304 | +/** | |
| 5305 | + * mpi3mr_check_op_admin_proc - | |
| 5306 | + * @mrioc: Adapter instance reference | |
| 5307 | + * | |
| 5308 | + * Check if any of the operation reply queues | |
| 5309 | + * or the admin reply queue are currently in use. | |
| 5310 | + * If any queue is in use, this function waits for | |
| 5311 | + * a maximum of 10 seconds for them to become available. | |
| 5312 | + * | |
| 5313 | + * Return: 0 on success, non-zero on failure. | |
| 5314 | + */ | |
| 5315 | +static int mpi3mr_check_op_admin_proc(struct mpi3mr_ioc *mrioc) | |
| 5316 | +{ | |
| 5317 | + | |
| 5318 | + u16 timeout = 10 * 10; | |
| 5319 | + u16 elapsed_time = 0; | |
| 5320 | + bool op_admin_in_use = false; | |
| 5321 | + | |
| 5322 | + do { | |
| 5323 | + op_admin_in_use = false; | |
| 5324 | + | |
| 5325 | + /* Check admin_reply queue first to exit early */ | |
| 5326 | + if (atomic_read(&mrioc->admin_reply_q_in_use) == 1) | |
| 5327 | + op_admin_in_use = true; | |
| 5328 | + else { | |
| 5329 | + /* Check op_reply queues */ | |
| 5330 | + int i; | |
| 5331 | + | |
| 5332 | + for (i = 0; i < mrioc->num_queues; i++) { | |
| 5333 | + if (atomic_read(&mrioc->op_reply_qinfo[i].in_use) == 1) { | |
| 5334 | + op_admin_in_use = true; | |
| 5335 | + break; | |
| 5336 | + } | |
| 5337 | + } | |
| 5338 | + } | |
| 5339 | + | |
| 5340 | + if (!op_admin_in_use) | |
| 5341 | + break; | |
| 5342 | + | |
| 5343 | + msleep(100); | |
| 5344 | + | |
| 5345 | + } while (++elapsed_time < timeout); | |
| 5346 | + | |
| 5347 | + if (op_admin_in_use) | |
| 5348 | + return 1; | |
| 5349 | + | |
| 5350 | + return 0; | |
| 5351 | +} | |
| 5352 | + | |
| 5231 | 5353 | /** |
| 5232 | 5354 | * mpi3mr_soft_reset_handler - Reset the controller |
| 5233 | 5355 | * @mrioc: Adapter instance reference |
| @@ -5308,6 +5430,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, · 74 unmodified lines | ||
| 5308 | 5430 | mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT); |
| 5309 | 5431 | |
| 5310 | 5432 | mpi3mr_ioc_disable_intr(mrioc); |
| 5433 | + mrioc->io_admin_reset_sync = 1; | |
| 5311 | 5434 | |
| 5312 | 5435 | if (snapdump) { |
| 5313 | 5436 | mpi3mr_set_diagsave(mrioc); |
| @@ -5335,6 +5458,16 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, · 21 unmodified lines | ||
| 5335 | 5458 | ioc_err(mrioc, "Failed to issue soft reset to the ioc\n"); |
| 5336 | 5459 | goto out; |
| 5337 | 5460 | } |
| 5461 | + | |
| 5462 | + retval = mpi3mr_check_op_admin_proc(mrioc); | |
| 5463 | + if (retval) { | |
| 5464 | + ioc_err(mrioc, "Soft reset failed due to an Admin or I/O queue polling\n" | |
| 5465 | + "thread still processing replies even after a 10 second\n" | |
| 5466 | + "timeout. Marking the controller as unrecoverable!\n"); | |
| 5467 | + | |
| 5468 | + goto out; | |
| 5469 | + } | |
| 5470 | + | |
| 5338 | 5471 | if (mrioc->num_io_throttle_group != |
| 5339 | 5472 | mrioc->facts.max_io_throttle_group) { |
| 5340 | 5473 | ioc_err(mrioc, |
| @@ -3839,6 +3839,18 @@ int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, · 3838 unmodified lines | ||
| 3839 | 3839 | tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle); |
| 3840 | 3840 | |
| 3841 | 3841 | if (scmd) { |
| 3842 | + if (tm_type == MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { | |
| 3843 | + cmd_priv = scsi_cmd_priv(scmd); | |
| 3844 | + if (!cmd_priv) | |
| 3845 | + goto out_unlock; | |
| 3846 | + | |
| 3847 | + struct op_req_qinfo *op_req_q; | |
| 3848 | + | |
| 3849 | + op_req_q = &mrioc->req_qinfo[cmd_priv->req_q_idx]; | |
| 3850 | + tm_req.task_host_tag = cpu_to_le16(cmd_priv->host_tag); | |
| 3851 | + tm_req.task_request_queue_id = | |
| 3852 | + cpu_to_le16(op_req_q->qid); | |
| 3853 | + } | |
| 3842 | 3854 | sdev = scmd->device; |
| 3843 | 3855 | sdev_priv_data = sdev->hostdata; |
| 3844 | 3856 | scsi_tgt_priv_data = ((sdev_priv_data) ? |
| @@ -4387,6 +4399,92 @@ out: · 542 unmodified lines | ||
| 4387 | 4399 | return retval; |
| 4388 | 4400 | } |
| 4389 | 4401 | |
| 4402 | +/** | |
| 4403 | + * mpi3mr_eh_abort - Callback function for abort error handling | |
| 4404 | + * @scmd: SCSI command reference | |
| 4405 | + * | |
| 4406 | + * Issues Abort Task Management if the command is in LLD scope | |
| 4407 | + * and verifies if it is aborted successfully, and return status | |
| 4408 | + * accordingly. | |
| 4409 | + * | |
| 4410 | + * Return: SUCCESS if the abort was successful, otherwise FAILED | |
| 4411 | + */ | |
| 4412 | +static int mpi3mr_eh_abort(struct scsi_cmnd *scmd) | |
| 4413 | +{ | |
| 4414 | + struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host); | |
| 4415 | + struct mpi3mr_stgt_priv_data *stgt_priv_data; | |
| 4416 | + struct mpi3mr_sdev_priv_data *sdev_priv_data; | |
| 4417 | + struct scmd_priv *cmd_priv; | |
| 4418 | + u16 dev_handle, timeout = MPI3MR_ABORTTM_TIMEOUT; | |
| 4419 | + u8 resp_code = 0; | |
| 4420 | + int retval = FAILED, ret = 0; | |
| 4421 | + struct request *rq = scsi_cmd_to_rq(scmd); | |
| 4422 | + unsigned long scmd_age_ms = jiffies_to_msecs(jiffies - scmd->jiffies_at_alloc); | |
| 4423 | + unsigned long scmd_age_sec = scmd_age_ms / HZ; | |
| 4424 | + | |
| 4425 | + sdev_printk(KERN_INFO, scmd->device, | |
| 4426 | + "%s: attempting abort task for scmd(%p)\n", mrioc->name, scmd); | |
| 4427 | + | |
| 4428 | + sdev_printk(KERN_INFO, scmd->device, | |
| 4429 | + "%s: scmd(0x%p) is outstanding for %lus %lums, timeout %us, retries %d, allowed %d\n", | |
| 4430 | + mrioc->name, scmd, scmd_age_sec, scmd_age_ms % HZ, rq->timeout / HZ, | |
| 4431 | + scmd->retries, scmd->allowed); | |
| 4432 | + | |
| 4433 | + scsi_print_command(scmd); | |
| 4434 | + | |
| 4435 | + sdev_priv_data = scmd->device->hostdata; | |
| 4436 | + if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) { | |
| 4437 | + sdev_printk(KERN_INFO, scmd->device, | |
| 4438 | + "%s: Device not available, Skip issuing abort task\n", | |
| 4439 | + mrioc->name); | |
| 4440 | + retval = SUCCESS; | |
| 4441 | + goto out; | |
| 4442 | + } | |
| 4443 | + | |
| 4444 | + stgt_priv_data = sdev_priv_data->tgt_priv_data; | |
| 4445 | + dev_handle = stgt_priv_data->dev_handle; | |
| 4446 | + | |
| 4447 | + cmd_priv = scsi_cmd_priv(scmd); | |
| 4448 | + if (!cmd_priv->in_lld_scope || | |
| 4449 | + cmd_priv->host_tag == MPI3MR_HOSTTAG_INVALID) { | |
| 4450 | + sdev_printk(KERN_INFO, scmd->device, | |
| 4451 | + "%s: scmd (0x%p) not in LLD scope, Skip issuing Abort Task\n", | |
| 4452 | + mrioc->name, scmd); | |
| 4453 | + retval = SUCCESS; | |
| 4454 | + goto out; | |
| 4455 | + } | |
| 4456 | + | |
| 4457 | + if (stgt_priv_data->dev_removed) { | |
| 4458 | + sdev_printk(KERN_INFO, scmd->device, | |
| 4459 | + "%s: Device (handle = 0x%04x) removed, Skip issuing Abort Task\n", | |
| 4460 | + mrioc->name, dev_handle); | |
| 4461 | + retval = FAILED; | |
| 4462 | + goto out; | |
| 4463 | + } | |
| 4464 | + | |
| 4465 | + ret = mpi3mr_issue_tm(mrioc, MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK, | |
| 4466 | + dev_handle, sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS, | |
| 4467 | + timeout, &mrioc->host_tm_cmds, &resp_code, scmd); | |
| 4468 | + | |
| 4469 | + if (ret) | |
| 4470 | + goto out; | |
| 4471 | + | |
| 4472 | + if (cmd_priv->in_lld_scope) { | |
| 4473 | + sdev_printk(KERN_INFO, scmd->device, | |
| 4474 | + "%s: Abort task failed. scmd (0x%p) was not terminated\n", | |
| 4475 | + mrioc->name, scmd); | |
| 4476 | + goto out; | |
| 4477 | + } | |
| 4478 | + | |
| 4479 | + retval = SUCCESS; | |
| 4480 | +out: | |
| 4481 | + sdev_printk(KERN_INFO, scmd->device, | |
| 4482 | + "%s: Abort Task %s for scmd (0x%p)\n", mrioc->name, | |
| 4483 | + ((retval == SUCCESS) ? "SUCCEEDED" : "FAILED"), scmd); | |
| 4484 | + | |
| 4485 | + return retval; | |
| 4486 | +} | |
| 4487 | + | |
| 4390 | 4488 | /** |
| 4391 | 4489 | * mpi3mr_scan_start - Scan start callback handler |
| 4392 | 4490 | * @shost: SCSI host reference |
| @@ -5069,6 +5167,7 @@ static const struct scsi_host_template mpi3mr_driver_template = { · 676 unmodified lines | ||
| 5069 | 5167 | .scan_finished = mpi3mr_scan_finished, |
| 5070 | 5168 | .scan_start = mpi3mr_scan_start, |
| 5071 | 5169 | .change_queue_depth = mpi3mr_change_queue_depth, |
| 5170 | + .eh_abort_handler = mpi3mr_eh_abort, | |
| 5072 | 5171 | .eh_device_reset_handler = mpi3mr_eh_dev_reset, |
| 5073 | 5172 | .eh_target_reset_handler = mpi3mr_eh_target_reset, |
| 5074 | 5173 | .eh_bus_reset_handler = mpi3mr_eh_bus_reset, |
| @@ -5803,7 +5902,7 @@ static const struct pci_device_id mpi3mr_pci_id_table[] = { · 728 unmodified lines | ||
| 5803 | 5902 | }; |
| 5804 | 5903 | MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table); |
| 5805 | 5904 | |
| 5806 | −static struct pci_error_handlers mpi3mr_err_handler = { | |
| 5905 | +static const struct pci_error_handlers mpi3mr_err_handler = { | |
| 5807 | 5906 | .error_detected = mpi3mr_pcierr_error_detected, |
| 5808 | 5907 | .mmio_enabled = mpi3mr_pcierr_mmio_enabled, |
| 5809 | 5908 | .slot_reset = mpi3mr_pcierr_slot_reset, |
| @@ -125,6 +125,12 @@ · 124 unmodified lines | ||
| 125 | 125 | * 06-24-19 02.00.55 Bumped MPI2_HEADER_VERSION_UNIT |
| 126 | 126 | * 08-01-19 02.00.56 Bumped MPI2_HEADER_VERSION_UNIT |
| 127 | 127 | * 10-02-19 02.00.57 Bumped MPI2_HEADER_VERSION_UNIT |
| 128 | + * 07-20-20 02.00.58 Bumped MPI2_HEADER_VERSION_UNIT | |
| 129 | + * 03-30-21 02.00.59 Bumped MPI2_HEADER_VERSION_UNIT | |
| 130 | + * 06-03-22 02.00.60 Bumped MPI2_HEADER_VERSION_UNIT | |
| 131 | + * 09-20-23 02.00.61 Bumped MPI2_HEADER_VERSION_UNIT | |
| 132 | + * 09-13-24 02.00.62 Bumped MPI2_HEADER_VERSION_UNIT | |
| 133 | + * Added MPI2_FUNCTION_MCTP_PASSTHROUGH | |
| 128 | 134 | * -------------------------------------------------------------------------- |
| 129 | 135 | */ |
| 130 | 136 | |
| @@ -165,7 +171,7 @@ · 34 unmodified lines | ||
| 165 | 171 | |
| 166 | 172 | |
| 167 | 173 | /* Unit and Dev versioning for this MPI header set */ |
| 168 | −#define MPI2_HEADER_VERSION_UNIT (0x39) | |
| 174 | +#define MPI2_HEADER_VERSION_UNIT (0x3E) | |
| 169 | 175 | #define MPI2_HEADER_VERSION_DEV (0x00) |
| 170 | 176 | #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) |
| 171 | 177 | #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) |
| @@ -669,6 +675,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION { · 497 unmodified lines | ||
| 669 | 675 | #define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) |
| 670 | 676 | #define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) |
| 671 | 677 | #define MPI2_FUNCTION_NVME_ENCAPSULATED (0x33) |
| 678 | +#define MPI2_FUNCTION_MCTP_PASSTHROUGH (0x34) | |
| 672 | 679 | #define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) |
| 673 | 680 | #define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) |
| 674 | 681 | |
| @@ -251,6 +251,7 @@ · 250 unmodified lines | ||
| 251 | 251 | * 12-17-18 02.00.47 Swap locations of Slotx2 and Slotx4 in ManPage 7. |
| 252 | 252 | * 08-01-19 02.00.49 Add MPI26_MANPAGE7_FLAG_X2_X4_SLOT_INFO_VALID |
| 253 | 253 | * Add MPI26_IOUNITPAGE1_NVME_WRCACHE_SHIFT |
| 254 | + * 09-13-24 02.00.50 Added PCIe 32 GT/s link rate | |
| 254 | 255 | */ |
| 255 | 256 | |
| 256 | 257 | #ifndef MPI2_CNFG_H |
| @@ -1121,6 +1122,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { · 864 unmodified lines | ||
| 1121 | 1122 | #define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) |
| 1122 | 1123 | #define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) |
| 1123 | 1124 | #define MPI2_IOUNITPAGE7_PCIE_SPEED_16_0_GBPS (0x03) |
| 1125 | +#define MPI2_IOUNITPAGE7_PCIE_SPEED_32_0_GBPS (0x04) | |
| 1124 | 1126 | |
| 1125 | 1127 | /*defines for IO Unit Page 7 ProcessorState field */ |
| 1126 | 1128 | #define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) |
| @@ -2301,6 +2303,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 { · 1174 unmodified lines | ||
| 2301 | 2303 | #define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) |
| 2302 | 2304 | |
| 2303 | 2305 | /*values for SAS IO Unit Page 1 AdditionalControlFlags */ |
| 2306 | +#define MPI2_SASIOUNIT1_ACONTROL_PROD_SPECIFIC_1 (0x8000) | |
| 2304 | 2307 | #define MPI2_SASIOUNIT1_ACONTROL_DA_PERSIST_CONNECT (0x0100) |
| 2305 | 2308 | #define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) |
| 2306 | 2309 | #define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) |
| @@ -3591,6 +3594,7 @@ typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { · 1284 unmodified lines | ||
| 3591 | 3594 | #define MPI26_PCIE_NEG_LINK_RATE_5_0 (0x03) |
| 3592 | 3595 | #define MPI26_PCIE_NEG_LINK_RATE_8_0 (0x04) |
| 3593 | 3596 | #define MPI26_PCIE_NEG_LINK_RATE_16_0 (0x05) |
| 3597 | +#define MPI26_PCIE_NEG_LINK_RATE_32_0 (0x06) | |
| 3594 | 3598 | |
| 3595 | 3599 | |
| 3596 | 3600 | /**************************************************************************** |
| @@ -3700,6 +3704,7 @@ typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_1 { · 103 unmodified lines | ||
| 3700 | 3704 | #define MPI26_PCIEIOUNIT1_MAX_RATE_5_0 (0x30) |
| 3701 | 3705 | #define MPI26_PCIEIOUNIT1_MAX_RATE_8_0 (0x40) |
| 3702 | 3706 | #define MPI26_PCIEIOUNIT1_MAX_RATE_16_0 (0x50) |
| 3707 | +#define MPI26_PCIEIOUNIT1_MAX_RATE_32_0 (0x60) | |
| 3703 | 3708 | |
| 3704 | 3709 | /*values for PCIe IO Unit Page 1 DMDReportPCIe */ |
| 3705 | 3710 | #define MPI26_PCIEIOUNIT1_DMDRPT_UNIT_MASK (0x80) |
| @@ -179,6 +179,7 @@ · 178 unmodified lines | ||
| 179 | 179 | * Added MPI26_IOCFACTS_CAPABILITY_COREDUMP_ENABLED |
| 180 | 180 | * Added MPI2_FW_DOWNLOAD_ITYPE_COREDUMP |
| 181 | 181 | * Added MPI2_FW_UPLOAD_ITYPE_COREDUMP |
| 182 | + * 9-13-24 02.00.39 Added MPI26_MCTP_PASSTHROUGH messages | |
| 182 | 183 | * -------------------------------------------------------------------------- |
| 183 | 184 | */ |
| 184 | 185 | |
| @@ -382,6 +383,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY { · 197 unmodified lines | ||
| 382 | 383 | /*ProductID field uses MPI2_FW_HEADER_PID_ */ |
| 383 | 384 | |
| 384 | 385 | /*IOCCapabilities */ |
| 386 | +#define MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU (0x00800000) | |
| 385 | 387 | #define MPI26_IOCFACTS_CAPABILITY_COREDUMP_ENABLED (0x00200000) |
| 386 | 388 | #define MPI26_IOCFACTS_CAPABILITY_PCIE_SRIOV (0x00100000) |
| 387 | 389 | #define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000) |
| @@ -1798,5 +1800,57 @@ typedef struct _MPI26_IOUNIT_CONTROL_REPLY { · 1410 unmodified lines | ||
| 1798 | 1800 | Mpi26IoUnitControlReply_t, |
| 1799 | 1801 | *pMpi26IoUnitControlReply_t; |
| 1800 | 1802 | |
| 1803 | +/**************************************************************************** | |
| 1804 | + * MCTP Passthrough messages (MPI v2.6 and later only.) | |
| 1805 | + ****************************************************************************/ | |
| 1806 | + | |
| 1807 | +/* MCTP Passthrough Request Message */ | |
| 1808 | +typedef struct _MPI26_MCTP_PASSTHROUGH_REQUEST { | |
| 1809 | + U8 MsgContext; /* 0x00 */ | |
| 1810 | + U8 Reserved1[2]; /* 0x01 */ | |
| 1811 | + U8 Function; /* 0x03 */ | |
| 1812 | + U8 Reserved2[3]; /* 0x04 */ | |
| 1813 | + U8 MsgFlags; /* 0x07 */ | |
| 1814 | + U8 VP_ID; /* 0x08 */ | |
| 1815 | + U8 VF_ID; /* 0x09 */ | |
| 1816 | + U16 Reserved3; /* 0x0A */ | |
| 1817 | + U32 Reserved4; /* 0x0C */ | |
| 1818 | + U8 Flags; /* 0x10 */ | |
| 1819 | + U8 Reserved5[3]; /* 0x11 */ | |
| 1820 | + U32 Reserved6; /* 0x14 */ | |
| 1821 | + U32 H2DLength; /* 0x18 */ | |
| 1822 | + U32 D2HLength; /* 0x1C */ | |
| 1823 | + MPI25_SGE_IO_UNION H2DSGL; /* 0x20 */ | |
| 1824 | + MPI25_SGE_IO_UNION D2HSGL; /* 0x30 */ | |
| 1825 | +} MPI26_MCTP_PASSTHROUGH_REQUEST, | |
| 1826 | + *PTR_MPI26_MCTP_PASSTHROUGH_REQUEST, | |
| 1827 | + Mpi26MctpPassthroughRequest_t, | |
| 1828 | + *pMpi26MctpPassthroughRequest_t; | |
| 1829 | + | |
| 1830 | +/* values for the MsgContext field */ | |
| 1831 | +#define MPI26_MCTP_MSG_CONEXT_UNUSED (0x00) | |
| 1832 | + | |
| 1833 | +/* values for the Flags field */ | |
| 1834 | +#define MPI26_MCTP_FLAGS_MSG_FORMAT_MPT (0x01) | |
| 1835 | + | |
| 1836 | +/* MCTP Passthrough Reply Message */ | |
| 1837 | +typedef struct _MPI26_MCTP_PASSTHROUGH_REPLY { | |
| 1838 | + U8 MsgContext; /* 0x00 */ | |
| 1839 | + U8 Reserved1; /* 0x01 */ | |
| 1840 | + U8 MsgLength; /* 0x02 */ | |
| 1841 | + U8 Function; /* 0x03 */ | |
| 1842 | + U8 Reserved2[3]; /* 0x04 */ | |
| 1843 | + U8 MsgFlags; /* 0x07 */ | |
| 1844 | + U8 VP_ID; /* 0x08 */ | |
| 1845 | + U8 VF_ID; /* 0x09 */ | |
| 1846 | + U16 Reserved3; /* 0x0A */ | |
| 1847 | + U16 Reserved4; /* 0x0C */ | |
| 1848 | + U16 IOCStatus; /* 0x0E */ | |
| 1849 | + U32 IOCLogInfo; /* 0x10 */ | |
| 1850 | + U32 ResponseDataLength; /* 0x14 */ | |
| 1851 | +} MPI26_MCTP_PASSTHROUGH_REPLY, | |
| 1852 | + *PTR_MPI26_MCTP_PASSTHROUGH_REPLY, | |
| 1853 | + Mpi26MctpPassthroughReply_t, | |
| 1854 | + *pMpi26MctpPassthroughReply_t; | |
| 1801 | 1855 | |
| 1802 | 1856 | #endif |
| @@ -1202,6 +1202,11 @@ _base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, · 1201 unmodified lines | ||
| 1202 | 1202 | ioc->sge_size; |
| 1203 | 1203 | func_str = "nvme_encapsulated"; |
| 1204 | 1204 | break; |
| 1205 | + case MPI2_FUNCTION_MCTP_PASSTHROUGH: | |
| 1206 | + frame_sz = sizeof(Mpi26MctpPassthroughRequest_t) + | |
| 1207 | + ioc->sge_size; | |
| 1208 | + func_str = "mctp_passthru"; | |
| 1209 | + break; | |
| 1205 | 1210 | default: |
| 1206 | 1211 | frame_sz = 32; |
| 1207 | 1212 | func_str = "unknown"; |
| @@ -4874,6 +4879,12 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) · 3666 unmodified lines | ||
| 4874 | 4879 | i++; |
| 4875 | 4880 | } |
| 4876 | 4881 | |
| 4882 | + if (ioc->facts.IOCCapabilities & | |
| 4883 | + MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU) { | |
| 4884 | + pr_cont("%sMCTP Passthru", i ? "," : ""); | |
| 4885 | + i++; | |
| 4886 | + } | |
| 4887 | + | |
| 4877 | 4888 | iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); |
| 4878 | 4889 | if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) { |
| 4879 | 4890 | pr_cont("%sNCQ", i ? "," : ""); |
| @@ -8018,7 +8029,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) · 3138 unmodified lines | ||
| 8018 | 8029 | |
| 8019 | 8030 | mutex_lock(&ioc->hostdiag_unlock_mutex); |
| 8020 | 8031 | if (mpt3sas_base_unlock_and_get_host_diagnostic(ioc, &host_diagnostic)) |
| 8021 | − goto out; | |
| 8032 | + goto unlock; | |
| 8022 | 8033 | |
| 8023 | 8034 | hcb_size = ioc->base_readl(&ioc->chip->HCBSize); |
| 8024 | 8035 | drsprintk(ioc, ioc_info(ioc, "diag reset: issued\n")); |
| @@ -8038,7 +8049,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) · 13 unmodified lines | ||
| 8038 | 8049 | ioc_info(ioc, |
| 8039 | 8050 | "Invalid host diagnostic register value\n"); |
| 8040 | 8051 | _base_dump_reg_set(ioc); |
| 8041 | − goto out; | |
| 8052 | + goto unlock; | |
| 8042 | 8053 | } |
| 8043 | 8054 | if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER)) |
| 8044 | 8055 | break; |
| @@ -8074,17 +8085,19 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) · 29 unmodified lines | ||
| 8074 | 8085 | ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n", |
| 8075 | 8086 | __func__, ioc_state); |
| 8076 | 8087 | _base_dump_reg_set(ioc); |
| 8077 | − goto out; | |
| 8088 | + goto fail; | |
| 8078 | 8089 | } |
| 8079 | 8090 | |
| 8080 | 8091 | pci_cfg_access_unlock(ioc->pdev); |
| 8081 | 8092 | ioc_info(ioc, "diag reset: SUCCESS\n"); |
| 8082 | 8093 | return 0; |
| 8083 | 8094 | |
| 8084 | − out: | |
| 8095 | +unlock: | |
| 8096 | + mutex_unlock(&ioc->hostdiag_unlock_mutex); | |
| 8097 | + | |
| 8098 | +fail: | |
| 8085 | 8099 | pci_cfg_access_unlock(ioc->pdev); |
| 8086 | 8100 | ioc_err(ioc, "diag reset: FAILED\n"); |
| 8087 | − mutex_unlock(&ioc->hostdiag_unlock_mutex); | |
| 8088 | 8101 | return -EFAULT; |
| 8089 | 8102 | } |
| 8090 | 8103 | |
| @@ -77,8 +77,8 @@ · 76 unmodified lines | ||
| 77 | 77 | #define MPT3SAS_DRIVER_NAME "mpt3sas" |
| 78 | 78 | #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>" |
| 79 | 79 | #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" |
| 80 | −#define MPT3SAS_DRIVER_VERSION "51.100.00.00" | |
| 81 | −#define MPT3SAS_MAJOR_VERSION 51 | |
| 80 | +#define MPT3SAS_DRIVER_VERSION "52.100.00.00" | |
| 81 | +#define MPT3SAS_MAJOR_VERSION 52 | |
| 82 | 82 | #define MPT3SAS_MINOR_VERSION 100 |
| 83 | 83 | #define MPT3SAS_BUILD_VERSION 00 |
| 84 | 84 | #define MPT3SAS_RELEASE_VERSION 00 |
| @@ -1858,9 +1858,6 @@ int mpt3sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc, · 1773 unmodified lines | ||
| 1858 | 1858 | int mpt3sas_config_get_manufacturing_pg1(struct MPT3SAS_ADAPTER *ioc, |
| 1859 | 1859 | Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage1_t *config_page); |
| 1860 | 1860 | |
| 1861 | −int mpt3sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc, | |
| 1862 | − Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page, | |
| 1863 | − u16 sz); | |
| 1864 | 1861 | int mpt3sas_config_get_manufacturing_pg10(struct MPT3SAS_ADAPTER *ioc, |
| 1865 | 1862 | Mpi2ConfigReply_t *mpi_reply, |
| 1866 | 1863 | struct Mpi2ManufacturingPage10_t *config_page); |
| @@ -1887,9 +1884,6 @@ int mpt3sas_config_get_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t · 20 unmodified lines | ||
| 1887 | 1884 | int mpt3sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc, |
| 1888 | 1885 | Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage0_t *config_page, |
| 1889 | 1886 | u32 form, u32 handle); |
| 1890 | −int mpt3sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, | |
| 1891 | − Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page, | |
| 1892 | − u32 form, u32 handle); | |
| 1893 | 1887 | int mpt3sas_config_get_pcie_device_pg0(struct MPT3SAS_ADAPTER *ioc, |
| 1894 | 1888 | Mpi2ConfigReply_t *mpi_reply, Mpi26PCIeDevicePage0_t *config_page, |
| 1895 | 1889 | u32 form, u32 handle); |
| @@ -576,44 +576,6 @@ mpt3sas_config_get_manufacturing_pg1(struct MPT3SAS_ADAPTER *ioc, · 575 unmodified lines | ||
| 576 | 576 | return r; |
| 577 | 577 | } |
| 578 | 578 | |
| 579 | −/** | |
| 580 | − * mpt3sas_config_get_manufacturing_pg7 - obtain manufacturing page 7 | |
| 581 | − * @ioc: per adapter object | |
| 582 | − * @mpi_reply: reply mf payload returned from firmware | |
| 583 | − * @config_page: contents of the config page | |
| 584 | − * @sz: size of buffer passed in config_page | |
| 585 | − * Context: sleep. | |
| 586 | − * | |
| 587 | − * Return: 0 for success, non-zero for failure. | |
| 588 | − */ | |
| 589 | −int | |
| 590 | −mpt3sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc, | |
| 591 | − Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page, | |
| 592 | − u16 sz) | |
| 593 | −{ | |
| 594 | − Mpi2ConfigRequest_t mpi_request; | |
| 595 | − int r; | |
| 596 | − | |
| 597 | − memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); | |
| 598 | − mpi_request.Function = MPI2_FUNCTION_CONFIG; | |
| 599 | − mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; | |
| 600 | − mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; | |
| 601 | − mpi_request.Header.PageNumber = 7; | |
| 602 | − mpi_request.Header.PageVersion = MPI2_MANUFACTURING7_PAGEVERSION; | |
| 603 | − ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); | |
| 604 | − r = _config_request(ioc, &mpi_request, mpi_reply, | |
| 605 | − MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); | |
| 606 | − if (r) | |
| 607 | − goto out; | |
| 608 | − | |
| 609 | − mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; | |
| 610 | − r = _config_request(ioc, &mpi_request, mpi_reply, | |
| 611 | − MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, | |
| 612 | − sz); | |
| 613 | − out: | |
| 614 | − return r; | |
| 615 | −} | |
| 616 | − | |
| 617 | 579 | /** |
| 618 | 580 | * mpt3sas_config_get_manufacturing_pg10 - obtain manufacturing page 10 |
| 619 | 581 | * @ioc: per adapter object |
| @@ -1213,47 +1175,6 @@ mpt3sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc, · 593 unmodified lines | ||
| 1213 | 1175 | return r; |
| 1214 | 1176 | } |
| 1215 | 1177 | |
| 1216 | −/** | |
| 1217 | − * mpt3sas_config_get_sas_device_pg1 - obtain sas device page 1 | |
| 1218 | − * @ioc: per adapter object | |
| 1219 | − * @mpi_reply: reply mf payload returned from firmware | |
| 1220 | − * @config_page: contents of the config page | |
| 1221 | − * @form: GET_NEXT_HANDLE or HANDLE | |
| 1222 | − * @handle: device handle | |
| 1223 | − * Context: sleep. | |
| 1224 | − * | |
| 1225 | − * Return: 0 for success, non-zero for failure. | |
| 1226 | − */ | |
| 1227 | −int | |
| 1228 | −mpt3sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, | |
| 1229 | − Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page, | |
| 1230 | − u32 form, u32 handle) | |
| 1231 | −{ | |
| 1232 | − Mpi2ConfigRequest_t mpi_request; | |
| 1233 | − int r; | |
| 1234 | − | |
| 1235 | − memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); | |
| 1236 | − mpi_request.Function = MPI2_FUNCTION_CONFIG; | |
| 1237 | − mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; | |
| 1238 | − mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; | |
| 1239 | − mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; | |
| 1240 | − mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION; | |
| 1241 | − mpi_request.Header.PageNumber = 1; | |
| 1242 | − ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); | |
| 1243 | − r = _config_request(ioc, &mpi_request, mpi_reply, | |
| 1244 | − MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); | |
| 1245 | − if (r) | |
| 1246 | − goto out; | |
| 1247 | − | |
| 1248 | − mpi_request.PageAddress = cpu_to_le32(form | handle); | |
| 1249 | − mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; | |
| 1250 | − r = _config_request(ioc, &mpi_request, mpi_reply, | |
| 1251 | − MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, | |
| 1252 | − sizeof(*config_page)); | |
| 1253 | − out: | |
| 1254 | − return r; | |
| 1255 | −} | |
| 1256 | − | |
| 1257 | 1178 | /** |
| 1258 | 1179 | * mpt3sas_config_get_pcie_device_pg0 - obtain pcie device page 0 |
| 1259 | 1180 | * @ioc: per adapter object |
| @@ -186,6 +186,9 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, · 185 unmodified lines | ||
| 186 | 186 | case MPI2_FUNCTION_NVME_ENCAPSULATED: |
| 187 | 187 | desc = "nvme_encapsulated"; |
| 188 | 188 | break; |
| 189 | + case MPI2_FUNCTION_MCTP_PASSTHROUGH: | |
| 190 | + desc = "mctp_passthrough"; | |
| 191 | + break; | |
| 189 | 192 | } |
| 190 | 193 | |
| 191 | 194 | if (!desc) |
| @@ -652,6 +655,40 @@ _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg, · 460 unmodified lines | ||
| 652 | 655 | return 0; |
| 653 | 656 | } |
| 654 | 657 | |
| 658 | +/** | |
| 659 | + * _ctl_send_mctp_passthru_req - Send an MCTP passthru request | |
| 660 | + * @ioc: per adapter object | |
| 661 | + * @mctp_passthru_req: MPI mctp passhthru request from caller | |
| 662 | + * @psge: pointer to the H2DSGL | |
| 663 | + * @data_out_dma: DMA buffer for H2D SGL | |
| 664 | + * @data_out_sz: H2D length | |
| 665 | + * @data_in_dma: DMA buffer for D2H SGL | |
| 666 | + * @data_in_sz: D2H length | |
| 667 | + * @smid: SMID to submit the request | |
| 668 | + * | |
| 669 | + */ | |
| 670 | +static void | |
| 671 | +_ctl_send_mctp_passthru_req( | |
| 672 | + struct MPT3SAS_ADAPTER *ioc, | |
| 673 | + Mpi26MctpPassthroughRequest_t *mctp_passthru_req, void *psge, | |
| 674 | + dma_addr_t data_out_dma, int data_out_sz, | |
| 675 | + dma_addr_t data_in_dma, int data_in_sz, | |
| 676 | + u16 smid) | |
| 677 | +{ | |
| 678 | + mctp_passthru_req->H2DLength = data_out_sz; | |
| 679 | + mctp_passthru_req->D2HLength = data_in_sz; | |
| 680 | + | |
| 681 | + /* Build the H2D SGL from the data out buffer */ | |
| 682 | + ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, 0, 0); | |
| 683 | + | |
| 684 | + psge += ioc->sge_size_ieee; | |
| 685 | + | |
| 686 | + /* Build the D2H SGL for the data in buffer */ | |
| 687 | + ioc->build_sg(ioc, psge, 0, 0, data_in_dma, data_in_sz); | |
| 688 | + | |
| 689 | + ioc->put_smid_default(ioc, smid); | |
| 690 | +} | |
| 691 | + | |
| 655 | 692 | /** |
| 656 | 693 | * _ctl_do_mpt_command - main handler for MPT3COMMAND opcode |
| 657 | 694 | * @ioc: per adapter object |
| @@ -679,6 +716,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, · 21 unmodified lines | ||
| 679 | 716 | size_t data_in_sz = 0; |
| 680 | 717 | long ret; |
| 681 | 718 | u16 device_handle = MPT3SAS_INVALID_DEVICE_HANDLE; |
| 719 | + int tm_ret; | |
| 682 | 720 | |
| 683 | 721 | issue_reset = 0; |
| 684 | 722 | |
| @@ -792,6 +830,23 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, · 107 unmodified lines | ||
| 792 | 830 | |
| 793 | 831 | init_completion(&ioc->ctl_cmds.done); |
| 794 | 832 | switch (mpi_request->Function) { |
| 833 | + case MPI2_FUNCTION_MCTP_PASSTHROUGH: | |
| 834 | + { | |
| 835 | + Mpi26MctpPassthroughRequest_t *mctp_passthru_req = | |
| 836 | + (Mpi26MctpPassthroughRequest_t *)request; | |
| 837 | + | |
| 838 | + if (!(ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU)) { | |
| 839 | + ioc_err(ioc, "%s: MCTP Passthrough request not supported\n", | |
| 840 | + __func__); | |
| 841 | + mpt3sas_base_free_smid(ioc, smid); | |
| 842 | + ret = -EINVAL; | |
| 843 | + goto out; | |
| 844 | + } | |
| 845 | + | |
| 846 | + _ctl_send_mctp_passthru_req(ioc, mctp_passthru_req, psge, data_out_dma, | |
| 847 | + data_out_sz, data_in_dma, data_in_sz, smid); | |
| 848 | + break; | |
| 849 | + } | |
| 795 | 850 | case MPI2_FUNCTION_NVME_ENCAPSULATED: |
| 796 | 851 | { |
| 797 | 852 | nvme_encap_request = (Mpi26NVMeEncapsulatedRequest_t *)request; |
| @@ -1120,18 +1175,25 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, · 322 unmodified lines | ||
| 1120 | 1175 | if (pcie_device && (!ioc->tm_custom_handling) && |
| 1121 | 1176 | (!(mpt3sas_scsih_is_pcie_scsi_device( |
| 1122 | 1177 | pcie_device->device_info)))) |
| 1123 | − mpt3sas_scsih_issue_locked_tm(ioc, | |
| 1178 | + tm_ret = mpt3sas_scsih_issue_locked_tm(ioc, | |
| 1124 | 1179 | le16_to_cpu(mpi_request->FunctionDependent1), |
| 1125 | 1180 | 0, 0, 0, |
| 1126 | 1181 | MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, |
| 1127 | 1182 | 0, pcie_device->reset_timeout, |
| 1128 | 1183 | MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE); |
| 1129 | 1184 | else |
| 1130 | − mpt3sas_scsih_issue_locked_tm(ioc, | |
| 1185 | + tm_ret = mpt3sas_scsih_issue_locked_tm(ioc, | |
| 1131 | 1186 | le16_to_cpu(mpi_request->FunctionDependent1), |
| 1132 | 1187 | 0, 0, 0, |
| 1133 | 1188 | MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, |
| 1134 | 1189 | 0, 30, MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET); |
| 1190 | + | |
| 1191 | + if (tm_ret != SUCCESS) { | |
| 1192 | + ioc_info(ioc, | |
| 1193 | + "target reset failed, issue hard reset: handle (0x%04x)\n", | |
| 1194 | + le16_to_cpu(mpi_request->FunctionDependent1)); | |
| 1195 | + mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); | |
| 1196 | + } | |
| 1135 | 1197 | } else |
| 1136 | 1198 | mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); |
| 1137 | 1199 | } |
| @@ -1200,6 +1262,8 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) · 62 unmodified lines | ||
| 1200 | 1262 | } |
| 1201 | 1263 | karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); |
| 1202 | 1264 | |
| 1265 | + karg.driver_capability |= MPT3_IOCTL_IOCINFO_DRIVER_CAP_MCTP_PASSTHRU; | |
| 1266 | + | |
| 1203 | 1267 | if (copy_to_user(arg, &karg, sizeof(karg))) { |
| 1204 | 1268 | pr_err("failure at %s:%d/%s()!\n", |
| 1205 | 1269 | __FILE__, __LINE__, __func__); |
| @@ -2786,6 +2850,217 @@ out_unlock_pciaccess: · 1580 unmodified lines | ||
| 2786 | 2850 | return ret; |
| 2787 | 2851 | } |
| 2788 | 2852 | |
| 2853 | +/** | |
| 2854 | + * _ctl_get_mpt_mctp_passthru_adapter - Traverse the IOC list and return the IOC at | |
| 2855 | + * dev_index positionthat support MCTP passhtru | |
| 2856 | + * @dev_index: position in the mpt3sas_ioc_list to search for | |
| 2857 | + * Return pointer to the IOC on success | |
| 2858 | + * NULL if device not found error | |
| 2859 | + */ | |
| 2860 | +static struct MPT3SAS_ADAPTER * | |
| 2861 | +_ctl_get_mpt_mctp_passthru_adapter(int dev_index) | |
| 2862 | +{ | |
| 2863 | + struct MPT3SAS_ADAPTER *ioc = NULL; | |
| 2864 | + int count = 0; | |
| 2865 | + | |
| 2866 | + spin_lock(&gioc_lock); | |
| 2867 | + /* Traverse ioc list and return number of IOC that support MCTP passthru */ | |
| 2868 | + list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { | |
| 2869 | + if (ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU) { | |
| 2870 | + if (count == dev_index) { | |
| 2871 | + spin_unlock(&gioc_lock); | |
| 2872 | + return 0; | |
| 2873 | + } | |
| 2874 | + } | |
| 2875 | + } | |
| 2876 | + spin_unlock(&gioc_lock); | |
| 2877 | + | |
| 2878 | + return NULL; | |
| 2879 | +} | |
| 2880 | + | |
| 2881 | +/** | |
| 2882 | + * mpt3sas_get_device_count - Retrieve the count of MCTP passthrough | |
| 2883 | + * capable devices managed by the driver. | |
| 2884 | + * | |
| 2885 | + * Returns number of devices that support MCTP passthrough. | |
| 2886 | + */ | |
| 2887 | +int | |
| 2888 | +mpt3sas_get_device_count(void) | |
| 2889 | +{ | |
| 2890 | + int count = 0; | |
| 2891 | + struct MPT3SAS_ADAPTER *ioc = NULL; | |
| 2892 | + | |
| 2893 | + spin_lock(&gioc_lock); | |
| 2894 | + /* Traverse ioc list and return number of IOC that support MCTP passthru */ | |
| 2895 | + list_for_each_entry(ioc, &mpt3sas_ioc_list, list) | |
| 2896 | + if (ioc->facts.IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_MCTP_PASSTHRU) | |
| 2897 | + count++; | |
| 2898 | + | |
| 2899 | + spin_unlock(&gioc_lock); | |
| 2900 | + | |
| 2901 | + return count; | |
| 2902 | +} | |
| 2903 | +EXPORT_SYMBOL(mpt3sas_get_device_count); | |
| 2904 | + | |
| 2905 | +/** | |
| 2906 | + * mpt3sas_send_passthru_cmd - Send an MPI MCTP passthrough command to | |
| 2907 | + * firmware | |
| 2908 | + * @command: The MPI MCTP passthrough command to send to firmware | |
| 2909 | + * | |
| 2910 | + * Returns 0 on success, anything else is error. | |
| 2911 | + */ | |
| 2912 | +int mpt3sas_send_mctp_passthru_req(struct mpt3_passthru_command *command) | |
| 2913 | +{ | |
| 2914 | + struct MPT3SAS_ADAPTER *ioc; | |
| 2915 | + MPI2RequestHeader_t *mpi_request = NULL, *request; | |
| 2916 | + MPI2DefaultReply_t *mpi_reply; | |
| 2917 | + Mpi26MctpPassthroughRequest_t *mctp_passthru_req; | |
| 2918 | + u16 smid; | |
| 2919 | + unsigned long timeout; | |
| 2920 | + u8 issue_reset = 0; | |
| 2921 | + u32 sz; | |
| 2922 | + void *psge; | |
| 2923 | + void *data_out = NULL; | |
| 2924 | + dma_addr_t data_out_dma = 0; | |
| 2925 | + size_t data_out_sz = 0; | |
| 2926 | + void *data_in = NULL; | |
| 2927 | + dma_addr_t data_in_dma = 0; | |
| 2928 | + size_t data_in_sz = 0; | |
| 2929 | + long ret; | |
| 2930 | + | |
| 2931 | + /* Retrieve ioc from dev_index */ | |
| 2932 | + ioc = _ctl_get_mpt_mctp_passthru_adapter(command->dev_index); | |
| 2933 | + if (!ioc) | |
| 2934 | + return -ENODEV; | |
| 2935 | + | |
| 2936 | + mutex_lock(&ioc->pci_access_mutex); | |
| 2937 | + if (ioc->shost_recovery || | |
| 2938 | + ioc->pci_error_recovery || ioc->is_driver_loading || | |
| 2939 | + ioc->remove_host) { | |
| 2940 | + ret = -EAGAIN; | |
| 2941 | + goto unlock_pci_access; | |
| 2942 | + } | |
| 2943 | + | |
| 2944 | + /* Lock the ctl_cmds mutex to ensure a single ctl cmd is pending */ | |
| 2945 | + if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { | |
| 2946 | + ret = -ERESTARTSYS; | |
| 2947 | + goto unlock_pci_access; | |
| 2948 | + } | |
| 2949 | + | |
| 2950 | + if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { | |
| 2951 | + ioc_err(ioc, "%s: ctl_cmd in use\n", __func__); | |
| 2952 | + ret = -EAGAIN; | |
| 2953 | + goto unlock_ctl_cmds; | |
| 2954 | + } | |
| 2955 | + | |
| 2956 | + ret = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT); | |
| 2957 | + if (ret) | |
| 2958 | + goto unlock_ctl_cmds; | |
| 2959 | + | |
| 2960 | + mpi_request = (MPI2RequestHeader_t *)command->mpi_request; | |
| 2961 | + if (mpi_request->Function != MPI2_FUNCTION_MCTP_PASSTHROUGH) { | |
| 2962 | + ioc_err(ioc, "%s: Invalid request received, Function 0x%x\n", | |
| 2963 | + __func__, mpi_request->Function); | |
| 2964 | + ret = -EINVAL; | |
| 2965 | + goto unlock_ctl_cmds; | |
| 2966 | + } | |
| 2967 | + | |
| 2968 | + /* Use first reserved smid for passthrough commands */ | |
| 2969 | + smid = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT + 1; | |
| 2970 | + ret = 0; | |
| 2971 | + ioc->ctl_cmds.status = MPT3_CMD_PENDING; | |
| 2972 | + memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); | |
| 2973 | + request = mpt3sas_base_get_msg_frame(ioc, smid); | |
| 2974 | + memset(request, 0, ioc->request_sz); | |
| 2975 | + memcpy(request, command->mpi_request, sizeof(Mpi26MctpPassthroughRequest_t)); | |
| 2976 | + ioc->ctl_cmds.smid = smid; | |
| 2977 | + data_out_sz = command->data_out_size; | |
| 2978 | + data_in_sz = command->data_in_size; | |
| 2979 | + | |
| 2980 | + /* obtain dma-able memory for data transfer */ | |
| 2981 | + if (data_out_sz) /* WRITE */ { | |
| 2982 | + data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz, | |
| 2983 | + &data_out_dma, GFP_ATOMIC); | |
| 2984 | + if (!data_out) { | |
| 2985 | + ret = -ENOMEM; | |
| 2986 | + mpt3sas_base_free_smid(ioc, smid); | |
| 2987 | + goto out; | |
| 2988 | + } | |
| 2989 | + memcpy(data_out, command->data_out_buf_ptr, data_out_sz); | |
| 2990 | + | |
| 2991 | + } | |
| 2992 | + | |
| 2993 | + if (data_in_sz) /* READ */ { | |
| 2994 | + data_in = dma_alloc_coherent(&ioc->pdev->dev, data_in_sz, | |
| 2995 | + &data_in_dma, GFP_ATOMIC); | |
| 2996 | + if (!data_in) { | |
| 2997 | + ret = -ENOMEM; | |
| 2998 | + mpt3sas_base_free_smid(ioc, smid); | |
| 2999 | + goto out; | |
| 3000 | + } | |
| 3001 | + } | |
| 3002 | + | |
| 3003 | + psge = &((Mpi26MctpPassthroughRequest_t *)request)->H2DSGL; | |
| 3004 | + | |
| 3005 | + init_completion(&ioc->ctl_cmds.done); | |
| 3006 | + | |
| 3007 | + mctp_passthru_req = (Mpi26MctpPassthroughRequest_t *)request; | |
| 3008 | + | |
| 3009 | + _ctl_send_mctp_passthru_req(ioc, mctp_passthru_req, psge, data_out_dma, | |
| 3010 | + data_out_sz, data_in_dma, data_in_sz, smid); | |
| 3011 | + | |
| 3012 | + timeout = command->timeout; | |
| 3013 | + if (timeout < MPT3_IOCTL_DEFAULT_TIMEOUT) | |
| 3014 | + timeout = MPT3_IOCTL_DEFAULT_TIMEOUT; | |
| 3015 | + | |
| 3016 | + wait_for_completion_timeout(&ioc->ctl_cmds.done, timeout*HZ); | |
| 3017 | + if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { | |
| 3018 | + mpt3sas_check_cmd_timeout(ioc, | |
| 3019 | + ioc->ctl_cmds.status, mpi_request, | |
| 3020 | + sizeof(Mpi26MctpPassthroughRequest_t) / 4, issue_reset); | |
| 3021 | + goto issue_host_reset; | |
| 3022 | + } | |
| 3023 | + | |
| 3024 | + mpi_reply = ioc->ctl_cmds.reply; | |
| 3025 | + | |
| 3026 | + /* copy out xdata to user */ | |
| 3027 | + if (data_in_sz) | |
| 3028 | + memcpy(command->data_in_buf_ptr, data_in, data_in_sz); | |
| 3029 | + | |
| 3030 | + /* copy out reply message frame to user */ | |
| 3031 | + if (command->max_reply_bytes) { | |
| 3032 | + sz = min_t(u32, command->max_reply_bytes, ioc->reply_sz); | |
| 3033 | + memcpy(command->reply_frame_buf_ptr, ioc->ctl_cmds.reply, sz); | |
| 3034 | + } | |
| 3035 | + | |
| 3036 | +issue_host_reset: | |
| 3037 | + if (issue_reset) { | |
| 3038 | + ret = -ENODATA; | |
| 3039 | + mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); | |
| 3040 | + } | |
| 3041 | + | |
| 3042 | +out: | |
| 3043 | + /* free memory associated with sg buffers */ | |
| 3044 | + if (data_in) | |
| 3045 | + dma_free_coherent(&ioc->pdev->dev, data_in_sz, data_in, | |
| 3046 | + data_in_dma); | |
| 3047 | + | |
| 3048 | + if (data_out) | |
| 3049 | + dma_free_coherent(&ioc->pdev->dev, data_out_sz, data_out, | |
| 3050 | + data_out_dma); | |
| 3051 | + | |
| 3052 | + ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; | |
| 3053 | + | |
| 3054 | +unlock_ctl_cmds: | |
| 3055 | + mutex_unlock(&ioc->ctl_cmds.mutex); | |
| 3056 | + | |
| 3057 | +unlock_pci_access: | |
| 3058 | + mutex_unlock(&ioc->pci_access_mutex); | |
| 3059 | + return ret; | |
| 3060 | + | |
| 3061 | +} | |
| 3062 | +EXPORT_SYMBOL(mpt3sas_send_mctp_passthru_req); | |
| 3063 | + | |
| 2789 | 3064 | /** |
| 2790 | 3065 | * _ctl_ioctl - mpt3ctl main ioctl entry point (unlocked) |
| 2791 | 3066 | * @file: (struct file) |
| @@ -160,6 +160,9 @@ struct mpt3_ioctl_pci_info { · 159 unmodified lines | ||
| 160 | 160 | #define MPT3_IOCTL_INTERFACE_SAS35 (0x07) |
| 161 | 161 | #define MPT2_IOCTL_VERSION_LENGTH (32) |
| 162 | 162 | |
| 163 | +/* Bits set for mpt3_ioctl_iocinfo.driver_cap */ | |
| 164 | +#define MPT3_IOCTL_IOCINFO_DRIVER_CAP_MCTP_PASSTHRU 0x1 | |
| 165 | + | |
| 163 | 166 | /** |
| 164 | 167 | * struct mpt3_ioctl_iocinfo - generic controller info |
| 165 | 168 | * @hdr - generic header |
| @@ -175,6 +178,7 @@ struct mpt3_ioctl_pci_info { · 9 unmodified lines | ||
| 175 | 178 | * @driver_version - driver version - 32 ASCII characters |
| 176 | 179 | * @rsvd1 - reserved |
| 177 | 180 | * @scsi_id - scsi id of adapter 0 |
| 181 | + * @driver_capability - driver capabilities | |
| 178 | 182 | * @rsvd2 - reserved |
| 179 | 183 | * @pci_information - pci info (2nd revision) |
| 180 | 184 | */ |
| @@ -192,7 +196,8 @@ struct mpt3_ioctl_iocinfo { · 11 unmodified lines | ||
| 192 | 196 | uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH]; |
| 193 | 197 | uint8_t rsvd1; |
| 194 | 198 | uint8_t scsi_id; |
| 195 | − uint16_t rsvd2; | |
| 199 | + uint8_t driver_capability; | |
| 200 | + uint8_t rsvd2; | |
| 196 | 201 | struct mpt3_ioctl_pci_info pci_information; |
| 197 | 202 | }; |
| 198 | 203 | |
| @@ -458,4 +463,46 @@ struct mpt3_enable_diag_sbr_reload { · 259 unmodified lines | ||
| 458 | 463 | struct mpt3_ioctl_header hdr; |
| 459 | 464 | }; |
| 460 | 465 | |
| 466 | +/** | |
| 467 | + * struct mpt3_passthru_command - generic mpt firmware passthru command | |
| 468 | + * @dev_index - device index | |
| 469 | + * @timeout - command timeout in seconds. (if zero then use driver default | |
| 470 | + * value). | |
| 471 | + * @reply_frame_buf_ptr - MPI reply location | |
| 472 | + * @data_in_buf_ptr - destination for read | |
| 473 | + * @data_out_buf_ptr - data source for write | |
| 474 | + * @max_reply_bytes - maximum number of reply bytes to be sent to app. | |
| 475 | + * @data_in_size - number bytes for data transfer in (read) | |
| 476 | + * @data_out_size - number bytes for data transfer out (write) | |
| 477 | + * @mpi_request - request frame | |
| 478 | + */ | |
| 479 | +struct mpt3_passthru_command { | |
| 480 | + u8 dev_index; | |
| 481 | + uint32_t timeout; | |
| 482 | + void *reply_frame_buf_ptr; | |
| 483 | + void *data_in_buf_ptr; | |
| 484 | + void *data_out_buf_ptr; | |
| 485 | + uint32_t max_reply_bytes; | |
| 486 | + uint32_t data_in_size; | |
| 487 | + uint32_t data_out_size; | |
| 488 | + Mpi26MctpPassthroughRequest_t *mpi_request; | |
| 489 | +}; | |
| 490 | + | |
| 491 | +/* | |
| 492 | + * mpt3sas_get_device_count - Retrieve the count of MCTP passthrough | |
| 493 | + * capable devices managed by the driver. | |
| 494 | + * | |
| 495 | + * Returns number of devices that support MCTP passthrough. | |
| 496 | + */ | |
| 497 | +int mpt3sas_get_device_count(void); | |
| 498 | + | |
| 499 | +/* | |
| 500 | + * mpt3sas_send_passthru_cmd - Send an MPI MCTP passthrough command to | |
| 501 | + * firmware | |
| 502 | + * @command: The MPI MCTP passthrough command to send to firmware | |
| 503 | + * | |
| 504 | + * Returns 0 on success, anything else is error . | |
| 505 | + */ | |
| 506 | +int mpt3sas_send_mctp_passthru_req(struct mpt3_passthru_command *command); | |
| 507 | + | |
| 461 | 508 | #endif /* MPT3SAS_CTL_H_INCLUDED */ |
| @@ -2703,7 +2703,7 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · 2702 unmodified lines | ||
| 2703 | 2703 | ssp_target = 1; |
| 2704 | 2704 | if (sas_device->device_info & |
| 2705 | 2705 | MPI2_SAS_DEVICE_INFO_SEP) { |
| 2706 | − sdev_printk(KERN_WARNING, sdev, | |
| 2706 | + sdev_printk(KERN_INFO, sdev, | |
| 2707 | 2707 | "set ignore_delay_remove for handle(0x%04x)\n", |
| 2708 | 2708 | sas_device_priv_data->sas_target->handle); |
| 2709 | 2709 | sas_device_priv_data->ignore_delay_remove = 1; |
| @@ -12710,7 +12710,7 @@ static const struct pci_device_id mpt3sas_pci_table[] = { · 10000 unmodified lines | ||
| 12710 | 12710 | }; |
| 12711 | 12711 | MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table); |
| 12712 | 12712 | |
| 12713 | −static struct pci_error_handlers _mpt3sas_err_handler = { | |
| 12713 | +static const struct pci_error_handlers _mpt3sas_err_handler = { | |
| 12714 | 12714 | .error_detected = scsih_pci_error_detected, |
| 12715 | 12715 | .mmio_enabled = scsih_pci_mmio_enabled, |
| 12716 | 12716 | .slot_reset = scsih_pci_slot_reset, |
| @@ -151,16 +151,6 @@ static inline u8 mvs_assign_reg_set(struct mvs_info *mvi, · 150 unmodified lines | ||
| 151 | 151 | return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset); |
| 152 | 152 | } |
| 153 | 153 | |
| 154 | −void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard) | |
| 155 | −{ | |
| 156 | − u32 no; | |
| 157 | − for_each_phy(phy_mask, phy_mask, no) { | |
| 158 | − if (!(phy_mask & 1)) | |
| 159 | − continue; | |
| 160 | − MVS_CHIP_DISP->phy_reset(mvi, no, hard); | |
| 161 | − } | |
| 162 | −} | |
| 163 | − | |
| 164 | 154 | int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, |
| 165 | 155 | void *funcdata) |
| 166 | 156 | { |
| @@ -425,7 +425,6 @@ struct mvs_task_exec_info { · 424 unmodified lines | ||
| 425 | 425 | void mvs_get_sas_addr(void *buf, u32 buflen); |
| 426 | 426 | void mvs_iounmap(void __iomem *regs); |
| 427 | 427 | int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex); |
| 428 | −void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard); | |
| 429 | 428 | int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, |
| 430 | 429 | void *funcdata); |
| 431 | 430 | void mvs_set_sas_addr(struct mvs_info *mvi, int port_id, u32 off_lo, |
| @@ -2876,7 +2876,7 @@ MODULE_DEVICE_TABLE(pci, qedi_pci_tbl); · 2875 unmodified lines | ||
| 2876 | 2876 | |
| 2877 | 2877 | static enum cpuhp_state qedi_cpuhp_state; |
| 2878 | 2878 | |
| 2879 | −static struct pci_error_handlers qedi_err_handler = { | |
| 2879 | +static const struct pci_error_handlers qedi_err_handler = { | |
| 2880 | 2880 | .error_detected = qedi_io_error_detected, |
| 2881 | 2881 | }; |
| 2882 | 2882 | |
| @@ -2136,8 +2136,8 @@ qla2x00_write_flash_byte(struct qla_hw_data *ha, uint32_t addr, uint8_t data) · 2135 unmodified lines | ||
| 2136 | 2136 | * @flash_id: Flash ID |
| 2137 | 2137 | * |
| 2138 | 2138 | * This function polls the device until bit 7 of what is read matches data |
| 2139 | − * bit 7 or until data bit 5 becomes a 1. If that hapens, the flash ROM timed | |
| 2140 | − * out (a fatal error). The flash book recommeds reading bit 7 again after | |
| 2139 | + * bit 7 or until data bit 5 becomes a 1. If that happens, the flash ROM timed | |
| 2140 | + * out (a fatal error). The flash book recommends reading bit 7 again after | |
| 2141 | 2141 | * reading bit 5 as a 1. |
| 2142 | 2142 | * |
| 2143 | 2143 | * Returns 0 on success, else non-zero. |
| @@ -510,22 +510,34 @@ void scsi_attach_vpd(struct scsi_device *sdev) · 509 unmodified lines | ||
| 510 | 510 | return; |
| 511 | 511 | |
| 512 | 512 | for (i = 4; i < vpd_buf->len; i++) { |
| 513 | − if (vpd_buf->data[i] == 0x0) | |
| 513 | + switch (vpd_buf->data[i]) { | |
| 514 | + case 0x0: | |
| 514 | 515 | scsi_update_vpd_page(sdev, 0x0, &sdev->vpd_pg0); |
| 515 | − if (vpd_buf->data[i] == 0x80) | |
| 516 | + break; | |
| 517 | + case 0x80: | |
| 516 | 518 | scsi_update_vpd_page(sdev, 0x80, &sdev->vpd_pg80); |
| 517 | − if (vpd_buf->data[i] == 0x83) | |
| 519 | + break; | |
| 520 | + case 0x83: | |
| 518 | 521 | scsi_update_vpd_page(sdev, 0x83, &sdev->vpd_pg83); |
| 519 | − if (vpd_buf->data[i] == 0x89) | |
| 522 | + break; | |
| 523 | + case 0x89: | |
| 520 | 524 | scsi_update_vpd_page(sdev, 0x89, &sdev->vpd_pg89); |
| 521 | − if (vpd_buf->data[i] == 0xb0) | |
| 525 | + break; | |
| 526 | + case 0xb0: | |
| 522 | 527 | scsi_update_vpd_page(sdev, 0xb0, &sdev->vpd_pgb0); |
| 523 | − if (vpd_buf->data[i] == 0xb1) | |
| 528 | + break; | |
| 529 | + case 0xb1: | |
| 524 | 530 | scsi_update_vpd_page(sdev, 0xb1, &sdev->vpd_pgb1); |
| 525 | − if (vpd_buf->data[i] == 0xb2) | |
| 531 | + break; | |
| 532 | + case 0xb2: | |
| 526 | 533 | scsi_update_vpd_page(sdev, 0xb2, &sdev->vpd_pgb2); |
| 527 | − if (vpd_buf->data[i] == 0xb7) | |
| 534 | + break; | |
| 535 | + case 0xb7: | |
| 528 | 536 | scsi_update_vpd_page(sdev, 0xb7, &sdev->vpd_pgb7); |
| 537 | + break; | |
| 538 | + default: | |
| 539 | + break; | |
| 540 | + } | |
| 529 | 541 | } |
| 530 | 542 | kfree(vpd_buf); |
| 531 | 543 | } |
| @@ -71,6 +71,10 @@ static const char *sdebug_version_date = "20210520"; · 70 unmodified lines | ||
| 71 | 71 | #define NO_ADDITIONAL_SENSE 0x0 |
| 72 | 72 | #define OVERLAP_ATOMIC_COMMAND_ASC 0x0 |
| 73 | 73 | #define OVERLAP_ATOMIC_COMMAND_ASCQ 0x23 |
| 74 | +#define FILEMARK_DETECTED_ASCQ 0x1 | |
| 75 | +#define EOP_EOM_DETECTED_ASCQ 0x2 | |
| 76 | +#define BEGINNING_OF_P_M_DETECTED_ASCQ 0x4 | |
| 77 | +#define EOD_DETECTED_ASCQ 0x5 | |
| 74 | 78 | #define LOGICAL_UNIT_NOT_READY 0x4 |
| 75 | 79 | #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 |
| 76 | 80 | #define UNRECOVERED_READ_ERR 0x11 |
| @@ -80,8 +84,10 @@ static const char *sdebug_version_date = "20210520"; · 3 unmodified lines | ||
| 80 | 84 | #define INVALID_FIELD_IN_CDB 0x24 |
| 81 | 85 | #define INVALID_FIELD_IN_PARAM_LIST 0x26 |
| 82 | 86 | #define WRITE_PROTECTED 0x27 |
| 87 | +#define UA_READY_ASC 0x28 | |
| 83 | 88 | #define UA_RESET_ASC 0x29 |
| 84 | 89 | #define UA_CHANGED_ASC 0x2a |
| 90 | +#define TOO_MANY_IN_PARTITION_ASC 0x3b | |
| 85 | 91 | #define TARGET_CHANGED_ASC 0x3f |
| 86 | 92 | #define LUNS_CHANGED_ASCQ 0x0e |
| 87 | 93 | #define INSUFF_RES_ASC 0x55 |
| @@ -173,6 +179,37 @@ static const char *sdebug_version_date = "20210520"; · 85 unmodified lines | ||
| 173 | 179 | #define DEF_ZBC_MAX_OPEN_ZONES 8 |
| 174 | 180 | #define DEF_ZBC_NR_CONV_ZONES 1 |
| 175 | 181 | |
| 182 | +/* Default parameters for tape drives */ | |
| 183 | +#define TAPE_DEF_DENSITY 0x0 | |
| 184 | +#define TAPE_BAD_DENSITY 0x65 | |
| 185 | +#define TAPE_DEF_BLKSIZE 0 | |
| 186 | +#define TAPE_MIN_BLKSIZE 512 | |
| 187 | +#define TAPE_MAX_BLKSIZE 1048576 | |
| 188 | +#define TAPE_EW 20 | |
| 189 | +#define TAPE_MAX_PARTITIONS 2 | |
| 190 | +#define TAPE_UNITS 10000 | |
| 191 | +#define TAPE_PARTITION_1_UNITS 1000 | |
| 192 | + | |
| 193 | +/* The tape block data definitions */ | |
| 194 | +#define TAPE_BLOCK_FM_FLAG ((u32)0x1 << 30) | |
| 195 | +#define TAPE_BLOCK_EOD_FLAG ((u32)0x2 << 30) | |
| 196 | +#define TAPE_BLOCK_MARK_MASK ((u32)0x3 << 30) | |
| 197 | +#define TAPE_BLOCK_SIZE_MASK (~TAPE_BLOCK_MARK_MASK) | |
| 198 | +#define TAPE_BLOCK_MARK(a) (a & TAPE_BLOCK_MARK_MASK) | |
| 199 | +#define TAPE_BLOCK_SIZE(a) (a & TAPE_BLOCK_SIZE_MASK) | |
| 200 | +#define IS_TAPE_BLOCK_FM(a) ((a & TAPE_BLOCK_FM_FLAG) != 0) | |
| 201 | +#define IS_TAPE_BLOCK_EOD(a) ((a & TAPE_BLOCK_EOD_FLAG) != 0) | |
| 202 | + | |
| 203 | +struct tape_block { | |
| 204 | + u32 fl_size; | |
| 205 | + unsigned char data[4]; | |
| 206 | +}; | |
| 207 | + | |
| 208 | +/* Flags for sense data */ | |
| 209 | +#define SENSE_FLAG_FILEMARK 0x80 | |
| 210 | +#define SENSE_FLAG_EOM 0x40 | |
| 211 | +#define SENSE_FLAG_ILI 0x20 | |
| 212 | + | |
| 176 | 213 | #define SDEBUG_LUN_0_VAL 0 |
| 177 | 214 | |
| 178 | 215 | /* bit mask values for sdebug_opts */ |
| @@ -216,7 +253,8 @@ static const char *sdebug_version_date = "20210520"; · 37 unmodified lines | ||
| 216 | 253 | #define SDEBUG_UA_LUNS_CHANGED 5 |
| 217 | 254 | #define SDEBUG_UA_MICROCODE_CHANGED 6 /* simulate firmware change */ |
| 218 | 255 | #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 7 |
| 219 | −#define SDEBUG_NUM_UAS 8 | |
| 256 | +#define SDEBUG_UA_NOT_READY_TO_READY 8 | |
| 257 | +#define SDEBUG_NUM_UAS 9 | |
| 220 | 258 | |
| 221 | 259 | /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this |
| 222 | 260 | * sector on read commands: */ |
| @@ -262,11 +300,6 @@ static const char *sdebug_version_date = "20210520"; · 39 unmodified lines | ||
| 262 | 300 | |
| 263 | 301 | #define SDEB_XA_NOT_IN_USE XA_MARK_1 |
| 264 | 302 | |
| 265 | −static struct kmem_cache *queued_cmd_cache; | |
| 266 | − | |
| 267 | −#define TO_QUEUED_CMD(scmd) ((void *)(scmd)->host_scribble) | |
| 268 | −#define ASSIGN_QUEUED_CMD(scmnd, qc) { (scmnd)->host_scribble = (void *) qc; } | |
| 269 | − | |
| 270 | 303 | /* Zone types (zbcr05 table 25) */ |
| 271 | 304 | enum sdebug_z_type { |
| 272 | 305 | ZBC_ZTYPE_CNV = 0x1, |
| @@ -363,6 +396,19 @@ struct sdebug_dev_info { · 90 unmodified lines | ||
| 363 | 396 | ktime_t create_ts; /* time since bootup that this device was created */ |
| 364 | 397 | struct sdeb_zone_state *zstate; |
| 365 | 398 | |
| 399 | + /* For tapes */ | |
| 400 | + unsigned int tape_blksize; | |
| 401 | + unsigned int tape_density; | |
| 402 | + unsigned char tape_partition; | |
| 403 | + unsigned char tape_nbr_partitions; | |
| 404 | + unsigned char tape_pending_nbr_partitions; | |
| 405 | + unsigned int tape_pending_part_0_size; | |
| 406 | + unsigned int tape_pending_part_1_size; | |
| 407 | + unsigned char tape_dce; | |
| 408 | + unsigned int tape_location[TAPE_MAX_PARTITIONS]; | |
| 409 | + unsigned int tape_eop[TAPE_MAX_PARTITIONS]; | |
| 410 | + struct tape_block *tape_blocks[TAPE_MAX_PARTITIONS]; | |
| 411 | + | |
| 366 | 412 | struct dentry *debugfs_entry; |
| 367 | 413 | struct spinlock list_lock; |
| 368 | 414 | struct list_head inject_err_list; |
| @@ -409,24 +455,9 @@ struct sdebug_defer { · 40 unmodified lines | ||
| 409 | 455 | enum sdeb_defer_type defer_t; |
| 410 | 456 | }; |
| 411 | 457 | |
| 412 | −struct sdebug_device_access_info { | |
| 413 | − bool atomic_write; | |
| 414 | − u64 lba; | |
| 415 | − u32 num; | |
| 416 | − struct scsi_cmnd *self; | |
| 417 | −}; | |
| 418 | − | |
| 419 | −struct sdebug_queued_cmd { | |
| 420 | − /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue | |
| 421 | − * instance indicates this slot is in use. | |
| 422 | − */ | |
| 423 | − struct sdebug_defer sd_dp; | |
| 424 | − struct scsi_cmnd *scmd; | |
| 425 | − struct sdebug_device_access_info *i; | |
| 426 | −}; | |
| 427 | − | |
| 428 | 458 | struct sdebug_scsi_cmd { |
| 429 | 459 | spinlock_t lock; |
| 460 | + struct sdebug_defer sd_dp; | |
| 430 | 461 | }; |
| 431 | 462 | |
| 432 | 463 | static atomic_t sdebug_cmnd_count; /* number of incoming commands */ |
| @@ -483,22 +514,27 @@ enum sdeb_opcode_index { · 50 unmodified lines | ||
| 483 | 514 | SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */ |
| 484 | 515 | SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */ |
| 485 | 516 | SDEB_I_ATOMIC_WRITE_16 = 32, |
| 486 | − SDEB_I_LAST_ELEM_P1 = 33, /* keep this last (previous + 1) */ | |
| 517 | + SDEB_I_READ_BLOCK_LIMITS = 33, | |
| 518 | + SDEB_I_LOCATE = 34, | |
| 519 | + SDEB_I_WRITE_FILEMARKS = 35, | |
| 520 | + SDEB_I_SPACE = 36, | |
| 521 | + SDEB_I_FORMAT_MEDIUM = 37, | |
| 522 | + SDEB_I_LAST_ELEM_P1 = 38, /* keep this last (previous + 1) */ | |
| 487 | 523 | }; |
| 488 | 524 | |
| 489 | 525 | |
| 490 | 526 | static const unsigned char opcode_ind_arr[256] = { |
| 491 | 527 | /* 0x0; 0x0->0x1f: 6 byte cdbs */ |
| 492 | 528 | SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, |
| 493 | − 0, 0, 0, 0, | |
| 529 | + SDEB_I_FORMAT_MEDIUM, SDEB_I_READ_BLOCK_LIMITS, 0, 0, | |
| 494 | 530 | SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, |
| 495 | − 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, | |
| 496 | − SDEB_I_RELEASE, | |
| 531 | + SDEB_I_WRITE_FILEMARKS, SDEB_I_SPACE, SDEB_I_INQUIRY, 0, 0, | |
| 532 | + SDEB_I_MODE_SELECT, SDEB_I_RESERVE, SDEB_I_RELEASE, | |
| 497 | 533 | 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, |
| 498 | 534 | SDEB_I_ALLOW_REMOVAL, 0, |
| 499 | 535 | /* 0x20; 0x20->0x3f: 10 byte cdbs */ |
| 500 | 536 | 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, |
| 501 | − SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, | |
| 537 | + SDEB_I_READ, 0, SDEB_I_WRITE, SDEB_I_LOCATE, 0, 0, 0, SDEB_I_VERIFY, | |
| 502 | 538 | 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0, |
| 503 | 539 | 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, |
| 504 | 540 | /* 0x40; 0x40->0x5f: 10 byte cdbs */ |
| @@ -573,6 +609,12 @@ static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *); · 68 unmodified lines | ||
| 573 | 609 | static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *); |
| 574 | 610 | static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *); |
| 575 | 611 | static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *); |
| 612 | +static int resp_read_blklimits(struct scsi_cmnd *, struct sdebug_dev_info *); | |
| 613 | +static int resp_locate(struct scsi_cmnd *, struct sdebug_dev_info *); | |
| 614 | +static int resp_write_filemarks(struct scsi_cmnd *, struct sdebug_dev_info *); | |
| 615 | +static int resp_space(struct scsi_cmnd *, struct sdebug_dev_info *); | |
| 616 | +static int resp_rewind(struct scsi_cmnd *, struct sdebug_dev_info *); | |
| 617 | +static int resp_format_medium(struct scsi_cmnd *, struct sdebug_dev_info *); | |
| 576 | 618 | |
| 577 | 619 | static int sdebug_do_add_host(bool mk_new_store); |
| 578 | 620 | static int sdebug_add_host_helper(int per_host_idx); |
| @@ -581,8 +623,6 @@ static int sdebug_add_store(void); · 2 unmodified lines | ||
| 581 | 623 | static void sdebug_erase_store(int idx, struct sdeb_store_info *sip); |
| 582 | 624 | static void sdebug_erase_all_stores(bool apart_from_first); |
| 583 | 625 | |
| 584 | −static void sdebug_free_queued_cmd(struct sdebug_queued_cmd *sqcp); | |
| 585 | − | |
| 586 | 626 | /* |
| 587 | 627 | * The following are overflow arrays for cdbs that "hit" the same index in |
| 588 | 628 | * the opcode_info_arr array. The most time sensitive (or commonly used) cdb |
| @@ -773,7 +813,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { · 184 unmodified lines | ||
| 773 | 813 | /* 20 */ |
| 774 | 814 | {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ |
| 775 | 815 | {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, |
| 776 | − {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ | |
| 816 | + {0, 0x1, 0, 0, resp_rewind, NULL, | |
| 777 | 817 | {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, |
| 778 | 818 | {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ |
| 779 | 819 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, |
| @@ -800,6 +840,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { · 20 unmodified lines | ||
| 800 | 840 | resp_pre_fetch, pre_fetch_iarr, |
| 801 | 841 | {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, |
| 802 | 842 | 0, 0, 0, 0} }, /* PRE-FETCH (10) */ |
| 843 | + /* READ POSITION (10) */ | |
| 803 | 844 | |
| 804 | 845 | /* 30 */ |
| 805 | 846 | {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS, |
| @@ -810,11 +851,23 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { · 4 unmodified lines | ||
| 810 | 851 | resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ |
| 811 | 852 | {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
| 812 | 853 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, |
| 813 | −/* 31 */ | |
| 854 | +/* 32 */ | |
| 814 | 855 | {0, 0x0, 0x0, F_D_OUT | FF_MEDIA_IO, |
| 815 | 856 | resp_atomic_write, NULL, /* ATOMIC WRITE 16 */ |
| 816 | 857 | {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
| 817 | 858 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} }, |
| 859 | + {0, 0x05, 0, F_D_IN, resp_read_blklimits, NULL, /* READ BLOCK LIMITS (6) */ | |
| 860 | + {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | |
| 861 | + {0, 0x2b, 0, F_D_UNKN, resp_locate, NULL, /* LOCATE (10) */ | |
| 862 | + {10, 0x07, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xc7, 0, 0, | |
| 863 | + 0, 0, 0, 0} }, | |
| 864 | + {0, 0x10, 0, F_D_IN, resp_write_filemarks, NULL, /* WRITE FILEMARKS (6) */ | |
| 865 | + {6, 0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | |
| 866 | + {0, 0x11, 0, F_D_IN, resp_space, NULL, /* SPACE (6) */ | |
| 867 | + {6, 0x07, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | |
| 868 | + {0, 0x4, 0, 0, resp_format_medium, NULL, /* FORMAT MEDIUM (6) */ | |
| 869 | + {6, 0x3, 0x7, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | |
| 870 | +/* 38 */ | |
| 818 | 871 | /* sentinel */ |
| 819 | 872 | {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ |
| 820 | 873 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, |
| @@ -1331,6 +1384,30 @@ static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) · 510 unmodified lines | ||
| 1331 | 1384 | my_name, key, asc, asq); |
| 1332 | 1385 | } |
| 1333 | 1386 | |
| 1387 | +/* Sense data that has information fields for tapes */ | |
| 1388 | +static void mk_sense_info_tape(struct scsi_cmnd *scp, int key, int asc, int asq, | |
| 1389 | + unsigned int information, unsigned char tape_flags) | |
| 1390 | +{ | |
| 1391 | + if (!scp->sense_buffer) { | |
| 1392 | + sdev_printk(KERN_ERR, scp->device, | |
| 1393 | + "%s: sense_buffer is NULL\n", __func__); | |
| 1394 | + return; | |
| 1395 | + } | |
| 1396 | + memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); | |
| 1397 | + | |
| 1398 | + scsi_build_sense(scp, /* sdebug_dsense */ 0, key, asc, asq); | |
| 1399 | + /* only fixed format so far */ | |
| 1400 | + | |
| 1401 | + scp->sense_buffer[0] |= 0x80; /* valid */ | |
| 1402 | + scp->sense_buffer[2] |= tape_flags; | |
| 1403 | + put_unaligned_be32(information, &scp->sense_buffer[3]); | |
| 1404 | + | |
| 1405 | + if (sdebug_verbose) | |
| 1406 | + sdev_printk(KERN_INFO, scp->device, | |
| 1407 | + "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", | |
| 1408 | + my_name, key, asc, asq); | |
| 1409 | +} | |
| 1410 | + | |
| 1334 | 1411 | static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) |
| 1335 | 1412 | { |
| 1336 | 1413 | mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); |
| @@ -1493,6 +1570,12 @@ static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) · 156 unmodified lines | ||
| 1493 | 1570 | if (sdebug_verbose) |
| 1494 | 1571 | cp = "reported luns data has changed"; |
| 1495 | 1572 | break; |
| 1573 | + case SDEBUG_UA_NOT_READY_TO_READY: | |
| 1574 | + mk_sense_buffer(scp, UNIT_ATTENTION, UA_READY_ASC, | |
| 1575 | + 0); | |
| 1576 | + if (sdebug_verbose) | |
| 1577 | + cp = "not ready to ready transition/media change"; | |
| 1578 | + break; | |
| 1496 | 1579 | default: |
| 1497 | 1580 | pr_warn("unexpected unit attention code=%d\n", k); |
| 1498 | 1581 | if (sdebug_verbose) |
| @@ -2196,6 +2279,14 @@ static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) · 697 unmodified lines | ||
| 2196 | 2279 | changing = (stopped_state != want_stop); |
| 2197 | 2280 | if (changing) |
| 2198 | 2281 | atomic_xchg(&devip->stopped, want_stop); |
| 2282 | + if (sdebug_ptype == TYPE_TAPE && !want_stop) { | |
| 2283 | + int i; | |
| 2284 | + | |
| 2285 | + set_bit(SDEBUG_UA_NOT_READY_TO_READY, devip->uas_bm); /* not legal! */ | |
| 2286 | + for (i = 0; i < TAPE_MAX_PARTITIONS; i++) | |
| 2287 | + devip->tape_location[i] = 0; | |
| 2288 | + devip->tape_partition = 0; | |
| 2289 | + } | |
| 2199 | 2290 | if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */ |
| 2200 | 2291 | return SDEG_RES_IMMED_MASK; |
| 2201 | 2292 | else |
| @@ -2728,6 +2819,76 @@ static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) · 526 unmodified lines | ||
| 2728 | 2819 | return sizeof(sas_sha_m_pg); |
| 2729 | 2820 | } |
| 2730 | 2821 | |
| 2822 | +static unsigned char partition_pg[] = {0x11, 12, 1, 0, 0x24, 3, 9, 0, | |
| 2823 | + 0xff, 0xff, 0x00, 0x00}; | |
| 2824 | + | |
| 2825 | +static int resp_partition_m_pg(unsigned char *p, int pcontrol, int target) | |
| 2826 | +{ /* Partition page for mode_sense (tape) */ | |
| 2827 | + memcpy(p, partition_pg, sizeof(partition_pg)); | |
| 2828 | + if (pcontrol == 1) | |
| 2829 | + memset(p + 2, 0, sizeof(partition_pg) - 2); | |
| 2830 | + return sizeof(partition_pg); | |
| 2831 | +} | |
| 2832 | + | |
| 2833 | +static int process_medium_part_m_pg(struct sdebug_dev_info *devip, | |
| 2834 | + unsigned char *new, int pg_len) | |
| 2835 | +{ | |
| 2836 | + int new_nbr, p0_size, p1_size; | |
| 2837 | + | |
| 2838 | + if ((new[4] & 0x80) != 0) { /* FDP */ | |
| 2839 | + partition_pg[4] |= 0x80; | |
| 2840 | + devip->tape_pending_nbr_partitions = TAPE_MAX_PARTITIONS; | |
| 2841 | + devip->tape_pending_part_0_size = TAPE_UNITS - TAPE_PARTITION_1_UNITS; | |
| 2842 | + devip->tape_pending_part_1_size = TAPE_PARTITION_1_UNITS; | |
| 2843 | + } else { | |
| 2844 | + new_nbr = new[3] + 1; | |
| 2845 | + if (new_nbr > TAPE_MAX_PARTITIONS) | |
| 2846 | + return 3; | |
| 2847 | + if ((new[4] & 0x40) != 0) { /* SDP */ | |
| 2848 | + p1_size = TAPE_PARTITION_1_UNITS; | |
| 2849 | + p0_size = TAPE_UNITS - p1_size; | |
| 2850 | + if (p0_size < 100) | |
| 2851 | + return 4; | |
| 2852 | + } else if ((new[4] & 0x20) != 0) { | |
| 2853 | + if (new_nbr > 1) { | |
| 2854 | + p0_size = get_unaligned_be16(new + 8); | |
| 2855 | + p1_size = get_unaligned_be16(new + 10); | |
| 2856 | + if (p1_size == 0xFFFF) | |
| 2857 | + p1_size = TAPE_UNITS - p0_size; | |
| 2858 | + else if (p0_size == 0xFFFF) | |
| 2859 | + p0_size = TAPE_UNITS - p1_size; | |
| 2860 | + if (p0_size < 100 || p1_size < 100) | |
| 2861 | + return 8; | |
| 2862 | + } else { | |
| 2863 | + p0_size = TAPE_UNITS; | |
| 2864 | + p1_size = 0; | |
| 2865 | + } | |
| 2866 | + } else | |
| 2867 | + return 6; | |
| 2868 | + devip->tape_pending_nbr_partitions = new_nbr; | |
| 2869 | + devip->tape_pending_part_0_size = p0_size; | |
| 2870 | + devip->tape_pending_part_1_size = p1_size; | |
| 2871 | + partition_pg[3] = new_nbr; | |
| 2872 | + devip->tape_pending_nbr_partitions = new_nbr; | |
| 2873 | + } | |
| 2874 | + | |
| 2875 | + return 0; | |
| 2876 | +} | |
| 2877 | + | |
| 2878 | +static int resp_compression_m_pg(unsigned char *p, int pcontrol, int target, | |
| 2879 | + unsigned char dce) | |
| 2880 | +{ /* Compression page for mode_sense (tape) */ | |
| 2881 | + unsigned char compression_pg[] = {0x0f, 14, 0x40, 0, 0, 0, 0, 0, | |
| 2882 | + 0, 0, 0, 0, 00, 00}; | |
| 2883 | + | |
| 2884 | + memcpy(p, compression_pg, sizeof(compression_pg)); | |
| 2885 | + if (dce) | |
| 2886 | + p[2] |= 0x80; | |
| 2887 | + if (pcontrol == 1) | |
| 2888 | + memset(p + 2, 0, sizeof(compression_pg) - 2); | |
| 2889 | + return sizeof(compression_pg); | |
| 2890 | +} | |
| 2891 | + | |
| 2731 | 2892 | /* PAGE_SIZE is more than necessary but provides room for future expansion. */ |
| 2732 | 2893 | #define SDEBUG_MAX_MSENSE_SZ PAGE_SIZE |
| 2733 | 2894 | |
| @@ -2742,7 +2903,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp, · 8 unmodified lines | ||
| 2742 | 2903 | unsigned char *ap; |
| 2743 | 2904 | unsigned char *arr __free(kfree); |
| 2744 | 2905 | unsigned char *cmd = scp->cmnd; |
| 2745 | − bool dbd, llbaa, msense_6, is_disk, is_zbc; | |
| 2906 | + bool dbd, llbaa, msense_6, is_disk, is_zbc, is_tape; | |
| 2746 | 2907 | |
| 2747 | 2908 | arr = kzalloc(SDEBUG_MAX_MSENSE_SZ, GFP_ATOMIC); |
| 2748 | 2909 | if (!arr) |
| @@ -2755,7 +2916,8 @@ static int resp_mode_sense(struct scsi_cmnd *scp, · 6 unmodified lines | ||
| 2755 | 2916 | llbaa = msense_6 ? false : !!(cmd[1] & 0x10); |
| 2756 | 2917 | is_disk = (sdebug_ptype == TYPE_DISK); |
| 2757 | 2918 | is_zbc = devip->zoned; |
| 2758 | − if ((is_disk || is_zbc) && !dbd) | |
| 2919 | + is_tape = (sdebug_ptype == TYPE_TAPE); | |
| 2920 | + if ((is_disk || is_zbc || is_tape) && !dbd) | |
| 2759 | 2921 | bd_len = llbaa ? 16 : 8; |
| 2760 | 2922 | else |
| 2761 | 2923 | bd_len = 0; |
| @@ -2793,15 +2955,25 @@ static int resp_mode_sense(struct scsi_cmnd *scp, · 31 unmodified lines | ||
| 2793 | 2955 | put_unaligned_be32(0xffffffff, ap + 0); |
| 2794 | 2956 | else |
| 2795 | 2957 | put_unaligned_be32(sdebug_capacity, ap + 0); |
| 2796 | − put_unaligned_be16(sdebug_sector_size, ap + 6); | |
| 2958 | + if (is_tape) { | |
| 2959 | + ap[0] = devip->tape_density; | |
| 2960 | + put_unaligned_be16(devip->tape_blksize, ap + 6); | |
| 2961 | + } else | |
| 2962 | + put_unaligned_be16(sdebug_sector_size, ap + 6); | |
| 2797 | 2963 | offset += bd_len; |
| 2798 | 2964 | ap = arr + offset; |
| 2799 | 2965 | } else if (16 == bd_len) { |
| 2966 | + if (is_tape) { | |
| 2967 | + mk_sense_invalid_fld(scp, SDEB_IN_DATA, 1, 4); | |
| 2968 | + return check_condition_result; | |
| 2969 | + } | |
| 2800 | 2970 | put_unaligned_be64((u64)sdebug_capacity, ap + 0); |
| 2801 | 2971 | put_unaligned_be32(sdebug_sector_size, ap + 12); |
| 2802 | 2972 | offset += bd_len; |
| 2803 | 2973 | ap = arr + offset; |
| 2804 | 2974 | } |
| 2975 | + if (cmd[2] == 0) | |
| 2976 | + goto only_bd; /* Only block descriptor requested */ | |
| 2805 | 2977 | |
| 2806 | 2978 | /* |
| 2807 | 2979 | * N.B. If len>0 before resp_*_pg() call, then form of that call should be: |
| @@ -2857,6 +3029,18 @@ static int resp_mode_sense(struct scsi_cmnd *scp, · 49 unmodified lines | ||
| 2857 | 3029 | } |
| 2858 | 3030 | offset += len; |
| 2859 | 3031 | break; |
| 3032 | + case 0xf: /* Compression Mode Page (tape) */ | |
| 3033 | + if (!is_tape) | |
| 3034 | + goto bad_pcode; | |
| 3035 | + len = resp_compression_m_pg(ap, pcontrol, target, devip->tape_dce); | |
| 3036 | + offset += len; | |
| 3037 | + break; | |
| 3038 | + case 0x11: /* Partition Mode Page (tape) */ | |
| 3039 | + if (!is_tape) | |
| 3040 | + goto bad_pcode; | |
| 3041 | + len = resp_partition_m_pg(ap, pcontrol, target); | |
| 3042 | + offset += len; | |
| 3043 | + break; | |
| 2860 | 3044 | case 0x19: /* if spc==1 then sas phy, control+discover */ |
| 2861 | 3045 | if (subpcode > 0x2 && subpcode < 0xff) |
| 2862 | 3046 | goto bad_subpcode; |
| @@ -2902,6 +3086,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp, · 39 unmodified lines | ||
| 2902 | 3086 | default: |
| 2903 | 3087 | goto bad_pcode; |
| 2904 | 3088 | } |
| 3089 | +only_bd: | |
| 2905 | 3090 | if (msense_6) |
| 2906 | 3091 | arr[0] = offset - 1; |
| 2907 | 3092 | else |
| @@ -2945,8 +3130,34 @@ static int resp_mode_select(struct scsi_cmnd *scp, · 37 unmodified lines | ||
| 2945 | 3130 | __func__, param_len, res); |
| 2946 | 3131 | md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); |
| 2947 | 3132 | bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); |
| 2948 | − off = bd_len + (mselect6 ? 4 : 8); | |
| 2949 | − if (md_len > 2 || off >= res) { | |
| 3133 | + off = (mselect6 ? 4 : 8); | |
| 3134 | + if (sdebug_ptype == TYPE_TAPE) { | |
| 3135 | + int blksize; | |
| 3136 | + | |
| 3137 | + if (bd_len != 8) { | |
| 3138 | + mk_sense_invalid_fld(scp, SDEB_IN_DATA, | |
| 3139 | + mselect6 ? 3 : 6, -1); | |
| 3140 | + return check_condition_result; | |
| 3141 | + } | |
| 3142 | + if (arr[off] == TAPE_BAD_DENSITY) { | |
| 3143 | + mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); | |
| 3144 | + return check_condition_result; | |
| 3145 | + } | |
| 3146 | + blksize = get_unaligned_be16(arr + off + 6); | |
| 3147 | + if (blksize != 0 && | |
| 3148 | + (blksize < TAPE_MIN_BLKSIZE || | |
| 3149 | + blksize > TAPE_MAX_BLKSIZE || | |
| 3150 | + (blksize % 4) != 0)) { | |
| 3151 | + mk_sense_invalid_fld(scp, SDEB_IN_DATA, 1, -1); | |
| 3152 | + return check_condition_result; | |
| 3153 | + } | |
| 3154 | + devip->tape_density = arr[off]; | |
| 3155 | + devip->tape_blksize = blksize; | |
| 3156 | + } | |
| 3157 | + off += bd_len; | |
| 3158 | + if (off >= res) | |
| 3159 | + return 0; /* No page written, just descriptors */ | |
| 3160 | + if (md_len > 2) { | |
| 2950 | 3161 | mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); |
| 2951 | 3162 | return check_condition_result; |
| 2952 | 3163 | } |
| @@ -2984,6 +3195,25 @@ static int resp_mode_select(struct scsi_cmnd *scp, · 31 unmodified lines | ||
| 2984 | 3195 | goto set_mode_changed_ua; |
| 2985 | 3196 | } |
| 2986 | 3197 | break; |
| 3198 | + case 0xf: /* Compression mode page */ | |
| 3199 | + if (sdebug_ptype != TYPE_TAPE) | |
| 3200 | + goto bad_pcode; | |
| 3201 | + if ((arr[off + 2] & 0x40) != 0) { | |
| 3202 | + devip->tape_dce = (arr[off + 2] & 0x80) != 0; | |
| 3203 | + return 0; | |
| 3204 | + } | |
| 3205 | + break; | |
| 3206 | + case 0x11: /* Medium Partition Mode Page (tape) */ | |
| 3207 | + if (sdebug_ptype == TYPE_TAPE) { | |
| 3208 | + int fld; | |
| 3209 | + | |
| 3210 | + fld = process_medium_part_m_pg(devip, &arr[off], pg_len); | |
| 3211 | + if (fld == 0) | |
| 3212 | + return 0; | |
| 3213 | + mk_sense_invalid_fld(scp, SDEB_IN_DATA, fld, -1); | |
| 3214 | + return check_condition_result; | |
| 3215 | + } | |
| 3216 | + break; | |
| 2987 | 3217 | case 0x1c: /* Informational Exceptions Mode page */ |
| 2988 | 3218 | if (iec_m_pg[1] == arr[off + 1]) { |
| 2989 | 3219 | memcpy(iec_m_pg + 2, arr + off + 2, |
| @@ -2999,6 +3229,10 @@ static int resp_mode_select(struct scsi_cmnd *scp, · 9 unmodified lines | ||
| 2999 | 3229 | set_mode_changed_ua: |
| 3000 | 3230 | set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); |
| 3001 | 3231 | return 0; |
| 3232 | + | |
| 3233 | +bad_pcode: | |
| 3234 | + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); | |
| 3235 | + return check_condition_result; | |
| 3002 | 3236 | } |
| 3003 | 3237 | |
| 3004 | 3238 | static int resp_temp_l_pg(unsigned char *arr) |
| @@ -3138,6 +3372,265 @@ static int resp_log_sense(struct scsi_cmnd *scp, · 133 unmodified lines | ||
| 3138 | 3372 | min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); |
| 3139 | 3373 | } |
| 3140 | 3374 | |
| 3375 | +enum {SDEBUG_READ_BLOCK_LIMITS_ARR_SZ = 6}; | |
| 3376 | +static int resp_read_blklimits(struct scsi_cmnd *scp, | |
| 3377 | + struct sdebug_dev_info *devip) | |
| 3378 | +{ | |
| 3379 | + unsigned char arr[SDEBUG_READ_BLOCK_LIMITS_ARR_SZ]; | |
| 3380 | + | |
| 3381 | + arr[0] = 4; | |
| 3382 | + put_unaligned_be24(TAPE_MAX_BLKSIZE, arr + 1); | |
| 3383 | + put_unaligned_be16(TAPE_MIN_BLKSIZE, arr + 4); | |
| 3384 | + return fill_from_dev_buffer(scp, arr, SDEBUG_READ_BLOCK_LIMITS_ARR_SZ); | |
| 3385 | +} | |
| 3386 | + | |
| 3387 | +static int resp_locate(struct scsi_cmnd *scp, | |
| 3388 | + struct sdebug_dev_info *devip) | |
| 3389 | +{ | |
| 3390 | + unsigned char *cmd = scp->cmnd; | |
| 3391 | + unsigned int i, pos; | |
| 3392 | + struct tape_block *blp; | |
| 3393 | + int partition; | |
| 3394 | + | |
| 3395 | + if ((cmd[1] & 0x02) != 0) { | |
| 3396 | + if (cmd[8] >= devip->tape_nbr_partitions) { | |
| 3397 | + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, -1); | |
| 3398 | + return check_condition_result; | |
| 3399 | + } | |
| 3400 | + devip->tape_partition = cmd[8]; | |
| 3401 | + } | |
| 3402 | + pos = get_unaligned_be32(cmd + 3); | |
| 3403 | + partition = devip->tape_partition; | |
| 3404 | + | |
| 3405 | + for (i = 0, blp = devip->tape_blocks[partition]; | |
| 3406 | + i < pos && i < devip->tape_eop[partition]; i++, blp++) | |
| 3407 | + if (IS_TAPE_BLOCK_EOD(blp->fl_size)) | |
| 3408 | + break; | |
| 3409 | + if (i < pos) { | |
| 3410 | + devip->tape_location[partition] = i; | |
| 3411 | + mk_sense_buffer(scp, BLANK_CHECK, 0x05, 0); | |
| 3412 | + return check_condition_result; | |
| 3413 | + } | |
| 3414 | + devip->tape_location[partition] = pos; | |
| 3415 | + | |
| 3416 | + return 0; | |
| 3417 | +} | |
| 3418 | + | |
| 3419 | +static int resp_write_filemarks(struct scsi_cmnd *scp, | |
| 3420 | + struct sdebug_dev_info *devip) | |
| 3421 | +{ | |
| 3422 | + unsigned char *cmd = scp->cmnd; | |
| 3423 | + unsigned int i, count, pos; | |
| 3424 | + u32 data; | |
| 3425 | + int partition = devip->tape_partition; | |
| 3426 | + | |
| 3427 | + if ((cmd[1] & 0xfe) != 0) { /* probably write setmarks, not in >= SCSI-3 */ | |
| 3428 | + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); | |
| 3429 | + return check_condition_result; | |
| 3430 | + } | |
| 3431 | + count = get_unaligned_be24(cmd + 2); | |
| 3432 | + data = TAPE_BLOCK_FM_FLAG; | |
| 3433 | + for (i = 0, pos = devip->tape_location[partition]; i < count; i++, pos++) { | |
| 3434 | + if (pos >= devip->tape_eop[partition] - 1) { /* don't overwrite EOD */ | |
| 3435 | + devip->tape_location[partition] = devip->tape_eop[partition] - 1; | |
| 3436 | + mk_sense_info_tape(scp, VOLUME_OVERFLOW, NO_ADDITIONAL_SENSE, | |
| 3437 | + EOP_EOM_DETECTED_ASCQ, count, SENSE_FLAG_EOM); | |
| 3438 | + return check_condition_result; | |
| 3439 | + } | |
| 3440 | + (devip->tape_blocks[partition] + pos)->fl_size = data; | |
| 3441 | + } | |
| 3442 | + (devip->tape_blocks[partition] + pos)->fl_size = | |
| 3443 | + TAPE_BLOCK_EOD_FLAG; | |
| 3444 | + devip->tape_location[partition] = pos; | |
| 3445 | + | |
| 3446 | + return 0; | |
| 3447 | +} | |
| 3448 | + | |
| 3449 | +static int resp_space(struct scsi_cmnd *scp, | |
| 3450 | + struct sdebug_dev_info *devip) | |
| 3451 | +{ | |
| 3452 | + unsigned char *cmd = scp->cmnd, code; | |
| 3453 | + int i = 0, pos, count; | |
| 3454 | + struct tape_block *blp; | |
| 3455 | + int partition = devip->tape_partition; | |
| 3456 | + | |
| 3457 | + count = get_unaligned_be24(cmd + 2); | |
| 3458 | + if ((count & 0x800000) != 0) /* extend negative to 32-bit count */ | |
| 3459 | + count |= 0xff000000; | |
| 3460 | + code = cmd[1] & 0x0f; | |
| 3461 | + | |
| 3462 | + pos = devip->tape_location[partition]; | |
| 3463 | + if (code == 0) { /* blocks */ | |
| 3464 | + if (count < 0) { | |
| 3465 | + count = (-count); | |
| 3466 | + pos -= 1; | |
| 3467 | + for (i = 0, blp = devip->tape_blocks[partition] + pos; i < count; | |
| 3468 | + i++) { | |
| 3469 | + if (pos < 0) | |
| 3470 | + goto is_bop; | |
| 3471 | + else if (IS_TAPE_BLOCK_FM(blp->fl_size)) | |
| 3472 | + goto is_fm; | |
| 3473 | + if (i > 0) { | |
| 3474 | + pos--; | |
| 3475 | + blp--; | |
| 3476 | + } | |
| 3477 | + } | |
| 3478 | + } else if (count > 0) { | |
| 3479 | + for (i = 0, blp = devip->tape_blocks[partition] + pos; i < count; | |
| 3480 | + i++, pos++, blp++) { | |
| 3481 | + if (IS_TAPE_BLOCK_EOD(blp->fl_size)) | |
| 3482 | + goto is_eod; | |
| 3483 | + if (IS_TAPE_BLOCK_FM(blp->fl_size)) { | |
| 3484 | + pos += 1; | |
| 3485 | + goto is_fm; | |
| 3486 | + } | |
| 3487 | + if (pos >= devip->tape_eop[partition]) | |
| 3488 | + goto is_eop; | |
| 3489 | + } | |
| 3490 | + } | |
| 3491 | + } else if (code == 1) { /* filemarks */ | |
| 3492 | + if (count < 0) { | |
| 3493 | + count = (-count); | |
| 3494 | + if (pos == 0) | |
| 3495 | + goto is_bop; | |
| 3496 | + else { | |
| 3497 | + for (i = 0, blp = devip->tape_blocks[partition] + pos; | |
| 3498 | + i < count && pos >= 0; i++, pos--, blp--) { | |
| 3499 | + for (pos--, blp-- ; !IS_TAPE_BLOCK_FM(blp->fl_size) && | |
| 3500 | + pos >= 0; pos--, blp--) | |
| 3501 | + ; /* empty */ | |
| 3502 | + if (pos < 0) | |
| 3503 | + goto is_bop; | |
| 3504 | + } | |
| 3505 | + } | |
| 3506 | + pos += 1; | |
| 3507 | + } else if (count > 0) { | |
| 3508 | + for (i = 0, blp = devip->tape_blocks[partition] + pos; | |
| 3509 | + i < count; i++, pos++, blp++) { | |
| 3510 | + for ( ; !IS_TAPE_BLOCK_FM(blp->fl_size) && | |
| 3511 | + !IS_TAPE_BLOCK_EOD(blp->fl_size) && | |
| 3512 | + pos < devip->tape_eop[partition]; | |
| 3513 | + pos++, blp++) | |
| 3514 | + ; /* empty */ | |
| 3515 | + if (IS_TAPE_BLOCK_EOD(blp->fl_size)) | |
| 3516 | + goto is_eod; | |
| 3517 | + if (pos >= devip->tape_eop[partition]) | |
| 3518 | + goto is_eop; | |
| 3519 | + } | |
| 3520 | + } | |
| 3521 | + } else if (code == 3) { /* EOD */ | |
| 3522 | + for (blp = devip->tape_blocks[partition] + pos; | |
| 3523 | + !IS_TAPE_BLOCK_EOD(blp->fl_size) && pos < devip->tape_eop[partition]; | |
| 3524 | + pos++, blp++) | |
| 3525 | + ; /* empty */ | |
| 3526 | + if (pos >= devip->tape_eop[partition]) | |
| 3527 | + goto is_eop; | |
| 3528 | + } else { | |
| 3529 | + /* sequential filemarks not supported */ | |
| 3530 | + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, -1); | |
| 3531 | + return check_condition_result; | |
| 3532 | + } | |
| 3533 | + devip->tape_location[partition] = pos; | |
| 3534 | + return 0; | |
| 3535 | + | |
| 3536 | +is_fm: | |
| 3537 | + devip->tape_location[partition] = pos; | |
| 3538 | + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, | |
| 3539 | + FILEMARK_DETECTED_ASCQ, count - i, | |
| 3540 | + SENSE_FLAG_FILEMARK); | |
| 3541 | + return check_condition_result; | |
| 3542 | + | |
| 3543 | +is_eod: | |
| 3544 | + devip->tape_location[partition] = pos; | |
| 3545 | + mk_sense_info_tape(scp, BLANK_CHECK, NO_ADDITIONAL_SENSE, | |
| 3546 | + EOD_DETECTED_ASCQ, count - i, | |
| 3547 | + 0); | |
| 3548 | + return check_condition_result; | |
| 3549 | + | |
| 3550 | +is_bop: | |
| 3551 | + devip->tape_location[partition] = 0; | |
| 3552 | + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, | |
| 3553 | + BEGINNING_OF_P_M_DETECTED_ASCQ, count - i, | |
| 3554 | + SENSE_FLAG_EOM); | |
| 3555 | + devip->tape_location[partition] = 0; | |
| 3556 | + return check_condition_result; | |
| 3557 | + | |
| 3558 | +is_eop: | |
| 3559 | + devip->tape_location[partition] = devip->tape_eop[partition] - 1; | |
| 3560 | + mk_sense_info_tape(scp, MEDIUM_ERROR, NO_ADDITIONAL_SENSE, | |
| 3561 | + EOP_EOM_DETECTED_ASCQ, (unsigned int)i, | |
| 3562 | + SENSE_FLAG_EOM); | |
| 3563 | + return check_condition_result; | |
| 3564 | +} | |
| 3565 | + | |
| 3566 | +static int resp_rewind(struct scsi_cmnd *scp, | |
| 3567 | + struct sdebug_dev_info *devip) | |
| 3568 | +{ | |
| 3569 | + devip->tape_location[devip->tape_partition] = 0; | |
| 3570 | + | |
| 3571 | + return 0; | |
| 3572 | +} | |
| 3573 | + | |
| 3574 | +static int partition_tape(struct sdebug_dev_info *devip, int nbr_partitions, | |
| 3575 | + int part_0_size, int part_1_size) | |
| 3576 | +{ | |
| 3577 | + int i; | |
| 3578 | + | |
| 3579 | + if (part_0_size + part_1_size > TAPE_UNITS) | |
| 3580 | + return -1; | |
| 3581 | + devip->tape_eop[0] = part_0_size; | |
| 3582 | + devip->tape_blocks[0]->fl_size = TAPE_BLOCK_EOD_FLAG; | |
| 3583 | + devip->tape_eop[1] = part_1_size; | |
| 3584 | + devip->tape_blocks[1] = devip->tape_blocks[0] + | |
| 3585 | + devip->tape_eop[0]; | |
| 3586 | + devip->tape_blocks[1]->fl_size = TAPE_BLOCK_EOD_FLAG; | |
| 3587 | + | |
| 3588 | + for (i = 0 ; i < TAPE_MAX_PARTITIONS; i++) | |
| 3589 | + devip->tape_location[i] = 0; | |
| 3590 | + | |
| 3591 | + devip->tape_nbr_partitions = nbr_partitions; | |
| 3592 | + devip->tape_partition = 0; | |
| 3593 | + | |
| 3594 | + partition_pg[3] = nbr_partitions - 1; | |
| 3595 | + put_unaligned_be16(devip->tape_eop[0], partition_pg + 8); | |
| 3596 | + put_unaligned_be16(devip->tape_eop[1], partition_pg + 10); | |
| 3597 | + | |
| 3598 | + return nbr_partitions; | |
| 3599 | +} | |
| 3600 | + | |
| 3601 | +static int resp_format_medium(struct scsi_cmnd *scp, | |
| 3602 | + struct sdebug_dev_info *devip) | |
| 3603 | +{ | |
| 3604 | + int res = 0; | |
| 3605 | + unsigned char *cmd = scp->cmnd; | |
| 3606 | + | |
| 3607 | + if (sdebug_ptype != TYPE_TAPE) { | |
| 3608 | + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 0, -1); | |
| 3609 | + return check_condition_result; | |
| 3610 | + } | |
| 3611 | + if (cmd[2] > 2) { | |
| 3612 | + mk_sense_invalid_fld(scp, SDEB_IN_DATA, 2, -1); | |
| 3613 | + return check_condition_result; | |
| 3614 | + } | |
| 3615 | + if (cmd[2] != 0) { | |
| 3616 | + if (devip->tape_pending_nbr_partitions > 0) { | |
| 3617 | + res = partition_tape(devip, | |
| 3618 | + devip->tape_pending_nbr_partitions, | |
| 3619 | + devip->tape_pending_part_0_size, | |
| 3620 | + devip->tape_pending_part_1_size); | |
| 3621 | + } else | |
| 3622 | + res = partition_tape(devip, devip->tape_nbr_partitions, | |
| 3623 | + devip->tape_eop[0], devip->tape_eop[1]); | |
| 3624 | + } else | |
| 3625 | + res = partition_tape(devip, 1, TAPE_UNITS, 0); | |
| 3626 | + if (res < 0) | |
| 3627 | + return -EINVAL; | |
| 3628 | + | |
| 3629 | + devip->tape_pending_nbr_partitions = -1; | |
| 3630 | + | |
| 3631 | + return 0; | |
| 3632 | +} | |
| 3633 | + | |
| 3141 | 3634 | static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) |
| 3142 | 3635 | { |
| 3143 | 3636 | return devip->nr_zones != 0; |
| @@ -3871,6 +4364,98 @@ static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, · 727 unmodified lines | ||
| 3871 | 4364 | return ret; |
| 3872 | 4365 | } |
| 3873 | 4366 | |
| 4367 | +static int resp_read_tape(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) | |
| 4368 | +{ | |
| 4369 | + u32 i, num, transfer, size; | |
| 4370 | + u8 *cmd = scp->cmnd; | |
| 4371 | + struct scsi_data_buffer *sdb = &scp->sdb; | |
| 4372 | + int partition = devip->tape_partition; | |
| 4373 | + u32 pos = devip->tape_location[partition]; | |
| 4374 | + struct tape_block *blp; | |
| 4375 | + bool fixed, sili; | |
| 4376 | + | |
| 4377 | + if (cmd[0] != READ_6) { /* Only Read(6) supported */ | |
| 4378 | + mk_sense_invalid_opcode(scp); | |
| 4379 | + return illegal_condition_result; | |
| 4380 | + } | |
| 4381 | + fixed = (cmd[1] & 0x1) != 0; | |
| 4382 | + sili = (cmd[1] & 0x2) != 0; | |
| 4383 | + if (fixed && sili) { | |
| 4384 | + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); | |
| 4385 | + return check_condition_result; | |
| 4386 | + } | |
| 4387 | + | |
| 4388 | + transfer = get_unaligned_be24(cmd + 2); | |
| 4389 | + if (fixed) { | |
| 4390 | + num = transfer; | |
| 4391 | + size = devip->tape_blksize; | |
| 4392 | + } else { | |
| 4393 | + if (transfer < TAPE_MIN_BLKSIZE || | |
| 4394 | + transfer > TAPE_MAX_BLKSIZE) { | |
| 4395 | + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); | |
| 4396 | + return check_condition_result; | |
| 4397 | + } | |
| 4398 | + num = 1; | |
| 4399 | + size = transfer; | |
| 4400 | + } | |
| 4401 | + | |
| 4402 | + for (i = 0, blp = devip->tape_blocks[partition] + pos; | |
| 4403 | + i < num && pos < devip->tape_eop[partition]; | |
| 4404 | + i++, pos++, blp++) { | |
| 4405 | + devip->tape_location[partition] = pos + 1; | |
| 4406 | + if (IS_TAPE_BLOCK_FM(blp->fl_size)) { | |
| 4407 | + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, | |
| 4408 | + FILEMARK_DETECTED_ASCQ, fixed ? num - i : size, | |
| 4409 | + SENSE_FLAG_FILEMARK); | |
| 4410 | + scsi_set_resid(scp, (num - i) * size); | |
| 4411 | + return check_condition_result; | |
| 4412 | + } | |
| 4413 | + /* Assume no REW */ | |
| 4414 | + if (IS_TAPE_BLOCK_EOD(blp->fl_size)) { | |
| 4415 | + mk_sense_info_tape(scp, BLANK_CHECK, NO_ADDITIONAL_SENSE, | |
| 4416 | + EOD_DETECTED_ASCQ, fixed ? num - i : size, | |
| 4417 | + 0); | |
| 4418 | + devip->tape_location[partition] = pos; | |
| 4419 | + scsi_set_resid(scp, (num - i) * size); | |
| 4420 | + return check_condition_result; | |
| 4421 | + } | |
| 4422 | + sg_zero_buffer(sdb->table.sgl, sdb->table.nents, | |
| 4423 | + size, i * size); | |
| 4424 | + sg_copy_buffer(sdb->table.sgl, sdb->table.nents, | |
| 4425 | + &(blp->data), 4, i * size, false); | |
| 4426 | + if (fixed) { | |
| 4427 | + if (blp->fl_size != devip->tape_blksize) { | |
| 4428 | + scsi_set_resid(scp, (num - i) * size); | |
| 4429 | + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, | |
| 4430 | + 0, num - i, | |
| 4431 | + SENSE_FLAG_ILI); | |
| 4432 | + return check_condition_result; | |
| 4433 | + } | |
| 4434 | + } else { | |
| 4435 | + if (blp->fl_size != size) { | |
| 4436 | + if (blp->fl_size < size) | |
| 4437 | + scsi_set_resid(scp, size - blp->fl_size); | |
| 4438 | + if (!sili) { | |
| 4439 | + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, | |
| 4440 | + 0, size - blp->fl_size, | |
| 4441 | + SENSE_FLAG_ILI); | |
| 4442 | + return check_condition_result; | |
| 4443 | + } | |
| 4444 | + } | |
| 4445 | + } | |
| 4446 | + } | |
| 4447 | + if (pos >= devip->tape_eop[partition]) { | |
| 4448 | + mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE, | |
| 4449 | + EOP_EOM_DETECTED_ASCQ, fixed ? num - i : size, | |
| 4450 | + SENSE_FLAG_EOM); | |
| 4451 | + devip->tape_location[partition] = pos - 1; | |
| 4452 | + return check_condition_result; | |
| 4453 | + } | |
| 4454 | + devip->tape_location[partition] = pos; | |
| 4455 | + | |
| 4456 | + return 0; | |
| 4457 | +} | |
| 4458 | + | |
| 3874 | 4459 | static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) |
| 3875 | 4460 | { |
| 3876 | 4461 | bool check_prot; |
| @@ -3882,6 +4467,9 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) · 5 unmodified lines | ||
| 3882 | 4467 | u8 *cmd = scp->cmnd; |
| 3883 | 4468 | bool meta_data_locked = false; |
| 3884 | 4469 | |
| 4470 | + if (sdebug_ptype == TYPE_TAPE) | |
| 4471 | + return resp_read_tape(scp, devip); | |
| 4472 | + | |
| 3885 | 4473 | switch (cmd[0]) { |
| 3886 | 4474 | case READ_16: |
| 3887 | 4475 | ei_lba = 0; |
| @@ -4178,6 +4766,67 @@ static void unmap_region(struct sdeb_store_info *sip, sector_t lba, · 290 unmodified lines | ||
| 4178 | 4766 | } |
| 4179 | 4767 | } |
| 4180 | 4768 | |
| 4769 | +static int resp_write_tape(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) | |
| 4770 | +{ | |
| 4771 | + u32 i, num, transfer, size, written = 0; | |
| 4772 | + u8 *cmd = scp->cmnd; | |
| 4773 | + struct scsi_data_buffer *sdb = &scp->sdb; | |
| 4774 | + int partition = devip->tape_partition; | |
| 4775 | + int pos = devip->tape_location[partition]; | |
| 4776 | + struct tape_block *blp; | |
| 4777 | + bool fixed, ew; | |
| 4778 | + | |
| 4779 | + if (cmd[0] != WRITE_6) { /* Only Write(6) supported */ | |
| 4780 | + mk_sense_invalid_opcode(scp); | |
| 4781 | + return illegal_condition_result; | |
| 4782 | + } | |
| 4783 | + | |
| 4784 | + fixed = (cmd[1] & 1) != 0; | |
| 4785 | + transfer = get_unaligned_be24(cmd + 2); | |
| 4786 | + if (fixed) { | |
| 4787 | + num = transfer; | |
| 4788 | + size = devip->tape_blksize; | |
| 4789 | + } else { | |
| 4790 | + if (transfer < TAPE_MIN_BLKSIZE || | |
| 4791 | + transfer > TAPE_MAX_BLKSIZE) { | |
| 4792 | + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); | |
| 4793 | + return check_condition_result; | |
| 4794 | + } | |
| 4795 | + num = 1; | |
| 4796 | + size = transfer; | |
| 4797 | + } | |
| 4798 | + | |
| 4799 | + scsi_set_resid(scp, num * transfer); | |
| 4800 | + for (i = 0, blp = devip->tape_blocks[partition] + pos, ew = false; | |
| 4801 | + i < num && pos < devip->tape_eop[partition] - 1; i++, pos++, blp++) { | |
| 4802 | + blp->fl_size = size; | |
| 4803 | + sg_copy_buffer(sdb->table.sgl, sdb->table.nents, | |
| 4804 | + &(blp->data), 4, i * size, true); | |
| 4805 | + written += size; | |
| 4806 | + scsi_set_resid(scp, num * transfer - written); | |
| 4807 | + ew |= (pos == devip->tape_eop[partition] - TAPE_EW); | |
| 4808 | + } | |
| 4809 | + | |
| 4810 | + devip->tape_location[partition] = pos; | |
| 4811 | + blp->fl_size = TAPE_BLOCK_EOD_FLAG; | |
| 4812 | + if (pos >= devip->tape_eop[partition] - 1) { | |
| 4813 | + mk_sense_info_tape(scp, VOLUME_OVERFLOW, | |
| 4814 | + NO_ADDITIONAL_SENSE, EOP_EOM_DETECTED_ASCQ, | |
| 4815 | + fixed ? num - i : transfer, | |
| 4816 | + SENSE_FLAG_EOM); | |
| 4817 | + return check_condition_result; | |
| 4818 | + } | |
| 4819 | + if (ew) { /* early warning */ | |
| 4820 | + mk_sense_info_tape(scp, NO_SENSE, | |
| 4821 | + NO_ADDITIONAL_SENSE, EOP_EOM_DETECTED_ASCQ, | |
| 4822 | + fixed ? num - i : transfer, | |
| 4823 | + SENSE_FLAG_EOM); | |
| 4824 | + return check_condition_result; | |
| 4825 | + } | |
| 4826 | + | |
| 4827 | + return 0; | |
| 4828 | +} | |
| 4829 | + | |
| 4181 | 4830 | static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) |
| 4182 | 4831 | { |
| 4183 | 4832 | bool check_prot; |
| @@ -4190,6 +4839,9 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) · 6 unmodified lines | ||
| 4190 | 4839 | u8 *cmd = scp->cmnd; |
| 4191 | 4840 | bool meta_data_locked = false; |
| 4192 | 4841 | |
| 4842 | + if (sdebug_ptype == TYPE_TAPE) | |
| 4843 | + return resp_write_tape(scp, devip); | |
| 4844 | + | |
| 4193 | 4845 | switch (cmd[0]) { |
| 4194 | 4846 | case WRITE_16: |
| 4195 | 4847 | ei_lba = 0; |
| @@ -4918,7 +5570,10 @@ static int resp_sync_cache(struct scsi_cmnd *scp, · 722 unmodified lines | ||
| 4918 | 5570 | * a GOOD status otherwise. Model a disk with a big cache and yield |
| 4919 | 5571 | * CONDITION MET. Actually tries to bring range in main memory into the |
| 4920 | 5572 | * cache associated with the CPU(s). |
| 5573 | + * | |
| 5574 | + * The pcode 0x34 is also used for READ POSITION by tape devices. | |
| 4921 | 5575 | */ |
| 5576 | +enum {SDEBUG_READ_POSITION_ARR_SZ = 20}; | |
| 4922 | 5577 | static int resp_pre_fetch(struct scsi_cmnd *scp, |
| 4923 | 5578 | struct sdebug_dev_info *devip) |
| 4924 | 5579 | { |
| @@ -4930,6 +5585,31 @@ static int resp_pre_fetch(struct scsi_cmnd *scp, · 5 unmodified lines | ||
| 4930 | 5585 | struct sdeb_store_info *sip = devip2sip(devip, true); |
| 4931 | 5586 | u8 *fsp = sip->storep; |
| 4932 | 5587 | |
| 5588 | + if (sdebug_ptype == TYPE_TAPE) { | |
| 5589 | + if (cmd[0] == PRE_FETCH) { /* READ POSITION (10) */ | |
| 5590 | + int all_length; | |
| 5591 | + unsigned char arr[20]; | |
| 5592 | + unsigned int pos; | |
| 5593 | + | |
| 5594 | + all_length = get_unaligned_be16(cmd + 7); | |
| 5595 | + if ((cmd[1] & 0xfe) != 0 || | |
| 5596 | + all_length != 0) { /* only short form */ | |
| 5597 | + mk_sense_invalid_fld(scp, SDEB_IN_CDB, | |
| 5598 | + all_length ? 7 : 1, 0); | |
| 5599 | + return check_condition_result; | |
| 5600 | + } | |
| 5601 | + memset(arr, 0, SDEBUG_READ_POSITION_ARR_SZ); | |
| 5602 | + arr[1] = devip->tape_partition; | |
| 5603 | + pos = devip->tape_location[devip->tape_partition]; | |
| 5604 | + put_unaligned_be32(pos, arr + 4); | |
| 5605 | + put_unaligned_be32(pos, arr + 8); | |
| 5606 | + return fill_from_dev_buffer(scp, arr, | |
| 5607 | + SDEBUG_READ_POSITION_ARR_SZ); | |
| 5608 | + } | |
| 5609 | + mk_sense_invalid_opcode(scp); | |
| 5610 | + return check_condition_result; | |
| 5611 | + } | |
| 5612 | + | |
| 4933 | 5613 | if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */ |
| 4934 | 5614 | lba = get_unaligned_be32(cmd + 2); |
| 4935 | 5615 | nblks = get_unaligned_be16(cmd + 7); |
| @@ -5638,10 +6318,10 @@ static u32 get_tag(struct scsi_cmnd *cmnd) · 702 unmodified lines | ||
| 5638 | 6318 | /* Queued (deferred) command completions converge here. */ |
| 5639 | 6319 | static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) |
| 5640 | 6320 | { |
| 5641 | − struct sdebug_queued_cmd *sqcp = container_of(sd_dp, struct sdebug_queued_cmd, sd_dp); | |
| 6321 | + struct sdebug_scsi_cmd *sdsc = container_of(sd_dp, | |
| 6322 | + typeof(*sdsc), sd_dp); | |
| 6323 | + struct scsi_cmnd *scp = (struct scsi_cmnd *)sdsc - 1; | |
| 5642 | 6324 | unsigned long flags; |
| 5643 | − struct scsi_cmnd *scp = sqcp->scmd; | |
| 5644 | − struct sdebug_scsi_cmd *sdsc; | |
| 5645 | 6325 | bool aborted; |
| 5646 | 6326 | |
| 5647 | 6327 | if (sdebug_statistics) { |
| @@ -5652,27 +6332,23 @@ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) · 4 unmodified lines | ||
| 5652 | 6332 | |
| 5653 | 6333 | if (!scp) { |
| 5654 | 6334 | pr_err("scmd=NULL\n"); |
| 5655 | − goto out; | |
| 6335 | + return; | |
| 5656 | 6336 | } |
| 5657 | 6337 | |
| 5658 | − sdsc = scsi_cmd_priv(scp); | |
| 5659 | 6338 | spin_lock_irqsave(&sdsc->lock, flags); |
| 5660 | 6339 | aborted = sd_dp->aborted; |
| 5661 | 6340 | if (unlikely(aborted)) |
| 5662 | 6341 | sd_dp->aborted = false; |
| 5663 | − ASSIGN_QUEUED_CMD(scp, NULL); | |
| 5664 | 6342 | |
| 5665 | 6343 | spin_unlock_irqrestore(&sdsc->lock, flags); |
| 5666 | 6344 | |
| 5667 | 6345 | if (aborted) { |
| 5668 | 6346 | pr_info("bypassing scsi_done() due to aborted cmd, kicking-off EH\n"); |
| 5669 | 6347 | blk_abort_request(scsi_cmd_to_rq(scp)); |
| 5670 | − goto out; | |
| 6348 | + return; | |
| 5671 | 6349 | } |
| 5672 | 6350 | |
| 5673 | 6351 | scsi_done(scp); /* callback to mid level */ |
| 5674 | −out: | |
| 5675 | − sdebug_free_queued_cmd(sqcp); | |
| 5676 | 6352 | } |
| 5677 | 6353 | |
| 5678 | 6354 | /* When high resolution timer goes off this function is called. */ |
| @@ -5835,6 +6511,10 @@ static struct sdebug_dev_info *sdebug_device_create( · 156 unmodified lines | ||
| 5835 | 6511 | } else { |
| 5836 | 6512 | devip->zoned = false; |
| 5837 | 6513 | } |
| 6514 | + if (sdebug_ptype == TYPE_TAPE) { | |
| 6515 | + devip->tape_density = TAPE_DEF_DENSITY; | |
| 6516 | + devip->tape_blksize = TAPE_DEF_BLKSIZE; | |
| 6517 | + } | |
| 5838 | 6518 | devip->create_ts = ktime_get_boottime(); |
| 5839 | 6519 | atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0)); |
| 5840 | 6520 | spin_lock_init(&devip->list_lock); |
| @@ -5905,6 +6585,21 @@ static int scsi_debug_sdev_configure(struct scsi_device *sdp, · 64 unmodified lines | ||
| 5905 | 6585 | if (devip == NULL) |
| 5906 | 6586 | return 1; /* no resources, will be marked offline */ |
| 5907 | 6587 | } |
| 6588 | + if (sdebug_ptype == TYPE_TAPE) { | |
| 6589 | + if (!devip->tape_blocks[0]) { | |
| 6590 | + devip->tape_blocks[0] = | |
| 6591 | + kcalloc(TAPE_UNITS, sizeof(struct tape_block), | |
| 6592 | + GFP_KERNEL); | |
| 6593 | + if (!devip->tape_blocks[0]) | |
| 6594 | + return 1; | |
| 6595 | + } | |
| 6596 | + devip->tape_pending_nbr_partitions = -1; | |
| 6597 | + if (partition_tape(devip, 1, TAPE_UNITS, 0) < 0) { | |
| 6598 | + kfree(devip->tape_blocks[0]); | |
| 6599 | + devip->tape_blocks[0] = NULL; | |
| 6600 | + return 1; | |
| 6601 | + } | |
| 6602 | + } | |
| 5908 | 6603 | sdp->hostdata = devip; |
| 5909 | 6604 | if (sdebug_no_uld) |
| 5910 | 6605 | sdp->no_uld_attach = 1; |
| @@ -5950,31 +6645,41 @@ static void scsi_debug_sdev_destroy(struct scsi_device *sdp) · 39 unmodified lines | ||
| 5950 | 6645 | |
| 5951 | 6646 | debugfs_remove(devip->debugfs_entry); |
| 5952 | 6647 | |
| 6648 | + if (sdebug_ptype == TYPE_TAPE) { | |
| 6649 | + kfree(devip->tape_blocks[0]); | |
| 6650 | + devip->tape_blocks[0] = NULL; | |
| 6651 | + } | |
| 6652 | + | |
| 5953 | 6653 | /* make this slot available for re-use */ |
| 5954 | 6654 | devip->used = false; |
| 5955 | 6655 | sdp->hostdata = NULL; |
| 5956 | 6656 | } |
| 5957 | 6657 | |
| 5958 | −/* Returns true if we require the queued memory to be freed by the caller. */ | |
| 5959 | −static bool stop_qc_helper(struct sdebug_defer *sd_dp, | |
| 5960 | − enum sdeb_defer_type defer_t) | |
| 6658 | +/* Returns true if cancelled or not running callback. */ | |
| 6659 | +static bool scsi_debug_stop_cmnd(struct scsi_cmnd *cmnd) | |
| 5961 | 6660 | { |
| 6661 | + struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); | |
| 6662 | + struct sdebug_defer *sd_dp = &sdsc->sd_dp; | |
| 6663 | + enum sdeb_defer_type defer_t = READ_ONCE(sd_dp->defer_t); | |
| 6664 | + | |
| 6665 | + lockdep_assert_held(&sdsc->lock); | |
| 6666 | + | |
| 5962 | 6667 | if (defer_t == SDEB_DEFER_HRT) { |
| 5963 | 6668 | int res = hrtimer_try_to_cancel(&sd_dp->hrt); |
| 5964 | 6669 | |
| 5965 | 6670 | switch (res) { |
| 5966 | − case 0: /* Not active, it must have already run */ | |
| 5967 | 6671 | case -1: /* -1 It's executing the CB */ |
| 5968 | 6672 | return false; |
| 6673 | + case 0: /* Not active, it must have already run */ | |
| 5969 | 6674 | case 1: /* Was active, we've now cancelled */ |
| 5970 | 6675 | default: |
| 5971 | 6676 | return true; |
| 5972 | 6677 | } |
| 5973 | 6678 | } else if (defer_t == SDEB_DEFER_WQ) { |
| 5974 | 6679 | /* Cancel if pending */ |
| 5975 | − if (cancel_work_sync(&sd_dp->ew.work)) | |
| 6680 | + if (cancel_work(&sd_dp->ew.work)) | |
| 5976 | 6681 | return true; |
| 5977 | − /* Was not pending, so it must have run */ | |
| 6682 | + /* callback may be running, so return false */ | |
| 5978 | 6683 | return false; |
| 5979 | 6684 | } else if (defer_t == SDEB_DEFER_POLL) { |
| 5980 | 6685 | return true; |
| @@ -5983,28 +6688,6 @@ static bool stop_qc_helper(struct sdebug_defer *sd_dp, · 2 unmodified lines | ||
| 5983 | 6688 | return false; |
| 5984 | 6689 | } |
| 5985 | 6690 | |
| 5986 | − | |
| 5987 | −static bool scsi_debug_stop_cmnd(struct scsi_cmnd *cmnd) | |
| 5988 | −{ | |
| 5989 | − enum sdeb_defer_type l_defer_t; | |
| 5990 | − struct sdebug_defer *sd_dp; | |
| 5991 | − struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); | |
| 5992 | − struct sdebug_queued_cmd *sqcp = TO_QUEUED_CMD(cmnd); | |
| 5993 | − | |
| 5994 | − lockdep_assert_held(&sdsc->lock); | |
| 5995 | − | |
| 5996 | − if (!sqcp) | |
| 5997 | − return false; | |
| 5998 | − sd_dp = &sqcp->sd_dp; | |
| 5999 | − l_defer_t = READ_ONCE(sd_dp->defer_t); | |
| 6000 | − ASSIGN_QUEUED_CMD(cmnd, NULL); | |
| 6001 | − | |
| 6002 | − if (stop_qc_helper(sd_dp, l_defer_t)) | |
| 6003 | − sdebug_free_queued_cmd(sqcp); | |
| 6004 | − | |
| 6005 | − return true; | |
| 6006 | −} | |
| 6007 | − | |
| 6008 | 6691 | /* |
| 6009 | 6692 | * Called from scsi_debug_abort() only, which is for timed-out cmd. |
| 6010 | 6693 | */ |
| @@ -6076,7 +6759,7 @@ static int sdebug_fail_abort(struct scsi_cmnd *cmnd) · 65 unmodified lines | ||
| 6076 | 6759 | |
| 6077 | 6760 | static int scsi_debug_abort(struct scsi_cmnd *SCpnt) |
| 6078 | 6761 | { |
| 6079 | − bool ok = scsi_debug_abort_cmnd(SCpnt); | |
| 6762 | + bool aborted = scsi_debug_abort_cmnd(SCpnt); | |
| 6080 | 6763 | u8 *cmd = SCpnt->cmnd; |
| 6081 | 6764 | u8 opcode = cmd[0]; |
| 6082 | 6765 | |
| @@ -6085,7 +6768,8 @@ static int scsi_debug_abort(struct scsi_cmnd *SCpnt) · 2 unmodified lines | ||
| 6085 | 6768 | if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) |
| 6086 | 6769 | sdev_printk(KERN_INFO, SCpnt->device, |
| 6087 | 6770 | "%s: command%s found\n", __func__, |
| 6088 | − ok ? "" : " not"); | |
| 6771 | + aborted ? "" : " not"); | |
| 6772 | + | |
| 6089 | 6773 | |
| 6090 | 6774 | if (sdebug_fail_abort(SCpnt)) { |
| 6091 | 6775 | scmd_printk(KERN_INFO, SCpnt, "fail abort command 0x%x\n", |
| @@ -6093,6 +6777,9 @@ static int scsi_debug_abort(struct scsi_cmnd *SCpnt) · 1 unmodified line | ||
| 6093 | 6777 | return FAILED; |
| 6094 | 6778 | } |
| 6095 | 6779 | |
| 6780 | + if (aborted == false) | |
| 6781 | + return FAILED; | |
| 6782 | + | |
| 6096 | 6783 | return SUCCESS; |
| 6097 | 6784 | } |
| 6098 | 6785 | |
| @@ -6144,6 +6831,22 @@ static int sdebug_fail_lun_reset(struct scsi_cmnd *cmnd) · 45 unmodified lines | ||
| 6144 | 6831 | return 0; |
| 6145 | 6832 | } |
| 6146 | 6833 | |
| 6834 | +static void scsi_tape_reset_clear(struct sdebug_dev_info *devip) | |
| 6835 | +{ | |
| 6836 | + if (sdebug_ptype == TYPE_TAPE) { | |
| 6837 | + int i; | |
| 6838 | + | |
| 6839 | + devip->tape_blksize = TAPE_DEF_BLKSIZE; | |
| 6840 | + devip->tape_density = TAPE_DEF_DENSITY; | |
| 6841 | + devip->tape_partition = 0; | |
| 6842 | + devip->tape_dce = 0; | |
| 6843 | + for (i = 0; i < TAPE_MAX_PARTITIONS; i++) | |
| 6844 | + devip->tape_location[i] = 0; | |
| 6845 | + devip->tape_pending_nbr_partitions = -1; | |
| 6846 | + /* Don't reset partitioning? */ | |
| 6847 | + } | |
| 6848 | +} | |
| 6849 | + | |
| 6147 | 6850 | static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) |
| 6148 | 6851 | { |
| 6149 | 6852 | struct scsi_device *sdp = SCpnt->device; |
| @@ -6157,8 +6860,10 @@ static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) · 7 unmodified lines | ||
| 6157 | 6860 | sdev_printk(KERN_INFO, sdp, "%s\n", __func__); |
| 6158 | 6861 | |
| 6159 | 6862 | scsi_debug_stop_all_queued(sdp); |
| 6160 | − if (devip) | |
| 6863 | + if (devip) { | |
| 6161 | 6864 | set_bit(SDEBUG_UA_POR, devip->uas_bm); |
| 6865 | + scsi_tape_reset_clear(devip); | |
| 6866 | + } | |
| 6162 | 6867 | |
| 6163 | 6868 | if (sdebug_fail_lun_reset(SCpnt)) { |
| 6164 | 6869 | scmd_printk(KERN_INFO, SCpnt, "fail lun reset 0x%x\n", opcode); |
| @@ -6196,6 +6901,7 @@ static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) · 31 unmodified lines | ||
| 6196 | 6901 | list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { |
| 6197 | 6902 | if (devip->target == sdp->id) { |
| 6198 | 6903 | set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); |
| 6904 | + scsi_tape_reset_clear(devip); | |
| 6199 | 6905 | ++k; |
| 6200 | 6906 | } |
| 6201 | 6907 | } |
| @@ -6227,6 +6933,7 @@ static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) · 25 unmodified lines | ||
| 6227 | 6933 | |
| 6228 | 6934 | list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { |
| 6229 | 6935 | set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); |
| 6936 | + scsi_tape_reset_clear(devip); | |
| 6230 | 6937 | ++k; |
| 6231 | 6938 | } |
| 6232 | 6939 | |
| @@ -6250,6 +6957,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) · 17 unmodified lines | ||
| 6250 | 6957 | list_for_each_entry(devip, &sdbg_host->dev_info_list, |
| 6251 | 6958 | dev_list) { |
| 6252 | 6959 | set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); |
| 6960 | + scsi_tape_reset_clear(devip); | |
| 6253 | 6961 | ++k; |
| 6254 | 6962 | } |
| 6255 | 6963 | } |
| @@ -6366,33 +7074,6 @@ static bool inject_on_this_cmd(void) · 110 unmodified lines | ||
| 6366 | 7074 | |
| 6367 | 7075 | #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ |
| 6368 | 7076 | |
| 6369 | − | |
| 6370 | −void sdebug_free_queued_cmd(struct sdebug_queued_cmd *sqcp) | |
| 6371 | −{ | |
| 6372 | − if (sqcp) | |
| 6373 | − kmem_cache_free(queued_cmd_cache, sqcp); | |
| 6374 | −} | |
| 6375 | − | |
| 6376 | −static struct sdebug_queued_cmd *sdebug_alloc_queued_cmd(struct scsi_cmnd *scmd) | |
| 6377 | −{ | |
| 6378 | − struct sdebug_queued_cmd *sqcp; | |
| 6379 | − struct sdebug_defer *sd_dp; | |
| 6380 | − | |
| 6381 | − sqcp = kmem_cache_zalloc(queued_cmd_cache, GFP_ATOMIC); | |
| 6382 | − if (!sqcp) | |
| 6383 | − return NULL; | |
| 6384 | − | |
| 6385 | − sd_dp = &sqcp->sd_dp; | |
| 6386 | − | |
| 6387 | − hrtimer_setup(&sd_dp->hrt, sdebug_q_cmd_hrt_complete, CLOCK_MONOTONIC, | |
| 6388 | − HRTIMER_MODE_REL_PINNED); | |
| 6389 | − INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); | |
| 6390 | − | |
| 6391 | − sqcp->scmd = scmd; | |
| 6392 | − | |
| 6393 | − return sqcp; | |
| 6394 | −} | |
| 6395 | − | |
| 6396 | 7077 | /* Complete the processing of the thread that queued a SCSI command to this |
| 6397 | 7078 | * driver. It either completes the command by calling cmnd_done() or |
| 6398 | 7079 | * schedules a hr timer or work queue then returns 0. Returns |
| @@ -6409,7 +7090,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, · 10 unmodified lines | ||
| 6409 | 7090 | struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); |
| 6410 | 7091 | unsigned long flags; |
| 6411 | 7092 | u64 ns_from_boot = 0; |
| 6412 | − struct sdebug_queued_cmd *sqcp; | |
| 6413 | 7093 | struct scsi_device *sdp; |
| 6414 | 7094 | struct sdebug_defer *sd_dp; |
| 6415 | 7095 | |
| @@ -6441,12 +7121,7 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, · 25 unmodified lines | ||
| 6441 | 7121 | } |
| 6442 | 7122 | } |
| 6443 | 7123 | |
| 6444 | − sqcp = sdebug_alloc_queued_cmd(cmnd); | |
| 6445 | − if (!sqcp) { | |
| 6446 | − pr_err("%s no alloc\n", __func__); | |
| 6447 | − return SCSI_MLQUEUE_HOST_BUSY; | |
| 6448 | − } | |
| 6449 | − sd_dp = &sqcp->sd_dp; | |
| 7124 | + sd_dp = &sdsc->sd_dp; | |
| 6450 | 7125 | |
| 6451 | 7126 | if (polled || (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)) |
| 6452 | 7127 | ns_from_boot = ktime_get_boottime_ns(); |
| @@ -6494,7 +7169,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, · 41 unmodified lines | ||
| 6494 | 7169 | |
| 6495 | 7170 | if (kt <= d) { /* elapsed duration >= kt */ |
| 6496 | 7171 | /* call scsi_done() from this thread */ |
| 6497 | − sdebug_free_queued_cmd(sqcp); | |
| 6498 | 7172 | scsi_done(cmnd); |
| 6499 | 7173 | return 0; |
| 6500 | 7174 | } |
| @@ -6507,13 +7181,11 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, · 6 unmodified lines | ||
| 6507 | 7181 | if (polled) { |
| 6508 | 7182 | spin_lock_irqsave(&sdsc->lock, flags); |
| 6509 | 7183 | sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt); |
| 6510 | − ASSIGN_QUEUED_CMD(cmnd, sqcp); | |
| 6511 | 7184 | WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); |
| 6512 | 7185 | spin_unlock_irqrestore(&sdsc->lock, flags); |
| 6513 | 7186 | } else { |
| 6514 | 7187 | /* schedule the invocation of scsi_done() for a later time */ |
| 6515 | 7188 | spin_lock_irqsave(&sdsc->lock, flags); |
| 6516 | − ASSIGN_QUEUED_CMD(cmnd, sqcp); | |
| 6517 | 7189 | WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT); |
| 6518 | 7190 | hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); |
| 6519 | 7191 | /* |
| @@ -6537,13 +7209,11 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, · 17 unmodified lines | ||
| 6537 | 7209 | sd_dp->issuing_cpu = raw_smp_processor_id(); |
| 6538 | 7210 | if (polled) { |
| 6539 | 7211 | spin_lock_irqsave(&sdsc->lock, flags); |
| 6540 | − ASSIGN_QUEUED_CMD(cmnd, sqcp); | |
| 6541 | 7212 | sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot); |
| 6542 | 7213 | WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); |
| 6543 | 7214 | spin_unlock_irqrestore(&sdsc->lock, flags); |
| 6544 | 7215 | } else { |
| 6545 | 7216 | spin_lock_irqsave(&sdsc->lock, flags); |
| 6546 | − ASSIGN_QUEUED_CMD(cmnd, sqcp); | |
| 6547 | 7217 | WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ); |
| 6548 | 7218 | schedule_work(&sd_dp->ew.work); |
| 6549 | 7219 | spin_unlock_irqrestore(&sdsc->lock, flags); |
| @@ -6835,7 +7505,7 @@ static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) · 285 unmodified lines | ||
| 6835 | 7505 | blk_mq_tagset_busy_iter(&host->tag_set, sdebug_submit_queue_iter, |
| 6836 | 7506 | &data); |
| 6837 | 7507 | if (f >= 0) { |
| 6838 | − seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", | |
| 7508 | + seq_printf(m, " BUSY: %s: %d,%d\n", | |
| 6839 | 7509 | "first,last bits", f, l); |
| 6840 | 7510 | } |
| 6841 | 7511 | } |
| @@ -7910,12 +8580,6 @@ static int __init scsi_debug_init(void) · 1068 unmodified lines | ||
| 7910 | 8580 | hosts_to_add = sdebug_add_host; |
| 7911 | 8581 | sdebug_add_host = 0; |
| 7912 | 8582 | |
| 7913 | − queued_cmd_cache = KMEM_CACHE(sdebug_queued_cmd, SLAB_HWCACHE_ALIGN); | |
| 7914 | − if (!queued_cmd_cache) { | |
| 7915 | − ret = -ENOMEM; | |
| 7916 | − goto driver_unreg; | |
| 7917 | − } | |
| 7918 | − | |
| 7919 | 8583 | sdebug_debugfs_root = debugfs_create_dir("scsi_debug", NULL); |
| 7920 | 8584 | if (IS_ERR_OR_NULL(sdebug_debugfs_root)) |
| 7921 | 8585 | pr_info("%s: failed to create initial debugfs directory\n", __func__); |
| @@ -7942,8 +8606,6 @@ static int __init scsi_debug_init(void) · 20 unmodified lines | ||
| 7942 | 8606 | |
| 7943 | 8607 | return 0; |
| 7944 | 8608 | |
| 7945 | −driver_unreg: | |
| 7946 | − driver_unregister(&sdebug_driverfs_driver); | |
| 7947 | 8609 | bus_unreg: |
| 7948 | 8610 | bus_unregister(&pseudo_lld_bus); |
| 7949 | 8611 | dev_unreg: |
| @@ -7959,7 +8621,6 @@ static void __exit scsi_debug_exit(void) · 9 unmodified lines | ||
| 7959 | 8621 | |
| 7960 | 8622 | for (; k; k--) |
| 7961 | 8623 | sdebug_do_remove_host(true); |
| 7962 | − kmem_cache_destroy(queued_cmd_cache); | |
| 7963 | 8624 | driver_unregister(&sdebug_driverfs_driver); |
| 7964 | 8625 | bus_unregister(&pseudo_lld_bus); |
| 7965 | 8626 | root_device_unregister(pseudo_primary); |
| @@ -8343,7 +9004,6 @@ static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) · 377 unmodified lines | ||
| 8343 | 9004 | struct sdebug_defer *sd_dp; |
| 8344 | 9005 | u32 unique_tag = blk_mq_unique_tag(rq); |
| 8345 | 9006 | u16 hwq = blk_mq_unique_tag_to_hwq(unique_tag); |
| 8346 | − struct sdebug_queued_cmd *sqcp; | |
| 8347 | 9007 | unsigned long flags; |
| 8348 | 9008 | int queue_num = data->queue_num; |
| 8349 | 9009 | ktime_t time; |
| @@ -8359,13 +9019,7 @@ static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) · 9 unmodified lines | ||
| 8359 | 9019 | time = ktime_get_boottime(); |
| 8360 | 9020 | |
| 8361 | 9021 | spin_lock_irqsave(&sdsc->lock, flags); |
| 8362 | − sqcp = TO_QUEUED_CMD(cmd); | |
| 8363 | − if (!sqcp) { | |
| 8364 | − spin_unlock_irqrestore(&sdsc->lock, flags); | |
| 8365 | − return true; | |
| 8366 | − } | |
| 8367 | − | |
| 8368 | − sd_dp = &sqcp->sd_dp; | |
| 9022 | + sd_dp = &sdsc->sd_dp; | |
| 8369 | 9023 | if (READ_ONCE(sd_dp->defer_t) != SDEB_DEFER_POLL) { |
| 8370 | 9024 | spin_unlock_irqrestore(&sdsc->lock, flags); |
| 8371 | 9025 | return true; |
| @@ -8375,8 +9029,6 @@ static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) · 3 unmodified lines | ||
| 8375 | 9029 | spin_unlock_irqrestore(&sdsc->lock, flags); |
| 8376 | 9030 | return true; |
| 8377 | 9031 | } |
| 8378 | − | |
| 8379 | − ASSIGN_QUEUED_CMD(cmd, NULL); | |
| 8380 | 9032 | spin_unlock_irqrestore(&sdsc->lock, flags); |
| 8381 | 9033 | |
| 8382 | 9034 | if (sdebug_statistics) { |
| @@ -8385,8 +9037,6 @@ static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) · 2 unmodified lines | ||
| 8385 | 9037 | atomic_inc(&sdebug_miss_cpus); |
| 8386 | 9038 | } |
| 8387 | 9039 | |
| 8388 | − sdebug_free_queued_cmd(sqcp); | |
| 8389 | − | |
| 8390 | 9040 | scsi_done(cmd); /* callback to mid level */ |
| 8391 | 9041 | (*data->num_entries)++; |
| 8392 | 9042 | return true; |
| @@ -8701,8 +9351,12 @@ err_out: · 308 unmodified lines | ||
| 8701 | 9351 | static int sdebug_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) |
| 8702 | 9352 | { |
| 8703 | 9353 | struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmd); |
| 9354 | + struct sdebug_defer *sd_dp = &sdsc->sd_dp; | |
| 8704 | 9355 | |
| 8705 | 9356 | spin_lock_init(&sdsc->lock); |
| 9357 | + hrtimer_setup(&sd_dp->hrt, sdebug_q_cmd_hrt_complete, CLOCK_MONOTONIC, | |
| 9358 | + HRTIMER_MODE_REL_PINNED); | |
| 9359 | + INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); | |
| 8706 | 9360 | |
| 8707 | 9361 | return 0; |
| 8708 | 9362 | } |
| @@ -547,6 +547,18 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd) · 546 unmodified lines | ||
| 547 | 547 | |
| 548 | 548 | scsi_report_sense(sdev, &sshdr); |
| 549 | 549 | |
| 550 | + if (sshdr.sense_key == UNIT_ATTENTION) { | |
| 551 | + /* | |
| 552 | + * Increment the counters for Power on/Reset or New Media so | |
| 553 | + * that all ULDs interested in these can see that those have | |
| 554 | + * happened, even if someone else gets the sense data. | |
| 555 | + */ | |
| 556 | + if (sshdr.asc == 0x28) | |
| 557 | + scmd->device->ua_new_media_ctr++; | |
| 558 | + else if (sshdr.asc == 0x29) | |
| 559 | + scmd->device->ua_por_ctr++; | |
| 560 | + } | |
| 561 | + | |
| 550 | 562 | if (scsi_sense_is_deferred(&sshdr)) |
| 551 | 563 | return NEEDS_RETRY; |
| 552 | 564 | |
| @@ -711,6 +723,13 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd) · 158 unmodified lines | ||
| 711 | 723 | return SUCCESS; |
| 712 | 724 | |
| 713 | 725 | case COMPLETED: |
| 726 | + /* | |
| 727 | + * A command using command duration limits (CDL) with a | |
| 728 | + * descriptor set with policy 0xD may be completed with success | |
| 729 | + * and the sense data DATA CURRENTLY UNAVAILABLE, indicating | |
| 730 | + * that the command was in fact aborted because it exceeded its | |
| 731 | + * duration limit. Never retry these commands. | |
| 732 | + */ | |
| 714 | 733 | if (sshdr.asc == 0x55 && sshdr.ascq == 0x0a) { |
| 715 | 734 | set_scsi_ml_byte(scmd, SCSIML_STAT_DL_TIMEOUT); |
| 716 | 735 | req->cmd_flags |= REQ_FAILFAST_DEV; |
| @@ -151,8 +151,9 @@ int scsi_complete_async_scans(void) · 150 unmodified lines | ||
| 151 | 151 | struct async_scan_data *data; |
| 152 | 152 | |
| 153 | 153 | do { |
| 154 | − if (list_empty(&scanning_hosts)) | |
| 155 | − return 0; | |
| 154 | + scoped_guard(spinlock, &async_scan_lock) | |
| 155 | + if (list_empty(&scanning_hosts)) | |
| 156 | + return 0; | |
| 156 | 157 | /* If we can't get memory immediately, that's OK. Just |
| 157 | 158 | * sleep a little. Even if we never get memory, the async |
| 158 | 159 | * scans will finish eventually. |
| @@ -17,7 +17,9 @@ static const struct ctl_table scsi_table[] = { · 16 unmodified lines | ||
| 17 | 17 | .data = &scsi_logging_level, |
| 18 | 18 | .maxlen = sizeof(scsi_logging_level), |
| 19 | 19 | .mode = 0644, |
| 20 | − .proc_handler = proc_dointvec }, | |
| 20 | + .proc_handler = proc_dointvec_minmax, | |
| 21 | + .extra1 = SYSCTL_ZERO, | |
| 22 | + .extra2 = SYSCTL_INT_MAX }, | |
| 21 | 23 | }; |
| 22 | 24 | |
| 23 | 25 | static struct ctl_table_header *scsi_table_header; |
| @@ -163,9 +163,11 @@ static const char *st_formats[] = { · 162 unmodified lines | ||
| 163 | 163 | |
| 164 | 164 | static int debugging = DEBUG; |
| 165 | 165 | |
| 166 | +/* Setting these non-zero may risk recognizing resets */ | |
| 166 | 167 | #define MAX_RETRIES 0 |
| 167 | 168 | #define MAX_WRITE_RETRIES 0 |
| 168 | 169 | #define MAX_READY_RETRIES 0 |
| 170 | + | |
| 169 | 171 | #define NO_TAPE NOT_READY |
| 170 | 172 | |
| 171 | 173 | #define ST_TIMEOUT (900 * HZ) |
| @@ -357,10 +359,18 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) · 185 unmodified lines | ||
| 357 | 359 | { |
| 358 | 360 | int result = SRpnt->result; |
| 359 | 361 | u8 scode; |
| 362 | + unsigned int ctr; | |
| 360 | 363 | DEB(const char *stp;) |
| 361 | 364 | char *name = STp->name; |
| 362 | 365 | struct st_cmdstatus *cmdstatp; |
| 363 | 366 | |
| 367 | + ctr = scsi_get_ua_por_ctr(STp->device); | |
| 368 | + if (ctr != STp->por_ctr) { | |
| 369 | + STp->por_ctr = ctr; | |
| 370 | + STp->pos_unknown = 1; /* ASC => power on / reset */ | |
| 371 | + st_printk(KERN_WARNING, STp, "Power on/reset recognized."); | |
| 372 | + } | |
| 373 | + | |
| 364 | 374 | if (!result) |
| 365 | 375 | return 0; |
| 366 | 376 | |
| @@ -413,10 +423,11 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) · 46 unmodified lines | ||
| 413 | 423 | if (cmdstatp->have_sense && |
| 414 | 424 | cmdstatp->sense_hdr.asc == 0 && cmdstatp->sense_hdr.ascq == 0x17) |
| 415 | 425 | STp->cleaning_req = 1; /* ASC and ASCQ => cleaning requested */ |
| 416 | − if (cmdstatp->have_sense && scode == UNIT_ATTENTION && cmdstatp->sense_hdr.asc == 0x29) | |
| 426 | + if (cmdstatp->have_sense && scode == UNIT_ATTENTION && | |
| 427 | + cmdstatp->sense_hdr.asc == 0x29 && !STp->pos_unknown) { | |
| 417 | 428 | STp->pos_unknown = 1; /* ASC => power on / reset */ |
| 418 | − | |
| 419 | − STp->pos_unknown |= STp->device->was_reset; | |
| 429 | + st_printk(KERN_WARNING, STp, "Power on/reset recognized."); | |
| 430 | + } | |
| 420 | 431 | |
| 421 | 432 | if (cmdstatp->have_sense && |
| 422 | 433 | scode == RECOVERED_ERROR |
| @@ -952,7 +963,6 @@ static void reset_state(struct scsi_tape *STp) · 529 unmodified lines | ||
| 952 | 963 | STp->partition = find_partition(STp); |
| 953 | 964 | if (STp->partition < 0) |
| 954 | 965 | STp->partition = 0; |
| 955 | − STp->new_partition = STp->partition; | |
| 956 | 966 | } |
| 957 | 967 | } |
| 958 | 968 | |
| @@ -969,6 +979,7 @@ static int test_ready(struct scsi_tape *STp, int do_wait) · 10 unmodified lines | ||
| 969 | 979 | { |
| 970 | 980 | int attentions, waits, max_wait, scode; |
| 971 | 981 | int retval = CHKRES_READY, new_session = 0; |
| 982 | + unsigned int ctr; | |
| 972 | 983 | unsigned char cmd[MAX_COMMAND_SIZE]; |
| 973 | 984 | struct st_request *SRpnt = NULL; |
| 974 | 985 | struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; |
| @@ -1025,6 +1036,13 @@ static int test_ready(struct scsi_tape *STp, int do_wait) · 50 unmodified lines | ||
| 1025 | 1036 | } |
| 1026 | 1037 | } |
| 1027 | 1038 | |
| 1039 | + ctr = scsi_get_ua_new_media_ctr(STp->device); | |
| 1040 | + if (ctr != STp->new_media_ctr) { | |
| 1041 | + STp->new_media_ctr = ctr; | |
| 1042 | + new_session = 1; | |
| 1043 | + DEBC_printk(STp, "New tape session."); | |
| 1044 | + } | |
| 1045 | + | |
| 1028 | 1046 | retval = (STp->buffer)->syscall_result; |
| 1029 | 1047 | if (!retval) |
| 1030 | 1048 | retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY; |
| @@ -2897,7 +2915,6 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon · 1866 unmodified lines | ||
| 2897 | 2915 | timeout = STp->long_timeout * 8; |
| 2898 | 2916 | |
| 2899 | 2917 | DEBC_printk(STp, "Erasing tape.\n"); |
| 2900 | − fileno = blkno = at_sm = 0; | |
| 2901 | 2918 | break; |
| 2902 | 2919 | case MTSETBLK: /* Set block length */ |
| 2903 | 2920 | case MTSETDENSITY: /* Set tape density */ |
| @@ -2930,14 +2947,17 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon · 26 unmodified lines | ||
| 2930 | 2947 | if (cmd_in == MTSETDENSITY) { |
| 2931 | 2948 | (STp->buffer)->b_data[4] = arg; |
| 2932 | 2949 | STp->density_changed = 1; /* At least we tried ;-) */ |
| 2950 | + STp->changed_density = arg; | |
| 2933 | 2951 | } else if (cmd_in == SET_DENS_AND_BLK) |
| 2934 | 2952 | (STp->buffer)->b_data[4] = arg >> 24; |
| 2935 | 2953 | else |
| 2936 | 2954 | (STp->buffer)->b_data[4] = STp->density; |
| 2937 | 2955 | if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { |
| 2938 | 2956 | ltmp = arg & MT_ST_BLKSIZE_MASK; |
| 2939 | − if (cmd_in == MTSETBLK) | |
| 2957 | + if (cmd_in == MTSETBLK) { | |
| 2940 | 2958 | STp->blksize_changed = 1; /* At least we tried ;-) */ |
| 2959 | + STp->changed_blksize = arg; | |
| 2960 | + } | |
| 2941 | 2961 | } else |
| 2942 | 2962 | ltmp = STp->block_size; |
| 2943 | 2963 | (STp->buffer)->b_data[9] = (ltmp >> 16); |
| @@ -3084,7 +3104,9 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon · 140 unmodified lines | ||
| 3084 | 3104 | cmd_in == MTSETDRVBUFFER || |
| 3085 | 3105 | cmd_in == SET_DENS_AND_BLK) { |
| 3086 | 3106 | if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST && |
| 3087 | − !(STp->use_pf & PF_TESTED)) { | |
| 3107 | + cmdstatp->sense_hdr.asc == 0x24 && | |
| 3108 | + (STp->device)->scsi_level <= SCSI_2 && | |
| 3109 | + !(STp->use_pf & PF_TESTED)) { | |
| 3088 | 3110 | /* Try the other possible state of Page Format if not |
| 3089 | 3111 | already tried */ |
| 3090 | 3112 | STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED; |
| @@ -3636,9 +3658,23 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) · 545 unmodified lines | ||
| 3636 | 3658 | retval = (-EIO); |
| 3637 | 3659 | goto out; |
| 3638 | 3660 | } |
| 3639 | − reset_state(STp); | |
| 3640 | − /* remove this when the midlevel properly clears was_reset */ | |
| 3641 | − STp->device->was_reset = 0; | |
| 3661 | + reset_state(STp); /* Clears pos_unknown */ | |
| 3662 | + | |
| 3663 | + /* Fix the device settings after reset, ignore errors */ | |
| 3664 | + if (mtc.mt_op == MTREW || mtc.mt_op == MTSEEK || | |
| 3665 | + mtc.mt_op == MTEOM) { | |
| 3666 | + if (STp->can_partitions) { | |
| 3667 | + /* STp->new_partition contains the | |
| 3668 | + * latest partition set | |
| 3669 | + */ | |
| 3670 | + STp->partition = 0; | |
| 3671 | + switch_partition(STp); | |
| 3672 | + } | |
| 3673 | + if (STp->density_changed) | |
| 3674 | + st_int_ioctl(STp, MTSETDENSITY, STp->changed_density); | |
| 3675 | + if (STp->blksize_changed) | |
| 3676 | + st_int_ioctl(STp, MTSETBLK, STp->changed_blksize); | |
| 3677 | + } | |
| 3642 | 3678 | } |
| 3643 | 3679 | |
| 3644 | 3680 | if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && |
| @@ -4122,7 +4158,7 @@ static void validate_options(void) · 477 unmodified lines | ||
| 4122 | 4158 | */ |
| 4123 | 4159 | static int __init st_setup(char *str) |
| 4124 | 4160 | { |
| 4125 | − int i, len, ints[5]; | |
| 4161 | + int i, len, ints[ARRAY_SIZE(parms) + 1]; | |
| 4126 | 4162 | char *stp; |
| 4127 | 4163 | |
| 4128 | 4164 | stp = get_options(str, ARRAY_SIZE(ints), ints); |
| @@ -4384,6 +4420,9 @@ static int st_probe(struct device *dev) · 255 unmodified lines | ||
| 4384 | 4420 | goto out_idr_remove; |
| 4385 | 4421 | } |
| 4386 | 4422 | |
| 4423 | + tpnt->new_media_ctr = scsi_get_ua_new_media_ctr(SDp); | |
| 4424 | + tpnt->por_ctr = scsi_get_ua_por_ctr(SDp); | |
| 4425 | + | |
| 4387 | 4426 | dev_set_drvdata(dev, tpnt); |
| 4388 | 4427 | |
| 4389 | 4428 | |
| @@ -4665,6 +4704,24 @@ options_show(struct device *dev, struct device_attribute *attr, char *buf) · 275 unmodified lines | ||
| 4665 | 4704 | } |
| 4666 | 4705 | static DEVICE_ATTR_RO(options); |
| 4667 | 4706 | |
| 4707 | +/** | |
| 4708 | + * position_lost_in_reset_show - Value 1 indicates that reads, writes, etc. | |
| 4709 | + * are blocked because a device reset has occurred and no operation positioning | |
| 4710 | + * the tape has been issued. | |
| 4711 | + * @dev: struct device | |
| 4712 | + * @attr: attribute structure | |
| 4713 | + * @buf: buffer to return formatted data in | |
| 4714 | + */ | |
| 4715 | +static ssize_t position_lost_in_reset_show(struct device *dev, | |
| 4716 | + struct device_attribute *attr, char *buf) | |
| 4717 | +{ | |
| 4718 | + struct st_modedef *STm = dev_get_drvdata(dev); | |
| 4719 | + struct scsi_tape *STp = STm->tape; | |
| 4720 | + | |
| 4721 | + return sprintf(buf, "%d", STp->pos_unknown); | |
| 4722 | +} | |
| 4723 | +static DEVICE_ATTR_RO(position_lost_in_reset); | |
| 4724 | + | |
| 4668 | 4725 | /* Support for tape stats */ |
| 4669 | 4726 | |
| 4670 | 4727 | /** |
| @@ -4849,6 +4906,7 @@ static struct attribute *st_dev_attrs[] = { · 178 unmodified lines | ||
| 4849 | 4906 | &dev_attr_default_density.attr, |
| 4850 | 4907 | &dev_attr_default_compression.attr, |
| 4851 | 4908 | &dev_attr_options.attr, |
| 4909 | + &dev_attr_position_lost_in_reset.attr, | |
| 4852 | 4910 | NULL, |
| 4853 | 4911 | }; |
| 4854 | 4912 | |
| @@ -165,6 +165,7 @@ struct scsi_tape { · 164 unmodified lines | ||
| 165 | 165 | unsigned char compression_changed; |
| 166 | 166 | unsigned char drv_buffer; |
| 167 | 167 | unsigned char density; |
| 168 | + unsigned char changed_density; | |
| 168 | 169 | unsigned char door_locked; |
| 169 | 170 | unsigned char autorew_dev; /* auto-rewind device */ |
| 170 | 171 | unsigned char rew_at_close; /* rewind necessary at close */ |
| @@ -172,11 +173,16 @@ struct scsi_tape { · 1 unmodified line | ||
| 172 | 173 | unsigned char cleaning_req; /* cleaning requested? */ |
| 173 | 174 | unsigned char first_tur; /* first TEST UNIT READY */ |
| 174 | 175 | int block_size; |
| 176 | + int changed_blksize; | |
| 175 | 177 | int min_block; |
| 176 | 178 | int max_block; |
| 177 | 179 | int recover_count; /* From tape opening */ |
| 178 | 180 | int recover_reg; /* From last status call */ |
| 179 | 181 | |
| 182 | + /* The saved values of midlevel counters */ | |
| 183 | + unsigned int new_media_ctr; | |
| 184 | + unsigned int por_ctr; | |
| 185 | + | |
| 180 | 186 | #if DEBUG |
| 181 | 187 | unsigned char write_pending; |
| 182 | 188 | int nbr_finished; |
| @@ -776,7 +776,7 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns) · 775 unmodified lines | ||
| 776 | 776 | |
| 777 | 777 | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || |
| 778 | 778 | vstor_packet->status != 0) { |
| 779 | − dev_err(dev, "Failed to create sub-channel: op=%d, sts=%d\n", | |
| 779 | + dev_err(dev, "Failed to create sub-channel: op=%d, host=0x%x\n", | |
| 780 | 780 | vstor_packet->operation, vstor_packet->status); |
| 781 | 781 | return; |
| 782 | 782 | } |
| @@ -1183,7 +1183,7 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, · 400 unmodified lines | ||
| 1183 | 1183 | STORVSC_LOGGING_WARN : STORVSC_LOGGING_ERROR; |
| 1184 | 1184 | |
| 1185 | 1185 | storvsc_log_ratelimited(device, loglevel, |
| 1186 | − "tag#%d cmd 0x%x status: scsi 0x%x srb 0x%x hv 0x%x\n", | |
| 1186 | + "tag#%d cmd 0x%x status: scsi 0x%x srb 0x%x host 0x%x\n", | |
| 1187 | 1187 | scsi_cmd_to_rq(request->cmd)->tag, |
| 1188 | 1188 | stor_pkt->vm_srb.cdb[0], |
| 1189 | 1189 | vstor_packet->vm_srb.scsi_status, |
| @@ -212,7 +212,7 @@ int iscsi_target_check_login_request( · 211 unmodified lines | ||
| 212 | 212 | |
| 213 | 213 | if ((login_req->max_version != login->version_max) || |
| 214 | 214 | (login_req->min_version != login->version_min)) { |
| 215 | − pr_err("Login request changed Version Max/Nin" | |
| 215 | + pr_err("Login request changed Version Max/Min" | |
| 216 | 216 | " unexpectedly to 0x%02x/0x%02x, protocol error\n", |
| 217 | 217 | login_req->max_version, login_req->min_version); |
| 218 | 218 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, |
| @@ -557,7 +557,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work) · 338 unmodified lines | ||
| 557 | 557 | * before initial PDU processing in iscsi_target_start_negotiation() |
| 558 | 558 | * has completed, go ahead and retry until it's cleared. |
| 559 | 559 | * |
| 560 | − * Otherwise if the TCP connection drops while this is occuring, | |
| 560 | + * Otherwise if the TCP connection drops while this is occurring, | |
| 561 | 561 | * iscsi_target_start_negotiation() will detect the failure, call |
| 562 | 562 | * cancel_delayed_work_sync(&conn->login_work), and cleanup the |
| 563 | 563 | * remaining iscsi connection resources from iscsi_np process context. |
| @@ -1050,7 +1050,7 @@ static int iscsi_target_do_login(struct iscsit_conn *conn, struct iscsi_login *l · 486 unmodified lines | ||
| 1050 | 1050 | /* |
| 1051 | 1051 | * Check to make sure the TCP connection has not |
| 1052 | 1052 | * dropped asynchronously while session reinstatement |
| 1053 | − * was occuring in this kthread context, before | |
| 1053 | + * was occurring in this kthread context, before | |
| 1054 | 1054 | * transitioning to full feature phase operation. |
| 1055 | 1055 | */ |
| 1056 | 1056 | if (iscsi_target_sk_check_close(conn)) |
| @@ -176,7 +176,7 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) · 175 unmodified lines | ||
| 176 | 176 | |
| 177 | 177 | memset(tl_cmd, 0, sizeof(*tl_cmd)); |
| 178 | 178 | tl_cmd->sc = sc; |
| 179 | − tl_cmd->sc_cmd_tag = scsi_cmd_to_rq(sc)->tag; | |
| 179 | + tl_cmd->sc_cmd_tag = blk_mq_unique_tag(scsi_cmd_to_rq(sc)); | |
| 180 | 180 | |
| 181 | 181 | tcm_loop_target_queue_cmd(tl_cmd); |
| 182 | 182 | return 0; |
| @@ -242,7 +242,8 @@ static int tcm_loop_abort_task(struct scsi_cmnd *sc) · 59 unmodified lines | ||
| 242 | 242 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); |
| 243 | 243 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; |
| 244 | 244 | ret = tcm_loop_issue_tmr(tl_tpg, sc->device->lun, |
| 245 | − scsi_cmd_to_rq(sc)->tag, TMR_ABORT_TASK); | |
| 245 | + blk_mq_unique_tag(scsi_cmd_to_rq(sc)), | |
| 246 | + TMR_ABORT_TASK); | |
| 246 | 247 | return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; |
| 247 | 248 | } |
| 248 | 249 | |
| @@ -123,7 +123,7 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item, · 122 unmodified lines | ||
| 123 | 123 | goto unlock; |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | − read_bytes = snprintf(db_root_stage, DB_ROOT_LEN, "%s", page); | |
| 126 | + read_bytes = scnprintf(db_root_stage, DB_ROOT_LEN, "%s", page); | |
| 127 | 127 | if (!read_bytes) |
| 128 | 128 | goto unlock; |
| 129 | 129 | |
| @@ -143,7 +143,7 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item, · 13 unmodified lines | ||
| 143 | 143 | } |
| 144 | 144 | filp_close(fp, NULL); |
| 145 | 145 | |
| 146 | − strncpy(db_root, db_root_stage, read_bytes); | |
| 146 | + strscpy(db_root, db_root_stage); | |
| 147 | 147 | pr_debug("Target_Core_ConfigFS: db_root set to %s\n", db_root); |
| 148 | 148 | |
| 149 | 149 | r = read_bytes; |
| @@ -3664,7 +3664,7 @@ static void target_init_dbroot(void) · 3514 unmodified lines | ||
| 3664 | 3664 | } |
| 3665 | 3665 | filp_close(fp, NULL); |
| 3666 | 3666 | |
| 3667 | − strncpy(db_root, db_root_stage, DB_ROOT_LEN); | |
| 3667 | + strscpy(db_root, db_root_stage); | |
| 3668 | 3668 | pr_debug("Target_Core_ConfigFS: db_root set to %s\n", db_root); |
| 3669 | 3669 | } |
| 3670 | 3670 | |
| @@ -1078,8 +1078,8 @@ passthrough_parse_cdb(struct se_cmd *cmd, · 1077 unmodified lines | ||
| 1078 | 1078 | if (!dev->dev_attrib.emulate_pr && |
| 1079 | 1079 | ((cdb[0] == PERSISTENT_RESERVE_IN) || |
| 1080 | 1080 | (cdb[0] == PERSISTENT_RESERVE_OUT) || |
| 1081 | − (cdb[0] == RELEASE || cdb[0] == RELEASE_10) || | |
| 1082 | − (cdb[0] == RESERVE || cdb[0] == RESERVE_10))) { | |
| 1081 | + (cdb[0] == RELEASE_6 || cdb[0] == RELEASE_10) || | |
| 1082 | + (cdb[0] == RESERVE_6 || cdb[0] == RESERVE_10))) { | |
| 1083 | 1083 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
| 1084 | 1084 | } |
| 1085 | 1085 | |
| @@ -1101,7 +1101,7 @@ passthrough_parse_cdb(struct se_cmd *cmd, · 15 unmodified lines | ||
| 1101 | 1101 | return target_cmd_size_check(cmd, size); |
| 1102 | 1102 | } |
| 1103 | 1103 | |
| 1104 | − if (cdb[0] == RELEASE || cdb[0] == RELEASE_10) { | |
| 1104 | + if (cdb[0] == RELEASE_6 || cdb[0] == RELEASE_10) { | |
| 1105 | 1105 | cmd->execute_cmd = target_scsi2_reservation_release; |
| 1106 | 1106 | if (cdb[0] == RELEASE_10) |
| 1107 | 1107 | size = get_unaligned_be16(&cdb[7]); |
| @@ -1109,7 +1109,7 @@ passthrough_parse_cdb(struct se_cmd *cmd, · 1 unmodified line | ||
| 1109 | 1109 | size = cmd->data_length; |
| 1110 | 1110 | return target_cmd_size_check(cmd, size); |
| 1111 | 1111 | } |
| 1112 | − if (cdb[0] == RESERVE || cdb[0] == RESERVE_10) { | |
| 1112 | + if (cdb[0] == RESERVE_6 || cdb[0] == RESERVE_10) { | |
| 1113 | 1113 | cmd->execute_cmd = target_scsi2_reservation_reserve; |
| 1114 | 1114 | if (cdb[0] == RESERVE_10) |
| 1115 | 1115 | size = get_unaligned_be16(&cdb[7]); |
| @@ -91,7 +91,7 @@ target_scsi2_reservation_check(struct se_cmd *cmd) · 90 unmodified lines | ||
| 91 | 91 | |
| 92 | 92 | switch (cmd->t_task_cdb[0]) { |
| 93 | 93 | case INQUIRY: |
| 94 | − case RELEASE: | |
| 94 | + case RELEASE_6: | |
| 95 | 95 | case RELEASE_10: |
| 96 | 96 | return 0; |
| 97 | 97 | default: |
| @@ -418,12 +418,12 @@ static int core_scsi3_pr_seq_non_holder(struct se_cmd *cmd, u32 pr_reg_type, · 320 unmodified lines | ||
| 418 | 418 | return -EINVAL; |
| 419 | 419 | } |
| 420 | 420 | break; |
| 421 | − case RELEASE: | |
| 421 | + case RELEASE_6: | |
| 422 | 422 | case RELEASE_10: |
| 423 | 423 | /* Handled by CRH=1 in target_scsi2_reservation_release() */ |
| 424 | 424 | ret = 0; |
| 425 | 425 | break; |
| 426 | − case RESERVE: | |
| 426 | + case RESERVE_6: | |
| 427 | 427 | case RESERVE_10: |
| 428 | 428 | /* Handled by CRH=1 in target_scsi2_reservation_reserve() */ |
| 429 | 429 | ret = 0; |
| @@ -1674,9 +1674,9 @@ static bool tcm_is_pr_enabled(struct target_opcode_descriptor *descr, · 1673 unmodified lines | ||
| 1674 | 1674 | return true; |
| 1675 | 1675 | |
| 1676 | 1676 | switch (descr->opcode) { |
| 1677 | − case RESERVE: | |
| 1677 | + case RESERVE_6: | |
| 1678 | 1678 | case RESERVE_10: |
| 1679 | − case RELEASE: | |
| 1679 | + case RELEASE_6: | |
| 1680 | 1680 | case RELEASE_10: |
| 1681 | 1681 | /* |
| 1682 | 1682 | * The pr_ops which are used by the backend modules don't |
| @@ -1828,9 +1828,9 @@ static struct target_opcode_descriptor tcm_opcode_pro_register_move = { · 145 unmodified lines | ||
| 1828 | 1828 | |
| 1829 | 1829 | static struct target_opcode_descriptor tcm_opcode_release = { |
| 1830 | 1830 | .support = SCSI_SUPPORT_FULL, |
| 1831 | − .opcode = RELEASE, | |
| 1831 | + .opcode = RELEASE_6, | |
| 1832 | 1832 | .cdb_size = 6, |
| 1833 | − .usage_bits = {RELEASE, 0x00, 0x00, 0x00, | |
| 1833 | + .usage_bits = {RELEASE_6, 0x00, 0x00, 0x00, | |
| 1834 | 1834 | 0x00, SCSI_CONTROL_MASK}, |
| 1835 | 1835 | .enabled = tcm_is_pr_enabled, |
| 1836 | 1836 | }; |
| @@ -1847,9 +1847,9 @@ static struct target_opcode_descriptor tcm_opcode_release10 = { · 10 unmodified lines | ||
| 1847 | 1847 | |
| 1848 | 1848 | static struct target_opcode_descriptor tcm_opcode_reserve = { |
| 1849 | 1849 | .support = SCSI_SUPPORT_FULL, |
| 1850 | − .opcode = RESERVE, | |
| 1850 | + .opcode = RESERVE_6, | |
| 1851 | 1851 | .cdb_size = 6, |
| 1852 | − .usage_bits = {RESERVE, 0x00, 0x00, 0x00, | |
| 1852 | + .usage_bits = {RESERVE_6, 0x00, 0x00, 0x00, | |
| 1853 | 1853 | 0x00, SCSI_CONTROL_MASK}, |
| 1854 | 1854 | .enabled = tcm_is_pr_enabled, |
| 1855 | 1855 | }; |
| @@ -2151,8 +2151,10 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) · 295 unmodified lines | ||
| 2151 | 2151 | if (descr->serv_action_valid) |
| 2152 | 2152 | return TCM_INVALID_CDB_FIELD; |
| 2153 | 2153 | |
| 2154 | − if (!descr->enabled || descr->enabled(descr, cmd)) | |
| 2154 | + if (!descr->enabled || descr->enabled(descr, cmd)) { | |
| 2155 | 2155 | *opcode = descr; |
| 2156 | + return TCM_NO_SENSE; | |
| 2157 | + } | |
| 2156 | 2158 | break; |
| 2157 | 2159 | case 0x2: |
| 2158 | 2160 | /* |
| @@ -2166,8 +2168,10 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) · 7 unmodified lines | ||
| 2166 | 2168 | if (descr->serv_action_valid && |
| 2167 | 2169 | descr->service_action == requested_sa) { |
| 2168 | 2170 | if (!descr->enabled || descr->enabled(descr, |
| 2169 | − cmd)) | |
| 2171 | + cmd)) { | |
| 2170 | 2172 | *opcode = descr; |
| 2173 | + return TCM_NO_SENSE; | |
| 2174 | + } | |
| 2171 | 2175 | } else if (!descr->serv_action_valid) |
| 2172 | 2176 | return TCM_INVALID_CDB_FIELD; |
| 2173 | 2177 | break; |
| @@ -2180,13 +2184,15 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode) · 6 unmodified lines | ||
| 2180 | 2184 | */ |
| 2181 | 2185 | if (descr->service_action == requested_sa) |
| 2182 | 2186 | if (!descr->enabled || descr->enabled(descr, |
| 2183 | − cmd)) | |
| 2187 | + cmd)) { | |
| 2184 | 2188 | *opcode = descr; |
| 2189 | + return TCM_NO_SENSE; | |
| 2190 | + } | |
| 2185 | 2191 | break; |
| 2186 | 2192 | } |
| 2187 | 2193 | } |
| 2188 | 2194 | |
| 2189 | − return 0; | |
| 2195 | + return TCM_NO_SENSE; | |
| 2190 | 2196 | } |
| 2191 | 2197 | |
| 2192 | 2198 | static sense_reason_t |
| @@ -2243,7 +2249,7 @@ spc_emulate_report_supp_op_codes(struct se_cmd *cmd) · 50 unmodified lines | ||
| 2243 | 2249 | response_length += spc_rsoc_encode_command_descriptor( |
| 2244 | 2250 | &buf[response_length], rctd, descr); |
| 2245 | 2251 | } |
| 2246 | − put_unaligned_be32(response_length - 3, buf); | |
| 2252 | + put_unaligned_be32(response_length - 4, buf); | |
| 2247 | 2253 | } else { |
| 2248 | 2254 | response_length = spc_rsoc_encode_one_command_descriptor( |
| 2249 | 2255 | &buf[response_length], rctd, descr, |
| @@ -2267,9 +2273,9 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) · 17 unmodified lines | ||
| 2267 | 2273 | unsigned char *cdb = cmd->t_task_cdb; |
| 2268 | 2274 | |
| 2269 | 2275 | switch (cdb[0]) { |
| 2270 | − case RESERVE: | |
| 2276 | + case RESERVE_6: | |
| 2271 | 2277 | case RESERVE_10: |
| 2272 | − case RELEASE: | |
| 2278 | + case RELEASE_6: | |
| 2273 | 2279 | case RELEASE_10: |
| 2274 | 2280 | if (!dev->dev_attrib.emulate_pr) |
| 2275 | 2281 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
| @@ -2313,7 +2319,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) · 37 unmodified lines | ||
| 2313 | 2319 | *size = get_unaligned_be32(&cdb[5]); |
| 2314 | 2320 | cmd->execute_cmd = target_scsi3_emulate_pr_out; |
| 2315 | 2321 | break; |
| 2316 | − case RELEASE: | |
| 2322 | + case RELEASE_6: | |
| 2317 | 2323 | case RELEASE_10: |
| 2318 | 2324 | if (cdb[0] == RELEASE_10) |
| 2319 | 2325 | *size = get_unaligned_be16(&cdb[7]); |
| @@ -2322,7 +2328,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) · 2 unmodified lines | ||
| 2322 | 2328 | |
| 2323 | 2329 | cmd->execute_cmd = target_scsi2_reservation_release; |
| 2324 | 2330 | break; |
| 2325 | − case RESERVE: | |
| 2331 | + case RESERVE_6: | |
| 2326 | 2332 | case RESERVE_10: |
| 2327 | 2333 | /* |
| 2328 | 2334 | * The SPC-2 RESERVE does not contain a size in the SCSI CDB. |
| @@ -458,6 +458,14 @@ static ssize_t pm_qos_enable_store(struct device *dev, · 457 unmodified lines | ||
| 458 | 458 | return count; |
| 459 | 459 | } |
| 460 | 460 | |
| 461 | +static ssize_t critical_health_show(struct device *dev, | |
| 462 | + struct device_attribute *attr, char *buf) | |
| 463 | +{ | |
| 464 | + struct ufs_hba *hba = dev_get_drvdata(dev); | |
| 465 | + | |
| 466 | + return sysfs_emit(buf, "%d\n", hba->critical_health_count); | |
| 467 | +} | |
| 468 | + | |
| 461 | 469 | static DEVICE_ATTR_RW(rpm_lvl); |
| 462 | 470 | static DEVICE_ATTR_RO(rpm_target_dev_state); |
| 463 | 471 | static DEVICE_ATTR_RO(rpm_target_link_state); |
| @@ -470,6 +478,7 @@ static DEVICE_ATTR_RW(enable_wb_buf_flush); · 6 unmodified lines | ||
| 470 | 478 | static DEVICE_ATTR_RW(wb_flush_threshold); |
| 471 | 479 | static DEVICE_ATTR_RW(rtc_update_ms); |
| 472 | 480 | static DEVICE_ATTR_RW(pm_qos_enable); |
| 481 | +static DEVICE_ATTR_RO(critical_health); | |
| 473 | 482 | |
| 474 | 483 | static struct attribute *ufs_sysfs_ufshcd_attrs[] = { |
| 475 | 484 | &dev_attr_rpm_lvl.attr, |
| @@ -484,6 +493,7 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = { · 8 unmodified lines | ||
| 484 | 493 | &dev_attr_wb_flush_threshold.attr, |
| 485 | 494 | &dev_attr_rtc_update_ms.attr, |
| 486 | 495 | &dev_attr_pm_qos_enable.attr, |
| 496 | + &dev_attr_critical_health.attr, | |
| 487 | 497 | NULL |
| 488 | 498 | }; |
| 489 | 499 | |
| @@ -83,34 +83,34 @@ UFS_CMD_TRACE_TSF_TYPES · 82 unmodified lines | ||
| 83 | 83 | |
| 84 | 84 | TRACE_EVENT(ufshcd_clk_gating, |
| 85 | 85 | |
| 86 | − TP_PROTO(const char *dev_name, int state), | |
| 86 | + TP_PROTO(struct ufs_hba *hba, int state), | |
| 87 | 87 | |
| 88 | − TP_ARGS(dev_name, state), | |
| 88 | + TP_ARGS(hba, state), | |
| 89 | 89 | |
| 90 | 90 | TP_STRUCT__entry( |
| 91 | − __string(dev_name, dev_name) | |
| 91 | + __field(struct ufs_hba *, hba) | |
| 92 | 92 | __field(int, state) |
| 93 | 93 | ), |
| 94 | 94 | |
| 95 | 95 | TP_fast_assign( |
| 96 | − __assign_str(dev_name); | |
| 96 | + __entry->hba = hba; | |
| 97 | 97 | __entry->state = state; |
| 98 | 98 | ), |
| 99 | 99 | |
| 100 | 100 | TP_printk("%s: gating state changed to %s", |
| 101 | − __get_str(dev_name), | |
| 101 | + dev_name(__entry->hba->dev), | |
| 102 | 102 | __print_symbolic(__entry->state, UFSCHD_CLK_GATING_STATES)) |
| 103 | 103 | ); |
| 104 | 104 | |
| 105 | 105 | TRACE_EVENT(ufshcd_clk_scaling, |
| 106 | 106 | |
| 107 | − TP_PROTO(const char *dev_name, const char *state, const char *clk, | |
| 107 | + TP_PROTO(struct ufs_hba *hba, const char *state, const char *clk, | |
| 108 | 108 | u32 prev_state, u32 curr_state), |
| 109 | 109 | |
| 110 | − TP_ARGS(dev_name, state, clk, prev_state, curr_state), | |
| 110 | + TP_ARGS(hba, state, clk, prev_state, curr_state), | |
| 111 | 111 | |
| 112 | 112 | TP_STRUCT__entry( |
| 113 | − __string(dev_name, dev_name) | |
| 113 | + __field(struct ufs_hba *, hba) | |
| 114 | 114 | __string(state, state) |
| 115 | 115 | __string(clk, clk) |
| 116 | 116 | __field(u32, prev_state) |
| @@ -118,7 +118,7 @@ TRACE_EVENT(ufshcd_clk_scaling, · 1 unmodified line | ||
| 118 | 118 | ), |
| 119 | 119 | |
| 120 | 120 | TP_fast_assign( |
| 121 | − __assign_str(dev_name); | |
| 121 | + __entry->hba = hba; | |
| 122 | 122 | __assign_str(state); |
| 123 | 123 | __assign_str(clk); |
| 124 | 124 | __entry->prev_state = prev_state; |
| @@ -126,80 +126,80 @@ TRACE_EVENT(ufshcd_clk_scaling, · 1 unmodified line | ||
| 126 | 126 | ), |
| 127 | 127 | |
| 128 | 128 | TP_printk("%s: %s %s from %u to %u Hz", |
| 129 | − __get_str(dev_name), __get_str(state), __get_str(clk), | |
| 129 | + dev_name(__entry->hba->dev), __get_str(state), __get_str(clk), | |
| 130 | 130 | __entry->prev_state, __entry->curr_state) |
| 131 | 131 | ); |
| 132 | 132 | |
| 133 | 133 | TRACE_EVENT(ufshcd_auto_bkops_state, |
| 134 | 134 | |
| 135 | − TP_PROTO(const char *dev_name, const char *state), | |
| 135 | + TP_PROTO(struct ufs_hba *hba, const char *state), | |
| 136 | 136 | |
| 137 | − TP_ARGS(dev_name, state), | |
| 137 | + TP_ARGS(hba, state), | |
| 138 | 138 | |
| 139 | 139 | TP_STRUCT__entry( |
| 140 | − __string(dev_name, dev_name) | |
| 140 | + __field(struct ufs_hba *, hba) | |
| 141 | 141 | __string(state, state) |
| 142 | 142 | ), |
| 143 | 143 | |
| 144 | 144 | TP_fast_assign( |
| 145 | − __assign_str(dev_name); | |
| 145 | + __entry->hba = hba; | |
| 146 | 146 | __assign_str(state); |
| 147 | 147 | ), |
| 148 | 148 | |
| 149 | 149 | TP_printk("%s: auto bkops - %s", |
| 150 | − __get_str(dev_name), __get_str(state)) | |
| 150 | + dev_name(__entry->hba->dev), __get_str(state)) | |
| 151 | 151 | ); |
| 152 | 152 | |
| 153 | 153 | DECLARE_EVENT_CLASS(ufshcd_profiling_template, |
| 154 | − TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us, | |
| 154 | + TP_PROTO(struct ufs_hba *hba, const char *profile_info, s64 time_us, | |
| 155 | 155 | int err), |
| 156 | 156 | |
| 157 | − TP_ARGS(dev_name, profile_info, time_us, err), | |
| 157 | + TP_ARGS(hba, profile_info, time_us, err), | |
| 158 | 158 | |
| 159 | 159 | TP_STRUCT__entry( |
| 160 | − __string(dev_name, dev_name) | |
| 160 | + __field(struct ufs_hba *, hba) | |
| 161 | 161 | __string(profile_info, profile_info) |
| 162 | 162 | __field(s64, time_us) |
| 163 | 163 | __field(int, err) |
| 164 | 164 | ), |
| 165 | 165 | |
| 166 | 166 | TP_fast_assign( |
| 167 | − __assign_str(dev_name); | |
| 167 | + __entry->hba = hba; | |
| 168 | 168 | __assign_str(profile_info); |
| 169 | 169 | __entry->time_us = time_us; |
| 170 | 170 | __entry->err = err; |
| 171 | 171 | ), |
| 172 | 172 | |
| 173 | 173 | TP_printk("%s: %s: took %lld usecs, err %d", |
| 174 | − __get_str(dev_name), __get_str(profile_info), | |
| 174 | + dev_name(__entry->hba->dev), __get_str(profile_info), | |
| 175 | 175 | __entry->time_us, __entry->err) |
| 176 | 176 | ); |
| 177 | 177 | |
| 178 | 178 | DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_hibern8, |
| 179 | − TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us, | |
| 179 | + TP_PROTO(struct ufs_hba *hba, const char *profile_info, s64 time_us, | |
| 180 | 180 | int err), |
| 181 | − TP_ARGS(dev_name, profile_info, time_us, err)); | |
| 181 | + TP_ARGS(hba, profile_info, time_us, err)); | |
| 182 | 182 | |
| 183 | 183 | DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_clk_gating, |
| 184 | − TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us, | |
| 184 | + TP_PROTO(struct ufs_hba *hba, const char *profile_info, s64 time_us, | |
| 185 | 185 | int err), |
| 186 | − TP_ARGS(dev_name, profile_info, time_us, err)); | |
| 186 | + TP_ARGS(hba, profile_info, time_us, err)); | |
| 187 | 187 | |
| 188 | 188 | DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_clk_scaling, |
| 189 | − TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us, | |
| 189 | + TP_PROTO(struct ufs_hba *hba, const char *profile_info, s64 time_us, | |
| 190 | 190 | int err), |
| 191 | − TP_ARGS(dev_name, profile_info, time_us, err)); | |
| 191 | + TP_ARGS(hba, profile_info, time_us, err)); | |
| 192 | 192 | |
| 193 | 193 | DECLARE_EVENT_CLASS(ufshcd_template, |
| 194 | − TP_PROTO(const char *dev_name, int err, s64 usecs, | |
| 194 | + TP_PROTO(struct ufs_hba *hba, int err, s64 usecs, | |
| 195 | 195 | int dev_state, int link_state), |
| 196 | 196 | |
| 197 | − TP_ARGS(dev_name, err, usecs, dev_state, link_state), | |
| 197 | + TP_ARGS(hba, err, usecs, dev_state, link_state), | |
| 198 | 198 | |
| 199 | 199 | TP_STRUCT__entry( |
| 200 | 200 | __field(s64, usecs) |
| 201 | 201 | __field(int, err) |
| 202 | − __string(dev_name, dev_name) | |
| 202 | + __field(struct ufs_hba *, hba) | |
| 203 | 203 | __field(int, dev_state) |
| 204 | 204 | __field(int, link_state) |
| 205 | 205 | ), |
| @@ -207,14 +207,14 @@ DECLARE_EVENT_CLASS(ufshcd_template, · 1 unmodified line | ||
| 207 | 207 | TP_fast_assign( |
| 208 | 208 | __entry->usecs = usecs; |
| 209 | 209 | __entry->err = err; |
| 210 | − __assign_str(dev_name); | |
| 210 | + __entry->hba = hba; | |
| 211 | 211 | __entry->dev_state = dev_state; |
| 212 | 212 | __entry->link_state = link_state; |
| 213 | 213 | ), |
| 214 | 214 | |
| 215 | 215 | TP_printk( |
| 216 | 216 | "%s: took %lld usecs, dev_state: %s, link_state: %s, err %d", |
| 217 | − __get_str(dev_name), | |
| 217 | + dev_name(__entry->hba->dev), | |
| 218 | 218 | __entry->usecs, |
| 219 | 219 | __print_symbolic(__entry->dev_state, UFS_PWR_MODES), |
| 220 | 220 | __print_symbolic(__entry->link_state, UFS_LINK_STATES), |
| @@ -223,60 +223,62 @@ DECLARE_EVENT_CLASS(ufshcd_template, · 2 unmodified lines | ||
| 223 | 223 | ); |
| 224 | 224 | |
| 225 | 225 | DEFINE_EVENT(ufshcd_template, ufshcd_system_suspend, |
| 226 | − TP_PROTO(const char *dev_name, int err, s64 usecs, | |
| 226 | + TP_PROTO(struct ufs_hba *hba, int err, s64 usecs, | |
| 227 | 227 | int dev_state, int link_state), |
| 228 | − TP_ARGS(dev_name, err, usecs, dev_state, link_state)); | |
| 228 | + TP_ARGS(hba, err, usecs, dev_state, link_state)); | |
| 229 | 229 | |
| 230 | 230 | DEFINE_EVENT(ufshcd_template, ufshcd_system_resume, |
| 231 | − TP_PROTO(const char *dev_name, int err, s64 usecs, | |
| 231 | + TP_PROTO(struct ufs_hba *hba, int err, s64 usecs, | |
| 232 | 232 | int dev_state, int link_state), |
| 233 | − TP_ARGS(dev_name, err, usecs, dev_state, link_state)); | |
| 233 | + TP_ARGS(hba, err, usecs, dev_state, link_state)); | |
| 234 | 234 | |
| 235 | 235 | DEFINE_EVENT(ufshcd_template, ufshcd_runtime_suspend, |
| 236 | − TP_PROTO(const char *dev_name, int err, s64 usecs, | |
| 236 | + TP_PROTO(struct ufs_hba *hba, int err, s64 usecs, | |
| 237 | 237 | int dev_state, int link_state), |
| 238 | − TP_ARGS(dev_name, err, usecs, dev_state, link_state)); | |
| 238 | + TP_ARGS(hba, err, usecs, dev_state, link_state)); | |
| 239 | 239 | |
| 240 | 240 | DEFINE_EVENT(ufshcd_template, ufshcd_runtime_resume, |
| 241 | − TP_PROTO(const char *dev_name, int err, s64 usecs, | |
| 241 | + TP_PROTO(struct ufs_hba *hba, int err, s64 usecs, | |
| 242 | 242 | int dev_state, int link_state), |
| 243 | − TP_ARGS(dev_name, err, usecs, dev_state, link_state)); | |
| 243 | + TP_ARGS(hba, err, usecs, dev_state, link_state)); | |
| 244 | 244 | |
| 245 | 245 | DEFINE_EVENT(ufshcd_template, ufshcd_init, |
| 246 | − TP_PROTO(const char *dev_name, int err, s64 usecs, | |
| 246 | + TP_PROTO(struct ufs_hba *hba, int err, s64 usecs, | |
| 247 | 247 | int dev_state, int link_state), |
| 248 | − TP_ARGS(dev_name, err, usecs, dev_state, link_state)); | |
| 248 | + TP_ARGS(hba, err, usecs, dev_state, link_state)); | |
| 249 | 249 | |
| 250 | 250 | DEFINE_EVENT(ufshcd_template, ufshcd_wl_suspend, |
| 251 | − TP_PROTO(const char *dev_name, int err, s64 usecs, | |
| 251 | + TP_PROTO(struct ufs_hba *hba, int err, s64 usecs, | |
| 252 | 252 | int dev_state, int link_state), |
| 253 | − TP_ARGS(dev_name, err, usecs, dev_state, link_state)); | |
| 253 | + TP_ARGS(hba, err, usecs, dev_state, link_state)); | |
| 254 | 254 | |
| 255 | 255 | DEFINE_EVENT(ufshcd_template, ufshcd_wl_resume, |
| 256 | − TP_PROTO(const char *dev_name, int err, s64 usecs, | |
| 256 | + TP_PROTO(struct ufs_hba *hba, int err, s64 usecs, | |
| 257 | 257 | int dev_state, int link_state), |
| 258 | − TP_ARGS(dev_name, err, usecs, dev_state, link_state)); | |
| 258 | + TP_ARGS(hba, err, usecs, dev_state, link_state)); | |
| 259 | 259 | |
| 260 | 260 | DEFINE_EVENT(ufshcd_template, ufshcd_wl_runtime_suspend, |
| 261 | − TP_PROTO(const char *dev_name, int err, s64 usecs, | |
| 261 | + TP_PROTO(struct ufs_hba *hba, int err, s64 usecs, | |
| 262 | 262 | int dev_state, int link_state), |
| 263 | − TP_ARGS(dev_name, err, usecs, dev_state, link_state)); | |
| 263 | + TP_ARGS(hba, err, usecs, dev_state, link_state)); | |
| 264 | 264 | |
| 265 | 265 | DEFINE_EVENT(ufshcd_template, ufshcd_wl_runtime_resume, |
| 266 | − TP_PROTO(const char *dev_name, int err, s64 usecs, | |
| 266 | + TP_PROTO(struct ufs_hba *hba, int err, s64 usecs, | |
| 267 | 267 | int dev_state, int link_state), |
| 268 | − TP_ARGS(dev_name, err, usecs, dev_state, link_state)); | |
| 268 | + TP_ARGS(hba, err, usecs, dev_state, link_state)); | |
| 269 | 269 | |
| 270 | 270 | TRACE_EVENT(ufshcd_command, |
| 271 | − TP_PROTO(struct scsi_device *sdev, enum ufs_trace_str_t str_t, | |
| 271 | + TP_PROTO(struct scsi_device *sdev, struct ufs_hba *hba, | |
| 272 | + enum ufs_trace_str_t str_t, | |
| 272 | 273 | unsigned int tag, u32 doorbell, u32 hwq_id, int transfer_len, |
| 273 | 274 | u32 intr, u64 lba, u8 opcode, u8 group_id), |
| 274 | 275 | |
| 275 | − TP_ARGS(sdev, str_t, tag, doorbell, hwq_id, transfer_len, intr, lba, | |
| 276 | + TP_ARGS(sdev, hba, str_t, tag, doorbell, hwq_id, transfer_len, intr, lba, | |
| 276 | 277 | opcode, group_id), |
| 277 | 278 | |
| 278 | 279 | TP_STRUCT__entry( |
| 279 | 280 | __field(struct scsi_device *, sdev) |
| 281 | + __field(struct ufs_hba *, hba) | |
| 280 | 282 | __field(enum ufs_trace_str_t, str_t) |
| 281 | 283 | __field(unsigned int, tag) |
| 282 | 284 | __field(u32, doorbell) |
| @@ -290,6 +292,7 @@ TRACE_EVENT(ufshcd_command, · 7 unmodified lines | ||
| 290 | 292 | |
| 291 | 293 | TP_fast_assign( |
| 292 | 294 | __entry->sdev = sdev; |
| 295 | + __entry->hba = hba; | |
| 293 | 296 | __entry->str_t = str_t; |
| 294 | 297 | __entry->tag = tag; |
| 295 | 298 | __entry->doorbell = doorbell; |
| @@ -312,13 +315,13 @@ TRACE_EVENT(ufshcd_command, · 16 unmodified lines | ||
| 312 | 315 | ); |
| 313 | 316 | |
| 314 | 317 | TRACE_EVENT(ufshcd_uic_command, |
| 315 | − TP_PROTO(const char *dev_name, enum ufs_trace_str_t str_t, u32 cmd, | |
| 318 | + TP_PROTO(struct ufs_hba *hba, enum ufs_trace_str_t str_t, u32 cmd, | |
| 316 | 319 | u32 arg1, u32 arg2, u32 arg3), |
| 317 | 320 | |
| 318 | − TP_ARGS(dev_name, str_t, cmd, arg1, arg2, arg3), | |
| 321 | + TP_ARGS(hba, str_t, cmd, arg1, arg2, arg3), | |
| 319 | 322 | |
| 320 | 323 | TP_STRUCT__entry( |
| 321 | − __string(dev_name, dev_name) | |
| 324 | + __field(struct ufs_hba *, hba) | |
| 322 | 325 | __field(enum ufs_trace_str_t, str_t) |
| 323 | 326 | __field(u32, cmd) |
| 324 | 327 | __field(u32, arg1) |
| @@ -327,7 +330,7 @@ TRACE_EVENT(ufshcd_uic_command, · 2 unmodified lines | ||
| 327 | 330 | ), |
| 328 | 331 | |
| 329 | 332 | TP_fast_assign( |
| 330 | − __assign_str(dev_name); | |
| 333 | + __entry->hba = hba; | |
| 331 | 334 | __entry->str_t = str_t; |
| 332 | 335 | __entry->cmd = cmd; |
| 333 | 336 | __entry->arg1 = arg1; |
| @@ -337,19 +340,19 @@ TRACE_EVENT(ufshcd_uic_command, · 3 unmodified lines | ||
| 337 | 340 | |
| 338 | 341 | TP_printk( |
| 339 | 342 | "%s: %s: cmd: 0x%x, arg1: 0x%x, arg2: 0x%x, arg3: 0x%x", |
| 340 | − show_ufs_cmd_trace_str(__entry->str_t), __get_str(dev_name), | |
| 343 | + show_ufs_cmd_trace_str(__entry->str_t), dev_name(__entry->hba->dev), | |
| 341 | 344 | __entry->cmd, __entry->arg1, __entry->arg2, __entry->arg3 |
| 342 | 345 | ) |
| 343 | 346 | ); |
| 344 | 347 | |
| 345 | 348 | TRACE_EVENT(ufshcd_upiu, |
| 346 | − TP_PROTO(const char *dev_name, enum ufs_trace_str_t str_t, void *hdr, | |
| 349 | + TP_PROTO(struct ufs_hba *hba, enum ufs_trace_str_t str_t, void *hdr, | |
| 347 | 350 | void *tsf, enum ufs_trace_tsf_t tsf_t), |
| 348 | 351 | |
| 349 | − TP_ARGS(dev_name, str_t, hdr, tsf, tsf_t), | |
| 352 | + TP_ARGS(hba, str_t, hdr, tsf, tsf_t), | |
| 350 | 353 | |
| 351 | 354 | TP_STRUCT__entry( |
| 352 | − __string(dev_name, dev_name) | |
| 355 | + __field(struct ufs_hba *, hba) | |
| 353 | 356 | __field(enum ufs_trace_str_t, str_t) |
| 354 | 357 | __array(unsigned char, hdr, 12) |
| 355 | 358 | __array(unsigned char, tsf, 16) |
| @@ -357,7 +360,7 @@ TRACE_EVENT(ufshcd_upiu, · 1 unmodified line | ||
| 357 | 360 | ), |
| 358 | 361 | |
| 359 | 362 | TP_fast_assign( |
| 360 | − __assign_str(dev_name); | |
| 363 | + __entry->hba = hba; | |
| 361 | 364 | __entry->str_t = str_t; |
| 362 | 365 | memcpy(__entry->hdr, hdr, sizeof(__entry->hdr)); |
| 363 | 366 | memcpy(__entry->tsf, tsf, sizeof(__entry->tsf)); |
| @@ -366,7 +369,7 @@ TRACE_EVENT(ufshcd_upiu, · 2 unmodified lines | ||
| 366 | 369 | |
| 367 | 370 | TP_printk( |
| 368 | 371 | "%s: %s: HDR:%s, %s:%s", |
| 369 | − show_ufs_cmd_trace_str(__entry->str_t), __get_str(dev_name), | |
| 372 | + show_ufs_cmd_trace_str(__entry->str_t), dev_name(__entry->hba->dev), | |
| 370 | 373 | __print_hex(__entry->hdr, sizeof(__entry->hdr)), |
| 371 | 374 | show_ufs_cmd_trace_tsf(__entry->tsf_t), |
| 372 | 375 | __print_hex(__entry->tsf, sizeof(__entry->tsf)) |
| @@ -375,22 +378,22 @@ TRACE_EVENT(ufshcd_upiu, · 2 unmodified lines | ||
| 375 | 378 | |
| 376 | 379 | TRACE_EVENT(ufshcd_exception_event, |
| 377 | 380 | |
| 378 | − TP_PROTO(const char *dev_name, u16 status), | |
| 381 | + TP_PROTO(struct ufs_hba *hba, u16 status), | |
| 379 | 382 | |
| 380 | − TP_ARGS(dev_name, status), | |
| 383 | + TP_ARGS(hba, status), | |
| 381 | 384 | |
| 382 | 385 | TP_STRUCT__entry( |
| 383 | − __string(dev_name, dev_name) | |
| 386 | + __field(struct ufs_hba *, hba) | |
| 384 | 387 | __field(u16, status) |
| 385 | 388 | ), |
| 386 | 389 | |
| 387 | 390 | TP_fast_assign( |
| 388 | − __assign_str(dev_name); | |
| 391 | + __entry->hba = hba; | |
| 389 | 392 | __entry->status = status; |
| 390 | 393 | ), |
| 391 | 394 | |
| 392 | 395 | TP_printk("%s: status 0x%x", |
| 393 | − __get_str(dev_name), __entry->status | |
| 396 | + dev_name(__entry->hba->dev), __entry->status | |
| 394 | 397 | ) |
| 395 | 398 | ); |
| 396 | 399 | |
| @@ -117,11 +117,12 @@ static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba) · 116 unmodified lines | ||
| 117 | 117 | return ufshcd_readl(hba, REG_UFS_VERSION); |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | −static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba, | |
| 121 | − bool up, enum ufs_notify_change_status status) | |
| 120 | +static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba, bool up, | |
| 121 | + unsigned long target_freq, | |
| 122 | + enum ufs_notify_change_status status) | |
| 122 | 123 | { |
| 123 | 124 | if (hba->vops && hba->vops->clk_scale_notify) |
| 124 | − return hba->vops->clk_scale_notify(hba, up, status); | |
| 125 | + return hba->vops->clk_scale_notify(hba, up, target_freq, status); | |
| 125 | 126 | return 0; |
| 126 | 127 | } |
| 127 | 128 | |
| @@ -159,9 +160,9 @@ static inline int ufshcd_vops_link_startup_notify(struct ufs_hba *hba, · 31 unmodified lines | ||
| 159 | 160 | } |
| 160 | 161 | |
| 161 | 162 | static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba, |
| 162 | − enum ufs_notify_change_status status, | |
| 163 | − struct ufs_pa_layer_attr *dev_max_params, | |
| 164 | − struct ufs_pa_layer_attr *dev_req_params) | |
| 163 | + enum ufs_notify_change_status status, | |
| 164 | + const struct ufs_pa_layer_attr *dev_max_params, | |
| 165 | + struct ufs_pa_layer_attr *dev_req_params) | |
| 165 | 166 | { |
| 166 | 167 | if (hba->vops && hba->vops->pwr_change_notify) |
| 167 | 168 | return hba->vops->pwr_change_notify(hba, status, |
| @@ -270,6 +271,14 @@ static inline int ufshcd_mcq_vops_config_esi(struct ufs_hba *hba) · 102 unmodified lines | ||
| 270 | 271 | return -EOPNOTSUPP; |
| 271 | 272 | } |
| 272 | 273 | |
| 274 | +static inline u32 ufshcd_vops_freq_to_gear_speed(struct ufs_hba *hba, unsigned long freq) | |
| 275 | +{ | |
| 276 | + if (hba->vops && hba->vops->freq_to_gear_speed) | |
| 277 | + return hba->vops->freq_to_gear_speed(hba, freq); | |
| 278 | + | |
| 279 | + return 0; | |
| 280 | +} | |
| 281 | + | |
| 273 | 282 | extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[]; |
| 274 | 283 | |
| 275 | 284 | /** |
| @@ -369,7 +369,7 @@ static void ufshcd_add_cmd_upiu_trace(struct ufs_hba *hba, unsigned int tag, · 368 unmodified lines | ||
| 369 | 369 | else |
| 370 | 370 | header = &hba->lrb[tag].ucd_rsp_ptr->header; |
| 371 | 371 | |
| 372 | − trace_ufshcd_upiu(dev_name(hba->dev), str_t, header, &rq->sc.cdb, | |
| 372 | + trace_ufshcd_upiu(hba, str_t, header, &rq->sc.cdb, | |
| 373 | 373 | UFS_TSF_CDB); |
| 374 | 374 | } |
| 375 | 375 | |
| @@ -380,7 +380,7 @@ static void ufshcd_add_query_upiu_trace(struct ufs_hba *hba, · 4 unmodified lines | ||
| 380 | 380 | if (!trace_ufshcd_upiu_enabled()) |
| 381 | 381 | return; |
| 382 | 382 | |
| 383 | − trace_ufshcd_upiu(dev_name(hba->dev), str_t, &rq_rsp->header, | |
| 383 | + trace_ufshcd_upiu(hba, str_t, &rq_rsp->header, | |
| 384 | 384 | &rq_rsp->qr, UFS_TSF_OSF); |
| 385 | 385 | } |
| 386 | 386 | |
| @@ -393,12 +393,12 @@ static void ufshcd_add_tm_upiu_trace(struct ufs_hba *hba, unsigned int tag, · 6 unmodified lines | ||
| 393 | 393 | return; |
| 394 | 394 | |
| 395 | 395 | if (str_t == UFS_TM_SEND) |
| 396 | − trace_ufshcd_upiu(dev_name(hba->dev), str_t, | |
| 396 | + trace_ufshcd_upiu(hba, str_t, | |
| 397 | 397 | &descp->upiu_req.req_header, |
| 398 | 398 | &descp->upiu_req.input_param1, |
| 399 | 399 | UFS_TSF_TM_INPUT); |
| 400 | 400 | else |
| 401 | − trace_ufshcd_upiu(dev_name(hba->dev), str_t, | |
| 401 | + trace_ufshcd_upiu(hba, str_t, | |
| 402 | 402 | &descp->upiu_rsp.rsp_header, |
| 403 | 403 | &descp->upiu_rsp.output_param1, |
| 404 | 404 | UFS_TSF_TM_OUTPUT); |
| @@ -418,7 +418,7 @@ static void ufshcd_add_uic_command_trace(struct ufs_hba *hba, · 13 unmodified lines | ||
| 418 | 418 | else |
| 419 | 419 | cmd = ufshcd_readl(hba, REG_UIC_COMMAND); |
| 420 | 420 | |
| 421 | − trace_ufshcd_uic_command(dev_name(hba->dev), str_t, cmd, | |
| 421 | + trace_ufshcd_uic_command(hba, str_t, cmd, | |
| 422 | 422 | ufshcd_readl(hba, REG_UIC_COMMAND_ARG_1), |
| 423 | 423 | ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2), |
| 424 | 424 | ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3)); |
| @@ -473,7 +473,7 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, · 48 unmodified lines | ||
| 473 | 473 | } else { |
| 474 | 474 | doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); |
| 475 | 475 | } |
| 476 | − trace_ufshcd_command(cmd->device, str_t, tag, doorbell, hwq_id, | |
| 476 | + trace_ufshcd_command(cmd->device, hba, str_t, tag, doorbell, hwq_id, | |
| 477 | 477 | transfer_len, intr, lba, opcode, group_id); |
| 478 | 478 | } |
| 479 | 479 | |
| @@ -1063,7 +1063,7 @@ static int ufshcd_set_clk_freq(struct ufs_hba *hba, bool scale_up) · 583 unmodified lines | ||
| 1063 | 1063 | clki->max_freq, ret); |
| 1064 | 1064 | break; |
| 1065 | 1065 | } |
| 1066 | − trace_ufshcd_clk_scaling(dev_name(hba->dev), | |
| 1066 | + trace_ufshcd_clk_scaling(hba, | |
| 1067 | 1067 | "scaled up", clki->name, |
| 1068 | 1068 | clki->curr_freq, |
| 1069 | 1069 | clki->max_freq); |
| @@ -1081,7 +1081,7 @@ static int ufshcd_set_clk_freq(struct ufs_hba *hba, bool scale_up) · 11 unmodified lines | ||
| 1081 | 1081 | clki->min_freq, ret); |
| 1082 | 1082 | break; |
| 1083 | 1083 | } |
| 1084 | − trace_ufshcd_clk_scaling(dev_name(hba->dev), | |
| 1084 | + trace_ufshcd_clk_scaling(hba, | |
| 1085 | 1085 | "scaled down", clki->name, |
| 1086 | 1086 | clki->curr_freq, |
| 1087 | 1087 | clki->min_freq); |
| @@ -1122,7 +1122,7 @@ int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table, · 34 unmodified lines | ||
| 1122 | 1122 | return ret; |
| 1123 | 1123 | } |
| 1124 | 1124 | |
| 1125 | − trace_ufshcd_clk_scaling(dev_name(dev), | |
| 1125 | + trace_ufshcd_clk_scaling(hba, | |
| 1126 | 1126 | (scaling_down ? "scaled down" : "scaled up"), |
| 1127 | 1127 | clki->name, hba->clk_scaling.target_freq, freq); |
| 1128 | 1128 | } |
| @@ -1162,7 +1162,7 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq, · 33 unmodified lines | ||
| 1162 | 1162 | int ret = 0; |
| 1163 | 1163 | ktime_t start = ktime_get(); |
| 1164 | 1164 | |
| 1165 | − ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE); | |
| 1165 | + ret = ufshcd_vops_clk_scale_notify(hba, scale_up, freq, PRE_CHANGE); | |
| 1166 | 1166 | if (ret) |
| 1167 | 1167 | goto out; |
| 1168 | 1168 | |
| @@ -1173,7 +1173,7 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq, · 4 unmodified lines | ||
| 1173 | 1173 | if (ret) |
| 1174 | 1174 | goto out; |
| 1175 | 1175 | |
| 1176 | − ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE); | |
| 1176 | + ret = ufshcd_vops_clk_scale_notify(hba, scale_up, freq, POST_CHANGE); | |
| 1177 | 1177 | if (ret) { |
| 1178 | 1178 | if (hba->use_pm_opp) |
| 1179 | 1179 | ufshcd_opp_set_rate(hba, |
| @@ -1186,7 +1186,7 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq, · 6 unmodified lines | ||
| 1186 | 1186 | ufshcd_pm_qos_update(hba, scale_up); |
| 1187 | 1187 | |
| 1188 | 1188 | out: |
| 1189 | − trace_ufshcd_profile_clk_scaling(dev_name(hba->dev), | |
| 1189 | + trace_ufshcd_profile_clk_scaling(hba, | |
| 1190 | 1190 | (scale_up ? "up" : "down"), |
| 1191 | 1191 | ktime_to_us(ktime_sub(ktime_get(), start)), ret); |
| 1192 | 1192 | return ret; |
| @@ -1313,16 +1313,26 @@ out: · 120 unmodified lines | ||
| 1313 | 1313 | /** |
| 1314 | 1314 | * ufshcd_scale_gear - scale up/down UFS gear |
| 1315 | 1315 | * @hba: per adapter instance |
| 1316 | + * @target_gear: target gear to scale to | |
| 1316 | 1317 | * @scale_up: True for scaling up gear and false for scaling down |
| 1317 | 1318 | * |
| 1318 | 1319 | * Return: 0 for success; -EBUSY if scaling can't happen at this time; |
| 1319 | 1320 | * non-zero for any other errors. |
| 1320 | 1321 | */ |
| 1321 | −static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up) | |
| 1322 | +static int ufshcd_scale_gear(struct ufs_hba *hba, u32 target_gear, bool scale_up) | |
| 1322 | 1323 | { |
| 1323 | 1324 | int ret = 0; |
| 1324 | 1325 | struct ufs_pa_layer_attr new_pwr_info; |
| 1325 | 1326 | |
| 1327 | + if (target_gear) { | |
| 1328 | + new_pwr_info = hba->pwr_info; | |
| 1329 | + new_pwr_info.gear_tx = target_gear; | |
| 1330 | + new_pwr_info.gear_rx = target_gear; | |
| 1331 | + | |
| 1332 | + goto config_pwr_mode; | |
| 1333 | + } | |
| 1334 | + | |
| 1335 | + /* Legacy gear scaling, in case vops_freq_to_gear_speed() is not implemented */ | |
| 1326 | 1336 | if (scale_up) { |
| 1327 | 1337 | memcpy(&new_pwr_info, &hba->clk_scaling.saved_pwr_info, |
| 1328 | 1338 | sizeof(struct ufs_pa_layer_attr)); |
| @@ -1343,6 +1353,7 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up) · 14 unmodified lines | ||
| 1343 | 1353 | } |
| 1344 | 1354 | } |
| 1345 | 1355 | |
| 1356 | +config_pwr_mode: | |
| 1346 | 1357 | /* check if the power mode needs to be changed or not? */ |
| 1347 | 1358 | ret = ufshcd_config_pwr_mode(hba, &new_pwr_info); |
| 1348 | 1359 | if (ret) |
| @@ -1387,13 +1398,13 @@ out: · 38 unmodified lines | ||
| 1387 | 1398 | return ret; |
| 1388 | 1399 | } |
| 1389 | 1400 | |
| 1390 | −static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err, bool scale_up) | |
| 1401 | +static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err) | |
| 1391 | 1402 | { |
| 1392 | 1403 | up_write(&hba->clk_scaling_lock); |
| 1393 | 1404 | |
| 1394 | − /* Enable Write Booster if we have scaled up else disable it */ | |
| 1405 | + /* Enable Write Booster if current gear requires it else disable it */ | |
| 1395 | 1406 | if (ufshcd_enable_wb_if_scaling_up(hba) && !err) |
| 1396 | − ufshcd_wb_toggle(hba, scale_up); | |
| 1407 | + ufshcd_wb_toggle(hba, hba->pwr_info.gear_rx >= hba->clk_scaling.wb_gear); | |
| 1397 | 1408 | |
| 1398 | 1409 | mutex_unlock(&hba->wb_mutex); |
| 1399 | 1410 | |
| @@ -1413,15 +1424,19 @@ static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err, bool sc · 13 unmodified lines | ||
| 1413 | 1424 | static int ufshcd_devfreq_scale(struct ufs_hba *hba, unsigned long freq, |
| 1414 | 1425 | bool scale_up) |
| 1415 | 1426 | { |
| 1427 | + u32 old_gear = hba->pwr_info.gear_rx; | |
| 1428 | + u32 new_gear = 0; | |
| 1416 | 1429 | int ret = 0; |
| 1417 | 1430 | |
| 1431 | + new_gear = ufshcd_vops_freq_to_gear_speed(hba, freq); | |
| 1432 | + | |
| 1418 | 1433 | ret = ufshcd_clock_scaling_prepare(hba, 1 * USEC_PER_SEC); |
| 1419 | 1434 | if (ret) |
| 1420 | 1435 | return ret; |
| 1421 | 1436 | |
| 1422 | 1437 | /* scale down the gear before scaling down clocks */ |
| 1423 | 1438 | if (!scale_up) { |
| 1424 | − ret = ufshcd_scale_gear(hba, false); | |
| 1439 | + ret = ufshcd_scale_gear(hba, new_gear, false); | |
| 1425 | 1440 | if (ret) |
| 1426 | 1441 | goto out_unprepare; |
| 1427 | 1442 | } |
| @@ -1429,13 +1444,13 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, unsigned long freq, · 1 unmodified line | ||
| 1429 | 1444 | ret = ufshcd_scale_clks(hba, freq, scale_up); |
| 1430 | 1445 | if (ret) { |
| 1431 | 1446 | if (!scale_up) |
| 1432 | − ufshcd_scale_gear(hba, true); | |
| 1447 | + ufshcd_scale_gear(hba, old_gear, true); | |
| 1433 | 1448 | goto out_unprepare; |
| 1434 | 1449 | } |
| 1435 | 1450 | |
| 1436 | 1451 | /* scale up the gear after scaling up clocks */ |
| 1437 | 1452 | if (scale_up) { |
| 1438 | − ret = ufshcd_scale_gear(hba, true); | |
| 1453 | + ret = ufshcd_scale_gear(hba, new_gear, true); | |
| 1439 | 1454 | if (ret) { |
| 1440 | 1455 | ufshcd_scale_clks(hba, hba->devfreq->previous_freq, |
| 1441 | 1456 | false); |
| @@ -1444,7 +1459,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, unsigned long freq, · 2 unmodified lines | ||
| 1444 | 1459 | } |
| 1445 | 1460 | |
| 1446 | 1461 | out_unprepare: |
| 1447 | − ufshcd_clock_scaling_unprepare(hba, ret, scale_up); | |
| 1462 | + ufshcd_clock_scaling_unprepare(hba, ret); | |
| 1448 | 1463 | return ret; |
| 1449 | 1464 | } |
| 1450 | 1465 | |
| @@ -1548,7 +1563,7 @@ static int ufshcd_devfreq_target(struct device *dev, · 97 unmodified lines | ||
| 1548 | 1563 | if (!ret) |
| 1549 | 1564 | hba->clk_scaling.target_freq = *freq; |
| 1550 | 1565 | |
| 1551 | − trace_ufshcd_profile_clk_scaling(dev_name(hba->dev), | |
| 1566 | + trace_ufshcd_profile_clk_scaling(hba, | |
| 1552 | 1567 | (scale_up ? "up" : "down"), |
| 1553 | 1568 | ktime_to_us(ktime_sub(ktime_get(), start)), ret); |
| 1554 | 1569 | |
| @@ -1720,6 +1735,8 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev, · 165 unmodified lines | ||
| 1720 | 1735 | struct device_attribute *attr, const char *buf, size_t count) |
| 1721 | 1736 | { |
| 1722 | 1737 | struct ufs_hba *hba = dev_get_drvdata(dev); |
| 1738 | + struct ufs_clk_info *clki; | |
| 1739 | + unsigned long freq; | |
| 1723 | 1740 | u32 value; |
| 1724 | 1741 | int err = 0; |
| 1725 | 1742 | |
| @@ -1743,14 +1760,25 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev, · 17 unmodified lines | ||
| 1743 | 1760 | |
| 1744 | 1761 | if (value) { |
| 1745 | 1762 | ufshcd_resume_clkscaling(hba); |
| 1746 | − } else { | |
| 1747 | − ufshcd_suspend_clkscaling(hba); | |
| 1748 | − err = ufshcd_devfreq_scale(hba, ULONG_MAX, true); | |
| 1749 | − if (err) | |
| 1750 | − dev_err(hba->dev, "%s: failed to scale clocks up %d\n", | |
| 1751 | − __func__, err); | |
| 1763 | + goto out_rel; | |
| 1752 | 1764 | } |
| 1753 | 1765 | |
| 1766 | + clki = list_first_entry(&hba->clk_list_head, struct ufs_clk_info, list); | |
| 1767 | + freq = clki->max_freq; | |
| 1768 | + | |
| 1769 | + ufshcd_suspend_clkscaling(hba); | |
| 1770 | + | |
| 1771 | + if (!ufshcd_is_devfreq_scaling_required(hba, freq, true)) | |
| 1772 | + goto out_rel; | |
| 1773 | + | |
| 1774 | + err = ufshcd_devfreq_scale(hba, freq, true); | |
| 1775 | + if (err) | |
| 1776 | + dev_err(hba->dev, "%s: failed to scale clocks up %d\n", | |
| 1777 | + __func__, err); | |
| 1778 | + else | |
| 1779 | + hba->clk_scaling.target_freq = freq; | |
| 1780 | + | |
| 1781 | +out_rel: | |
| 1754 | 1782 | ufshcd_release(hba); |
| 1755 | 1783 | ufshcd_rpm_put_sync(hba); |
| 1756 | 1784 | out: |
| @@ -1783,6 +1811,10 @@ static void ufshcd_init_clk_scaling(struct ufs_hba *hba) · 26 unmodified lines | ||
| 1783 | 1811 | if (!hba->clk_scaling.min_gear) |
| 1784 | 1812 | hba->clk_scaling.min_gear = UFS_HS_G1; |
| 1785 | 1813 | |
| 1814 | + if (!hba->clk_scaling.wb_gear) | |
| 1815 | + /* Use intermediate gear speed HS_G3 as the default wb_gear */ | |
| 1816 | + hba->clk_scaling.wb_gear = UFS_HS_G3; | |
| 1817 | + | |
| 1786 | 1818 | INIT_WORK(&hba->clk_scaling.suspend_work, |
| 1787 | 1819 | ufshcd_clk_scaling_suspend_work); |
| 1788 | 1820 | INIT_WORK(&hba->clk_scaling.resume_work, |
| @@ -1881,7 +1913,7 @@ start: · 92 unmodified lines | ||
| 1881 | 1913 | case REQ_CLKS_OFF: |
| 1882 | 1914 | if (cancel_delayed_work(&hba->clk_gating.gate_work)) { |
| 1883 | 1915 | hba->clk_gating.state = CLKS_ON; |
| 1884 | − trace_ufshcd_clk_gating(dev_name(hba->dev), | |
| 1916 | + trace_ufshcd_clk_gating(hba, | |
| 1885 | 1917 | hba->clk_gating.state); |
| 1886 | 1918 | break; |
| 1887 | 1919 | } |
| @@ -1893,7 +1925,7 @@ start: · 5 unmodified lines | ||
| 1893 | 1925 | fallthrough; |
| 1894 | 1926 | case CLKS_OFF: |
| 1895 | 1927 | hba->clk_gating.state = REQ_CLKS_ON; |
| 1896 | − trace_ufshcd_clk_gating(dev_name(hba->dev), | |
| 1928 | + trace_ufshcd_clk_gating(hba, | |
| 1897 | 1929 | hba->clk_gating.state); |
| 1898 | 1930 | queue_work(hba->clk_gating.clk_gating_workq, |
| 1899 | 1931 | &hba->clk_gating.ungate_work); |
| @@ -1933,7 +1965,7 @@ static void ufshcd_gate_work(struct work_struct *work) · 33 unmodified lines | ||
| 1933 | 1965 | if (hba->clk_gating.is_suspended || |
| 1934 | 1966 | hba->clk_gating.state != REQ_CLKS_OFF) { |
| 1935 | 1967 | hba->clk_gating.state = CLKS_ON; |
| 1936 | − trace_ufshcd_clk_gating(dev_name(hba->dev), | |
| 1968 | + trace_ufshcd_clk_gating(hba, | |
| 1937 | 1969 | hba->clk_gating.state); |
| 1938 | 1970 | return; |
| 1939 | 1971 | } |
| @@ -1955,7 +1987,7 @@ static void ufshcd_gate_work(struct work_struct *work) · 15 unmodified lines | ||
| 1955 | 1987 | hba->clk_gating.state = CLKS_ON; |
| 1956 | 1988 | dev_err(hba->dev, "%s: hibern8 enter failed %d\n", |
| 1957 | 1989 | __func__, ret); |
| 1958 | − trace_ufshcd_clk_gating(dev_name(hba->dev), | |
| 1990 | + trace_ufshcd_clk_gating(hba, | |
| 1959 | 1991 | hba->clk_gating.state); |
| 1960 | 1992 | return; |
| 1961 | 1993 | } |
| @@ -1980,7 +2012,7 @@ static void ufshcd_gate_work(struct work_struct *work) · 18 unmodified lines | ||
| 1980 | 2012 | guard(spinlock_irqsave)(&hba->clk_gating.lock); |
| 1981 | 2013 | if (hba->clk_gating.state == REQ_CLKS_OFF) { |
| 1982 | 2014 | hba->clk_gating.state = CLKS_OFF; |
| 1983 | − trace_ufshcd_clk_gating(dev_name(hba->dev), | |
| 2015 | + trace_ufshcd_clk_gating(hba, | |
| 1984 | 2016 | hba->clk_gating.state); |
| 1985 | 2017 | } |
| 1986 | 2018 | } |
| @@ -2006,7 +2038,7 @@ static void __ufshcd_release(struct ufs_hba *hba) · 19 unmodified lines | ||
| 2006 | 2038 | } |
| 2007 | 2039 | |
| 2008 | 2040 | hba->clk_gating.state = REQ_CLKS_OFF; |
| 2009 | − trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); | |
| 2041 | + trace_ufshcd_clk_gating(hba, hba->clk_gating.state); | |
| 2010 | 2042 | queue_delayed_work(hba->clk_gating.clk_gating_workq, |
| 2011 | 2043 | &hba->clk_gating.gate_work, |
| 2012 | 2044 | msecs_to_jiffies(hba->clk_gating.delay_ms)); |
| @@ -4005,7 +4037,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba) · 1992 unmodified lines | ||
| 4005 | 4037 | * |
| 4006 | 4038 | * Return: 0 on success, non-zero value on failure. |
| 4007 | 4039 | */ |
| 4008 | −static int ufshcd_dme_reset(struct ufs_hba *hba) | |
| 4040 | +int ufshcd_dme_reset(struct ufs_hba *hba) | |
| 4009 | 4041 | { |
| 4010 | 4042 | struct uic_command uic_cmd = { |
| 4011 | 4043 | .command = UIC_CMD_DME_RESET, |
| @@ -4019,6 +4051,7 @@ static int ufshcd_dme_reset(struct ufs_hba *hba) · 7 unmodified lines | ||
| 4019 | 4051 | |
| 4020 | 4052 | return ret; |
| 4021 | 4053 | } |
| 4054 | +EXPORT_SYMBOL_GPL(ufshcd_dme_reset); | |
| 4022 | 4055 | |
| 4023 | 4056 | int ufshcd_dme_configure_adapt(struct ufs_hba *hba, |
| 4024 | 4057 | int agreed_gear, |
| @@ -4044,7 +4077,7 @@ EXPORT_SYMBOL_GPL(ufshcd_dme_configure_adapt); · 19 unmodified lines | ||
| 4044 | 4077 | * |
| 4045 | 4078 | * Return: 0 on success, non-zero value on failure. |
| 4046 | 4079 | */ |
| 4047 | −static int ufshcd_dme_enable(struct ufs_hba *hba) | |
| 4080 | +int ufshcd_dme_enable(struct ufs_hba *hba) | |
| 4048 | 4081 | { |
| 4049 | 4082 | struct uic_command uic_cmd = { |
| 4050 | 4083 | .command = UIC_CMD_DME_ENABLE, |
| @@ -4058,6 +4091,7 @@ static int ufshcd_dme_enable(struct ufs_hba *hba) · 7 unmodified lines | ||
| 4058 | 4091 | |
| 4059 | 4092 | return ret; |
| 4060 | 4093 | } |
| 4094 | +EXPORT_SYMBOL_GPL(ufshcd_dme_enable); | |
| 4061 | 4095 | |
| 4062 | 4096 | static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba) |
| 4063 | 4097 | { |
| @@ -4422,7 +4456,7 @@ int ufshcd_uic_hibern8_enter(struct ufs_hba *hba) · 358 unmodified lines | ||
| 4422 | 4456 | ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_ENTER, PRE_CHANGE); |
| 4423 | 4457 | |
| 4424 | 4458 | ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); |
| 4425 | − trace_ufshcd_profile_hibern8(dev_name(hba->dev), "enter", | |
| 4459 | + trace_ufshcd_profile_hibern8(hba, "enter", | |
| 4426 | 4460 | ktime_to_us(ktime_sub(ktime_get(), start)), ret); |
| 4427 | 4461 | |
| 4428 | 4462 | if (ret) |
| @@ -4447,7 +4481,7 @@ int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) · 18 unmodified lines | ||
| 4447 | 4481 | ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_EXIT, PRE_CHANGE); |
| 4448 | 4482 | |
| 4449 | 4483 | ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); |
| 4450 | − trace_ufshcd_profile_hibern8(dev_name(hba->dev), "exit", | |
| 4484 | + trace_ufshcd_profile_hibern8(hba, "exit", | |
| 4451 | 4485 | ktime_to_us(ktime_sub(ktime_get(), start)), ret); |
| 4452 | 4486 | |
| 4453 | 4487 | if (ret) { |
| @@ -5808,7 +5842,7 @@ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba) · 1354 unmodified lines | ||
| 5808 | 5842 | } |
| 5809 | 5843 | |
| 5810 | 5844 | hba->auto_bkops_enabled = true; |
| 5811 | − trace_ufshcd_auto_bkops_state(dev_name(hba->dev), "Enabled"); | |
| 5845 | + trace_ufshcd_auto_bkops_state(hba, "Enabled"); | |
| 5812 | 5846 | |
| 5813 | 5847 | /* No need of URGENT_BKOPS exception from the device */ |
| 5814 | 5848 | err = ufshcd_disable_ee(hba, MASK_EE_URGENT_BKOPS); |
| @@ -5859,7 +5893,7 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba) · 44 unmodified lines | ||
| 5859 | 5893 | } |
| 5860 | 5894 | |
| 5861 | 5895 | hba->auto_bkops_enabled = false; |
| 5862 | − trace_ufshcd_auto_bkops_state(dev_name(hba->dev), "Disabled"); | |
| 5896 | + trace_ufshcd_auto_bkops_state(hba, "Disabled"); | |
| 5863 | 5897 | hba->is_urgent_bkops_lvl_checked = false; |
| 5864 | 5898 | out: |
| 5865 | 5899 | return err; |
| @@ -6193,7 +6227,7 @@ static void ufshcd_exception_event_handler(struct work_struct *work) · 327 unmodified lines | ||
| 6193 | 6227 | return; |
| 6194 | 6228 | } |
| 6195 | 6229 | |
| 6196 | − trace_ufshcd_exception_event(dev_name(hba->dev), status); | |
| 6230 | + trace_ufshcd_exception_event(hba, status); | |
| 6197 | 6231 | |
| 6198 | 6232 | if (status & hba->ee_drv_mask & MASK_EE_URGENT_BKOPS) |
| 6199 | 6233 | ufshcd_bkops_exception_event_handler(hba); |
| @@ -6201,6 +6235,11 @@ static void ufshcd_exception_event_handler(struct work_struct *work) · 1 unmodified line | ||
| 6201 | 6235 | if (status & hba->ee_drv_mask & MASK_EE_URGENT_TEMP) |
| 6202 | 6236 | ufs_hwmon_notify_event(hba, status & MASK_EE_URGENT_TEMP); |
| 6203 | 6237 | |
| 6238 | + if (status & hba->ee_drv_mask & MASK_EE_HEALTH_CRITICAL) { | |
| 6239 | + hba->critical_health_count++; | |
| 6240 | + sysfs_notify(&hba->dev->kobj, NULL, "critical_health"); | |
| 6241 | + } | |
| 6242 | + | |
| 6204 | 6243 | ufs_debugfs_exception_event(hba, status); |
| 6205 | 6244 | } |
| 6206 | 6245 | |
| @@ -7652,7 +7691,7 @@ static void ufshcd_process_probe_result(struct ufs_hba *hba, · 1445 unmodified lines | ||
| 7652 | 7691 | hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; |
| 7653 | 7692 | spin_unlock_irqrestore(hba->host->host_lock, flags); |
| 7654 | 7693 | |
| 7655 | − trace_ufshcd_init(dev_name(hba->dev), ret, | |
| 7694 | + trace_ufshcd_init(hba, ret, | |
| 7656 | 7695 | ktime_to_us(ktime_sub(ktime_get(), probe_start)), |
| 7657 | 7696 | hba->curr_dev_pwr_mode, hba->uic_link_state); |
| 7658 | 7697 | } |
| @@ -8293,6 +8332,11 @@ static int ufs_get_device_desc(struct ufs_hba *hba) · 634 unmodified lines | ||
| 8293 | 8332 | |
| 8294 | 8333 | ufshcd_temp_notif_probe(hba, desc_buf); |
| 8295 | 8334 | |
| 8335 | + if (dev_info->wspecversion >= 0x410) { | |
| 8336 | + hba->critical_health_count = 0; | |
| 8337 | + ufshcd_enable_ee(hba, MASK_EE_HEALTH_CRITICAL); | |
| 8338 | + } | |
| 8339 | + | |
| 8296 | 8340 | ufs_init_rtc(hba, desc_buf); |
| 8297 | 8341 | |
| 8298 | 8342 | /* |
| @@ -9148,12 +9192,12 @@ out: · 849 unmodified lines | ||
| 9148 | 9192 | } else if (!ret && on && hba->clk_gating.is_initialized) { |
| 9149 | 9193 | scoped_guard(spinlock_irqsave, &hba->clk_gating.lock) |
| 9150 | 9194 | hba->clk_gating.state = CLKS_ON; |
| 9151 | − trace_ufshcd_clk_gating(dev_name(hba->dev), | |
| 9195 | + trace_ufshcd_clk_gating(hba, | |
| 9152 | 9196 | hba->clk_gating.state); |
| 9153 | 9197 | } |
| 9154 | 9198 | |
| 9155 | 9199 | if (clk_state_changed) |
| 9156 | − trace_ufshcd_profile_clk_gating(dev_name(hba->dev), | |
| 9200 | + trace_ufshcd_profile_clk_gating(hba, | |
| 9157 | 9201 | (on ? "on" : "off"), |
| 9158 | 9202 | ktime_to_us(ktime_sub(ktime_get(), start)), ret); |
| 9159 | 9203 | return ret; |
| @@ -9853,7 +9897,7 @@ static int ufshcd_wl_runtime_suspend(struct device *dev) · 693 unmodified lines | ||
| 9853 | 9897 | if (ret) |
| 9854 | 9898 | dev_err(&sdev->sdev_gendev, "%s failed: %d\n", __func__, ret); |
| 9855 | 9899 | |
| 9856 | − trace_ufshcd_wl_runtime_suspend(dev_name(dev), ret, | |
| 9900 | + trace_ufshcd_wl_runtime_suspend(hba, ret, | |
| 9857 | 9901 | ktime_to_us(ktime_sub(ktime_get(), start)), |
| 9858 | 9902 | hba->curr_dev_pwr_mode, hba->uic_link_state); |
| 9859 | 9903 | |
| @@ -9873,7 +9917,7 @@ static int ufshcd_wl_runtime_resume(struct device *dev) · 13 unmodified lines | ||
| 9873 | 9917 | if (ret) |
| 9874 | 9918 | dev_err(&sdev->sdev_gendev, "%s failed: %d\n", __func__, ret); |
| 9875 | 9919 | |
| 9876 | − trace_ufshcd_wl_runtime_resume(dev_name(dev), ret, | |
| 9920 | + trace_ufshcd_wl_runtime_resume(hba, ret, | |
| 9877 | 9921 | ktime_to_us(ktime_sub(ktime_get(), start)), |
| 9878 | 9922 | hba->curr_dev_pwr_mode, hba->uic_link_state); |
| 9879 | 9923 | |
| @@ -9905,7 +9949,7 @@ static int ufshcd_wl_suspend(struct device *dev) · 25 unmodified lines | ||
| 9905 | 9949 | out: |
| 9906 | 9950 | if (!ret) |
| 9907 | 9951 | hba->is_sys_suspended = true; |
| 9908 | − trace_ufshcd_wl_suspend(dev_name(dev), ret, | |
| 9952 | + trace_ufshcd_wl_suspend(hba, ret, | |
| 9909 | 9953 | ktime_to_us(ktime_sub(ktime_get(), start)), |
| 9910 | 9954 | hba->curr_dev_pwr_mode, hba->uic_link_state); |
| 9911 | 9955 | |
| @@ -9928,7 +9972,7 @@ static int ufshcd_wl_resume(struct device *dev) · 16 unmodified lines | ||
| 9928 | 9972 | if (ret) |
| 9929 | 9973 | dev_err(&sdev->sdev_gendev, "%s failed: %d\n", __func__, ret); |
| 9930 | 9974 | out: |
| 9931 | − trace_ufshcd_wl_resume(dev_name(dev), ret, | |
| 9975 | + trace_ufshcd_wl_resume(hba, ret, | |
| 9932 | 9976 | ktime_to_us(ktime_sub(ktime_get(), start)), |
| 9933 | 9977 | hba->curr_dev_pwr_mode, hba->uic_link_state); |
| 9934 | 9978 | if (!ret) |
| @@ -9966,7 +10010,7 @@ static int ufshcd_suspend(struct ufs_hba *hba) · 31 unmodified lines | ||
| 9966 | 10010 | } |
| 9967 | 10011 | if (ufshcd_is_clkgating_allowed(hba)) { |
| 9968 | 10012 | hba->clk_gating.state = CLKS_OFF; |
| 9969 | − trace_ufshcd_clk_gating(dev_name(hba->dev), | |
| 10013 | + trace_ufshcd_clk_gating(hba, | |
| 9970 | 10014 | hba->clk_gating.state); |
| 9971 | 10015 | } |
| 9972 | 10016 | |
| @@ -10039,7 +10083,7 @@ int ufshcd_system_suspend(struct device *dev) · 66 unmodified lines | ||
| 10039 | 10083 | |
| 10040 | 10084 | ret = ufshcd_suspend(hba); |
| 10041 | 10085 | out: |
| 10042 | − trace_ufshcd_system_suspend(dev_name(hba->dev), ret, | |
| 10086 | + trace_ufshcd_system_suspend(hba, ret, | |
| 10043 | 10087 | ktime_to_us(ktime_sub(ktime_get(), start)), |
| 10044 | 10088 | hba->curr_dev_pwr_mode, hba->uic_link_state); |
| 10045 | 10089 | return ret; |
| @@ -10067,7 +10111,7 @@ int ufshcd_system_resume(struct device *dev) · 21 unmodified lines | ||
| 10067 | 10111 | ret = ufshcd_resume(hba); |
| 10068 | 10112 | |
| 10069 | 10113 | out: |
| 10070 | − trace_ufshcd_system_resume(dev_name(hba->dev), ret, | |
| 10114 | + trace_ufshcd_system_resume(hba, ret, | |
| 10071 | 10115 | ktime_to_us(ktime_sub(ktime_get(), start)), |
| 10072 | 10116 | hba->curr_dev_pwr_mode, hba->uic_link_state); |
| 10073 | 10117 | |
| @@ -10093,7 +10137,7 @@ int ufshcd_runtime_suspend(struct device *dev) · 19 unmodified lines | ||
| 10093 | 10137 | |
| 10094 | 10138 | ret = ufshcd_suspend(hba); |
| 10095 | 10139 | |
| 10096 | − trace_ufshcd_runtime_suspend(dev_name(hba->dev), ret, | |
| 10140 | + trace_ufshcd_runtime_suspend(hba, ret, | |
| 10097 | 10141 | ktime_to_us(ktime_sub(ktime_get(), start)), |
| 10098 | 10142 | hba->curr_dev_pwr_mode, hba->uic_link_state); |
| 10099 | 10143 | return ret; |
| @@ -10120,7 +10164,7 @@ int ufshcd_runtime_resume(struct device *dev) · 20 unmodified lines | ||
| 10120 | 10164 | |
| 10121 | 10165 | ret = ufshcd_resume(hba); |
| 10122 | 10166 | |
| 10123 | − trace_ufshcd_runtime_resume(dev_name(hba->dev), ret, | |
| 10167 | + trace_ufshcd_runtime_resume(hba, ret, | |
| 10124 | 10168 | ktime_to_us(ktime_sub(ktime_get(), start)), |
| 10125 | 10169 | hba->curr_dev_pwr_mode, hba->uic_link_state); |
| 10126 | 10170 | return ret; |
| @@ -142,3 +142,15 @@ config SCSI_UFS_SPRD · 141 unmodified lines | ||
| 142 | 142 | |
| 143 | 143 | Select this if you have UFS controller on Unisoc chipset. |
| 144 | 144 | If unsure, say N. |
| 145 | + | |
| 146 | +config SCSI_UFS_ROCKCHIP | |
| 147 | + tristate "Rockchip UFS host controller driver" | |
| 148 | + depends on SCSI_UFSHCD_PLATFORM && (ARCH_ROCKCHIP || COMPILE_TEST) | |
| 149 | + help | |
| 150 | + This selects the Rockchip specific additions to UFSHCD platform driver. | |
| 151 | + UFS host on Rockchip needs some vendor specific configuration before | |
| 152 | + accessing the hardware which includes PHY configuration and vendor | |
| 153 | + specific registers. | |
| 154 | + | |
| 155 | + Select this if you have UFS controller on Rockchip chipset. | |
| 156 | + If unsure, say N. | |
| @@ -10,5 +10,6 @@ obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o · 9 unmodified lines | ||
| 10 | 10 | obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o |
| 11 | 11 | obj-$(CONFIG_SCSI_UFS_MEDIATEK) += ufs-mediatek.o |
| 12 | 12 | obj-$(CONFIG_SCSI_UFS_RENESAS) += ufs-renesas.o |
| 13 | +obj-$(CONFIG_SCSI_UFS_ROCKCHIP) += ufs-rockchip.o | |
| 13 | 14 | obj-$(CONFIG_SCSI_UFS_SPRD) += ufs-sprd.o |
| 14 | 15 | obj-$(CONFIG_SCSI_UFS_TI_J721E) += ti-j721e-ufs.o |
| @@ -321,7 +321,7 @@ static int exynosauto_ufs_pre_pwr_change(struct exynos_ufs *ufs, · 320 unmodified lines | ||
| 321 | 321 | } |
| 322 | 322 | |
| 323 | 323 | static int exynosauto_ufs_post_pwr_change(struct exynos_ufs *ufs, |
| 324 | − struct ufs_pa_layer_attr *pwr) | |
| 324 | + const struct ufs_pa_layer_attr *pwr) | |
| 325 | 325 | { |
| 326 | 326 | struct ufs_hba *hba = ufs->hba; |
| 327 | 327 | u32 enabled_vh; |
| @@ -396,7 +396,7 @@ static int exynos7_ufs_pre_pwr_change(struct exynos_ufs *ufs, · 68 unmodified lines | ||
| 396 | 396 | } |
| 397 | 397 | |
| 398 | 398 | static int exynos7_ufs_post_pwr_change(struct exynos_ufs *ufs, |
| 399 | − struct ufs_pa_layer_attr *pwr) | |
| 399 | + const struct ufs_pa_layer_attr *pwr) | |
| 400 | 400 | { |
| 401 | 401 | struct ufs_hba *hba = ufs->hba; |
| 402 | 402 | int lanes = max_t(u32, pwr->lane_rx, pwr->lane_tx); |
| @@ -813,7 +813,7 @@ static u32 exynos_ufs_get_hs_gear(struct ufs_hba *hba) · 410 unmodified lines | ||
| 813 | 813 | } |
| 814 | 814 | |
| 815 | 815 | static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, |
| 816 | − struct ufs_pa_layer_attr *dev_max_params, | |
| 816 | + const struct ufs_pa_layer_attr *dev_max_params, | |
| 817 | 817 | struct ufs_pa_layer_attr *dev_req_params) |
| 818 | 818 | { |
| 819 | 819 | struct exynos_ufs *ufs = ufshcd_get_variant(hba); |
| @@ -865,7 +865,7 @@ out: · 45 unmodified lines | ||
| 865 | 865 | |
| 866 | 866 | #define PWR_MODE_STR_LEN 64 |
| 867 | 867 | static int exynos_ufs_post_pwr_mode(struct ufs_hba *hba, |
| 868 | − struct ufs_pa_layer_attr *pwr_req) | |
| 868 | + const struct ufs_pa_layer_attr *pwr_req) | |
| 869 | 869 | { |
| 870 | 870 | struct exynos_ufs *ufs = ufshcd_get_variant(hba); |
| 871 | 871 | struct phy *generic_phy = ufs->phy; |
| @@ -1635,7 +1635,7 @@ static int exynos_ufs_link_startup_notify(struct ufs_hba *hba, · 763 unmodified lines | ||
| 1635 | 1635 | |
| 1636 | 1636 | static int exynos_ufs_pwr_change_notify(struct ufs_hba *hba, |
| 1637 | 1637 | enum ufs_notify_change_status status, |
| 1638 | − struct ufs_pa_layer_attr *dev_max_params, | |
| 1638 | + const struct ufs_pa_layer_attr *dev_max_params, | |
| 1639 | 1639 | struct ufs_pa_layer_attr *dev_req_params) |
| 1640 | 1640 | { |
| 1641 | 1641 | int ret = 0; |
| @@ -188,7 +188,7 @@ struct exynos_ufs_drv_data { · 187 unmodified lines | ||
| 188 | 188 | int (*pre_pwr_change)(struct exynos_ufs *ufs, |
| 189 | 189 | struct ufs_pa_layer_attr *pwr); |
| 190 | 190 | int (*post_pwr_change)(struct exynos_ufs *ufs, |
| 191 | − struct ufs_pa_layer_attr *pwr); | |
| 191 | + const struct ufs_pa_layer_attr *pwr); | |
| 192 | 192 | int (*pre_hce_enable)(struct exynos_ufs *ufs); |
| 193 | 193 | int (*post_hce_enable)(struct exynos_ufs *ufs); |
| 194 | 194 | }; |
| @@ -361,9 +361,9 @@ static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba) · 360 unmodified lines | ||
| 361 | 361 | } |
| 362 | 362 | |
| 363 | 363 | static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, |
| 364 | − enum ufs_notify_change_status status, | |
| 365 | − struct ufs_pa_layer_attr *dev_max_params, | |
| 366 | − struct ufs_pa_layer_attr *dev_req_params) | |
| 364 | + enum ufs_notify_change_status status, | |
| 365 | + const struct ufs_pa_layer_attr *dev_max_params, | |
| 366 | + struct ufs_pa_layer_attr *dev_req_params) | |
| 367 | 367 | { |
| 368 | 368 | struct ufs_host_params host_params; |
| 369 | 369 | int ret = 0; |
| @@ -1081,8 +1081,8 @@ static bool ufs_mtk_pmc_via_fastauto(struct ufs_hba *hba, · 1080 unmodified lines | ||
| 1081 | 1081 | } |
| 1082 | 1082 | |
| 1083 | 1083 | static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, |
| 1084 | − struct ufs_pa_layer_attr *dev_max_params, | |
| 1085 | − struct ufs_pa_layer_attr *dev_req_params) | |
| 1084 | + const struct ufs_pa_layer_attr *dev_max_params, | |
| 1085 | + struct ufs_pa_layer_attr *dev_req_params) | |
| 1086 | 1086 | { |
| 1087 | 1087 | struct ufs_mtk_host *host = ufshcd_get_variant(hba); |
| 1088 | 1088 | struct ufs_host_params host_params; |
| @@ -1134,9 +1134,9 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, · 45 unmodified lines | ||
| 1134 | 1134 | } |
| 1135 | 1135 | |
| 1136 | 1136 | static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba, |
| 1137 | − enum ufs_notify_change_status stage, | |
| 1138 | − struct ufs_pa_layer_attr *dev_max_params, | |
| 1139 | − struct ufs_pa_layer_attr *dev_req_params) | |
| 1137 | + enum ufs_notify_change_status stage, | |
| 1138 | + const struct ufs_pa_layer_attr *dev_max_params, | |
| 1139 | + struct ufs_pa_layer_attr *dev_req_params) | |
| 1140 | 1140 | { |
| 1141 | 1141 | int ret = 0; |
| 1142 | 1142 | |
| @@ -1643,6 +1643,7 @@ static void ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up) · 500 unmodified lines | ||
| 1643 | 1643 | } |
| 1644 | 1644 | |
| 1645 | 1645 | static int ufs_mtk_clk_scale_notify(struct ufs_hba *hba, bool scale_up, |
| 1646 | + unsigned long target_freq, | |
| 1646 | 1647 | enum ufs_notify_change_status status) |
| 1647 | 1648 | { |
| 1648 | 1649 | if (!ufshcd_is_clkscaling_supported(hba)) |
| @@ -15,6 +15,8 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <linux/platform_device.h> |
| 16 | 16 | #include <linux/reset-controller.h> |
| 17 | 17 | #include <linux/time.h> |
| 18 | +#include <linux/unaligned.h> | |
| 19 | +#include <linux/units.h> | |
| 18 | 20 | |
| 19 | 21 | #include <soc/qcom/ice.h> |
| 20 | 22 | |
| @@ -97,7 +99,7 @@ static const struct __ufs_qcom_bw_table { · 76 unmodified lines | ||
| 97 | 99 | }; |
| 98 | 100 | |
| 99 | 101 | static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); |
| 100 | −static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up); | |
| 102 | +static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq); | |
| 101 | 103 | |
| 102 | 104 | static struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd) |
| 103 | 105 | { |
| @@ -105,6 +107,26 @@ static struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd) · 1 unmodified line | ||
| 105 | 107 | } |
| 106 | 108 | |
| 107 | 109 | #ifdef CONFIG_SCSI_UFS_CRYPTO |
| 110 | +/** | |
| 111 | + * ufs_qcom_config_ice_allocator() - ICE core allocator configuration | |
| 112 | + * | |
| 113 | + * @host: pointer to qcom specific variant structure. | |
| 114 | + */ | |
| 115 | +static void ufs_qcom_config_ice_allocator(struct ufs_qcom_host *host) | |
| 116 | +{ | |
| 117 | + struct ufs_hba *hba = host->hba; | |
| 118 | + static const uint8_t val[4] = { NUM_RX_R1W0, NUM_TX_R0W1, NUM_RX_R1W1, NUM_TX_R1W1 }; | |
| 119 | + u32 config; | |
| 120 | + | |
| 121 | + if (!(host->caps & UFS_QCOM_CAP_ICE_CONFIG) || | |
| 122 | + !(host->hba->caps & UFSHCD_CAP_CRYPTO)) | |
| 123 | + return; | |
| 124 | + | |
| 125 | + config = get_unaligned_le32(val); | |
| 126 | + | |
| 127 | + ufshcd_writel(hba, ICE_ALLOCATOR_TYPE, REG_UFS_MEM_ICE_CONFIG); | |
| 128 | + ufshcd_writel(hba, config, REG_UFS_MEM_ICE_NUM_CORE); | |
| 129 | +} | |
| 108 | 130 | |
| 109 | 131 | static inline void ufs_qcom_ice_enable(struct ufs_qcom_host *host) |
| 110 | 132 | { |
| @@ -249,6 +271,11 @@ static inline int ufs_qcom_ice_suspend(struct ufs_qcom_host *host) · 138 unmodified lines | ||
| 249 | 271 | { |
| 250 | 272 | return 0; |
| 251 | 273 | } |
| 274 | + | |
| 275 | +static void ufs_qcom_config_ice_allocator(struct ufs_qcom_host *host) | |
| 276 | +{ | |
| 277 | +} | |
| 278 | + | |
| 252 | 279 | #endif |
| 253 | 280 | |
| 254 | 281 | static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host) |
| @@ -497,6 +524,7 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, · 242 unmodified lines | ||
| 497 | 524 | err = ufs_qcom_check_hibern8(hba); |
| 498 | 525 | ufs_qcom_enable_hw_clk_gating(hba); |
| 499 | 526 | ufs_qcom_ice_enable(host); |
| 527 | + ufs_qcom_config_ice_allocator(host); | |
| 500 | 528 | break; |
| 501 | 529 | default: |
| 502 | 530 | dev_err(hba->dev, "%s: invalid status %d\n", __func__, status); |
| @@ -510,16 +538,10 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, · 7 unmodified lines | ||
| 510 | 538 | * ufs_qcom_cfg_timers - Configure ufs qcom cfg timers |
| 511 | 539 | * |
| 512 | 540 | * @hba: host controller instance |
| 513 | − * @gear: Current operating gear | |
| 514 | − * @hs: current power mode | |
| 515 | − * @rate: current operating rate (A or B) | |
| 516 | − * @update_link_startup_timer: indicate if link_start ongoing | |
| 517 | 541 | * @is_pre_scale_up: flag to check if pre scale up condition. |
| 518 | 542 | * Return: zero for success and non-zero in case of a failure. |
| 519 | 543 | */ |
| 520 | −static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, | |
| 521 | − u32 hs, u32 rate, bool update_link_startup_timer, | |
| 522 | − bool is_pre_scale_up) | |
| 544 | +static int ufs_qcom_cfg_timers(struct ufs_hba *hba, bool is_pre_scale_up) | |
| 523 | 545 | { |
| 524 | 546 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
| 525 | 547 | struct ufs_clk_info *clki; |
| @@ -535,11 +557,6 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, · 9 unmodified lines | ||
| 535 | 557 | if (host->hw_ver.major < 4 && !ufshcd_is_intr_aggr_allowed(hba)) |
| 536 | 558 | return 0; |
| 537 | 559 | |
| 538 | − if (gear == 0) { | |
| 539 | − dev_err(hba->dev, "%s: invalid gear = %d\n", __func__, gear); | |
| 540 | − return -EINVAL; | |
| 541 | − } | |
| 542 | − | |
| 543 | 560 | list_for_each_entry(clki, &hba->clk_list_head, list) { |
| 544 | 561 | if (!strcmp(clki->name, "core_clk")) { |
| 545 | 562 | if (is_pre_scale_up) |
| @@ -575,14 +592,13 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, · 29 unmodified lines | ||
| 575 | 592 | |
| 576 | 593 | switch (status) { |
| 577 | 594 | case PRE_CHANGE: |
| 578 | − if (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE, | |
| 579 | − 0, true, false)) { | |
| 595 | + if (ufs_qcom_cfg_timers(hba, false)) { | |
| 580 | 596 | dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", |
| 581 | 597 | __func__); |
| 582 | 598 | return -EINVAL; |
| 583 | 599 | } |
| 584 | 600 | |
| 585 | − err = ufs_qcom_set_core_clk_ctrl(hba, true); | |
| 601 | + err = ufs_qcom_set_core_clk_ctrl(hba, ULONG_MAX); | |
| 586 | 602 | if (err) |
| 587 | 603 | dev_err(hba->dev, "cfg core clk ctrl failed\n"); |
| 588 | 604 | /* |
| @@ -781,7 +797,7 @@ static int ufs_qcom_icc_update_bw(struct ufs_qcom_host *host) · 192 unmodified lines | ||
| 781 | 797 | |
| 782 | 798 | static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, |
| 783 | 799 | enum ufs_notify_change_status status, |
| 784 | − struct ufs_pa_layer_attr *dev_max_params, | |
| 800 | + const struct ufs_pa_layer_attr *dev_max_params, | |
| 785 | 801 | struct ufs_pa_layer_attr *dev_req_params) |
| 786 | 802 | { |
| 787 | 803 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
| @@ -832,9 +848,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, · 44 unmodified lines | ||
| 832 | 848 | } |
| 833 | 849 | break; |
| 834 | 850 | case POST_CHANGE: |
| 835 | − if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, | |
| 836 | − dev_req_params->pwr_rx, | |
| 837 | − dev_req_params->hs_rate, false, false)) { | |
| 851 | + if (ufs_qcom_cfg_timers(hba, false)) { | |
| 838 | 852 | dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", |
| 839 | 853 | __func__); |
| 840 | 854 | /* |
| @@ -990,6 +1004,14 @@ static void ufs_qcom_set_host_params(struct ufs_hba *hba) · 149 unmodified lines | ||
| 990 | 1004 | host_params->hs_tx_gear = host_params->hs_rx_gear = ufs_qcom_get_hs_gear(hba); |
| 991 | 1005 | } |
| 992 | 1006 | |
| 1007 | +static void ufs_qcom_set_host_caps(struct ufs_hba *hba) | |
| 1008 | +{ | |
| 1009 | + struct ufs_qcom_host *host = ufshcd_get_variant(hba); | |
| 1010 | + | |
| 1011 | + if (host->hw_ver.major >= 0x5) | |
| 1012 | + host->caps |= UFS_QCOM_CAP_ICE_CONFIG; | |
| 1013 | +} | |
| 1014 | + | |
| 993 | 1015 | static void ufs_qcom_set_caps(struct ufs_hba *hba) |
| 994 | 1016 | { |
| 995 | 1017 | hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; |
| @@ -998,6 +1020,8 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba) · 2 unmodified lines | ||
| 998 | 1020 | hba->caps |= UFSHCD_CAP_WB_EN; |
| 999 | 1021 | hba->caps |= UFSHCD_CAP_AGGR_POWER_COLLAPSE; |
| 1000 | 1022 | hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND; |
| 1023 | + | |
| 1024 | + ufs_qcom_set_host_caps(hba); | |
| 1001 | 1025 | } |
| 1002 | 1026 | |
| 1003 | 1027 | /** |
| @@ -1293,7 +1317,7 @@ static int ufs_qcom_set_clk_40ns_cycles(struct ufs_hba *hba, · 289 unmodified lines | ||
| 1293 | 1317 | return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), reg); |
| 1294 | 1318 | } |
| 1295 | 1319 | |
| 1296 | −static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up) | |
| 1320 | +static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq) | |
| 1297 | 1321 | { |
| 1298 | 1322 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
| 1299 | 1323 | struct list_head *head = &hba->clk_list_head; |
| @@ -1307,10 +1331,11 @@ static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up) · 7 unmodified lines | ||
| 1307 | 1331 | !strcmp(clki->name, "core_clk_unipro")) { |
| 1308 | 1332 | if (!clki->max_freq) |
| 1309 | 1333 | cycles_in_1us = 150; /* default for backwards compatibility */ |
| 1310 | − else if (is_scale_up) | |
| 1311 | − cycles_in_1us = ceil(clki->max_freq, (1000 * 1000)); | |
| 1334 | + else if (freq == ULONG_MAX) | |
| 1335 | + cycles_in_1us = ceil(clki->max_freq, HZ_PER_MHZ); | |
| 1312 | 1336 | else |
| 1313 | − cycles_in_1us = ceil(clk_get_rate(clki->clk), (1000 * 1000)); | |
| 1337 | + cycles_in_1us = ceil(freq, HZ_PER_MHZ); | |
| 1338 | + | |
| 1314 | 1339 | break; |
| 1315 | 1340 | } |
| 1316 | 1341 | } |
| @@ -1347,20 +1372,17 @@ static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up) · 30 unmodified lines | ||
| 1347 | 1372 | return ufs_qcom_set_clk_40ns_cycles(hba, cycles_in_1us); |
| 1348 | 1373 | } |
| 1349 | 1374 | |
| 1350 | −static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) | |
| 1375 | +static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba, unsigned long freq) | |
| 1351 | 1376 | { |
| 1352 | − struct ufs_qcom_host *host = ufshcd_get_variant(hba); | |
| 1353 | − struct ufs_pa_layer_attr *attr = &host->dev_req_params; | |
| 1354 | 1377 | int ret; |
| 1355 | 1378 | |
| 1356 | − ret = ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx, | |
| 1357 | − attr->hs_rate, false, true); | |
| 1379 | + ret = ufs_qcom_cfg_timers(hba, true); | |
| 1358 | 1380 | if (ret) { |
| 1359 | 1381 | dev_err(hba->dev, "%s ufs cfg timer failed\n", __func__); |
| 1360 | 1382 | return ret; |
| 1361 | 1383 | } |
| 1362 | 1384 | /* set unipro core clock attributes and clear clock divider */ |
| 1363 | − return ufs_qcom_set_core_clk_ctrl(hba, true); | |
| 1385 | + return ufs_qcom_set_core_clk_ctrl(hba, freq); | |
| 1364 | 1386 | } |
| 1365 | 1387 | |
| 1366 | 1388 | static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba) |
| @@ -1389,14 +1411,15 @@ static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) · 22 unmodified lines | ||
| 1389 | 1411 | return err; |
| 1390 | 1412 | } |
| 1391 | 1413 | |
| 1392 | −static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba) | |
| 1414 | +static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba, unsigned long freq) | |
| 1393 | 1415 | { |
| 1394 | 1416 | /* set unipro core clock attributes and clear clock divider */ |
| 1395 | − return ufs_qcom_set_core_clk_ctrl(hba, false); | |
| 1417 | + return ufs_qcom_set_core_clk_ctrl(hba, freq); | |
| 1396 | 1418 | } |
| 1397 | 1419 | |
| 1398 | −static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, | |
| 1399 | − bool scale_up, enum ufs_notify_change_status status) | |
| 1420 | +static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, bool scale_up, | |
| 1421 | + unsigned long target_freq, | |
| 1422 | + enum ufs_notify_change_status status) | |
| 1400 | 1423 | { |
| 1401 | 1424 | struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
| 1402 | 1425 | int err; |
| @@ -1410,7 +1433,7 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, · 7 unmodified lines | ||
| 1410 | 1433 | if (err) |
| 1411 | 1434 | return err; |
| 1412 | 1435 | if (scale_up) |
| 1413 | − err = ufs_qcom_clk_scale_up_pre_change(hba); | |
| 1436 | + err = ufs_qcom_clk_scale_up_pre_change(hba, target_freq); | |
| 1414 | 1437 | else |
| 1415 | 1438 | err = ufs_qcom_clk_scale_down_pre_change(hba); |
| 1416 | 1439 | |
| @@ -1422,7 +1445,7 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, · 5 unmodified lines | ||
| 1422 | 1445 | if (scale_up) |
| 1423 | 1446 | err = ufs_qcom_clk_scale_up_post_change(hba); |
| 1424 | 1447 | else |
| 1425 | − err = ufs_qcom_clk_scale_down_post_change(hba); | |
| 1448 | + err = ufs_qcom_clk_scale_down_post_change(hba, target_freq); | |
| 1426 | 1449 | |
| 1427 | 1450 | |
| 1428 | 1451 | if (err) { |
| @@ -1859,6 +1882,36 @@ cleanup: · 430 unmodified lines | ||
| 1859 | 1882 | return ret; |
| 1860 | 1883 | } |
| 1861 | 1884 | |
| 1885 | +static u32 ufs_qcom_freq_to_gear_speed(struct ufs_hba *hba, unsigned long freq) | |
| 1886 | +{ | |
| 1887 | + u32 gear = 0; | |
| 1888 | + | |
| 1889 | + switch (freq) { | |
| 1890 | + case 403000000: | |
| 1891 | + gear = UFS_HS_G5; | |
| 1892 | + break; | |
| 1893 | + case 300000000: | |
| 1894 | + gear = UFS_HS_G4; | |
| 1895 | + break; | |
| 1896 | + case 201500000: | |
| 1897 | + gear = UFS_HS_G3; | |
| 1898 | + break; | |
| 1899 | + case 150000000: | |
| 1900 | + case 100000000: | |
| 1901 | + gear = UFS_HS_G2; | |
| 1902 | + break; | |
| 1903 | + case 75000000: | |
| 1904 | + case 37500000: | |
| 1905 | + gear = UFS_HS_G1; | |
| 1906 | + break; | |
| 1907 | + default: | |
| 1908 | + dev_err(hba->dev, "%s: Unsupported clock freq : %lu\n", __func__, freq); | |
| 1909 | + break; | |
| 1910 | + } | |
| 1911 | + | |
| 1912 | + return gear; | |
| 1913 | +} | |
| 1914 | + | |
| 1862 | 1915 | /* |
| 1863 | 1916 | * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations |
| 1864 | 1917 | * |
| @@ -1887,6 +1940,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { · 22 unmodified lines | ||
| 1887 | 1940 | .op_runtime_config = ufs_qcom_op_runtime_config, |
| 1888 | 1941 | .get_outstanding_cqs = ufs_qcom_get_outstanding_cqs, |
| 1889 | 1942 | .config_esi = ufs_qcom_config_esi, |
| 1943 | + .freq_to_gear_speed = ufs_qcom_freq_to_gear_speed, | |
| 1890 | 1944 | }; |
| 1891 | 1945 | |
| 1892 | 1946 | /** |
| @@ -50,6 +50,9 @@ enum { · 49 unmodified lines | ||
| 50 | 50 | */ |
| 51 | 51 | UFS_AH8_CFG = 0xFC, |
| 52 | 52 | |
| 53 | + REG_UFS_MEM_ICE_CONFIG = 0x260C, | |
| 54 | + REG_UFS_MEM_ICE_NUM_CORE = 0x2664, | |
| 55 | + | |
| 53 | 56 | REG_UFS_CFG3 = 0x271C, |
| 54 | 57 | |
| 55 | 58 | REG_UFS_DEBUG_SPARE_CFG = 0x284C, |
| @@ -110,6 +113,9 @@ enum { · 54 unmodified lines | ||
| 110 | 113 | /* bit definition for UFS_UFS_TEST_BUS_CTRL_n */ |
| 111 | 114 | #define TEST_BUS_SUB_SEL_MASK GENMASK(4, 0) /* All XXX_SEL fields are 5 bits wide */ |
| 112 | 115 | |
| 116 | +/* bit definition for UFS Shared ICE config */ | |
| 117 | +#define UFS_QCOM_CAP_ICE_CONFIG BIT(0) | |
| 118 | + | |
| 113 | 119 | #define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\ |
| 114 | 120 | TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\ |
| 115 | 121 | DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\ |
| @@ -135,6 +141,37 @@ enum { · 19 unmodified lines | ||
| 135 | 141 | #define UNIPRO_CORE_CLK_FREQ_201_5_MHZ 202 |
| 136 | 142 | #define UNIPRO_CORE_CLK_FREQ_403_MHZ 403 |
| 137 | 143 | |
| 144 | +/* ICE allocator type to share AES engines among TX stream and RX stream */ | |
| 145 | +#define ICE_ALLOCATOR_TYPE 2 | |
| 146 | + | |
| 147 | +/* | |
| 148 | + * Number of cores allocated for RX stream when Read data block received and | |
| 149 | + * Write data block is not in progress | |
| 150 | + */ | |
| 151 | +#define NUM_RX_R1W0 28 | |
| 152 | + | |
| 153 | +/* | |
| 154 | + * Number of cores allocated for TX stream when Device asked to send write | |
| 155 | + * data block and Read data block is not in progress | |
| 156 | + */ | |
| 157 | +#define NUM_TX_R0W1 28 | |
| 158 | + | |
| 159 | +/* | |
| 160 | + * Number of cores allocated for RX stream when Read data block received and | |
| 161 | + * Write data block is in progress | |
| 162 | + * OR | |
| 163 | + * Device asked to send write data block and Read data block is in progress | |
| 164 | + */ | |
| 165 | +#define NUM_RX_R1W1 15 | |
| 166 | + | |
| 167 | +/* | |
| 168 | + * Number of cores allocated for TX stream (UFS write) when Read data block | |
| 169 | + * received and Write data block is in progress | |
| 170 | + * OR | |
| 171 | + * Device asked to send write data block and Read data block is in progress | |
| 172 | + */ | |
| 173 | +#define NUM_TX_R1W1 13 | |
| 174 | + | |
| 138 | 175 | static inline void |
| 139 | 176 | ufs_qcom_get_controller_revision(struct ufs_hba *hba, |
| 140 | 177 | u8 *major, u16 *minor, u16 *step) |
| @@ -196,7 +233,7 @@ struct ufs_qcom_host { · 55 unmodified lines | ||
| 196 | 233 | #ifdef CONFIG_SCSI_UFS_CRYPTO |
| 197 | 234 | struct qcom_ice *ice; |
| 198 | 235 | #endif |
| 199 | − | |
| 236 | + u32 caps; | |
| 200 | 237 | void __iomem *dev_ref_clk_ctrl_mmio; |
| 201 | 238 | bool is_dev_ref_clk_enabled; |
| 202 | 239 | struct ufs_hw_version hw_ver; |
| @@ -9,324 +9,408 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/delay.h> |
| 10 | 10 | #include <linux/dma-mapping.h> |
| 11 | 11 | #include <linux/err.h> |
| 12 | +#include <linux/firmware.h> | |
| 12 | 13 | #include <linux/iopoll.h> |
| 13 | 14 | #include <linux/kernel.h> |
| 14 | 15 | #include <linux/module.h> |
| 16 | +#include <linux/nvmem-consumer.h> | |
| 15 | 17 | #include <linux/of.h> |
| 16 | 18 | #include <linux/platform_device.h> |
| 17 | 19 | #include <linux/pm_runtime.h> |
| 20 | +#include <linux/sys_soc.h> | |
| 18 | 21 | #include <ufs/ufshcd.h> |
| 19 | 22 | |
| 20 | 23 | #include "ufshcd-pltfrm.h" |
| 21 | 24 | |
| 25 | +#define EFUSE_CALIB_SIZE 8 | |
| 26 | + | |
| 22 | 27 | struct ufs_renesas_priv { |
| 28 | + const struct firmware *fw; | |
| 29 | + void (*pre_init)(struct ufs_hba *hba); | |
| 23 | 30 | bool initialized; /* The hardware needs initialization once */ |
| 31 | + u8 calib[EFUSE_CALIB_SIZE]; | |
| 24 | 32 | }; |
| 25 | 33 | |
| 26 | −enum { | |
| 27 | − SET_PHY_INDEX_LO = 0, | |
| 28 | − SET_PHY_INDEX_HI, | |
| 29 | − TIMER_INDEX, | |
| 30 | − MAX_INDEX | |
| 31 | −}; | |
| 34 | +#define UFS_RENESAS_FIRMWARE_NAME "r8a779f0_ufs.bin" | |
| 35 | +MODULE_FIRMWARE(UFS_RENESAS_FIRMWARE_NAME); | |
| 32 | 36 | |
| 33 | −enum ufs_renesas_init_param_mode { | |
| 34 | − MODE_RESTORE, | |
| 35 | − MODE_SET, | |
| 36 | − MODE_SAVE, | |
| 37 | − MODE_POLL, | |
| 38 | − MODE_WAIT, | |
| 39 | − MODE_WRITE, | |
| 40 | −}; | |
| 37 | +static void ufs_renesas_dbg_register_dump(struct ufs_hba *hba) | |
| 38 | +{ | |
| 39 | + ufshcd_dump_regs(hba, 0xc0, 0x40, "regs: 0xc0 + "); | |
| 40 | +} | |
| 41 | 41 | |
| 42 | −#define PARAM_RESTORE(_reg, _index) \ | |
| 43 | − { .mode = MODE_RESTORE, .reg = _reg, .index = _index } | |
| 44 | −#define PARAM_SET(_index, _set) \ | |
| 45 | − { .mode = MODE_SET, .index = _index, .u.set = _set } | |
| 46 | −#define PARAM_SAVE(_reg, _mask, _index) \ | |
| 47 | − { .mode = MODE_SAVE, .reg = _reg, .mask = (u32)(_mask), \ | |
| 48 | − .index = _index } | |
| 49 | −#define PARAM_POLL(_reg, _expected, _mask) \ | |
| 50 | − { .mode = MODE_POLL, .reg = _reg, .u.expected = _expected, \ | |
| 51 | − .mask = (u32)(_mask) } | |
| 52 | −#define PARAM_WAIT(_delay_us) \ | |
| 53 | − { .mode = MODE_WAIT, .u.delay_us = _delay_us } | |
| 54 | − | |
| 55 | −#define PARAM_WRITE(_reg, _val) \ | |
| 56 | − { .mode = MODE_WRITE, .reg = _reg, .u.val = _val } | |
| 57 | − | |
| 58 | −#define PARAM_WRITE_D0_D4(_d0, _d4) \ | |
| 59 | − PARAM_WRITE(0xd0, _d0), PARAM_WRITE(0xd4, _d4) | |
| 60 | − | |
| 61 | −#define PARAM_WRITE_800_80C_POLL(_addr, _data_800) \ | |
| 62 | − PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), \ | |
| 63 | − PARAM_WRITE_D0_D4(0x00000800, ((_data_800) << 16) | BIT(8) | (_addr)), \ | |
| 64 | − PARAM_WRITE(0xd0, 0x0000080c), \ | |
| 65 | − PARAM_POLL(0xd4, BIT(8), BIT(8)) | |
| 66 | − | |
| 67 | −#define PARAM_RESTORE_800_80C_POLL(_index) \ | |
| 68 | − PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), \ | |
| 69 | − PARAM_WRITE(0xd0, 0x00000800), \ | |
| 70 | − PARAM_RESTORE(0xd4, _index), \ | |
| 71 | − PARAM_WRITE(0xd0, 0x0000080c), \ | |
| 72 | − PARAM_POLL(0xd4, BIT(8), BIT(8)) | |
| 73 | − | |
| 74 | −#define PARAM_WRITE_804_80C_POLL(_addr, _data_804) \ | |
| 75 | − PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), \ | |
| 76 | − PARAM_WRITE_D0_D4(0x00000804, ((_data_804) << 16) | BIT(8) | (_addr)), \ | |
| 77 | − PARAM_WRITE(0xd0, 0x0000080c), \ | |
| 78 | − PARAM_POLL(0xd4, BIT(8), BIT(8)) | |
| 79 | − | |
| 80 | −#define PARAM_WRITE_828_82C_POLL(_data_828) \ | |
| 81 | − PARAM_WRITE_D0_D4(0x0000082c, 0x0f000000), \ | |
| 82 | − PARAM_WRITE_D0_D4(0x00000828, _data_828), \ | |
| 83 | − PARAM_WRITE(0xd0, 0x0000082c), \ | |
| 84 | − PARAM_POLL(0xd4, _data_828, _data_828) | |
| 85 | − | |
| 86 | −#define PARAM_WRITE_PHY(_addr16, _data16) \ | |
| 87 | − PARAM_WRITE(0xf0, 1), \ | |
| 88 | − PARAM_WRITE_800_80C_POLL(0x16, (_addr16) & 0xff), \ | |
| 89 | − PARAM_WRITE_800_80C_POLL(0x17, ((_addr16) >> 8) & 0xff), \ | |
| 90 | − PARAM_WRITE_800_80C_POLL(0x18, (_data16) & 0xff), \ | |
| 91 | − PARAM_WRITE_800_80C_POLL(0x19, ((_data16) >> 8) & 0xff), \ | |
| 92 | − PARAM_WRITE_800_80C_POLL(0x1c, 0x01), \ | |
| 93 | − PARAM_WRITE_828_82C_POLL(0x0f000000), \ | |
| 94 | − PARAM_WRITE(0xf0, 0) | |
| 95 | − | |
| 96 | −#define PARAM_SET_PHY(_addr16, _data16) \ | |
| 97 | − PARAM_WRITE(0xf0, 1), \ | |
| 98 | − PARAM_WRITE_800_80C_POLL(0x16, (_addr16) & 0xff), \ | |
| 99 | − PARAM_WRITE_800_80C_POLL(0x17, ((_addr16) >> 8) & 0xff), \ | |
| 100 | − PARAM_WRITE_800_80C_POLL(0x1c, 0x01), \ | |
| 101 | − PARAM_WRITE_828_82C_POLL(0x0f000000), \ | |
| 102 | − PARAM_WRITE_804_80C_POLL(0x1a, 0), \ | |
| 103 | − PARAM_WRITE(0xd0, 0x00000808), \ | |
| 104 | − PARAM_SAVE(0xd4, 0xff, SET_PHY_INDEX_LO), \ | |
| 105 | − PARAM_WRITE_804_80C_POLL(0x1b, 0), \ | |
| 106 | − PARAM_WRITE(0xd0, 0x00000808), \ | |
| 107 | − PARAM_SAVE(0xd4, 0xff, SET_PHY_INDEX_HI), \ | |
| 108 | − PARAM_WRITE_828_82C_POLL(0x0f000000), \ | |
| 109 | − PARAM_WRITE(0xf0, 0), \ | |
| 110 | − PARAM_WRITE(0xf0, 1), \ | |
| 111 | − PARAM_WRITE_800_80C_POLL(0x16, (_addr16) & 0xff), \ | |
| 112 | − PARAM_WRITE_800_80C_POLL(0x17, ((_addr16) >> 8) & 0xff), \ | |
| 113 | − PARAM_SET(SET_PHY_INDEX_LO, ((_data16 & 0xff) << 16) | BIT(8) | 0x18), \ | |
| 114 | − PARAM_RESTORE_800_80C_POLL(SET_PHY_INDEX_LO), \ | |
| 115 | − PARAM_SET(SET_PHY_INDEX_HI, (((_data16 >> 8) & 0xff) << 16) | BIT(8) | 0x19), \ | |
| 116 | − PARAM_RESTORE_800_80C_POLL(SET_PHY_INDEX_HI), \ | |
| 117 | − PARAM_WRITE_800_80C_POLL(0x1c, 0x01), \ | |
| 118 | − PARAM_WRITE_828_82C_POLL(0x0f000000), \ | |
| 119 | − PARAM_WRITE(0xf0, 0) | |
| 120 | − | |
| 121 | −#define PARAM_INDIRECT_WRITE(_gpio, _addr, _data_800) \ | |
| 122 | − PARAM_WRITE(0xf0, _gpio), \ | |
| 123 | − PARAM_WRITE_800_80C_POLL(_addr, _data_800), \ | |
| 124 | − PARAM_WRITE_828_82C_POLL(0x0f000000), \ | |
| 125 | − PARAM_WRITE(0xf0, 0) | |
| 126 | − | |
| 127 | −#define PARAM_INDIRECT_POLL(_gpio, _addr, _expected, _mask) \ | |
| 128 | − PARAM_WRITE(0xf0, _gpio), \ | |
| 129 | − PARAM_WRITE_800_80C_POLL(_addr, 0), \ | |
| 130 | − PARAM_WRITE(0xd0, 0x00000808), \ | |
| 131 | − PARAM_POLL(0xd4, _expected, _mask), \ | |
| 132 | − PARAM_WRITE(0xf0, 0) | |
| 133 | − | |
| 134 | −struct ufs_renesas_init_param { | |
| 135 | − enum ufs_renesas_init_param_mode mode; | |
| 136 | − u32 reg; | |
| 137 | − union { | |
| 138 | − u32 expected; | |
| 139 | − u32 delay_us; | |
| 140 | − u32 set; | |
| 141 | − u32 val; | |
| 142 | − } u; | |
| 143 | − u32 mask; | |
| 144 | − u32 index; | |
| 145 | −}; | |
| 42 | +static void ufs_renesas_poll(struct ufs_hba *hba, u32 reg, u32 expected, u32 mask) | |
| 43 | +{ | |
| 44 | + int ret; | |
| 45 | + u32 val; | |
| 146 | 46 | |
| 147 | −/* This setting is for SERIES B */ | |
| 148 | −static const struct ufs_renesas_init_param ufs_param[] = { | |
| 149 | − PARAM_WRITE(0xc0, 0x49425308), | |
| 150 | − PARAM_WRITE_D0_D4(0x00000104, 0x00000002), | |
| 151 | − PARAM_WAIT(1), | |
| 152 | − PARAM_WRITE_D0_D4(0x00000828, 0x00000200), | |
| 153 | − PARAM_WAIT(1), | |
| 154 | − PARAM_WRITE_D0_D4(0x00000828, 0x00000000), | |
| 155 | − PARAM_WRITE_D0_D4(0x00000104, 0x00000001), | |
| 156 | − PARAM_WRITE_D0_D4(0x00000940, 0x00000001), | |
| 157 | − PARAM_WAIT(1), | |
| 158 | − PARAM_WRITE_D0_D4(0x00000940, 0x00000000), | |
| 159 | − | |
| 160 | − PARAM_WRITE(0xc0, 0x49425308), | |
| 161 | − PARAM_WRITE(0xc0, 0x41584901), | |
| 162 | − | |
| 163 | − PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), | |
| 164 | − PARAM_WRITE_D0_D4(0x00000804, 0x00000000), | |
| 165 | − PARAM_WRITE(0xd0, 0x0000080c), | |
| 166 | − PARAM_POLL(0xd4, BIT(8), BIT(8)), | |
| 167 | − | |
| 168 | − PARAM_WRITE(REG_CONTROLLER_ENABLE, 0x00000001), | |
| 169 | − | |
| 170 | − PARAM_WRITE(0xd0, 0x00000804), | |
| 171 | − PARAM_POLL(0xd4, BIT(8) | BIT(6) | BIT(0), BIT(8) | BIT(6) | BIT(0)), | |
| 172 | − | |
| 173 | − PARAM_WRITE(0xd0, 0x00000d00), | |
| 174 | − PARAM_SAVE(0xd4, 0x0000ffff, TIMER_INDEX), | |
| 175 | − PARAM_WRITE(0xd4, 0x00000000), | |
| 176 | − PARAM_WRITE_D0_D4(0x0000082c, 0x0f000000), | |
| 177 | − PARAM_WRITE_D0_D4(0x00000828, 0x08000000), | |
| 178 | − PARAM_WRITE(0xd0, 0x0000082c), | |
| 179 | − PARAM_POLL(0xd4, BIT(27), BIT(27)), | |
| 180 | − PARAM_WRITE(0xd0, 0x00000d2c), | |
| 181 | − PARAM_POLL(0xd4, BIT(0), BIT(0)), | |
| 47 | + ret = readl_poll_timeout_atomic(hba->mmio_base + reg, | |
| 48 | + val, (val & mask) == expected, | |
| 49 | + 10, 1000); | |
| 50 | + if (ret) | |
| 51 | + dev_err(hba->dev, "%s: poll failed %d (%08x, %08x, %08x)\n", | |
| 52 | + __func__, ret, val, mask, expected); | |
| 53 | +} | |
| 182 | 54 | |
| 183 | − /* phy setup */ | |
| 184 | − PARAM_INDIRECT_WRITE(1, 0x01, 0x001f), | |
| 185 | − PARAM_INDIRECT_WRITE(7, 0x5d, 0x0014), | |
| 186 | − PARAM_INDIRECT_WRITE(7, 0x5e, 0x0014), | |
| 187 | − PARAM_INDIRECT_WRITE(7, 0x0d, 0x0003), | |
| 188 | − PARAM_INDIRECT_WRITE(7, 0x0e, 0x0007), | |
| 189 | − PARAM_INDIRECT_WRITE(7, 0x5f, 0x0003), | |
| 190 | − PARAM_INDIRECT_WRITE(7, 0x60, 0x0003), | |
| 191 | − PARAM_INDIRECT_WRITE(7, 0x5b, 0x00a6), | |
| 192 | − PARAM_INDIRECT_WRITE(7, 0x5c, 0x0003), | |
| 193 | − | |
| 194 | − PARAM_INDIRECT_POLL(7, 0x3c, 0, BIT(7)), | |
| 195 | − PARAM_INDIRECT_POLL(7, 0x4c, 0, BIT(4)), | |
| 196 | − | |
| 197 | − PARAM_INDIRECT_WRITE(1, 0x32, 0x0080), | |
| 198 | − PARAM_INDIRECT_WRITE(1, 0x1f, 0x0001), | |
| 199 | − PARAM_INDIRECT_WRITE(0, 0x2c, 0x0001), | |
| 200 | − PARAM_INDIRECT_WRITE(0, 0x32, 0x0087), | |
| 201 | − | |
| 202 | − PARAM_INDIRECT_WRITE(1, 0x4d, 0x0061), | |
| 203 | − PARAM_INDIRECT_WRITE(4, 0x9b, 0x0009), | |
| 204 | − PARAM_INDIRECT_WRITE(4, 0xa6, 0x0005), | |
| 205 | − PARAM_INDIRECT_WRITE(4, 0xa5, 0x0058), | |
| 206 | − PARAM_INDIRECT_WRITE(1, 0x39, 0x0027), | |
| 207 | − PARAM_INDIRECT_WRITE(1, 0x47, 0x004c), | |
| 208 | − | |
| 209 | − PARAM_INDIRECT_WRITE(7, 0x0d, 0x0002), | |
| 210 | − PARAM_INDIRECT_WRITE(7, 0x0e, 0x0007), | |
| 211 | − | |
| 212 | − PARAM_WRITE_PHY(0x0028, 0x0061), | |
| 213 | − PARAM_WRITE_PHY(0x4014, 0x0061), | |
| 214 | − PARAM_SET_PHY(0x401c, BIT(2)), | |
| 215 | − PARAM_WRITE_PHY(0x4000, 0x0000), | |
| 216 | − PARAM_WRITE_PHY(0x4001, 0x0000), | |
| 217 | − | |
| 218 | − PARAM_WRITE_PHY(0x10ae, 0x0001), | |
| 219 | − PARAM_WRITE_PHY(0x10ad, 0x0000), | |
| 220 | − PARAM_WRITE_PHY(0x10af, 0x0001), | |
| 221 | − PARAM_WRITE_PHY(0x10b6, 0x0001), | |
| 222 | − PARAM_WRITE_PHY(0x10ae, 0x0000), | |
| 223 | − | |
| 224 | − PARAM_WRITE_PHY(0x10ae, 0x0001), | |
| 225 | − PARAM_WRITE_PHY(0x10ad, 0x0000), | |
| 226 | − PARAM_WRITE_PHY(0x10af, 0x0002), | |
| 227 | − PARAM_WRITE_PHY(0x10b6, 0x0001), | |
| 228 | − PARAM_WRITE_PHY(0x10ae, 0x0000), | |
| 229 | − | |
| 230 | − PARAM_WRITE_PHY(0x10ae, 0x0001), | |
| 231 | − PARAM_WRITE_PHY(0x10ad, 0x0080), | |
| 232 | − PARAM_WRITE_PHY(0x10af, 0x0000), | |
| 233 | − PARAM_WRITE_PHY(0x10b6, 0x0001), | |
| 234 | − PARAM_WRITE_PHY(0x10ae, 0x0000), | |
| 235 | − | |
| 236 | − PARAM_WRITE_PHY(0x10ae, 0x0001), | |
| 237 | − PARAM_WRITE_PHY(0x10ad, 0x0080), | |
| 238 | − PARAM_WRITE_PHY(0x10af, 0x001a), | |
| 239 | − PARAM_WRITE_PHY(0x10b6, 0x0001), | |
| 240 | − PARAM_WRITE_PHY(0x10ae, 0x0000), | |
| 241 | − | |
| 242 | − PARAM_INDIRECT_WRITE(7, 0x70, 0x0016), | |
| 243 | − PARAM_INDIRECT_WRITE(7, 0x71, 0x0016), | |
| 244 | − PARAM_INDIRECT_WRITE(7, 0x72, 0x0014), | |
| 245 | − PARAM_INDIRECT_WRITE(7, 0x73, 0x0014), | |
| 246 | − PARAM_INDIRECT_WRITE(7, 0x74, 0x0000), | |
| 247 | − PARAM_INDIRECT_WRITE(7, 0x75, 0x0000), | |
| 248 | − PARAM_INDIRECT_WRITE(7, 0x76, 0x0010), | |
| 249 | − PARAM_INDIRECT_WRITE(7, 0x77, 0x0010), | |
| 250 | − PARAM_INDIRECT_WRITE(7, 0x78, 0x00ff), | |
| 251 | − PARAM_INDIRECT_WRITE(7, 0x79, 0x0000), | |
| 252 | − | |
| 253 | − PARAM_INDIRECT_WRITE(7, 0x19, 0x0007), | |
| 254 | − | |
| 255 | − PARAM_INDIRECT_WRITE(7, 0x1a, 0x0007), | |
| 256 | − | |
| 257 | − PARAM_INDIRECT_WRITE(7, 0x24, 0x000c), | |
| 258 | − | |
| 259 | − PARAM_INDIRECT_WRITE(7, 0x25, 0x000c), | |
| 260 | − | |
| 261 | − PARAM_INDIRECT_WRITE(7, 0x62, 0x0000), | |
| 262 | − PARAM_INDIRECT_WRITE(7, 0x63, 0x0000), | |
| 263 | − PARAM_INDIRECT_WRITE(7, 0x5d, 0x0014), | |
| 264 | − PARAM_INDIRECT_WRITE(7, 0x5e, 0x0017), | |
| 265 | − PARAM_INDIRECT_WRITE(7, 0x5d, 0x0004), | |
| 266 | − PARAM_INDIRECT_WRITE(7, 0x5e, 0x0017), | |
| 267 | − PARAM_INDIRECT_POLL(7, 0x55, 0, BIT(6)), | |
| 268 | − PARAM_INDIRECT_POLL(7, 0x41, 0, BIT(7)), | |
| 269 | − /* end of phy setup */ | |
| 55 | +static u32 ufs_renesas_read(struct ufs_hba *hba, u32 reg) | |
| 56 | +{ | |
| 57 | + return ufshcd_readl(hba, reg); | |
| 58 | +} | |
| 270 | 59 | |
| 271 | − PARAM_WRITE(0xf0, 0), | |
| 272 | − PARAM_WRITE(0xd0, 0x00000d00), | |
| 273 | − PARAM_RESTORE(0xd4, TIMER_INDEX), | |
| 274 | −}; | |
| 60 | +static void ufs_renesas_write(struct ufs_hba *hba, u32 reg, u32 value) | |
| 61 | +{ | |
| 62 | + ufshcd_writel(hba, value, reg); | |
| 63 | +} | |
| 275 | 64 | |
| 276 | −static void ufs_renesas_dbg_register_dump(struct ufs_hba *hba) | |
| 65 | +static void ufs_renesas_write_d0_d4(struct ufs_hba *hba, u32 data_d0, u32 data_d4) | |
| 277 | 66 | { |
| 278 | − ufshcd_dump_regs(hba, 0xc0, 0x40, "regs: 0xc0 + "); | |
| 67 | + ufs_renesas_write(hba, 0xd0, data_d0); | |
| 68 | + ufs_renesas_write(hba, 0xd4, data_d4); | |
| 279 | 69 | } |
| 280 | 70 | |
| 281 | −static void ufs_renesas_reg_control(struct ufs_hba *hba, | |
| 282 | − const struct ufs_renesas_init_param *p) | |
| 71 | +static void ufs_renesas_write_800_80c_poll(struct ufs_hba *hba, u32 addr, | |
| 72 | + u32 data_800) | |
| 283 | 73 | { |
| 284 | − static u32 save[MAX_INDEX]; | |
| 285 | − int ret; | |
| 286 | − u32 val; | |
| 74 | + ufs_renesas_write_d0_d4(hba, 0x0000080c, 0x00000100); | |
| 75 | + ufs_renesas_write_d0_d4(hba, 0x00000800, (data_800 << 16) | BIT(8) | addr); | |
| 76 | + ufs_renesas_write(hba, 0xd0, 0x0000080c); | |
| 77 | + ufs_renesas_poll(hba, 0xd4, BIT(8), BIT(8)); | |
| 78 | +} | |
| 79 | + | |
| 80 | +static void ufs_renesas_write_804_80c_poll(struct ufs_hba *hba, u32 addr, u32 data_804) | |
| 81 | +{ | |
| 82 | + ufs_renesas_write_d0_d4(hba, 0x0000080c, 0x00000100); | |
| 83 | + ufs_renesas_write_d0_d4(hba, 0x00000804, (data_804 << 16) | BIT(8) | addr); | |
| 84 | + ufs_renesas_write(hba, 0xd0, 0x0000080c); | |
| 85 | + ufs_renesas_poll(hba, 0xd4, BIT(8), BIT(8)); | |
| 86 | +} | |
| 87 | + | |
| 88 | +static void ufs_renesas_write_828_82c_poll(struct ufs_hba *hba, u32 data_828) | |
| 89 | +{ | |
| 90 | + ufs_renesas_write_d0_d4(hba, 0x0000082c, 0x0f000000); | |
| 91 | + ufs_renesas_write_d0_d4(hba, 0x00000828, data_828); | |
| 92 | + ufs_renesas_write(hba, 0xd0, 0x0000082c); | |
| 93 | + ufs_renesas_poll(hba, 0xd4, data_828, data_828); | |
| 94 | +} | |
| 95 | + | |
| 96 | +static void ufs_renesas_write_phy(struct ufs_hba *hba, u32 addr16, u32 data16) | |
| 97 | +{ | |
| 98 | + ufs_renesas_write(hba, 0xf0, 1); | |
| 99 | + ufs_renesas_write_800_80c_poll(hba, 0x16, addr16 & 0xff); | |
| 100 | + ufs_renesas_write_800_80c_poll(hba, 0x17, (addr16 >> 8) & 0xff); | |
| 101 | + ufs_renesas_write_800_80c_poll(hba, 0x18, data16 & 0xff); | |
| 102 | + ufs_renesas_write_800_80c_poll(hba, 0x19, (data16 >> 8) & 0xff); | |
| 103 | + ufs_renesas_write_800_80c_poll(hba, 0x1c, 0x01); | |
| 104 | + ufs_renesas_write_828_82c_poll(hba, 0x0f000000); | |
| 105 | + ufs_renesas_write(hba, 0xf0, 0); | |
| 106 | +} | |
| 107 | + | |
| 108 | +static void ufs_renesas_set_phy(struct ufs_hba *hba, u32 addr16, u32 data16) | |
| 109 | +{ | |
| 110 | + u32 low, high; | |
| 111 | + | |
| 112 | + ufs_renesas_write(hba, 0xf0, 1); | |
| 113 | + ufs_renesas_write_800_80c_poll(hba, 0x16, addr16 & 0xff); | |
| 114 | + ufs_renesas_write_800_80c_poll(hba, 0x17, (addr16 >> 8) & 0xff); | |
| 115 | + ufs_renesas_write_800_80c_poll(hba, 0x1c, 0x01); | |
| 116 | + ufs_renesas_write_828_82c_poll(hba, 0x0f000000); | |
| 117 | + ufs_renesas_write_804_80c_poll(hba, 0x1a, 0); | |
| 118 | + ufs_renesas_write(hba, 0xd0, 0x00000808); | |
| 119 | + low = ufs_renesas_read(hba, 0xd4) & 0xff; | |
| 120 | + ufs_renesas_write_804_80c_poll(hba, 0x1b, 0); | |
| 121 | + ufs_renesas_write(hba, 0xd0, 0x00000808); | |
| 122 | + high = ufs_renesas_read(hba, 0xd4) & 0xff; | |
| 123 | + ufs_renesas_write_828_82c_poll(hba, 0x0f000000); | |
| 124 | + ufs_renesas_write(hba, 0xf0, 0); | |
| 125 | + | |
| 126 | + data16 |= (high << 8) | low; | |
| 127 | + ufs_renesas_write_phy(hba, addr16, data16); | |
| 128 | +} | |
| 129 | + | |
| 130 | +static void ufs_renesas_reset_indirect_write(struct ufs_hba *hba, int gpio, | |
| 131 | + u32 addr, u32 data) | |
| 132 | +{ | |
| 133 | + ufs_renesas_write(hba, 0xf0, gpio); | |
| 134 | + ufs_renesas_write_800_80c_poll(hba, addr, data); | |
| 135 | +} | |
| 136 | + | |
| 137 | +static void ufs_renesas_reset_indirect_update(struct ufs_hba *hba) | |
| 138 | +{ | |
| 139 | + ufs_renesas_write_d0_d4(hba, 0x0000082c, 0x0f000000); | |
| 140 | + ufs_renesas_write_d0_d4(hba, 0x00000828, 0x0f000000); | |
| 141 | + ufs_renesas_write(hba, 0xd0, 0x0000082c); | |
| 142 | + ufs_renesas_poll(hba, 0xd4, BIT(27) | BIT(26) | BIT(24), BIT(27) | BIT(26) | BIT(24)); | |
| 143 | + ufs_renesas_write(hba, 0xf0, 0); | |
| 144 | +} | |
| 145 | + | |
| 146 | +static void ufs_renesas_indirect_write(struct ufs_hba *hba, u32 gpio, u32 addr, | |
| 147 | + u32 data_800) | |
| 148 | +{ | |
| 149 | + ufs_renesas_write(hba, 0xf0, gpio); | |
| 150 | + ufs_renesas_write_800_80c_poll(hba, addr, data_800); | |
| 151 | + ufs_renesas_write_828_82c_poll(hba, 0x0f000000); | |
| 152 | + ufs_renesas_write(hba, 0xf0, 0); | |
| 153 | +} | |
| 154 | + | |
| 155 | +static void ufs_renesas_indirect_poll(struct ufs_hba *hba, u32 gpio, u32 addr, | |
| 156 | + u32 expected, u32 mask) | |
| 157 | +{ | |
| 158 | + ufs_renesas_write(hba, 0xf0, gpio); | |
| 159 | + ufs_renesas_write_800_80c_poll(hba, addr, 0); | |
| 160 | + ufs_renesas_write(hba, 0xd0, 0x00000808); | |
| 161 | + ufs_renesas_poll(hba, 0xd4, expected, mask); | |
| 162 | + ufs_renesas_write(hba, 0xf0, 0); | |
| 163 | +} | |
| 164 | + | |
| 165 | +static void ufs_renesas_init_step1_to_3(struct ufs_hba *hba, bool init108) | |
| 166 | +{ | |
| 167 | + ufs_renesas_write(hba, 0xc0, 0x49425308); | |
| 168 | + ufs_renesas_write_d0_d4(hba, 0x00000104, 0x00000002); | |
| 169 | + if (init108) | |
| 170 | + ufs_renesas_write_d0_d4(hba, 0x00000108, 0x00000002); | |
| 171 | + udelay(1); | |
| 172 | + ufs_renesas_write_d0_d4(hba, 0x00000828, 0x00000200); | |
| 173 | + udelay(1); | |
| 174 | + ufs_renesas_write_d0_d4(hba, 0x00000828, 0x00000000); | |
| 175 | + ufs_renesas_write_d0_d4(hba, 0x00000104, 0x00000001); | |
| 176 | + if (init108) | |
| 177 | + ufs_renesas_write_d0_d4(hba, 0x00000108, 0x00000001); | |
| 178 | + ufs_renesas_write_d0_d4(hba, 0x00000940, 0x00000001); | |
| 179 | + udelay(1); | |
| 180 | + ufs_renesas_write_d0_d4(hba, 0x00000940, 0x00000000); | |
| 181 | + | |
| 182 | + ufs_renesas_write(hba, 0xc0, 0x49425308); | |
| 183 | + ufs_renesas_write(hba, 0xc0, 0x41584901); | |
| 184 | +} | |
| 185 | + | |
| 186 | +static void ufs_renesas_init_step4_to_6(struct ufs_hba *hba) | |
| 187 | +{ | |
| 188 | + ufs_renesas_write_d0_d4(hba, 0x0000080c, 0x00000100); | |
| 189 | + ufs_renesas_write_d0_d4(hba, 0x00000804, 0x00000000); | |
| 190 | + ufs_renesas_write(hba, 0xd0, 0x0000080c); | |
| 191 | + ufs_renesas_poll(hba, 0xd4, BIT(8), BIT(8)); | |
| 287 | 192 | |
| 288 | − WARN_ON(p->index >= MAX_INDEX); | |
| 289 | − | |
| 290 | − switch (p->mode) { | |
| 291 | − case MODE_RESTORE: | |
| 292 | − ufshcd_writel(hba, save[p->index], p->reg); | |
| 293 | − break; | |
| 294 | − case MODE_SET: | |
| 295 | − save[p->index] |= p->u.set; | |
| 296 | − break; | |
| 297 | − case MODE_SAVE: | |
| 298 | − save[p->index] = ufshcd_readl(hba, p->reg) & p->mask; | |
| 299 | − break; | |
| 300 | − case MODE_POLL: | |
| 301 | − ret = readl_poll_timeout_atomic(hba->mmio_base + p->reg, | |
| 302 | − val, | |
| 303 | − (val & p->mask) == p->u.expected, | |
| 304 | − 10, 1000); | |
| 305 | − if (ret) | |
| 306 | − dev_err(hba->dev, "%s: poll failed %d (%08x, %08x, %08x)\n", | |
| 307 | − __func__, ret, val, p->mask, p->u.expected); | |
| 308 | − break; | |
| 309 | − case MODE_WAIT: | |
| 310 | − if (p->u.delay_us > 1000) | |
| 311 | − mdelay(DIV_ROUND_UP(p->u.delay_us, 1000)); | |
| 312 | − else | |
| 313 | − udelay(p->u.delay_us); | |
| 314 | − break; | |
| 315 | − case MODE_WRITE: | |
| 316 | − ufshcd_writel(hba, p->u.val, p->reg); | |
| 317 | − break; | |
| 318 | − default: | |
| 319 | − break; | |
| 193 | + ufs_renesas_write(hba, REG_CONTROLLER_ENABLE, 0x00000001); | |
| 194 | + | |
| 195 | + ufs_renesas_write(hba, 0xd0, 0x00000804); | |
| 196 | + ufs_renesas_poll(hba, 0xd4, BIT(8) | BIT(6) | BIT(0), BIT(8) | BIT(6) | BIT(0)); | |
| 197 | +} | |
| 198 | + | |
| 199 | +static u32 ufs_renesas_init_disable_timer(struct ufs_hba *hba) | |
| 200 | +{ | |
| 201 | + u32 timer_val; | |
| 202 | + | |
| 203 | + ufs_renesas_write(hba, 0xd0, 0x00000d00); | |
| 204 | + timer_val = ufs_renesas_read(hba, 0xd4) & 0x0000ffff; | |
| 205 | + ufs_renesas_write(hba, 0xd4, 0x00000000); | |
| 206 | + ufs_renesas_write_d0_d4(hba, 0x0000082c, 0x0f000000); | |
| 207 | + ufs_renesas_write_d0_d4(hba, 0x00000828, 0x08000000); | |
| 208 | + ufs_renesas_write(hba, 0xd0, 0x0000082c); | |
| 209 | + ufs_renesas_poll(hba, 0xd4, BIT(27), BIT(27)); | |
| 210 | + ufs_renesas_write(hba, 0xd0, 0x00000d2c); | |
| 211 | + ufs_renesas_poll(hba, 0xd4, BIT(0), BIT(0)); | |
| 212 | + | |
| 213 | + return timer_val; | |
| 214 | +} | |
| 215 | + | |
| 216 | +static void ufs_renesas_init_enable_timer(struct ufs_hba *hba, u32 timer_val) | |
| 217 | +{ | |
| 218 | + ufs_renesas_write(hba, 0xf0, 0); | |
| 219 | + ufs_renesas_write(hba, 0xd0, 0x00000d00); | |
| 220 | + ufs_renesas_write(hba, 0xd4, timer_val); | |
| 221 | +} | |
| 222 | + | |
| 223 | +static void ufs_renesas_write_phy_10ad_10af(struct ufs_hba *hba, | |
| 224 | + u32 data_10ad, u32 data_10af) | |
| 225 | +{ | |
| 226 | + ufs_renesas_write_phy(hba, 0x10ae, 0x0001); | |
| 227 | + ufs_renesas_write_phy(hba, 0x10ad, data_10ad); | |
| 228 | + ufs_renesas_write_phy(hba, 0x10af, data_10af); | |
| 229 | + ufs_renesas_write_phy(hba, 0x10b6, 0x0001); | |
| 230 | + ufs_renesas_write_phy(hba, 0x10ae, 0x0000); | |
| 231 | +} | |
| 232 | + | |
| 233 | +static void ufs_renesas_init_compensation_and_slicers(struct ufs_hba *hba) | |
| 234 | +{ | |
| 235 | + ufs_renesas_write_phy_10ad_10af(hba, 0x0000, 0x0001); | |
| 236 | + ufs_renesas_write_phy_10ad_10af(hba, 0x0000, 0x0002); | |
| 237 | + ufs_renesas_write_phy_10ad_10af(hba, 0x0080, 0x0000); | |
| 238 | + ufs_renesas_write_phy_10ad_10af(hba, 0x0080, 0x001a); | |
| 239 | +} | |
| 240 | + | |
| 241 | +static void ufs_renesas_r8a779f0_es10_pre_init(struct ufs_hba *hba) | |
| 242 | +{ | |
| 243 | + u32 timer_val; | |
| 244 | + | |
| 245 | + /* This setting is for SERIES B */ | |
| 246 | + ufs_renesas_init_step1_to_3(hba, false); | |
| 247 | + | |
| 248 | + ufs_renesas_init_step4_to_6(hba); | |
| 249 | + | |
| 250 | + timer_val = ufs_renesas_init_disable_timer(hba); | |
| 251 | + | |
| 252 | + /* phy setup */ | |
| 253 | + ufs_renesas_indirect_write(hba, 1, 0x01, 0x001f); | |
| 254 | + ufs_renesas_indirect_write(hba, 7, 0x5d, 0x0014); | |
| 255 | + ufs_renesas_indirect_write(hba, 7, 0x5e, 0x0014); | |
| 256 | + ufs_renesas_indirect_write(hba, 7, 0x0d, 0x0003); | |
| 257 | + ufs_renesas_indirect_write(hba, 7, 0x0e, 0x0007); | |
| 258 | + ufs_renesas_indirect_write(hba, 7, 0x5f, 0x0003); | |
| 259 | + ufs_renesas_indirect_write(hba, 7, 0x60, 0x0003); | |
| 260 | + ufs_renesas_indirect_write(hba, 7, 0x5b, 0x00a6); | |
| 261 | + ufs_renesas_indirect_write(hba, 7, 0x5c, 0x0003); | |
| 262 | + | |
| 263 | + ufs_renesas_indirect_poll(hba, 7, 0x3c, 0, BIT(7)); | |
| 264 | + ufs_renesas_indirect_poll(hba, 7, 0x4c, 0, BIT(4)); | |
| 265 | + | |
| 266 | + ufs_renesas_indirect_write(hba, 1, 0x32, 0x0080); | |
| 267 | + ufs_renesas_indirect_write(hba, 1, 0x1f, 0x0001); | |
| 268 | + ufs_renesas_indirect_write(hba, 0, 0x2c, 0x0001); | |
| 269 | + ufs_renesas_indirect_write(hba, 0, 0x32, 0x0087); | |
| 270 | + | |
| 271 | + ufs_renesas_indirect_write(hba, 1, 0x4d, 0x0061); | |
| 272 | + ufs_renesas_indirect_write(hba, 4, 0x9b, 0x0009); | |
| 273 | + ufs_renesas_indirect_write(hba, 4, 0xa6, 0x0005); | |
| 274 | + ufs_renesas_indirect_write(hba, 4, 0xa5, 0x0058); | |
| 275 | + ufs_renesas_indirect_write(hba, 1, 0x39, 0x0027); | |
| 276 | + ufs_renesas_indirect_write(hba, 1, 0x47, 0x004c); | |
| 277 | + | |
| 278 | + ufs_renesas_indirect_write(hba, 7, 0x0d, 0x0002); | |
| 279 | + ufs_renesas_indirect_write(hba, 7, 0x0e, 0x0007); | |
| 280 | + | |
| 281 | + ufs_renesas_write_phy(hba, 0x0028, 0x0061); | |
| 282 | + ufs_renesas_write_phy(hba, 0x4014, 0x0061); | |
| 283 | + ufs_renesas_set_phy(hba, 0x401c, BIT(2)); | |
| 284 | + ufs_renesas_write_phy(hba, 0x4000, 0x0000); | |
| 285 | + ufs_renesas_write_phy(hba, 0x4001, 0x0000); | |
| 286 | + | |
| 287 | + ufs_renesas_init_compensation_and_slicers(hba); | |
| 288 | + | |
| 289 | + ufs_renesas_indirect_write(hba, 7, 0x70, 0x0016); | |
| 290 | + ufs_renesas_indirect_write(hba, 7, 0x71, 0x0016); | |
| 291 | + ufs_renesas_indirect_write(hba, 7, 0x72, 0x0014); | |
| 292 | + ufs_renesas_indirect_write(hba, 7, 0x73, 0x0014); | |
| 293 | + ufs_renesas_indirect_write(hba, 7, 0x74, 0x0000); | |
| 294 | + ufs_renesas_indirect_write(hba, 7, 0x75, 0x0000); | |
| 295 | + ufs_renesas_indirect_write(hba, 7, 0x76, 0x0010); | |
| 296 | + ufs_renesas_indirect_write(hba, 7, 0x77, 0x0010); | |
| 297 | + ufs_renesas_indirect_write(hba, 7, 0x78, 0x00ff); | |
| 298 | + ufs_renesas_indirect_write(hba, 7, 0x79, 0x0000); | |
| 299 | + | |
| 300 | + ufs_renesas_indirect_write(hba, 7, 0x19, 0x0007); | |
| 301 | + ufs_renesas_indirect_write(hba, 7, 0x1a, 0x0007); | |
| 302 | + ufs_renesas_indirect_write(hba, 7, 0x24, 0x000c); | |
| 303 | + ufs_renesas_indirect_write(hba, 7, 0x25, 0x000c); | |
| 304 | + ufs_renesas_indirect_write(hba, 7, 0x62, 0x0000); | |
| 305 | + ufs_renesas_indirect_write(hba, 7, 0x63, 0x0000); | |
| 306 | + ufs_renesas_indirect_write(hba, 7, 0x5d, 0x0014); | |
| 307 | + ufs_renesas_indirect_write(hba, 7, 0x5e, 0x0017); | |
| 308 | + ufs_renesas_indirect_write(hba, 7, 0x5d, 0x0004); | |
| 309 | + ufs_renesas_indirect_write(hba, 7, 0x5e, 0x0017); | |
| 310 | + ufs_renesas_indirect_poll(hba, 7, 0x55, 0, BIT(6)); | |
| 311 | + ufs_renesas_indirect_poll(hba, 7, 0x41, 0, BIT(7)); | |
| 312 | + /* end of phy setup */ | |
| 313 | + | |
| 314 | + ufs_renesas_init_enable_timer(hba, timer_val); | |
| 315 | +} | |
| 316 | + | |
| 317 | +static void ufs_renesas_r8a779f0_init_step3_add(struct ufs_hba *hba, bool assert) | |
| 318 | +{ | |
| 319 | + u32 val_2x = 0, val_3x = 0, val_4x = 0; | |
| 320 | + | |
| 321 | + if (assert) { | |
| 322 | + val_2x = 0x0001; | |
| 323 | + val_3x = 0x0003; | |
| 324 | + val_4x = 0x0001; | |
| 320 | 325 | } |
| 326 | + | |
| 327 | + ufs_renesas_reset_indirect_write(hba, 7, 0x20, val_2x); | |
| 328 | + ufs_renesas_reset_indirect_write(hba, 7, 0x4a, val_4x); | |
| 329 | + ufs_renesas_reset_indirect_write(hba, 7, 0x35, val_3x); | |
| 330 | + ufs_renesas_reset_indirect_update(hba); | |
| 331 | + ufs_renesas_reset_indirect_write(hba, 7, 0x21, val_2x); | |
| 332 | + ufs_renesas_reset_indirect_write(hba, 7, 0x4b, val_4x); | |
| 333 | + ufs_renesas_reset_indirect_write(hba, 7, 0x36, val_3x); | |
| 334 | + ufs_renesas_reset_indirect_update(hba); | |
| 321 | 335 | } |
| 322 | 336 | |
| 323 | −static void ufs_renesas_pre_init(struct ufs_hba *hba) | |
| 337 | +static void ufs_renesas_r8a779f0_pre_init(struct ufs_hba *hba) | |
| 324 | 338 | { |
| 325 | − const struct ufs_renesas_init_param *p = ufs_param; | |
| 326 | − unsigned int i; | |
| 339 | + struct ufs_renesas_priv *priv = ufshcd_get_variant(hba); | |
| 340 | + u32 timer_val; | |
| 341 | + u32 data; | |
| 342 | + int i; | |
| 343 | + | |
| 344 | + /* This setting is for SERIES B */ | |
| 345 | + ufs_renesas_init_step1_to_3(hba, true); | |
| 346 | + | |
| 347 | + ufs_renesas_r8a779f0_init_step3_add(hba, true); | |
| 348 | + ufs_renesas_reset_indirect_write(hba, 7, 0x5f, 0x0063); | |
| 349 | + ufs_renesas_reset_indirect_update(hba); | |
| 350 | + ufs_renesas_reset_indirect_write(hba, 7, 0x60, 0x0003); | |
| 351 | + ufs_renesas_reset_indirect_update(hba); | |
| 352 | + ufs_renesas_reset_indirect_write(hba, 7, 0x5b, 0x00a6); | |
| 353 | + ufs_renesas_reset_indirect_update(hba); | |
| 354 | + ufs_renesas_reset_indirect_write(hba, 7, 0x5c, 0x0003); | |
| 355 | + ufs_renesas_reset_indirect_update(hba); | |
| 356 | + ufs_renesas_r8a779f0_init_step3_add(hba, false); | |
| 357 | + | |
| 358 | + ufs_renesas_init_step4_to_6(hba); | |
| 359 | + | |
| 360 | + timer_val = ufs_renesas_init_disable_timer(hba); | |
| 361 | + | |
| 362 | + ufs_renesas_indirect_write(hba, 1, 0x01, 0x001f); | |
| 363 | + ufs_renesas_indirect_write(hba, 7, 0x5d, 0x0014); | |
| 364 | + ufs_renesas_indirect_write(hba, 7, 0x5e, 0x0014); | |
| 365 | + ufs_renesas_indirect_write(hba, 7, 0x0d, 0x0007); | |
| 366 | + ufs_renesas_indirect_write(hba, 7, 0x0e, 0x0007); | |
| 367 | + | |
| 368 | + ufs_renesas_indirect_poll(hba, 7, 0x3c, 0, BIT(7)); | |
| 369 | + ufs_renesas_indirect_poll(hba, 7, 0x4c, 0, BIT(4)); | |
| 370 | + | |
| 371 | + ufs_renesas_indirect_write(hba, 1, 0x32, 0x0080); | |
| 372 | + ufs_renesas_indirect_write(hba, 1, 0x1f, 0x0001); | |
| 373 | + ufs_renesas_indirect_write(hba, 1, 0x2c, 0x0001); | |
| 374 | + ufs_renesas_indirect_write(hba, 1, 0x32, 0x0087); | |
| 375 | + | |
| 376 | + ufs_renesas_indirect_write(hba, 1, 0x4d, priv->calib[2]); | |
| 377 | + ufs_renesas_indirect_write(hba, 1, 0x4e, priv->calib[3]); | |
| 378 | + ufs_renesas_indirect_write(hba, 1, 0x0d, 0x0006); | |
| 379 | + ufs_renesas_indirect_write(hba, 1, 0x0e, 0x0007); | |
| 380 | + ufs_renesas_write_phy(hba, 0x0028, priv->calib[3]); | |
| 381 | + ufs_renesas_write_phy(hba, 0x4014, priv->calib[3]); | |
| 382 | + | |
| 383 | + ufs_renesas_set_phy(hba, 0x401c, BIT(2)); | |
| 384 | + | |
| 385 | + ufs_renesas_write_phy(hba, 0x4000, priv->calib[6]); | |
| 386 | + ufs_renesas_write_phy(hba, 0x4001, priv->calib[7]); | |
| 387 | + | |
| 388 | + ufs_renesas_indirect_write(hba, 1, 0x14, 0x0001); | |
| 389 | + | |
| 390 | + ufs_renesas_init_compensation_and_slicers(hba); | |
| 391 | + | |
| 392 | + ufs_renesas_indirect_write(hba, 7, 0x79, 0x0000); | |
| 393 | + ufs_renesas_indirect_write(hba, 7, 0x24, 0x000c); | |
| 394 | + ufs_renesas_indirect_write(hba, 7, 0x25, 0x000c); | |
| 395 | + ufs_renesas_indirect_write(hba, 7, 0x62, 0x00c0); | |
| 396 | + ufs_renesas_indirect_write(hba, 7, 0x63, 0x0001); | |
| 397 | + | |
| 398 | + for (i = 0; i < priv->fw->size / 2; i++) { | |
| 399 | + data = (priv->fw->data[i * 2 + 1] << 8) | priv->fw->data[i * 2]; | |
| 400 | + ufs_renesas_write_phy(hba, 0xc000 + i, data); | |
| 401 | + } | |
| 327 | 402 | |
| 328 | − for (i = 0; i < ARRAY_SIZE(ufs_param); i++) | |
| 329 | − ufs_renesas_reg_control(hba, &p[i]); | |
| 403 | + ufs_renesas_indirect_write(hba, 7, 0x0d, 0x0002); | |
| 404 | + ufs_renesas_indirect_write(hba, 7, 0x0e, 0x0007); | |
| 405 | + | |
| 406 | + ufs_renesas_indirect_write(hba, 7, 0x5d, 0x0014); | |
| 407 | + ufs_renesas_indirect_write(hba, 7, 0x5e, 0x0017); | |
| 408 | + ufs_renesas_indirect_write(hba, 7, 0x5d, 0x0004); | |
| 409 | + ufs_renesas_indirect_write(hba, 7, 0x5e, 0x0017); | |
| 410 | + ufs_renesas_indirect_poll(hba, 7, 0x55, 0, BIT(6)); | |
| 411 | + ufs_renesas_indirect_poll(hba, 7, 0x41, 0, BIT(7)); | |
| 412 | + | |
| 413 | + ufs_renesas_init_enable_timer(hba, timer_val); | |
| 330 | 414 | } |
| 331 | 415 | |
| 332 | 416 | static int ufs_renesas_hce_enable_notify(struct ufs_hba *hba, |
| @@ -338,7 +422,7 @@ static int ufs_renesas_hce_enable_notify(struct ufs_hba *hba, · 5 unmodified lines | ||
| 338 | 422 | return 0; |
| 339 | 423 | |
| 340 | 424 | if (status == PRE_CHANGE) |
| 341 | − ufs_renesas_pre_init(hba); | |
| 425 | + priv->pre_init(hba); | |
| 342 | 426 | |
| 343 | 427 | priv->initialized = true; |
| 344 | 428 | |
| @@ -356,20 +440,78 @@ static int ufs_renesas_setup_clocks(struct ufs_hba *hba, bool on, · 11 unmodified lines | ||
| 356 | 440 | return 0; |
| 357 | 441 | } |
| 358 | 442 | |
| 443 | +static const struct soc_device_attribute ufs_fallback[] = { | |
| 444 | + { .soc_id = "r8a779f0", .revision = "ES1.[01]" }, | |
| 445 | + { /* Sentinel */ } | |
| 446 | +}; | |
| 447 | + | |
| 359 | 448 | static int ufs_renesas_init(struct ufs_hba *hba) |
| 360 | 449 | { |
| 450 | + const struct soc_device_attribute *attr; | |
| 451 | + struct nvmem_cell *cell = NULL; | |
| 452 | + struct device *dev = hba->dev; | |
| 361 | 453 | struct ufs_renesas_priv *priv; |
| 454 | + u8 *data = NULL; | |
| 455 | + size_t len; | |
| 456 | + int ret; | |
| 362 | 457 | |
| 363 | − priv = devm_kzalloc(hba->dev, sizeof(*priv), GFP_KERNEL); | |
| 458 | + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
| 364 | 459 | if (!priv) |
| 365 | 460 | return -ENOMEM; |
| 366 | 461 | ufshcd_set_variant(hba, priv); |
| 367 | 462 | |
| 368 | 463 | hba->quirks |= UFSHCD_QUIRK_HIBERN_FASTAUTO; |
| 369 | 464 | |
| 465 | + attr = soc_device_match(ufs_fallback); | |
| 466 | + if (attr) | |
| 467 | + goto fallback; | |
| 468 | + | |
| 469 | + ret = request_firmware(&priv->fw, UFS_RENESAS_FIRMWARE_NAME, dev); | |
| 470 | + if (ret) { | |
| 471 | + dev_warn(dev, "Failed to load firmware\n"); | |
| 472 | + goto fallback; | |
| 473 | + } | |
| 474 | + | |
| 475 | + cell = nvmem_cell_get(dev, "calibration"); | |
| 476 | + if (IS_ERR(cell)) { | |
| 477 | + dev_warn(dev, "No calibration data specified\n"); | |
| 478 | + goto fallback; | |
| 479 | + } | |
| 480 | + | |
| 481 | + data = nvmem_cell_read(cell, &len); | |
| 482 | + if (IS_ERR(data)) { | |
| 483 | + dev_warn(dev, "Failed to read calibration data: %pe\n", data); | |
| 484 | + goto fallback; | |
| 485 | + } | |
| 486 | + | |
| 487 | + if (len != EFUSE_CALIB_SIZE) { | |
| 488 | + dev_warn(dev, "Invalid calibration data size %zu\n", len); | |
| 489 | + goto fallback; | |
| 490 | + } | |
| 491 | + | |
| 492 | + memcpy(priv->calib, data, EFUSE_CALIB_SIZE); | |
| 493 | + priv->pre_init = ufs_renesas_r8a779f0_pre_init; | |
| 494 | + goto out; | |
| 495 | + | |
| 496 | +fallback: | |
| 497 | + dev_info(dev, "Using ES1.0 init code\n"); | |
| 498 | + priv->pre_init = ufs_renesas_r8a779f0_es10_pre_init; | |
| 499 | + | |
| 500 | +out: | |
| 501 | + kfree(data); | |
| 502 | + if (!IS_ERR_OR_NULL(cell)) | |
| 503 | + nvmem_cell_put(cell); | |
| 504 | + | |
| 370 | 505 | return 0; |
| 371 | 506 | } |
| 372 | 507 | |
| 508 | +static void ufs_renesas_exit(struct ufs_hba *hba) | |
| 509 | +{ | |
| 510 | + struct ufs_renesas_priv *priv = ufshcd_get_variant(hba); | |
| 511 | + | |
| 512 | + release_firmware(priv->fw); | |
| 513 | +} | |
| 514 | + | |
| 373 | 515 | static int ufs_renesas_set_dma_mask(struct ufs_hba *hba) |
| 374 | 516 | { |
| 375 | 517 | return dma_set_mask_and_coherent(hba->dev, DMA_BIT_MASK(32)); |
| @@ -378,6 +520,7 @@ static int ufs_renesas_set_dma_mask(struct ufs_hba *hba) · 2 unmodified lines | ||
| 378 | 520 | static const struct ufs_hba_variant_ops ufs_renesas_vops = { |
| 379 | 521 | .name = "renesas", |
| 380 | 522 | .init = ufs_renesas_init, |
| 523 | + .exit = ufs_renesas_exit, | |
| 381 | 524 | .set_dma_mask = ufs_renesas_set_dma_mask, |
| 382 | 525 | .setup_clocks = ufs_renesas_setup_clocks, |
| 383 | 526 | .hce_enable_notify = ufs_renesas_hce_enable_notify, |
| @@ -0,0 +1,354 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +/* | |
| 3 | + * Rockchip UFS Host Controller driver | |
| 4 | + * | |
| 5 | + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/clk.h> | |
| 9 | +#include <linux/gpio.h> | |
| 10 | +#include <linux/mfd/syscon.h> | |
| 11 | +#include <linux/of.h> | |
| 12 | +#include <linux/platform_device.h> | |
| 13 | +#include <linux/pm_domain.h> | |
| 14 | +#include <linux/pm_wakeup.h> | |
| 15 | +#include <linux/regmap.h> | |
| 16 | +#include <linux/reset.h> | |
| 17 | + | |
| 18 | +#include <ufs/ufshcd.h> | |
| 19 | +#include <ufs/unipro.h> | |
| 20 | +#include "ufshcd-pltfrm.h" | |
| 21 | +#include "ufs-rockchip.h" | |
| 22 | + | |
| 23 | +static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba, | |
| 24 | + enum ufs_notify_change_status status) | |
| 25 | +{ | |
| 26 | + int err = 0; | |
| 27 | + | |
| 28 | + if (status == POST_CHANGE) { | |
| 29 | + err = ufshcd_dme_reset(hba); | |
| 30 | + if (err) | |
| 31 | + return err; | |
| 32 | + | |
| 33 | + err = ufshcd_dme_enable(hba); | |
| 34 | + if (err) | |
| 35 | + return err; | |
| 36 | + | |
| 37 | + return ufshcd_vops_phy_initialization(hba); | |
| 38 | + } | |
| 39 | + | |
| 40 | + return 0; | |
| 41 | +} | |
| 42 | + | |
| 43 | +static void ufs_rockchip_set_pm_lvl(struct ufs_hba *hba) | |
| 44 | +{ | |
| 45 | + hba->rpm_lvl = UFS_PM_LVL_5; | |
| 46 | + hba->spm_lvl = UFS_PM_LVL_5; | |
| 47 | +} | |
| 48 | + | |
| 49 | +static int ufs_rockchip_rk3576_phy_init(struct ufs_hba *hba) | |
| 50 | +{ | |
| 51 | + struct ufs_rockchip_host *host = ufshcd_get_variant(hba); | |
| 52 | + | |
| 53 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(PA_LOCAL_TX_LCC_ENABLE, 0x0), 0x0); | |
| 54 | + /* enable the mphy DME_SET cfg */ | |
| 55 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MPHY_CFG, 0x0), MPHY_CFG_ENABLE); | |
| 56 | + for (int i = 0; i < 2; i++) { | |
| 57 | + /* Configuration M - TX */ | |
| 58 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD, SEL_TX_LANE0 + i), 0x06); | |
| 59 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD_EN, SEL_TX_LANE0 + i), 0x02); | |
| 60 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_VALUE, SEL_TX_LANE0 + i), 0x44); | |
| 61 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE1, SEL_TX_LANE0 + i), 0xe6); | |
| 62 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE2, SEL_TX_LANE0 + i), 0x07); | |
| 63 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_TASE_VALUE, SEL_TX_LANE0 + i), 0x93); | |
| 64 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_BASE_NVALUE, SEL_TX_LANE0 + i), 0xc9); | |
| 65 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_POWER_SAVING_CTRL, SEL_TX_LANE0 + i), 0x00); | |
| 66 | + /* Configuration M - RX */ | |
| 67 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD, SEL_RX_LANE0 + i), 0x06); | |
| 68 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD_EN, SEL_RX_LANE0 + i), 0x00); | |
| 69 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE, SEL_RX_LANE0 + i), 0x58); | |
| 70 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE1, SEL_RX_LANE0 + i), 0x8c); | |
| 71 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE2, SEL_RX_LANE0 + i), 0x02); | |
| 72 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_OPTION, SEL_RX_LANE0 + i), 0xf6); | |
| 73 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_POWER_SAVING_CTRL, SEL_RX_LANE0 + i), 0x69); | |
| 74 | + } | |
| 75 | + | |
| 76 | + /* disable the mphy DME_SET cfg */ | |
| 77 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MPHY_CFG, 0x0), MPHY_CFG_DISABLE); | |
| 78 | + | |
| 79 | + ufs_sys_writel(host->mphy_base, 0x80, CMN_REG23); | |
| 80 | + ufs_sys_writel(host->mphy_base, 0xB5, TRSV0_REG14); | |
| 81 | + ufs_sys_writel(host->mphy_base, 0xB5, TRSV1_REG14); | |
| 82 | + | |
| 83 | + ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG15); | |
| 84 | + ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG15); | |
| 85 | + | |
| 86 | + ufs_sys_writel(host->mphy_base, 0x38, TRSV0_REG08); | |
| 87 | + ufs_sys_writel(host->mphy_base, 0x38, TRSV1_REG08); | |
| 88 | + | |
| 89 | + ufs_sys_writel(host->mphy_base, 0x50, TRSV0_REG29); | |
| 90 | + ufs_sys_writel(host->mphy_base, 0x50, TRSV1_REG29); | |
| 91 | + | |
| 92 | + ufs_sys_writel(host->mphy_base, 0x80, TRSV0_REG2E); | |
| 93 | + ufs_sys_writel(host->mphy_base, 0x80, TRSV1_REG2E); | |
| 94 | + | |
| 95 | + ufs_sys_writel(host->mphy_base, 0x18, TRSV0_REG3C); | |
| 96 | + ufs_sys_writel(host->mphy_base, 0x18, TRSV1_REG3C); | |
| 97 | + | |
| 98 | + ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG16); | |
| 99 | + ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG16); | |
| 100 | + | |
| 101 | + ufs_sys_writel(host->mphy_base, 0x20, TRSV0_REG17); | |
| 102 | + ufs_sys_writel(host->mphy_base, 0x20, TRSV1_REG17); | |
| 103 | + | |
| 104 | + ufs_sys_writel(host->mphy_base, 0xC0, TRSV0_REG18); | |
| 105 | + ufs_sys_writel(host->mphy_base, 0xC0, TRSV1_REG18); | |
| 106 | + | |
| 107 | + ufs_sys_writel(host->mphy_base, 0x03, CMN_REG25); | |
| 108 | + | |
| 109 | + ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG3D); | |
| 110 | + ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG3D); | |
| 111 | + | |
| 112 | + ufs_sys_writel(host->mphy_base, 0xC0, CMN_REG23); | |
| 113 | + udelay(1); | |
| 114 | + ufs_sys_writel(host->mphy_base, 0x00, CMN_REG23); | |
| 115 | + | |
| 116 | + usleep_range(200, 250); | |
| 117 | + /* start link up */ | |
| 118 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_TX_ENDIAN, 0), 0x0); | |
| 119 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_RX_ENDIAN, 0), 0x0); | |
| 120 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID, 0), 0x0); | |
| 121 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID_VALID, 0), 0x1); | |
| 122 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_PEERDEVICEID, 0), 0x1); | |
| 123 | + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_CONNECTIONSTATE, 0), 0x1); | |
| 124 | + | |
| 125 | + return 0; | |
| 126 | +} | |
| 127 | + | |
| 128 | +static int ufs_rockchip_common_init(struct ufs_hba *hba) | |
| 129 | +{ | |
| 130 | + struct device *dev = hba->dev; | |
| 131 | + struct platform_device *pdev = to_platform_device(dev); | |
| 132 | + struct ufs_rockchip_host *host; | |
| 133 | + int err; | |
| 134 | + | |
| 135 | + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); | |
| 136 | + if (!host) | |
| 137 | + return -ENOMEM; | |
| 138 | + | |
| 139 | + host->ufs_sys_ctrl = devm_platform_ioremap_resource_byname(pdev, "hci_grf"); | |
| 140 | + if (IS_ERR(host->ufs_sys_ctrl)) | |
| 141 | + return dev_err_probe(dev, PTR_ERR(host->ufs_sys_ctrl), | |
| 142 | + "Failed to map HCI system control registers\n"); | |
| 143 | + | |
| 144 | + host->ufs_phy_ctrl = devm_platform_ioremap_resource_byname(pdev, "mphy_grf"); | |
| 145 | + if (IS_ERR(host->ufs_phy_ctrl)) | |
| 146 | + return dev_err_probe(dev, PTR_ERR(host->ufs_phy_ctrl), | |
| 147 | + "Failed to map mphy system control registers\n"); | |
| 148 | + | |
| 149 | + host->mphy_base = devm_platform_ioremap_resource_byname(pdev, "mphy"); | |
| 150 | + if (IS_ERR(host->mphy_base)) | |
| 151 | + return dev_err_probe(dev, PTR_ERR(host->mphy_base), | |
| 152 | + "Failed to map mphy base registers\n"); | |
| 153 | + | |
| 154 | + host->rst = devm_reset_control_array_get_exclusive(dev); | |
| 155 | + if (IS_ERR(host->rst)) | |
| 156 | + return dev_err_probe(dev, PTR_ERR(host->rst), | |
| 157 | + "failed to get reset control\n"); | |
| 158 | + | |
| 159 | + reset_control_assert(host->rst); | |
| 160 | + udelay(1); | |
| 161 | + reset_control_deassert(host->rst); | |
| 162 | + | |
| 163 | + host->ref_out_clk = devm_clk_get_enabled(dev, "ref_out"); | |
| 164 | + if (IS_ERR(host->ref_out_clk)) | |
| 165 | + return dev_err_probe(dev, PTR_ERR(host->ref_out_clk), | |
| 166 | + "ref_out clock unavailable\n"); | |
| 167 | + | |
| 168 | + host->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | |
| 169 | + if (IS_ERR(host->rst_gpio)) | |
| 170 | + return dev_err_probe(dev, PTR_ERR(host->rst_gpio), | |
| 171 | + "failed to get reset gpio\n"); | |
| 172 | + | |
| 173 | + err = devm_clk_bulk_get_all_enabled(dev, &host->clks); | |
| 174 | + if (err < 0) | |
| 175 | + return dev_err_probe(dev, err, "failed to enable clocks\n"); | |
| 176 | + | |
| 177 | + host->hba = hba; | |
| 178 | + | |
| 179 | + ufshcd_set_variant(hba, host); | |
| 180 | + | |
| 181 | + return 0; | |
| 182 | +} | |
| 183 | + | |
| 184 | +static int ufs_rockchip_rk3576_init(struct ufs_hba *hba) | |
| 185 | +{ | |
| 186 | + struct device *dev = hba->dev; | |
| 187 | + int ret; | |
| 188 | + | |
| 189 | + hba->quirks = UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING; | |
| 190 | + | |
| 191 | + /* Enable BKOPS when suspend */ | |
| 192 | + hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; | |
| 193 | + /* Enable putting device into deep sleep */ | |
| 194 | + hba->caps |= UFSHCD_CAP_DEEPSLEEP; | |
| 195 | + /* Enable devfreq of UFS */ | |
| 196 | + hba->caps |= UFSHCD_CAP_CLK_SCALING; | |
| 197 | + /* Enable WriteBooster */ | |
| 198 | + hba->caps |= UFSHCD_CAP_WB_EN; | |
| 199 | + | |
| 200 | + /* Set the default desired pm level in case no users set via sysfs */ | |
| 201 | + ufs_rockchip_set_pm_lvl(hba); | |
| 202 | + | |
| 203 | + ret = ufs_rockchip_common_init(hba); | |
| 204 | + if (ret) | |
| 205 | + return dev_err_probe(dev, ret, "ufs common init fail\n"); | |
| 206 | + | |
| 207 | + return 0; | |
| 208 | +} | |
| 209 | + | |
| 210 | +static int ufs_rockchip_device_reset(struct ufs_hba *hba) | |
| 211 | +{ | |
| 212 | + struct ufs_rockchip_host *host = ufshcd_get_variant(hba); | |
| 213 | + | |
| 214 | + gpiod_set_value_cansleep(host->rst_gpio, 1); | |
| 215 | + usleep_range(20, 25); | |
| 216 | + | |
| 217 | + gpiod_set_value_cansleep(host->rst_gpio, 0); | |
| 218 | + usleep_range(20, 25); | |
| 219 | + | |
| 220 | + return 0; | |
| 221 | +} | |
| 222 | + | |
| 223 | +static const struct ufs_hba_variant_ops ufs_hba_rk3576_vops = { | |
| 224 | + .name = "rk3576", | |
| 225 | + .init = ufs_rockchip_rk3576_init, | |
| 226 | + .device_reset = ufs_rockchip_device_reset, | |
| 227 | + .hce_enable_notify = ufs_rockchip_hce_enable_notify, | |
| 228 | + .phy_initialization = ufs_rockchip_rk3576_phy_init, | |
| 229 | +}; | |
| 230 | + | |
| 231 | +static const struct of_device_id ufs_rockchip_of_match[] = { | |
| 232 | + { .compatible = "rockchip,rk3576-ufshc", .data = &ufs_hba_rk3576_vops }, | |
| 233 | + { }, | |
| 234 | +}; | |
| 235 | +MODULE_DEVICE_TABLE(of, ufs_rockchip_of_match); | |
| 236 | + | |
| 237 | +static int ufs_rockchip_probe(struct platform_device *pdev) | |
| 238 | +{ | |
| 239 | + struct device *dev = &pdev->dev; | |
| 240 | + const struct ufs_hba_variant_ops *vops; | |
| 241 | + int err; | |
| 242 | + | |
| 243 | + vops = device_get_match_data(dev); | |
| 244 | + if (!vops) | |
| 245 | + return dev_err_probe(dev, -ENODATA, "ufs_hba_variant_ops not defined.\n"); | |
| 246 | + | |
| 247 | + err = ufshcd_pltfrm_init(pdev, vops); | |
| 248 | + if (err) | |
| 249 | + return dev_err_probe(dev, err, "ufshcd_pltfrm_init failed\n"); | |
| 250 | + | |
| 251 | + return 0; | |
| 252 | +} | |
| 253 | + | |
| 254 | +static void ufs_rockchip_remove(struct platform_device *pdev) | |
| 255 | +{ | |
| 256 | + ufshcd_pltfrm_remove(pdev); | |
| 257 | +} | |
| 258 | + | |
| 259 | +#ifdef CONFIG_PM | |
| 260 | +static int ufs_rockchip_runtime_suspend(struct device *dev) | |
| 261 | +{ | |
| 262 | + struct ufs_hba *hba = dev_get_drvdata(dev); | |
| 263 | + struct ufs_rockchip_host *host = ufshcd_get_variant(hba); | |
| 264 | + | |
| 265 | + clk_disable_unprepare(host->ref_out_clk); | |
| 266 | + | |
| 267 | + /* Do not power down the genpd if rpm_lvl is less than level 5 */ | |
| 268 | + dev_pm_genpd_rpm_always_on(dev, hba->rpm_lvl < UFS_PM_LVL_5); | |
| 269 | + | |
| 270 | + return ufshcd_runtime_suspend(dev); | |
| 271 | +} | |
| 272 | + | |
| 273 | +static int ufs_rockchip_runtime_resume(struct device *dev) | |
| 274 | +{ | |
| 275 | + struct ufs_hba *hba = dev_get_drvdata(dev); | |
| 276 | + struct ufs_rockchip_host *host = ufshcd_get_variant(hba); | |
| 277 | + int err; | |
| 278 | + | |
| 279 | + err = clk_prepare_enable(host->ref_out_clk); | |
| 280 | + if (err) { | |
| 281 | + dev_err(hba->dev, "failed to enable ref_out clock %d\n", err); | |
| 282 | + return err; | |
| 283 | + } | |
| 284 | + | |
| 285 | + reset_control_assert(host->rst); | |
| 286 | + udelay(1); | |
| 287 | + reset_control_deassert(host->rst); | |
| 288 | + | |
| 289 | + return ufshcd_runtime_resume(dev); | |
| 290 | +} | |
| 291 | +#endif | |
| 292 | + | |
| 293 | +#ifdef CONFIG_PM_SLEEP | |
| 294 | +static int ufs_rockchip_system_suspend(struct device *dev) | |
| 295 | +{ | |
| 296 | + struct ufs_hba *hba = dev_get_drvdata(dev); | |
| 297 | + struct ufs_rockchip_host *host = ufshcd_get_variant(hba); | |
| 298 | + int err; | |
| 299 | + | |
| 300 | + /* | |
| 301 | + * If spm_lvl is less than level 5, it means we need to keep the host | |
| 302 | + * controller in powered-on state. So device_set_awake_path() is | |
| 303 | + * calling pm core to notify the genpd provider to meet this requirement | |
| 304 | + */ | |
| 305 | + if (hba->spm_lvl < UFS_PM_LVL_5) | |
| 306 | + device_set_awake_path(dev); | |
| 307 | + | |
| 308 | + err = ufshcd_system_suspend(dev); | |
| 309 | + if (err) { | |
| 310 | + dev_err(hba->dev, "UFSHCD system suspend failed %d\n", err); | |
| 311 | + return err; | |
| 312 | + } | |
| 313 | + | |
| 314 | + clk_disable_unprepare(host->ref_out_clk); | |
| 315 | + | |
| 316 | + return 0; | |
| 317 | +} | |
| 318 | + | |
| 319 | +static int ufs_rockchip_system_resume(struct device *dev) | |
| 320 | +{ | |
| 321 | + struct ufs_hba *hba = dev_get_drvdata(dev); | |
| 322 | + struct ufs_rockchip_host *host = ufshcd_get_variant(hba); | |
| 323 | + int err; | |
| 324 | + | |
| 325 | + err = clk_prepare_enable(host->ref_out_clk); | |
| 326 | + if (err) { | |
| 327 | + dev_err(hba->dev, "failed to enable ref_out clock %d\n", err); | |
| 328 | + return err; | |
| 329 | + } | |
| 330 | + | |
| 331 | + return ufshcd_system_resume(dev); | |
| 332 | +} | |
| 333 | +#endif | |
| 334 | + | |
| 335 | +static const struct dev_pm_ops ufs_rockchip_pm_ops = { | |
| 336 | + SET_SYSTEM_SLEEP_PM_OPS(ufs_rockchip_system_suspend, ufs_rockchip_system_resume) | |
| 337 | + SET_RUNTIME_PM_OPS(ufs_rockchip_runtime_suspend, ufs_rockchip_runtime_resume, NULL) | |
| 338 | + .prepare = ufshcd_suspend_prepare, | |
| 339 | + .complete = ufshcd_resume_complete, | |
| 340 | +}; | |
| 341 | + | |
| 342 | +static struct platform_driver ufs_rockchip_pltform = { | |
| 343 | + .probe = ufs_rockchip_probe, | |
| 344 | + .remove = ufs_rockchip_remove, | |
| 345 | + .driver = { | |
| 346 | + .name = "ufshcd-rockchip", | |
| 347 | + .pm = &ufs_rockchip_pm_ops, | |
| 348 | + .of_match_table = ufs_rockchip_of_match, | |
| 349 | + }, | |
| 350 | +}; | |
| 351 | +module_platform_driver(ufs_rockchip_pltform); | |
| 352 | + | |
| 353 | +MODULE_LICENSE("GPL"); | |
| 354 | +MODULE_DESCRIPTION("Rockchip UFS Host Driver"); | |
| @@ -0,0 +1,90 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * Rockchip UFS Host Controller driver | |
| 4 | + * | |
| 5 | + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#ifndef _UFS_ROCKCHIP_H_ | |
| 9 | +#define _UFS_ROCKCHIP_H_ | |
| 10 | + | |
| 11 | +#define SEL_TX_LANE0 0x0 | |
| 12 | +#define SEL_TX_LANE1 0x1 | |
| 13 | +#define SEL_TX_LANE2 0x2 | |
| 14 | +#define SEL_TX_LANE3 0x3 | |
| 15 | +#define SEL_RX_LANE0 0x4 | |
| 16 | +#define SEL_RX_LANE1 0x5 | |
| 17 | +#define SEL_RX_LANE2 0x6 | |
| 18 | +#define SEL_RX_LANE3 0x7 | |
| 19 | + | |
| 20 | +#define VND_TX_CLK_PRD 0xAA | |
| 21 | +#define VND_TX_CLK_PRD_EN 0xA9 | |
| 22 | +#define VND_TX_LINERESET_PVALUE2 0xAB | |
| 23 | +#define VND_TX_LINERESET_PVALUE1 0xAC | |
| 24 | +#define VND_TX_LINERESET_VALUE 0xAD | |
| 25 | +#define VND_TX_BASE_NVALUE 0x93 | |
| 26 | +#define VND_TX_TASE_VALUE 0x94 | |
| 27 | +#define VND_TX_POWER_SAVING_CTRL 0x7F | |
| 28 | +#define VND_RX_CLK_PRD 0x12 | |
| 29 | +#define VND_RX_CLK_PRD_EN 0x11 | |
| 30 | +#define VND_RX_LINERESET_PVALUE2 0x1B | |
| 31 | +#define VND_RX_LINERESET_PVALUE1 0x1C | |
| 32 | +#define VND_RX_LINERESET_VALUE 0x1D | |
| 33 | +#define VND_RX_LINERESET_OPTION 0x25 | |
| 34 | +#define VND_RX_POWER_SAVING_CTRL 0x2F | |
| 35 | +#define VND_RX_SAVE_DET_CTRL 0x1E | |
| 36 | + | |
| 37 | +#define CMN_REG23 0x8C | |
| 38 | +#define CMN_REG25 0x94 | |
| 39 | +#define TRSV0_REG08 0xE0 | |
| 40 | +#define TRSV1_REG08 0x220 | |
| 41 | +#define TRSV0_REG14 0x110 | |
| 42 | +#define TRSV1_REG14 0x250 | |
| 43 | +#define TRSV0_REG15 0x134 | |
| 44 | +#define TRSV1_REG15 0x274 | |
| 45 | +#define TRSV0_REG16 0x128 | |
| 46 | +#define TRSV1_REG16 0x268 | |
| 47 | +#define TRSV0_REG17 0x12C | |
| 48 | +#define TRSV1_REG17 0x26c | |
| 49 | +#define TRSV0_REG18 0x120 | |
| 50 | +#define TRSV1_REG18 0x260 | |
| 51 | +#define TRSV0_REG29 0x164 | |
| 52 | +#define TRSV1_REG29 0x2A4 | |
| 53 | +#define TRSV0_REG2E 0x178 | |
| 54 | +#define TRSV1_REG2E 0x2B8 | |
| 55 | +#define TRSV0_REG3C 0x1B0 | |
| 56 | +#define TRSV1_REG3C 0x2F0 | |
| 57 | +#define TRSV0_REG3D 0x1B4 | |
| 58 | +#define TRSV1_REG3D 0x2F4 | |
| 59 | + | |
| 60 | +#define MPHY_CFG 0x200 | |
| 61 | +#define MPHY_CFG_ENABLE 0x40 | |
| 62 | +#define MPHY_CFG_DISABLE 0x0 | |
| 63 | + | |
| 64 | +#define MIB_T_DBG_CPORT_TX_ENDIAN 0xc022 | |
| 65 | +#define MIB_T_DBG_CPORT_RX_ENDIAN 0xc023 | |
| 66 | + | |
| 67 | +struct ufs_rockchip_host { | |
| 68 | + struct ufs_hba *hba; | |
| 69 | + void __iomem *ufs_phy_ctrl; | |
| 70 | + void __iomem *ufs_sys_ctrl; | |
| 71 | + void __iomem *mphy_base; | |
| 72 | + struct gpio_desc *rst_gpio; | |
| 73 | + struct reset_control *rst; | |
| 74 | + struct clk *ref_out_clk; | |
| 75 | + struct clk_bulk_data *clks; | |
| 76 | + uint64_t caps; | |
| 77 | +}; | |
| 78 | + | |
| 79 | +#define ufs_sys_writel(base, val, reg) \ | |
| 80 | + writel((val), (base) + (reg)) | |
| 81 | +#define ufs_sys_readl(base, reg) readl((base) + (reg)) | |
| 82 | +#define ufs_sys_set_bits(base, mask, reg) \ | |
| 83 | + ufs_sys_writel( \ | |
| 84 | + (base), ((mask) | (ufs_sys_readl((base), (reg)))), (reg)) | |
| 85 | +#define ufs_sys_ctrl_clr_bits(base, mask, reg) \ | |
| 86 | + ufs_sys_writel((base), \ | |
| 87 | + ((~(mask)) & (ufs_sys_readl((base), (reg)))), \ | |
| 88 | + (reg)) | |
| 89 | + | |
| 90 | +#endif /* _UFS_ROCKCHIP_H_ */ | |
| @@ -160,9 +160,9 @@ static int ufs_sprd_common_init(struct ufs_hba *hba) · 159 unmodified lines | ||
| 160 | 160 | } |
| 161 | 161 | |
| 162 | 162 | static int sprd_ufs_pwr_change_notify(struct ufs_hba *hba, |
| 163 | − enum ufs_notify_change_status status, | |
| 164 | − struct ufs_pa_layer_attr *dev_max_params, | |
| 165 | − struct ufs_pa_layer_attr *dev_req_params) | |
| 163 | + enum ufs_notify_change_status status, | |
| 164 | + const struct ufs_pa_layer_attr *dev_max_params, | |
| 165 | + struct ufs_pa_layer_attr *dev_req_params) | |
| 166 | 166 | { |
| 167 | 167 | struct ufs_sprd_host *host = ufshcd_get_variant(hba); |
| 168 | 168 | |
| @@ -157,7 +157,7 @@ static int ufs_intel_set_lanes(struct ufs_hba *hba, u32 lanes) · 156 unmodified lines | ||
| 157 | 157 | |
| 158 | 158 | static int ufs_intel_lkf_pwr_change_notify(struct ufs_hba *hba, |
| 159 | 159 | enum ufs_notify_change_status status, |
| 160 | − struct ufs_pa_layer_attr *dev_max_params, | |
| 160 | + const struct ufs_pa_layer_attr *dev_max_params, | |
| 161 | 161 | struct ufs_pa_layer_attr *dev_req_params) |
| 162 | 162 | { |
| 163 | 163 | int err = 0; |
| @@ -2142,8 +2142,8 @@ static int do_scsi_command(struct fsg_common *common) · 2141 unmodified lines | ||
| 2142 | 2142 | * of Posix locks. |
| 2143 | 2143 | */ |
| 2144 | 2144 | case FORMAT_UNIT: |
| 2145 | − case RELEASE: | |
| 2146 | − case RESERVE: | |
| 2145 | + case RELEASE_6: | |
| 2146 | + case RESERVE_6: | |
| 2147 | 2147 | case SEND_DIAGNOSTIC: |
| 2148 | 2148 | |
| 2149 | 2149 | default: |
| @@ -58,8 +58,8 @@ void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb) · 57 unmodified lines | ||
| 58 | 58 | case INQUIRY: what = "INQUIRY"; break; |
| 59 | 59 | case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break; |
| 60 | 60 | case MODE_SELECT: what = "MODE_SELECT"; break; |
| 61 | − case RESERVE: what = "RESERVE"; break; | |
| 62 | − case RELEASE: what = "RELEASE"; break; | |
| 61 | + case RESERVE_6: what = "RESERVE"; break; | |
| 62 | + case RELEASE_6: what = "RELEASE"; break; | |
| 63 | 63 | case COPY: what = "COPY"; break; |
| 64 | 64 | case ERASE: what = "ERASE"; break; |
| 65 | 65 | case MODE_SENSE: what = "MODE_SENSE"; break; |
| @@ -15,7 +15,6 @@ · 14 unmodified lines | ||
| 15 | 15 | struct iscsi_tcp_conn; |
| 16 | 16 | struct iscsi_segment; |
| 17 | 17 | struct sk_buff; |
| 18 | −struct ahash_request; | |
| 19 | 18 | |
| 20 | 19 | typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *, |
| 21 | 20 | struct iscsi_segment *); |
| @@ -27,7 +26,7 @@ struct iscsi_segment { · 5 unmodified lines | ||
| 27 | 26 | unsigned int total_size; |
| 28 | 27 | unsigned int total_copied; |
| 29 | 28 | |
| 30 | − struct ahash_request *hash; | |
| 29 | + u32 *crcp; | |
| 31 | 30 | unsigned char padbuf[ISCSI_PAD_LEN]; |
| 32 | 31 | unsigned char recv_digest[ISCSI_DIGEST_SIZE]; |
| 33 | 32 | unsigned char digest[ISCSI_DIGEST_SIZE]; |
| @@ -61,8 +60,8 @@ struct iscsi_tcp_conn { · 27 unmodified lines | ||
| 61 | 60 | * stop to terminate */ |
| 62 | 61 | /* control data */ |
| 63 | 62 | struct iscsi_tcp_recv in; /* TCP receive context */ |
| 64 | − /* CRC32C (Rx) LLD should set this is they do not offload */ | |
| 65 | − struct ahash_request *rx_hash; | |
| 63 | + /* CRC32C (Rx) LLD should set this if they do not offload */ | |
| 64 | + u32 *rx_crcp; | |
| 66 | 65 | }; |
| 67 | 66 | |
| 68 | 67 | struct iscsi_tcp_task { |
| @@ -99,18 +98,15 @@ extern void iscsi_tcp_segment_unmap(struct iscsi_segment *segment); · 30 unmodified lines | ||
| 99 | 98 | |
| 100 | 99 | extern void iscsi_segment_init_linear(struct iscsi_segment *segment, |
| 101 | 100 | void *data, size_t size, |
| 102 | − iscsi_segment_done_fn_t *done, | |
| 103 | − struct ahash_request *hash); | |
| 101 | + iscsi_segment_done_fn_t *done, u32 *crcp); | |
| 104 | 102 | extern int |
| 105 | 103 | iscsi_segment_seek_sg(struct iscsi_segment *segment, |
| 106 | 104 | struct scatterlist *sg_list, unsigned int sg_count, |
| 107 | 105 | unsigned int offset, size_t size, |
| 108 | − iscsi_segment_done_fn_t *done, | |
| 109 | − struct ahash_request *hash); | |
| 106 | + iscsi_segment_done_fn_t *done, u32 *crcp); | |
| 110 | 107 | |
| 111 | 108 | /* digest helpers */ |
| 112 | −extern void iscsi_tcp_dgst_header(struct ahash_request *hash, const void *hdr, | |
| 113 | − size_t hdrlen, | |
| 109 | +extern void iscsi_tcp_dgst_header(const void *hdr, size_t hdrlen, | |
| 114 | 110 | unsigned char digest[ISCSI_DIGEST_SIZE]); |
| 115 | 111 | extern struct iscsi_cls_conn * |
| 116 | 112 | iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size, |
| @@ -247,6 +247,9 @@ struct scsi_device { · 246 unmodified lines | ||
| 247 | 247 | unsigned int queue_stopped; /* request queue is quiesced */ |
| 248 | 248 | bool offline_already; /* Device offline message logged */ |
| 249 | 249 | |
| 250 | + unsigned int ua_new_media_ctr; /* Counter for New Media UNIT ATTENTIONs */ | |
| 251 | + unsigned int ua_por_ctr; /* Counter for Power On / Reset UAs */ | |
| 252 | + | |
| 250 | 253 | atomic_t disk_events_disable_depth; /* disable depth for disk events */ |
| 251 | 254 | |
| 252 | 255 | DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ |
| @@ -684,6 +687,12 @@ static inline int scsi_device_busy(struct scsi_device *sdev) · 431 unmodified lines | ||
| 684 | 687 | return sbitmap_weight(&sdev->budget_map); |
| 685 | 688 | } |
| 686 | 689 | |
| 690 | +/* Macros to access the UNIT ATTENTION counters */ | |
| 691 | +#define scsi_get_ua_new_media_ctr(sdev) \ | |
| 692 | + ((const unsigned int)(sdev->ua_new_media_ctr)) | |
| 693 | +#define scsi_get_ua_por_ctr(sdev) \ | |
| 694 | + ((const unsigned int)(sdev->ua_por_ctr)) | |
| 695 | + | |
| 687 | 696 | #define MODULE_ALIAS_SCSI_DEVICE(type) \ |
| 688 | 697 | MODULE_ALIAS("scsi:t-" __stringify(type) "*") |
| 689 | 698 | #define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x" |
| @@ -33,8 +33,8 @@ · 32 unmodified lines | ||
| 33 | 33 | #define INQUIRY 0x12 |
| 34 | 34 | #define RECOVER_BUFFERED_DATA 0x14 |
| 35 | 35 | #define MODE_SELECT 0x15 |
| 36 | −#define RESERVE 0x16 | |
| 37 | −#define RELEASE 0x17 | |
| 36 | +#define RESERVE_6 0x16 | |
| 37 | +#define RELEASE_6 0x17 | |
| 38 | 38 | #define COPY 0x18 |
| 39 | 39 | #define ERASE 0x19 |
| 40 | 40 | #define MODE_SENSE 0x1a |
| @@ -29,8 +29,8 @@ · 28 unmodified lines | ||
| 29 | 29 | scsi_opcode_name(INQUIRY), \ |
| 30 | 30 | scsi_opcode_name(RECOVER_BUFFERED_DATA), \ |
| 31 | 31 | scsi_opcode_name(MODE_SELECT), \ |
| 32 | − scsi_opcode_name(RESERVE), \ | |
| 33 | − scsi_opcode_name(RELEASE), \ | |
| 32 | + scsi_opcode_name(RESERVE_6), \ | |
| 33 | + scsi_opcode_name(RELEASE_6), \ | |
| 34 | 34 | scsi_opcode_name(COPY), \ |
| 35 | 35 | scsi_opcode_name(ERASE), \ |
| 36 | 36 | scsi_opcode_name(MODE_SENSE), \ |
| @@ -31,8 +31,8 @@ · 30 unmodified lines | ||
| 31 | 31 | scsi_opcode_name(INQUIRY), \ |
| 32 | 32 | scsi_opcode_name(RECOVER_BUFFERED_DATA), \ |
| 33 | 33 | scsi_opcode_name(MODE_SELECT), \ |
| 34 | − scsi_opcode_name(RESERVE), \ | |
| 35 | − scsi_opcode_name(RELEASE), \ | |
| 34 | + scsi_opcode_name(RESERVE_6), \ | |
| 35 | + scsi_opcode_name(RELEASE_6), \ | |
| 36 | 36 | scsi_opcode_name(COPY), \ |
| 37 | 37 | scsi_opcode_name(ERASE), \ |
| 38 | 38 | scsi_opcode_name(MODE_SENSE), \ |
| @@ -1,276 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ | |
| 2 | −/* | |
| 3 | − * CXL Flash Device Driver | |
| 4 | − * | |
| 5 | − * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation | |
| 6 | − * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation | |
| 7 | − * | |
| 8 | − * Copyright (C) 2015 IBM Corporation | |
| 9 | − * | |
| 10 | − * This program is free software; you can redistribute it and/or | |
| 11 | − * modify it under the terms of the GNU General Public License | |
| 12 | − * as published by the Free Software Foundation; either version | |
| 13 | − * 2 of the License, or (at your option) any later version. | |
| 14 | − */ | |
| 15 | − | |
| 16 | −#ifndef _CXLFLASH_IOCTL_H | |
| 17 | −#define _CXLFLASH_IOCTL_H | |
| 18 | − | |
| 19 | −#include <linux/types.h> | |
| 20 | − | |
| 21 | −/* | |
| 22 | − * Structure and definitions for all CXL Flash ioctls | |
| 23 | − */ | |
| 24 | −#define CXLFLASH_WWID_LEN 16 | |
| 25 | − | |
| 26 | −/* | |
| 27 | − * Structure and flag definitions CXL Flash superpipe ioctls | |
| 28 | − */ | |
| 29 | − | |
| 30 | −#define DK_CXLFLASH_VERSION_0 0 | |
| 31 | − | |
| 32 | −struct dk_cxlflash_hdr { | |
| 33 | − __u16 version; /* Version data */ | |
| 34 | − __u16 rsvd[3]; /* Reserved for future use */ | |
| 35 | − __u64 flags; /* Input flags */ | |
| 36 | − __u64 return_flags; /* Returned flags */ | |
| 37 | −}; | |
| 38 | − | |
| 39 | −/* | |
| 40 | − * Return flag definitions available to all superpipe ioctls | |
| 41 | − * | |
| 42 | − * Similar to the input flags, these are grown from the bottom-up with the | |
| 43 | − * intention that ioctl-specific return flag definitions would grow from the | |
| 44 | − * top-down, allowing the two sets to co-exist. While not required/enforced | |
| 45 | − * at this time, this provides future flexibility. | |
| 46 | − */ | |
| 47 | −#define DK_CXLFLASH_ALL_PORTS_ACTIVE 0x0000000000000001ULL | |
| 48 | −#define DK_CXLFLASH_APP_CLOSE_ADAP_FD 0x0000000000000002ULL | |
| 49 | −#define DK_CXLFLASH_CONTEXT_SQ_CMD_MODE 0x0000000000000004ULL | |
| 50 | − | |
| 51 | −/* | |
| 52 | − * General Notes: | |
| 53 | − * ------------- | |
| 54 | − * The 'context_id' field of all ioctl structures contains the context | |
| 55 | − * identifier for a context in the lower 32-bits (upper 32-bits are not | |
| 56 | − * to be used when identifying a context to the AFU). That said, the value | |
| 57 | − * in its entirety (all 64-bits) is to be treated as an opaque cookie and | |
| 58 | − * should be presented as such when issuing ioctls. | |
| 59 | − */ | |
| 60 | − | |
| 61 | −/* | |
| 62 | − * DK_CXLFLASH_ATTACH Notes: | |
| 63 | − * ------------------------ | |
| 64 | − * Read/write access permissions are specified via the O_RDONLY, O_WRONLY, | |
| 65 | − * and O_RDWR flags defined in the fcntl.h header file. | |
| 66 | − * | |
| 67 | − * A valid adapter file descriptor (fd >= 0) is only returned on the initial | |
| 68 | − * attach (successful) of a context. When a context is shared(reused), the user | |
| 69 | − * is expected to already 'know' the adapter file descriptor associated with the | |
| 70 | − * context. | |
| 71 | − */ | |
| 72 | −#define DK_CXLFLASH_ATTACH_REUSE_CONTEXT 0x8000000000000000ULL | |
| 73 | − | |
| 74 | −struct dk_cxlflash_attach { | |
| 75 | − struct dk_cxlflash_hdr hdr; /* Common fields */ | |
| 76 | − __u64 num_interrupts; /* Requested number of interrupts */ | |
| 77 | − __u64 context_id; /* Returned context */ | |
| 78 | − __u64 mmio_size; /* Returned size of MMIO area */ | |
| 79 | − __u64 block_size; /* Returned block size, in bytes */ | |
| 80 | − __u64 adap_fd; /* Returned adapter file descriptor */ | |
| 81 | − __u64 last_lba; /* Returned last LBA on the device */ | |
| 82 | − __u64 max_xfer; /* Returned max transfer size, blocks */ | |
| 83 | − __u64 reserved[8]; /* Reserved for future use */ | |
| 84 | −}; | |
| 85 | − | |
| 86 | −struct dk_cxlflash_detach { | |
| 87 | − struct dk_cxlflash_hdr hdr; /* Common fields */ | |
| 88 | − __u64 context_id; /* Context to detach */ | |
| 89 | − __u64 reserved[8]; /* Reserved for future use */ | |
| 90 | −}; | |
| 91 | − | |
| 92 | −struct dk_cxlflash_udirect { | |
| 93 | − struct dk_cxlflash_hdr hdr; /* Common fields */ | |
| 94 | − __u64 context_id; /* Context to own physical resources */ | |
| 95 | − __u64 rsrc_handle; /* Returned resource handle */ | |
| 96 | − __u64 last_lba; /* Returned last LBA on the device */ | |
| 97 | − __u64 reserved[8]; /* Reserved for future use */ | |
| 98 | −}; | |
| 99 | − | |
| 100 | −#define DK_CXLFLASH_UVIRTUAL_NEED_WRITE_SAME 0x8000000000000000ULL | |
| 101 | − | |
| 102 | −struct dk_cxlflash_uvirtual { | |
| 103 | − struct dk_cxlflash_hdr hdr; /* Common fields */ | |
| 104 | − __u64 context_id; /* Context to own virtual resources */ | |
| 105 | − __u64 lun_size; /* Requested size, in 4K blocks */ | |
| 106 | − __u64 rsrc_handle; /* Returned resource handle */ | |
| 107 | − __u64 last_lba; /* Returned last LBA of LUN */ | |
| 108 | − __u64 reserved[8]; /* Reserved for future use */ | |
| 109 | −}; | |
| 110 | − | |
| 111 | −struct dk_cxlflash_release { | |
| 112 | − struct dk_cxlflash_hdr hdr; /* Common fields */ | |
| 113 | − __u64 context_id; /* Context owning resources */ | |
| 114 | − __u64 rsrc_handle; /* Resource handle to release */ | |
| 115 | − __u64 reserved[8]; /* Reserved for future use */ | |
| 116 | −}; | |
| 117 | − | |
| 118 | −struct dk_cxlflash_resize { | |
| 119 | − struct dk_cxlflash_hdr hdr; /* Common fields */ | |
| 120 | − __u64 context_id; /* Context owning resources */ | |
| 121 | − __u64 rsrc_handle; /* Resource handle of LUN to resize */ | |
| 122 | − __u64 req_size; /* New requested size, in 4K blocks */ | |
| 123 | − __u64 last_lba; /* Returned last LBA of LUN */ | |
| 124 | − __u64 reserved[8]; /* Reserved for future use */ | |
| 125 | −}; | |
| 126 | − | |
| 127 | −struct dk_cxlflash_clone { | |
| 128 | − struct dk_cxlflash_hdr hdr; /* Common fields */ | |
| 129 | − __u64 context_id_src; /* Context to clone from */ | |
| 130 | − __u64 context_id_dst; /* Context to clone to */ | |
| 131 | − __u64 adap_fd_src; /* Source context adapter fd */ | |
| 132 | − __u64 reserved[8]; /* Reserved for future use */ | |
| 133 | −}; | |
| 134 | − | |
| 135 | −#define DK_CXLFLASH_VERIFY_SENSE_LEN 18 | |
| 136 | −#define DK_CXLFLASH_VERIFY_HINT_SENSE 0x8000000000000000ULL | |
| 137 | − | |
| 138 | −struct dk_cxlflash_verify { | |
| 139 | − struct dk_cxlflash_hdr hdr; /* Common fields */ | |
| 140 | − __u64 context_id; /* Context owning resources to verify */ | |
| 141 | − __u64 rsrc_handle; /* Resource handle of LUN */ | |
| 142 | − __u64 hint; /* Reasons for verify */ | |
| 143 | − __u64 last_lba; /* Returned last LBA of device */ | |
| 144 | − __u8 sense_data[DK_CXLFLASH_VERIFY_SENSE_LEN]; /* SCSI sense data */ | |
| 145 | − __u8 pad[6]; /* Pad to next 8-byte boundary */ | |
| 146 | − __u64 reserved[8]; /* Reserved for future use */ | |
| 147 | −}; | |
| 148 | − | |
| 149 | −#define DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET 0x8000000000000000ULL | |
| 150 | − | |
| 151 | −struct dk_cxlflash_recover_afu { | |
| 152 | − struct dk_cxlflash_hdr hdr; /* Common fields */ | |
| 153 | − __u64 reason; /* Reason for recovery request */ | |
| 154 | − __u64 context_id; /* Context to recover / updated ID */ | |
| 155 | − __u64 mmio_size; /* Returned size of MMIO area */ | |
| 156 | − __u64 adap_fd; /* Returned adapter file descriptor */ | |
| 157 | − __u64 reserved[8]; /* Reserved for future use */ | |
| 158 | −}; | |
| 159 | − | |
| 160 | −#define DK_CXLFLASH_MANAGE_LUN_WWID_LEN CXLFLASH_WWID_LEN | |
| 161 | −#define DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE 0x8000000000000000ULL | |
| 162 | −#define DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE 0x4000000000000000ULL | |
| 163 | −#define DK_CXLFLASH_MANAGE_LUN_ALL_PORTS_ACCESSIBLE 0x2000000000000000ULL | |
| 164 | − | |
| 165 | −struct dk_cxlflash_manage_lun { | |
| 166 | − struct dk_cxlflash_hdr hdr; /* Common fields */ | |
| 167 | − __u8 wwid[DK_CXLFLASH_MANAGE_LUN_WWID_LEN]; /* Page83 WWID, NAA-6 */ | |
| 168 | − __u64 reserved[8]; /* Rsvd, future use */ | |
| 169 | −}; | |
| 170 | − | |
| 171 | −union cxlflash_ioctls { | |
| 172 | − struct dk_cxlflash_attach attach; | |
| 173 | − struct dk_cxlflash_detach detach; | |
| 174 | − struct dk_cxlflash_udirect udirect; | |
| 175 | − struct dk_cxlflash_uvirtual uvirtual; | |
| 176 | − struct dk_cxlflash_release release; | |
| 177 | − struct dk_cxlflash_resize resize; | |
| 178 | − struct dk_cxlflash_clone clone; | |
| 179 | − struct dk_cxlflash_verify verify; | |
| 180 | − struct dk_cxlflash_recover_afu recover_afu; | |
| 181 | − struct dk_cxlflash_manage_lun manage_lun; | |
| 182 | −}; | |
| 183 | − | |
| 184 | −#define MAX_CXLFLASH_IOCTL_SZ (sizeof(union cxlflash_ioctls)) | |
| 185 | − | |
| 186 | −#define CXL_MAGIC 0xCA | |
| 187 | −#define CXL_IOWR(_n, _s) _IOWR(CXL_MAGIC, _n, struct _s) | |
| 188 | − | |
| 189 | −/* | |
| 190 | − * CXL Flash superpipe ioctls start at base of the reserved CXL_MAGIC | |
| 191 | − * region (0x80) and grow upwards. | |
| 192 | − */ | |
| 193 | −#define DK_CXLFLASH_ATTACH CXL_IOWR(0x80, dk_cxlflash_attach) | |
| 194 | −#define DK_CXLFLASH_USER_DIRECT CXL_IOWR(0x81, dk_cxlflash_udirect) | |
| 195 | −#define DK_CXLFLASH_RELEASE CXL_IOWR(0x82, dk_cxlflash_release) | |
| 196 | −#define DK_CXLFLASH_DETACH CXL_IOWR(0x83, dk_cxlflash_detach) | |
| 197 | −#define DK_CXLFLASH_VERIFY CXL_IOWR(0x84, dk_cxlflash_verify) | |
| 198 | −#define DK_CXLFLASH_RECOVER_AFU CXL_IOWR(0x85, dk_cxlflash_recover_afu) | |
| 199 | −#define DK_CXLFLASH_MANAGE_LUN CXL_IOWR(0x86, dk_cxlflash_manage_lun) | |
| 200 | −#define DK_CXLFLASH_USER_VIRTUAL CXL_IOWR(0x87, dk_cxlflash_uvirtual) | |
| 201 | −#define DK_CXLFLASH_VLUN_RESIZE CXL_IOWR(0x88, dk_cxlflash_resize) | |
| 202 | −#define DK_CXLFLASH_VLUN_CLONE CXL_IOWR(0x89, dk_cxlflash_clone) | |
| 203 | − | |
| 204 | −/* | |
| 205 | − * Structure and flag definitions CXL Flash host ioctls | |
| 206 | − */ | |
| 207 | − | |
| 208 | −#define HT_CXLFLASH_VERSION_0 0 | |
| 209 | − | |
| 210 | −struct ht_cxlflash_hdr { | |
| 211 | − __u16 version; /* Version data */ | |
| 212 | − __u16 subcmd; /* Sub-command */ | |
| 213 | − __u16 rsvd[2]; /* Reserved for future use */ | |
| 214 | − __u64 flags; /* Input flags */ | |
| 215 | − __u64 return_flags; /* Returned flags */ | |
| 216 | −}; | |
| 217 | − | |
| 218 | −/* | |
| 219 | − * Input flag definitions available to all host ioctls | |
| 220 | − * | |
| 221 | − * These are grown from the bottom-up with the intention that ioctl-specific | |
| 222 | − * input flag definitions would grow from the top-down, allowing the two sets | |
| 223 | − * to co-exist. While not required/enforced at this time, this provides future | |
| 224 | − * flexibility. | |
| 225 | − */ | |
| 226 | −#define HT_CXLFLASH_HOST_READ 0x0000000000000000ULL | |
| 227 | −#define HT_CXLFLASH_HOST_WRITE 0x0000000000000001ULL | |
| 228 | − | |
| 229 | −#define HT_CXLFLASH_LUN_PROVISION_SUBCMD_CREATE_LUN 0x0001 | |
| 230 | −#define HT_CXLFLASH_LUN_PROVISION_SUBCMD_DELETE_LUN 0x0002 | |
| 231 | −#define HT_CXLFLASH_LUN_PROVISION_SUBCMD_QUERY_PORT 0x0003 | |
| 232 | − | |
| 233 | −struct ht_cxlflash_lun_provision { | |
| 234 | − struct ht_cxlflash_hdr hdr; /* Common fields */ | |
| 235 | − __u16 port; /* Target port for provision request */ | |
| 236 | − __u16 reserved16[3]; /* Reserved for future use */ | |
| 237 | − __u64 size; /* Size of LUN (4K blocks) */ | |
| 238 | − __u64 lun_id; /* SCSI LUN ID */ | |
| 239 | − __u8 wwid[CXLFLASH_WWID_LEN];/* Page83 WWID, NAA-6 */ | |
| 240 | − __u64 max_num_luns; /* Maximum number of LUNs provisioned */ | |
| 241 | − __u64 cur_num_luns; /* Current number of LUNs provisioned */ | |
| 242 | − __u64 max_cap_port; /* Total capacity for port (4K blocks) */ | |
| 243 | − __u64 cur_cap_port; /* Current capacity for port (4K blocks) */ | |
| 244 | − __u64 reserved[8]; /* Reserved for future use */ | |
| 245 | −}; | |
| 246 | − | |
| 247 | −#define HT_CXLFLASH_AFU_DEBUG_MAX_DATA_LEN 262144 /* 256K */ | |
| 248 | −#define HT_CXLFLASH_AFU_DEBUG_SUBCMD_LEN 12 | |
| 249 | −struct ht_cxlflash_afu_debug { | |
| 250 | − struct ht_cxlflash_hdr hdr; /* Common fields */ | |
| 251 | − __u8 reserved8[4]; /* Reserved for future use */ | |
| 252 | − __u8 afu_subcmd[HT_CXLFLASH_AFU_DEBUG_SUBCMD_LEN]; /* AFU subcommand, | |
24 more lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.