libxcoder  5.3.1
ni_nvme.c
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * Copyright (C) 2022 NETINT Technologies
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18  * SOFTWARE.
19  *
20  ******************************************************************************/
21 
22 /*!*****************************************************************************
23  * \file ni_nvme.c
24  *
25  * \brief Private definitions for interfacing with NETINT video processing
26  * devices over NVMe
27  ******************************************************************************/
28 
29 #include <stdint.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <errno.h>
33 
34 #ifdef _WIN32
35  #include <windows.h>
36 #include <ntddstor.h>
37 #include <winioctl.h>
38 #include <Ntddscsi.h>
39 #elif __linux__ || __APPLE__
40 #if __linux__
41 #include <linux/types.h>
42 #endif
43 #include <sys/ioctl.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46 #endif
47 
48 #include "ni_nvme.h"
49 #include "ni_util.h"
50 
51 #define ROUND_TO_ULONG(x) ni_round_up(x,sizeof(uint32_t))
52 
53 /*!******************************************************************************
54  * \brief Check f/w error return code, and if it's a fatal one, terminate
55  * application's decoding/encoding processing by sending
56  * self a SIGTERM signal. Application shall handle this gracefully.
57  *
58  * \param
59  *
60  * \return 1 (or non-zero) if need to terminate, 0 otherwise
61  ******************************************************************************/
62 ni_retcode_t ni_nvme_check_error_code(int rc, int opcode, uint32_t xcoder_type,
63  uint32_t hw_id, uint32_t *p_instance_id)
64 {
65  const char* type_str = GET_XCODER_DEVICE_TYPE_STR(xcoder_type);
66 
67  switch (rc)
68  {
69  case NI_RETCODE_SUCCESS:
70  return NI_RETCODE_SUCCESS;
73  "Hardware %u %s experiencing insufficient resource (instance %u opcode %x)!\n",
74  hw_id, type_str, *p_instance_id, opcode);
78  "Hardware %u %s failed to open session due to invalid "
79  "combination of "
80  "parameter values given (instance %u opcode %x)!\n",
81  hw_id, type_str, *p_instance_id, opcode);
85  "Hardware %u %s got stream error (instance %u opcode %x)!\n",
86  hw_id, type_str, *p_instance_id, opcode);
90  "Error: Hardware %u %s doesn't support Interlaced video (instance %u opcode %x)!\n",
91  hw_id, type_str, *p_instance_id, opcode);
93  default:
94  if (xcoder_type == NI_DEVICE_TYPE_AI)
95  {
96  ni_log(NI_LOG_ERROR, "Error rc = %d, %s, op = %02x, %s %u.0x%x\n",
97  rc, ni_ai_errno_to_str(rc), opcode,
98  type_str, hw_id, *p_instance_id);
99  } else
100  {
102  "Error rc = 0x%x, op = %02x, %s %u.%u terminating?\n", rc,
103  opcode, type_str, hw_id,
104  *p_instance_id);
105  }
106  return NI_RETCODE_FAILURE;
107  }
108 }
109 
110 #ifdef __linux__
111 
112 /*!******************************************************************************
113  * \brief Submit a nvme admin passthrough command to the driver
114  *
115  * \param
116  *
117  * \return
118  *******************************************************************************/
119 int32_t
120 ni_nvme_send_admin_pass_through_command(ni_device_handle_t handle,
121  ni_nvme_passthrough_cmd_t *p_cmd)
122 {
123  ni_log(NI_LOG_TRACE, "%s: handle=%d\n", __func__, handle);
124  ni_log(NI_LOG_TRACE, "opcode: %02x\n", p_cmd->opcode);
125  ni_log(NI_LOG_TRACE, "flags: %02x\n", p_cmd->flags);
126  ni_log(NI_LOG_TRACE, "rsvd1: %04x\n", p_cmd->rsvd1);
127  ni_log(NI_LOG_TRACE, "nsid: %08x\n", p_cmd->nsid);
128  ni_log(NI_LOG_TRACE, "cdw2: %08x\n", p_cmd->cdw2);
129  ni_log(NI_LOG_TRACE, "cdw3: %08x\n", p_cmd->cdw3);
130  //ni_log(NI_LOG_TRACE, "metadata: %"PRIx64"\n", p_cmd->metadata);
131  //ni_log(NI_LOG_TRACE, "addr: %"PRIx64"\n", p_cmd->addr);
132  ni_log(NI_LOG_TRACE, "metadata_len: %08x\n", p_cmd->metadata_len);
133  ni_log(NI_LOG_TRACE, "data_len: %08x\n", p_cmd->data_len);
134  ni_log(NI_LOG_TRACE, "cdw10: %08x\n", p_cmd->cdw10);
135  ni_log(NI_LOG_TRACE, "cdw11: %08x\n", p_cmd->cdw11);
136  ni_log(NI_LOG_TRACE, "cdw12: %08x\n", p_cmd->cdw12);
137  ni_log(NI_LOG_TRACE, "cdw13: %08x\n", p_cmd->cdw13);
138  ni_log(NI_LOG_TRACE, "cdw14: %08x\n", p_cmd->cdw14);
139  ni_log(NI_LOG_TRACE, "cdw15: %08x\n", p_cmd->cdw15);
140  ni_log(NI_LOG_TRACE, "timeout_ms: %08x\n", p_cmd->timeout_ms);
141  ni_log(NI_LOG_TRACE, "result: %08x\n", p_cmd->result);
142 
143  return ioctl(handle, NVME_IOCTL_ADMIN_CMD, p_cmd);
144 }
145 
146 /*!******************************************************************************
147  * \brief Submit a nvme io passthrough command to the driver
148  *
149  * \param
150  *
151  * \return
152  *******************************************************************************/
153 int32_t ni_nvme_send_io_pass_through_command(ni_device_handle_t handle,
154  ni_nvme_passthrough_cmd_t *p_cmd)
155 {
156  ni_log(NI_LOG_TRACE, "%s: handle=%d\n", __func__, handle);
157  ni_log(NI_LOG_TRACE, "opcode: %02x\n", p_cmd->opcode);
158  ni_log(NI_LOG_TRACE, "flags: %02x\n", p_cmd->flags);
159  ni_log(NI_LOG_TRACE, "rsvd1: %04x\n", p_cmd->rsvd1);
160  ni_log(NI_LOG_TRACE, "nsid: %08x\n", p_cmd->nsid);
161  ni_log(NI_LOG_TRACE, "cdw2: %08x\n", p_cmd->cdw2);
162  ni_log(NI_LOG_TRACE, "cdw3: %08x\n", p_cmd->cdw3);
163  // ni_log(NI_LOG_TRACE, "metadata: %"PRIx64"\n", p_cmd->metadata);
164  // ni_log(NI_LOG_TRACE, "addr: %"PRIx64"\n", p_cmd->addr);
165  ni_log(NI_LOG_TRACE, "metadata_len: %08x\n", p_cmd->metadata_len);
166  ni_log(NI_LOG_TRACE, "data_len: %08x\n", p_cmd->data_len);
167  ni_log(NI_LOG_TRACE, "cdw10: %08x\n", p_cmd->cdw10);
168  ni_log(NI_LOG_TRACE, "cdw11: %08x\n", p_cmd->cdw11);
169  ni_log(NI_LOG_TRACE, "cdw12: %08x\n", p_cmd->cdw12);
170  ni_log(NI_LOG_TRACE, "cdw13: %08x\n", p_cmd->cdw13);
171  ni_log(NI_LOG_TRACE, "cdw14: %08x\n", p_cmd->cdw14);
172  ni_log(NI_LOG_TRACE, "cdw15: %08x\n", p_cmd->cdw15);
173  ni_log(NI_LOG_TRACE, "timeout_ms: %08x\n", p_cmd->timeout_ms);
174  ni_log(NI_LOG_TRACE, "result: %08x\n", p_cmd->result);
175 
176  return ioctl(handle, NVME_IOCTL_IO_CMD, p_cmd);
177 }
178 
179 #endif //__linux__ defined
180 
181 #ifdef _WIN32
182 
183 #define ROUND_TO_DWORD_PTR(x) ni_round_up(x,sizeof(PDWORD))
184 
185 static ni_retcode_t ni_nvme_get_identity(HANDLE handle, HANDLE event_handle,
186  PVOID p_identity)
187 {
188  uint32_t lba = IDENTIFY_DEVICE_R;
189  DWORD data_len = NI_NVME_IDENTITY_CMD_DATA_SZ;
190  return ni_nvme_send_read_cmd(handle, event_handle, p_identity, data_len,
191  lba);
192 }
193 
195 (
196  char ni_devices[][NI_MAX_DEVICE_NAME_LEN],
197  int max_handles
198 )
199 {
200  TCHAR port_name_buffer[NI_MAX_DEVICE_NAME_LEN] = {0};
201  LPTSTR p_scsi_path = "\\\\.\\PHYSICALDRIVE";
202  LPCTSTR p_format = "%s%d";
203  PUCHAR p_buffer = NULL;
204  ni_retcode_t rc;
205  CHAR firmware_revision[8] = {0};
206  int device_count = 0;
207  int scsi_port = 0;
208  DWORD retval;
209  DWORD data_len = NI_NVME_IDENTITY_CMD_DATA_SZ;
210  CHAR serial_num[20] = {0};
211  CHAR model_name[40] = {0};
212  ni_nvme_identity_t *p_ni_identity = NULL;
213 
214  ni_log(NI_LOG_DEBUG, "Searching for NETINT NVMe devices ...\n\n");
215 
216  if (ni_posix_memalign((void **)(&p_buffer), sysconf(_SC_PAGESIZE),
217  data_len))
218  {
219  ni_log(NI_LOG_ERROR, "ERROR %d: %s() alloc buffer failed\n", NI_ERRNO,
220  __func__);
222  }
223 
224  memset(p_buffer, 0, data_len);
225  ni_event_handle_t event_handle = NULL;
226 
227  for (scsi_port = 0; scsi_port < max_handles; scsi_port++)
228  {
229  wsprintf(port_name_buffer, p_format, p_scsi_path, scsi_port);
230  HANDLE handle =
231  CreateFile(port_name_buffer, GENERIC_READ | GENERIC_WRITE,
232  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
233  FILE_ATTRIBUTE_NORMAL, NULL);
234  if (INVALID_HANDLE_VALUE == handle)
235  {
236  retval = NI_ERRNO;
237  ni_log(NI_LOG_DEBUG, "Bad handle, ret=%d\n", retval);
238  }
239  else
240  {
241  DISK_GEOMETRY_EX disk_geometry = { 0 };
242  DWORD bytes_returned;
243  if (DeviceIoControl(
244  handle,
245  IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
246  NULL,
247  0,
248  &disk_geometry,
249  sizeof(disk_geometry),
250  &bytes_returned,
251  NULL))
252  {
253  LONGLONG disk_size = disk_geometry.DiskSize.QuadPart;
255  {
256  ZeroMemory(p_buffer, data_len);
257  rc = ni_nvme_get_identity(handle, event_handle, p_buffer);
258  }
259  else
260  {
261  ni_log(NI_LOG_DEBUG,"port %s size: %.2f is not NETINT card\n",
262  port_name_buffer, (double)disk_size);
263  rc = NI_RETCODE_FAILURE;
264  }
265  } else {
266  rc = NI_RETCODE_FAILURE;
267  }
268 
269  if (NI_RETCODE_SUCCESS == rc)
270  {
271  ni_nvme_identity_t *p_ni_id_data =
272  (ni_nvme_identity_t *)p_buffer;
274  "Identity information retrieved from the device "
275  "at port %s\n",
276  port_name_buffer);
278  " VID: 0x%x \n SSVID: 0x%x \n",
279  p_ni_id_data->ui16Vid, p_ni_id_data->ui16Ssvid);
280 
281  if (NETINT_PCI_VENDOR_ID == p_ni_id_data->ui16Vid &&
282  NETINT_PCI_VENDOR_ID == p_ni_id_data->ui16Ssvid &&
283  is_supported_xcoder(p_ni_id_data->device_is_xcoder))
284  {
285  /* make the fw revision/model name/serial num to string*/
286  memset(firmware_revision, 0, sizeof(firmware_revision));
287  memcpy(firmware_revision, p_ni_id_data->ai8Fr,
288  sizeof(firmware_revision));
289  firmware_revision[sizeof(firmware_revision) - 1] = 0;
290 
291  memset(model_name, 0, sizeof(model_name));
292  memcpy(model_name, p_ni_id_data->ai8Mn, sizeof(model_name));
293  model_name[sizeof(model_name) - 1] = 0;
294 
295  memset(serial_num, 0, sizeof(serial_num));
296  memcpy(serial_num, p_ni_id_data->ai8Sn, sizeof(serial_num));
297  serial_num[sizeof(serial_num) - 1] = 0;
298  ni_log(NI_LOG_DEBUG, " Device Model: %s \n",
299  model_name);
300  ni_log(NI_LOG_DEBUG, " Firmware Rev: %s \n",
301  firmware_revision);
302  ni_log(NI_LOG_DEBUG, " Serial Number: %s \n",
303  serial_num);
305  "NETINT %s NVMe video transcoder identified "
306  "at port %s\n\n",
307  model_name, port_name_buffer);
308  strncpy(ni_devices[device_count++], port_name_buffer,
310  } else
311  {
313  "Device at port %s %d is not a NETINT NVMe device\n",
314  port_name_buffer, p_ni_id_data->device_is_xcoder);
315  }
316  CloseHandle(handle);
317  } else
318  {
319  retval = NI_ERRNO;
320  ni_log(
321  NI_LOG_DEBUG,
322  "Device at port %s is not a NETINT NVMe device,ret=%d\n\n",
323  port_name_buffer, retval);
324  CloseHandle(handle);
325  }
326  }
327  } // end for loop
328 
329  if (p_buffer)
330  {
331  ni_aligned_free(p_buffer);
332  }
333 
335  "Total Number of NETINT NVMe Transcoders identified: %d \n\n",
336  device_count);
337  return device_count;
338 }
339 
340 #endif //_WIN32 defined
341 
342 #ifndef XCODER_IO_RW_ENABLED
343 /*!******************************************************************************
344  * \brief Compose a nvme admin command
345  *
346  * \param
347  *
348  * \return
349  *******************************************************************************/
351  ni_device_handle_t handle,
352  ni_nvme_command_t *p_ni_nvme_cmd,
353  uint32_t data_len, void *p_data,
354  uint32_t *p_result)
355 {
356  int32_t rc = -1;
357 #ifdef _WIN32
358  //Windows inbox driver requires to send identity through different
359  //api than regular pass through commands
360  if (nvme_admin_cmd_identify == opcode)
361  {
362  rc = ni_nvme_get_identity(handle, NI_INVALID_EVENT_HANDLE, p_data);
363  *p_result = NI_RETCODE_SUCCESS;
364  }
365 #elif __APPLE__
366 #else
367  ni_nvme_passthrough_cmd_t nvme_cmd = {0};
368 
369  nvme_cmd.opcode = opcode;
370  nvme_cmd.cdw10 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw10);
371  nvme_cmd.cdw11 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw11);
372  nvme_cmd.cdw12 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw12);
373  nvme_cmd.cdw13 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw13);
374  nvme_cmd.cdw14 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw14);
375  nvme_cmd.cdw15 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw15);
376  nvme_cmd.addr = (__u64)ni_htonll((uintptr_t)p_data);
377  nvme_cmd.data_len = ni_htonl(data_len);
378 
379  rc = ni_nvme_send_admin_pass_through_command(handle, &nvme_cmd);
380 
381  *p_result = ni_htonl(nvme_cmd.result);
382 #endif
383 
384  ni_log(NI_LOG_DEBUG, "%s: handle=%" PRIx64 ", result=%08x, rc=%d\n",
385  __func__, (int64_t)handle, (uint32_t)(*p_result), rc);
386 
387  return rc;
388 }
389 
390 /*!******************************************************************************
391  * \brief Compose a nvme io command
392  *
393  * \param
394  *
395  * \return
396  *******************************************************************************/
397 int32_t ni_nvme_send_io_cmd(ni_nvme_opcode_t opcode, ni_device_handle_t handle,
398  ni_nvme_command_t *p_ni_nvme_cmd, uint32_t data_len,
399  void *p_data, uint32_t *p_result)
400 {
401  int32_t rc = -1;
402 #ifdef _WIN32
403 #elif __APPLE__
404 #else
405  ni_nvme_passthrough_cmd_t nvme_cmd;
406  //int32_t *p_addr = NULL;
407 
408  memset(&nvme_cmd, 0, sizeof(nvme_cmd));
409  nvme_cmd.opcode = opcode;
410  nvme_cmd.nsid = ni_htonl(1);
411  nvme_cmd.addr = (__u64)ni_htonll((uintptr_t)p_data);
412  nvme_cmd.data_len = ni_htonl(data_len);
413  nvme_cmd.cdw2 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw2);
414  nvme_cmd.cdw3 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw3);
415  nvme_cmd.cdw10 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw10);
416  nvme_cmd.cdw11 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw11);
417  nvme_cmd.cdw12 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw12);
418  nvme_cmd.cdw13 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw13);
419  nvme_cmd.cdw14 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw14);
420  nvme_cmd.cdw15 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw15);
421 
422  rc = ni_nvme_send_io_pass_through_command(handle, &nvme_cmd);
423 
424  //p_addr = &nvme_cmd.result;
425  //*!pResult = *p_addr;
426  *p_result = ni_htonl(nvme_cmd.result);
427 #endif
428 
429  ni_log(NI_LOG_DEBUG, "%s: handle=%" PRIx64 ", result=%08x, rc=%d\n",
430  __func__, (int64_t)handle, (uint32_t)(*p_result), rc);
431 
432  return rc;
433 }
434 #endif
435 
436 #ifdef __linux__
437 
438 /*!******************************************************************************
439  * \brief Compose a nvme io through admin command
440  *
441  * \param
442  *
443  * \return
444  *******************************************************************************/
446  ni_device_handle_t handle,
447  ni_nvme_command_t *p_ni_nvme_cmd,
448  uint32_t data_len, void *p_data,
449  uint32_t *p_result)
450 {
451  int32_t rc;
452  ni_nvme_passthrough_cmd_t nvme_cmd = {0};
453 
454  nvme_cmd.opcode = opcode;
455  nvme_cmd.nsid = ni_htonl(1);
456  nvme_cmd.addr = (__u64)ni_htonll((uintptr_t)p_data);
457  nvme_cmd.data_len = ni_htonl(data_len);
458  nvme_cmd.cdw10 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw10);
459  nvme_cmd.cdw11 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw11);
460  nvme_cmd.cdw12 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw12);
461  nvme_cmd.cdw13 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw13);
462  nvme_cmd.cdw14 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw14);
463  nvme_cmd.cdw15 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw15);
464 
465  rc = ni_nvme_send_admin_pass_through_command(handle, &nvme_cmd);
466 
467  //p_addr = &nvme_cmd.result;
468  //*!pResult = *p_addr;
469  *p_result = ni_htonl(nvme_cmd.result);
470 
471  ni_log(NI_LOG_DEBUG, "%s: handle=%d, result=%08x, rc=%d\n", __func__,
472  handle, *p_result, rc);
473 
474  return rc;
475 }
476 #endif //__linux__ defined
477 
478 /*!******************************************************************************
479  * \brief parse the lba opcode, subtype, option
480  * It's called only if a I/O read/write fails,
481  * so just use the print level "NI_LOG_ERROR" now.
482  *
483  * \param lba is 4k aligned
484  *
485  * \return
486  *******************************************************************************/
487 void ni_parse_lba(uint64_t lba)
488 {
489  uint64_t lba_high = (lba >> NI_INSTANCE_TYPE_OFFSET);
490  uint64_t lba_low = (lba & 0x3FFFF);
491  uint8_t device_type = (lba_high & NI_DEVICE_TYPE_ENCODER);
492  uint16_t session_id = (uint16_t)(
494  if (device_type == NI_DEVICE_TYPE_ENCODER)
495  {
497  "encoder lba:0x%" PRIx64 "(4K-aligned), 0x%" PRIx64
498  "(512B-aligned), session ID:%u\n",
499  lba, ((uint64_t)lba << 3), session_id);
500  if (lba_low >= WR_OFFSET_IN_4K)
501  {
502  ni_log(NI_LOG_ERROR, "encoder send frame failed\n");
503  } else if (lba_low >= RD_OFFSET_IN_4K)
504  {
505  ni_log(NI_LOG_ERROR, "encoder receive packet failed\n");
506  } else
507  {
509  "encoder ctrl command failed: op-0x%x, "
510  "subtype-0x%x, option-0x%x\n",
511  (uint32_t)(
512  ((lba_low - START_OFFSET_IN_4K) >> NI_OP_BIT_OFFSET) +
513  0xD0),
514  (uint32_t)((lba_low >> NI_SUB_BIT_OFFSET) & 0xF),
515  (uint32_t)(lba_low & 0xF));
516  }
517  }
518  else
519  {
521  "decoder lba:0x%" PRIx64 "(4K-aligned), 0x%" PRIx64
522  "(512B-aligned), session ID:%u\n",
523  lba, ((uint64_t)lba << 3), session_id);
524  if (lba_low >= WR_OFFSET_IN_4K)
525  {
526  ni_log(NI_LOG_ERROR, "decoder send packet failed\n");
527  } else if (lba_low >= RD_OFFSET_IN_4K)
528  {
529  ni_log(NI_LOG_ERROR, "decoder receive frame failed\n");
530  } else
531  {
533  "decoder ctrl command failed: op-0x%x, "
534  "subtype-0x%x, option-0x%x\n",
535  (uint32_t)(
536  ((lba_low - START_OFFSET_IN_4K) >> NI_OP_BIT_OFFSET) +
537  0xD0),
538  (uint32_t)((lba_low >> NI_SUB_BIT_OFFSET) & 0xF),
539  (uint32_t)(lba_low & 0xF));
540  }
541  }
542 }
543 
544 /*!******************************************************************************
545  * \brief Compose an io read command
546  *
547  * \param
548  *
549  * \return value < 0, failed, return failure code.
550  * value >= 0, success,
551  * windows return success code,
552  * linux return actural size
553  *******************************************************************************/
554 int32_t ni_nvme_send_read_cmd(ni_device_handle_t handle,
555  ni_event_handle_t event_handle, void *p_data,
556  uint32_t data_len, uint32_t lba)
557 {
558  int32_t rc;
559  uint64_t offset = (uint64_t)lba << LBA_BIT_OFFSET;
560 
561  if (!p_data)
562  {
563  ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameter: p_data=%p\n", __func__, p_data);
565  }
566 
567 #ifdef _WIN32
568  uint32_t offset_l = (uint32_t)(offset & 0xFFFFFFFF);
569  DWORD offset_h = (DWORD)(offset >> 32);
570  OVERLAPPED overlap;
572  "%s: handle=%" PRIx64 ", lba=0x%lx, len=%d,offset:0x%x,0x%x\n",
573  __func__, (int64_t)handle, ((uint64_t)lba << 3), data_len, offset_l, offset_h);
574  memset(&overlap, 0, sizeof(overlap));
575  overlap.Offset = offset_l;
576  overlap.OffsetHigh = offset_h;
577 
578  DWORD data_len_; //data real count
579  rc = ReadFile(handle, p_data, data_len, &data_len_, &overlap);
580  ni_log(NI_LOG_TRACE, "rc=%d,actlen=%d\n", rc, data_len_);
581  if (rc == FALSE)
582  {
583  rc = NI_ERRNO;
585  "%s() ReadFile handle=%" PRIx64 ", event_handle="
586  "%" PRIx64 ", lba=0x%lx, len=%d, rc=%d\n",
587  __func__, (int64_t)handle, (int64_t)event_handle, ((uint64_t)lba << 3),
588  data_len, rc);
589  ni_log(NI_LOG_ERROR, "ERROR %d: %s() failed\n", rc, __func__);
591  } else
592  {
593  rc = NI_RETCODE_SUCCESS;
594  }
595 #else
596  if (!handle || handle == NI_INVALID_DEVICE_HANDLE)
597  {
598  //if we can make sure that all handles are initialized to NI_INVALID_DEVICE_HANDLE
599  //we can remove the condition !handle
600  ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameters: handle=%" PRId32 "\n", __func__, handle);
602  }
603 
604  if (((uintptr_t)p_data) % NI_MEM_PAGE_ALIGNMENT)
605  {
607  "%s: Buffer not %d aligned = %p! Reading to aligned memory "
608  "and copying.\n",
609  __func__, NI_MEM_PAGE_ALIGNMENT, p_data);
610  void *p_buf = NULL;
611  if (ni_posix_memalign(&p_buf, sysconf(_SC_PAGESIZE), data_len))
612  {
614  "ERROR %d: %s() alloc data buffer failed\n", NI_ERRNO,
615  __func__);
617  }
618  else
619  {
620  rc = pread(handle, p_buf, data_len, offset);
621  if (rc >= 0)//copy only if anything has been read
622  {
623  memcpy(p_data, p_buf, data_len);
624  }
625  ni_aligned_free(p_buf);
626  }
627  } else
628  {
629  rc = pread(handle, p_data, data_len, offset);
630  }
632  "%s: handle=%" PRIx64
633  ", offset 0x%lx, lba=0x%lx, len=%d, rc=%d\n",
634  __func__, (int64_t)handle, offset, ((uint64_t)lba << 3), data_len, rc);
635  if (rc < 0 || rc != data_len)
636  {
638  "ERROR %d: %s failed, lba=0x%lx, len=%u, rc=%d, error=%d\n",
639  NI_ERRNO, __func__, ((uint64_t)lba << 3), data_len, rc, NI_ERRNO);
640  ni_parse_lba(lba);
642  } else
643  {
644  rc = NI_RETCODE_SUCCESS;
645  }
646 #endif
647  return rc;
648 }
649 
650 /*!******************************************************************************
651  * \brief Compose a io write command
652  *
653  * \param
654  *
655  * \return value < 0, failed, return failure code.
656  * value >= 0, success,
657  * windows return success code,
658  * linux return actural size
659  *******************************************************************************/
660 int32_t ni_nvme_send_write_cmd(ni_device_handle_t handle,
661  ni_event_handle_t event_handle, void *p_data,
662  uint32_t data_len, uint32_t lba)
663 {
664  int32_t rc;
665  uint64_t offset = (uint64_t)lba << LBA_BIT_OFFSET;
666 
667  if (!p_data)
668  {
669  ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameter: p_data=%p\n", __func__, p_data);
671  }
672 
673 #ifdef _WIN32
674  uint32_t offset_l = (uint32_t)(offset & 0xFFFFFFFF);
675  DWORD offset_h = (DWORD)(offset >> 32);
676  DWORD data_len_; //data real count
677  OVERLAPPED overlap;
678 
680  "%s: handle=%" PRIx64 ", lba=0x%lx, len=%d,offset:0x%x,0x%x\n",
681  __func__, (int64_t)handle, ((uint64_t)lba << 3), data_len, offset_l, offset_h);
682 
683  memset(&overlap, 0, sizeof(overlap));
684  overlap.Offset = offset_l;
685  overlap.OffsetHigh = offset_h;
686 
687  rc = WriteFile(handle, p_data, data_len, &data_len_, &overlap);
688  ni_log(NI_LOG_TRACE, "rc=%d,actlen=%d\n", rc, data_len_);
689  if (rc == FALSE)
690  {
691  rc = NI_ERRNO;
693  "%s() WriteFile handle=%" PRIx64 ", event_handle="
694  "%" PRIx64 ", lba=0x%lx, len=%d, rc=%d\n",
695  __func__, (int64_t)handle, (int64_t)event_handle, ((uint64_t)lba << 3),
696  data_len, rc);
697  ni_log(NI_LOG_ERROR, "ERROR %d: ni_nvme_send_write_cmd() failed\n", rc);
699  } else
700  {
701  rc = NI_RETCODE_SUCCESS;
702  }
703 #else
704  if (!handle || handle == NI_INVALID_DEVICE_HANDLE)
705  {
706  //if we can make sure that all handles are initialized to NI_INVALID_DEVICE_HANDLE
707  //we can remove the condition !handle
708  ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameters: handle=%" PRId32 "\n", __func__, handle);
710  }
711 
712  if (((uintptr_t)p_data) % NI_MEM_PAGE_ALIGNMENT)
713  {
715  "%s: Buffer not %d aligned = %p! Copying to aligned memory "
716  "and writing.\n",
717  __func__, NI_MEM_PAGE_ALIGNMENT, p_data);
718  void *p_buf = NULL;
719  if (ni_posix_memalign(&p_buf, sysconf(_SC_PAGESIZE), data_len))
720  {
722  "ERROR %d: %s() alloc data buffer failed\n", NI_ERRNO,
723  __func__);
725  }
726  else
727  {
728  memcpy(p_buf, p_data, data_len);
729  rc = pwrite(handle, p_buf, data_len, offset);
730  ni_aligned_free(p_buf);
731  }
732  }
733  else
734  {
735  rc = pwrite(handle, p_data, data_len, offset);
736  }
738  "%s: handle=%" PRIx64 ", lba=0x%lx, len=%d, rc=%d\n", __func__,
739  (int64_t)handle, ((uint64_t)lba << 3), data_len, rc);
740  if ((rc < 0) || (rc != data_len))
741  {
743  "ERROR %d: %s failed, lba=0x%lx, len=%u, rc=%d, error=%d\n",
744  NI_ERRNO, __func__, ((uint64_t)lba << 3), data_len, rc, NI_ERRNO);
745  ni_parse_lba(lba);
747  } else
748  {
749  rc = NI_RETCODE_SUCCESS;
750  }
751 #endif
752  return rc;
753 }
754 
755 //linux aio
756 #ifdef __linux__
757 void ni_nvme_setup_aio_iocb(ni_device_handle_t handle, ni_iocb_t *iocb,
758  void *p_data, uint32_t data_len, uint32_t lba,
759  int write)
760 {
761  memset(iocb, 0, sizeof(ni_iocb_t));
762  iocb->aio_fildes = handle;
763  iocb->aio_lio_opcode = write ? IOCB_CMD_PWRITE : IOCB_CMD_PREAD;
764  iocb->aio_reqprio = 0;
765  iocb->aio_buf = (uint64_t)p_data;
766  iocb->aio_nbytes = data_len;
767  iocb->aio_offset = (uint64_t)lba << LBA_BIT_OFFSET;
768 }
769 
770 int32_t ni_nvme_batch_cmd_aio(ni_aio_context_t ctx, ni_iocb_t **iocbs,
771  ni_io_event_t *events, int iocb_num)
772 {
773  int32_t rc;
774  int i;
775 
776  for (i = 0; i < iocb_num; i++) {
777  ni_iocb_t *iocb = iocbs[i];
778  ni_log(NI_LOG_TRACE, "%s: iocb %d, fdes %d, opcode %d, buf 0x%llx,"
779  " nbytes %llu, offset 0x%llx\n", i, iocb->aio_fildes, iocb->aio_lio_opcode,
780  iocb->aio_buf, iocb->aio_nbytes, iocb->aio_offset);
781  }
782 
783  rc = ni_aio_submit(ctx, iocb_num, iocbs);
784  if (rc != iocb_num) {
785  ni_log(NI_LOG_ERROR, "%s: ERROR: failed to submit enough aio iocb, rc=%d\n", __func__,
786  rc);
788  }
789 
790  rc = ni_aio_getevents(ctx, iocb_num, iocb_num, events, NULL);
791  if (rc != iocb_num) {
792  ni_log(NI_LOG_ERROR, "%s: ERROR: failed to get events, rc=%d\n", __func__, rc);
794  } else {
795  for (i = 0; i < iocb_num; i++) {
796  ni_io_event_t *evt = &events[i];
797  ni_iocb_t *iocb = (ni_iocb_t *)evt->obj;
798  if (iocb->aio_nbytes != evt->res) {
799  ni_log(NI_LOG_ERROR, "ERROR %s(): failed to write data, size %llu, res %lld\n",
800  __func__, iocb->aio_nbytes, evt->res);
802  }
803  }
804  rc = NI_RETCODE_SUCCESS;
805  }
806 
807  return rc;
808 }
809 #endif
nvme_admin_cmd_identify
@ nvme_admin_cmd_identify
Definition: ni_nvme.h:306
NI_DEVICE_TYPE_ENCODER
@ NI_DEVICE_TYPE_ENCODER
Definition: ni_defs.h:359
NI_OP_BIT_OFFSET
#define NI_OP_BIT_OFFSET
Definition: ni_nvme.h:628
NI_SUB_BIT_OFFSET
#define NI_SUB_BIT_OFFSET
Definition: ni_nvme.h:627
ni_nvme_opcode_t
enum _ni_nvme_opcode ni_nvme_opcode_t
LBA_BIT_OFFSET
#define LBA_BIT_OFFSET
Definition: ni_nvme.h:624
ni_nvme_enumerate_devices
int ni_nvme_enumerate_devices(char ni_devices[][NI_MAX_DEVICE_NAME_LEN], int max_handles)
NI_RETCODE_SUCCESS
@ NI_RETCODE_SUCCESS
Definition: ni_defs.h:439
_ni_nvme_command::cdw12
uint32_t cdw12
Definition: ni_nvme.h:46
_ni_nvme_identity::ai8Mn
uint8_t ai8Mn[40]
Definition: ni_nvme.h:96
START_OFFSET_IN_4K
#define START_OFFSET_IN_4K
Definition: ni_nvme.h:637
ni_nvme_send_admin_cmd
int32_t ni_nvme_send_admin_cmd(ni_nvme_admin_opcode_t opcode, ni_device_handle_t handle, ni_nvme_command_t *p_ni_nvme_cmd, uint32_t data_len, void *p_data, uint32_t *p_result)
Compose a nvme admin command.
Definition: ni_nvme.c:350
_ni_nvme_command::cdw11
uint32_t cdw11
Definition: ni_nvme.h:45
_ni_nvme_identity::ui16Vid
uint16_t ui16Vid
Definition: ni_nvme.h:93
NI_SESSION_ID_OFFSET
#define NI_SESSION_ID_OFFSET
Definition: ni_nvme.h:630
NI_RETCODE_ERROR_STREAM_ERROR
@ NI_RETCODE_ERROR_STREAM_ERROR
Definition: ni_defs.h:536
_ni_nvme_identity::device_is_xcoder
uint8_t device_is_xcoder
Definition: ni_nvme.h:155
NI_RETCODE_INVALID_PARAM
@ NI_RETCODE_INVALID_PARAM
Definition: ni_defs.h:441
ni_ai_errno_to_str
const char * ni_ai_errno_to_str(int rc)
return error string according to error code from firmware
Definition: ni_util.c:4321
_ni_nvme_command
Definition: ni_nvme.h:40
NI_RETCODE_ERROR_MEM_ALOC
@ NI_RETCODE_ERROR_MEM_ALOC
Definition: ni_defs.h:443
ni_retcode_t
ni_retcode_t
Definition: ni_defs.h:437
ni_nvme_send_write_cmd
int32_t ni_nvme_send_write_cmd(ni_device_handle_t handle, ni_event_handle_t event_handle, void *p_data, uint32_t data_len, uint32_t lba)
Compose a io write command.
Definition: ni_nvme.c:660
NI_LOG_INFO
@ NI_LOG_INFO
Definition: ni_log.h:61
_ni_nvme_identity
Definition: ni_nvme.h:89
RD_OFFSET_IN_4K
#define RD_OFFSET_IN_4K
Definition: ni_nvme.h:641
ni_parse_lba
void ni_parse_lba(uint64_t lba)
parse the lba opcode, subtype, option It's called only if a I/O read/write fails, so just use the pri...
Definition: ni_nvme.c:487
ni_nvme_send_io_cmd_thru_admin_queue
int32_t ni_nvme_send_io_cmd_thru_admin_queue(ni_nvme_admin_opcode_t opcode, ni_device_handle_t fd, ni_nvme_command_t *p_ni_nvme_cmd, uint32_t data_len, void *data, uint32_t *pResult)
NI_LOG_ERROR
@ NI_LOG_ERROR
Definition: ni_log.h:60
_ni_nvme_command::cdw10
uint32_t cdw10
Definition: ni_nvme.h:44
NI_DEVICE_TYPE_AI
@ NI_DEVICE_TYPE_AI
Definition: ni_defs.h:361
NETINT_PCI_VENDOR_ID
#define NETINT_PCI_VENDOR_ID
Definition: ni_defs.h:129
NI_RETCODE_ERROR_NVME_CMD_FAILED
@ NI_RETCODE_ERROR_NVME_CMD_FAILED
Definition: ni_defs.h:444
_ni_nvme_command::cdw14
uint32_t cdw14
Definition: ni_nvme.h:48
NI_MEM_PAGE_ALIGNMENT
#define NI_MEM_PAGE_ALIGNMENT
Definition: ni_defs.h:263
NI_LOG_TRACE
@ NI_LOG_TRACE
Definition: ni_log.h:63
NI_INSTANCE_TYPE_OFFSET
#define NI_INSTANCE_TYPE_OFFSET
Definition: ni_nvme.h:629
ni_log
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition: ni_log.c:183
_ni_nvme_identity::ai8Sn
uint8_t ai8Sn[20]
Definition: ni_nvme.h:95
ni_nvme_admin_opcode_t
enum _ni_nvme_admin_opcode ni_nvme_admin_opcode_t
NI_RETCODE_NVME_SC_INTERLACED_NOT_SUPPORTED
@ NI_RETCODE_NVME_SC_INTERLACED_NOT_SUPPORTED
Definition: ni_defs.h:558
_ni_nvme_command::cdw3
uint32_t cdw3
Definition: ni_nvme.h:43
_ni_nvme_command::cdw2
uint32_t cdw2
Definition: ni_nvme.h:42
_ni_nvme_command::cdw13
uint32_t cdw13
Definition: ni_nvme.h:47
NI_ERRNO
#define NI_ERRNO
Definition: ni_defs.h:229
NI_RETCODE_NVME_SC_STREAM_ERROR
@ NI_RETCODE_NVME_SC_STREAM_ERROR
Definition: ni_defs.h:557
NI_MAX_DEVICE_NAME_LEN
#define NI_MAX_DEVICE_NAME_LEN
Definition: ni_defs.h:236
ni_nvme_send_read_cmd
int32_t ni_nvme_send_read_cmd(ni_device_handle_t handle, ni_event_handle_t event_handle, void *p_data, uint32_t data_len, uint32_t lba)
Compose an io read command.
Definition: ni_nvme.c:554
WR_OFFSET_IN_4K
#define WR_OFFSET_IN_4K
Definition: ni_nvme.h:644
NI_RETCODE_NVME_SC_INVALID_PARAMETER
@ NI_RETCODE_NVME_SC_INVALID_PARAMETER
Definition: ni_defs.h:556
ni_nvme_check_error_code
ni_retcode_t ni_nvme_check_error_code(int rc, int opcode, uint32_t xcoder_type, uint32_t hw_id, uint32_t *p_instance_id)
Check f/w error return code, and if it's a fatal one, terminate application's decoding/encoding proce...
Definition: ni_nvme.c:62
_ni_nvme_command::cdw15
uint32_t cdw15
Definition: ni_nvme.h:49
NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT
@ NI_RETCODE_NVME_SC_VPU_RSRC_INSUFFICIENT
Definition: ni_defs.h:560
ni_posix_memalign
int ni_posix_memalign(void **memptr, size_t alignment, size_t size)
Allocate aligned memory.
Definition: ni_util.c:198
ni_nvme.h
Private definitions for interfacing with NETINT video processing devices over NVMe.
NI_NVME_IDENTITY_CMD_DATA_SZ
#define NI_NVME_IDENTITY_CMD_DATA_SZ
Definition: ni_nvme.h:38
NI_RETCODE_FAILURE
@ NI_RETCODE_FAILURE
Definition: ni_defs.h:440
_ni_nvme_identity::ui16Ssvid
uint16_t ui16Ssvid
Definition: ni_nvme.h:94
ni_util.h
Utility definitions.
ni_aligned_free
#define ni_aligned_free(p_memptr)
Definition: ni_util.h:399
ni_nvme_send_io_cmd
int32_t ni_nvme_send_io_cmd(ni_nvme_opcode_t opcode, ni_device_handle_t handle, ni_nvme_command_t *p_ni_nvme_cmd, uint32_t data_len, void *p_data, uint32_t *p_result)
Compose a nvme io command.
Definition: ni_nvme.c:397
GET_XCODER_DEVICE_TYPE_STR
#define GET_XCODER_DEVICE_TYPE_STR(t)
Definition: ni_defs.h:429
_ni_nvme_identity::ai8Fr
uint8_t ai8Fr[8]
Definition: ni_nvme.h:97
NI_LOG_DEBUG
@ NI_LOG_DEBUG
Definition: ni_log.h:62
NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE
@ NI_RETCODE_ERROR_RESOURCE_UNAVAILABLE
Definition: ni_defs.h:446
IDENTIFY_DEVICE_R
#define IDENTIFY_DEVICE_R
Definition: ni_nvme.h:686