libxcoder  5.2.0
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  ZeroMemory(p_buffer, data_len);
242  rc = ni_nvme_get_identity(handle, event_handle, p_buffer);
243  if (NI_RETCODE_SUCCESS == rc)
244  {
245  ni_nvme_identity_t *p_ni_id_data =
246  (ni_nvme_identity_t *)p_buffer;
248  "Identity information retrieved from the device "
249  "at port %s\n",
250  port_name_buffer);
252  " VID: 0x%x \n SSVID: 0x%x \n",
253  p_ni_id_data->ui16Vid, p_ni_id_data->ui16Ssvid);
254 
255  if (NETINT_PCI_VENDOR_ID == p_ni_id_data->ui16Vid &&
256  NETINT_PCI_VENDOR_ID == p_ni_id_data->ui16Ssvid &&
257  is_supported_xcoder(p_ni_id_data->device_is_xcoder))
258  {
259  /* make the fw revision/model name/serial num to string*/
260  memset(firmware_revision, 0, sizeof(firmware_revision));
261  memcpy(firmware_revision, p_ni_id_data->ai8Fr,
262  sizeof(firmware_revision));
263  firmware_revision[sizeof(firmware_revision) - 1] = 0;
264 
265  memset(model_name, 0, sizeof(model_name));
266  memcpy(model_name, p_ni_id_data->ai8Mn, sizeof(model_name));
267  model_name[sizeof(model_name) - 1] = 0;
268 
269  memset(serial_num, 0, sizeof(serial_num));
270  memcpy(serial_num, p_ni_id_data->ai8Sn, sizeof(serial_num));
271  serial_num[sizeof(serial_num) - 1] = 0;
272  ni_log(NI_LOG_DEBUG, " Device Model: %s \n",
273  model_name);
274  ni_log(NI_LOG_DEBUG, " Firmware Rev: %s \n",
275  firmware_revision);
276  ni_log(NI_LOG_DEBUG, " Serial Number: %s \n",
277  serial_num);
279  "NETINT %s NVMe video transcoder identified "
280  "at port %s\n\n",
281  model_name, port_name_buffer);
282  strncpy(ni_devices[device_count++], port_name_buffer,
284  } else
285  {
287  "Device at port %s %d is not a NETINT NVMe device\n",
288  port_name_buffer, p_ni_id_data->device_is_xcoder);
289  }
290  CloseHandle(handle);
291  } else
292  {
293  retval = NI_ERRNO;
294  ni_log(
295  NI_LOG_DEBUG,
296  "Device at port %s is not a NETINT NVMe device,ret=%d\n\n",
297  port_name_buffer, retval);
298  CloseHandle(handle);
299  }
300  }
301  } // end for loop
302 
303  if (p_buffer)
304  {
305  ni_aligned_free(p_buffer);
306  }
307 
309  "Total Number of NETINT NVMe Transcoders identified: %d \n\n",
310  device_count);
311  return device_count;
312 }
313 
314 #endif //_WIN32 defined
315 
316 #ifndef XCODER_IO_RW_ENABLED
317 /*!******************************************************************************
318  * \brief Compose a nvme admin command
319  *
320  * \param
321  *
322  * \return
323  *******************************************************************************/
325  ni_device_handle_t handle,
326  ni_nvme_command_t *p_ni_nvme_cmd,
327  uint32_t data_len, void *p_data,
328  uint32_t *p_result)
329 {
330  int32_t rc = -1;
331 #ifdef _WIN32
332  //Windows inbox driver requires to send identity through different
333  //api than regular pass through commands
334  if (nvme_admin_cmd_identify == opcode)
335  {
336  rc = ni_nvme_get_identity(handle, NI_INVALID_EVENT_HANDLE, p_data);
337  *p_result = NI_RETCODE_SUCCESS;
338  }
339 #elif __APPLE__
340 #else
341  ni_nvme_passthrough_cmd_t nvme_cmd = {0};
342 
343  nvme_cmd.opcode = opcode;
344  nvme_cmd.cdw10 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw10);
345  nvme_cmd.cdw11 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw11);
346  nvme_cmd.cdw12 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw12);
347  nvme_cmd.cdw13 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw13);
348  nvme_cmd.cdw14 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw14);
349  nvme_cmd.cdw15 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw15);
350  nvme_cmd.addr = (__u64)ni_htonll((uintptr_t)p_data);
351  nvme_cmd.data_len = ni_htonl(data_len);
352 
353  rc = ni_nvme_send_admin_pass_through_command(handle, &nvme_cmd);
354 
355  *p_result = ni_htonl(nvme_cmd.result);
356 #endif
357 
358  ni_log(NI_LOG_DEBUG, "%s: handle=%" PRIx64 ", result=%08x, rc=%d\n",
359  __func__, (int64_t)handle, (uint32_t)(*p_result), rc);
360 
361  return rc;
362 }
363 
364 /*!******************************************************************************
365  * \brief Compose a nvme io command
366  *
367  * \param
368  *
369  * \return
370  *******************************************************************************/
371 int32_t ni_nvme_send_io_cmd(ni_nvme_opcode_t opcode, ni_device_handle_t handle,
372  ni_nvme_command_t *p_ni_nvme_cmd, uint32_t data_len,
373  void *p_data, uint32_t *p_result)
374 {
375  int32_t rc = -1;
376 #ifdef _WIN32
377 #elif __APPLE__
378 #else
379  ni_nvme_passthrough_cmd_t nvme_cmd;
380  //int32_t *p_addr = NULL;
381 
382  memset(&nvme_cmd, 0, sizeof(nvme_cmd));
383  nvme_cmd.opcode = opcode;
384  nvme_cmd.nsid = ni_htonl(1);
385  nvme_cmd.addr = (__u64)ni_htonll((uintptr_t)p_data);
386  nvme_cmd.data_len = ni_htonl(data_len);
387  nvme_cmd.cdw2 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw2);
388  nvme_cmd.cdw3 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw3);
389  nvme_cmd.cdw10 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw10);
390  nvme_cmd.cdw11 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw11);
391  nvme_cmd.cdw12 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw12);
392  nvme_cmd.cdw13 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw13);
393  nvme_cmd.cdw14 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw14);
394  nvme_cmd.cdw15 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw15);
395 
396  rc = ni_nvme_send_io_pass_through_command(handle, &nvme_cmd);
397 
398  //p_addr = &nvme_cmd.result;
399  //*!pResult = *p_addr;
400  *p_result = ni_htonl(nvme_cmd.result);
401 #endif
402 
403  ni_log(NI_LOG_DEBUG, "%s: handle=%" PRIx64 ", result=%08x, rc=%d\n",
404  __func__, (int64_t)handle, (uint32_t)(*p_result), rc);
405 
406  return rc;
407 }
408 #endif
409 
410 #ifdef __linux__
411 
412 /*!******************************************************************************
413  * \brief Compose a nvme io through admin command
414  *
415  * \param
416  *
417  * \return
418  *******************************************************************************/
420  ni_device_handle_t handle,
421  ni_nvme_command_t *p_ni_nvme_cmd,
422  uint32_t data_len, void *p_data,
423  uint32_t *p_result)
424 {
425  int32_t rc;
426  ni_nvme_passthrough_cmd_t nvme_cmd = {0};
427 
428  nvme_cmd.opcode = opcode;
429  nvme_cmd.nsid = ni_htonl(1);
430  nvme_cmd.addr = (__u64)ni_htonll((uintptr_t)p_data);
431  nvme_cmd.data_len = ni_htonl(data_len);
432  nvme_cmd.cdw10 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw10);
433  nvme_cmd.cdw11 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw11);
434  nvme_cmd.cdw12 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw12);
435  nvme_cmd.cdw13 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw13);
436  nvme_cmd.cdw14 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw14);
437  nvme_cmd.cdw15 = (__u32)ni_htonl(p_ni_nvme_cmd->cdw15);
438 
439  rc = ni_nvme_send_admin_pass_through_command(handle, &nvme_cmd);
440 
441  //p_addr = &nvme_cmd.result;
442  //*!pResult = *p_addr;
443  *p_result = ni_htonl(nvme_cmd.result);
444 
445  ni_log(NI_LOG_DEBUG, "%s: handle=%d, result=%08x, rc=%d\n", __func__,
446  handle, *p_result, rc);
447 
448  return rc;
449 }
450 #endif //__linux__ defined
451 
452 /*!******************************************************************************
453  * \brief parse the lba opcode, subtype, option
454  * It's called only if a I/O read/write fails,
455  * so just use the print level "NI_LOG_ERROR" now.
456  *
457  * \param lba is 4k aligned
458  *
459  * \return
460  *******************************************************************************/
461 void ni_parse_lba(uint64_t lba)
462 {
463  uint64_t lba_high = (lba >> NI_INSTANCE_TYPE_OFFSET);
464  uint64_t lba_low = (lba & 0x3FFFF);
465  uint8_t device_type = (lba_high & NI_DEVICE_TYPE_ENCODER);
466  uint16_t session_id = (uint16_t)(
468  if (device_type == NI_DEVICE_TYPE_ENCODER)
469  {
471  "encoder lba:0x%" PRIx64 "(4K-aligned), 0x%" PRIx64
472  "(512B-aligned), session ID:%u\n",
473  lba, ((uint64_t)lba << 3), session_id);
474  if (lba_low >= WR_OFFSET_IN_4K)
475  {
476  ni_log(NI_LOG_ERROR, "encoder send frame failed\n");
477  } else if (lba_low >= RD_OFFSET_IN_4K)
478  {
479  ni_log(NI_LOG_ERROR, "encoder receive packet failed\n");
480  } else
481  {
483  "encoder ctrl command failed: op-0x%x, "
484  "subtype-0x%x, option-0x%x\n",
485  (uint32_t)(
486  ((lba_low - START_OFFSET_IN_4K) >> NI_OP_BIT_OFFSET) +
487  0xD0),
488  (uint32_t)((lba_low >> NI_SUB_BIT_OFFSET) & 0xF),
489  (uint32_t)(lba_low & 0xF));
490  }
491  }
492  else
493  {
495  "decoder lba:0x%" PRIx64 "(4K-aligned), 0x%" PRIx64
496  "(512B-aligned), session ID:%u\n",
497  lba, ((uint64_t)lba << 3), session_id);
498  if (lba_low >= WR_OFFSET_IN_4K)
499  {
500  ni_log(NI_LOG_ERROR, "decoder send packet failed\n");
501  } else if (lba_low >= RD_OFFSET_IN_4K)
502  {
503  ni_log(NI_LOG_ERROR, "decoder receive frame failed\n");
504  } else
505  {
507  "decoder ctrl command failed: op-0x%x, "
508  "subtype-0x%x, option-0x%x\n",
509  (uint32_t)(
510  ((lba_low - START_OFFSET_IN_4K) >> NI_OP_BIT_OFFSET) +
511  0xD0),
512  (uint32_t)((lba_low >> NI_SUB_BIT_OFFSET) & 0xF),
513  (uint32_t)(lba_low & 0xF));
514  }
515  }
516 }
517 
518 /*!******************************************************************************
519  * \brief Compose an io read command
520  *
521  * \param
522  *
523  * \return value < 0, failed, return failure code.
524  * value >= 0, success,
525  * windows return success code,
526  * linux return actural size
527  *******************************************************************************/
528 int32_t ni_nvme_send_read_cmd(ni_device_handle_t handle,
529  ni_event_handle_t event_handle, void *p_data,
530  uint32_t data_len, uint32_t lba)
531 {
532  int32_t rc;
533  uint64_t offset = (uint64_t)lba << LBA_BIT_OFFSET;
534 
535  if (!p_data)
536  {
537  ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameter: p_data=%p\n", __func__, p_data);
539  }
540 
541 #ifdef _WIN32
542  uint32_t offset_l = (uint32_t)(offset & 0xFFFFFFFF);
543  DWORD offset_h = (DWORD)(offset >> 32);
544  OVERLAPPED overlap;
546  "%s: handle=%" PRIx64 ", lba=0x%lx, len=%d,offset:0x%x,0x%x\n",
547  __func__, (int64_t)handle, ((uint64_t)lba << 3), data_len, offset_l, offset_h);
548  memset(&overlap, 0, sizeof(overlap));
549  overlap.Offset = offset_l;
550  overlap.OffsetHigh = offset_h;
551 
552  DWORD data_len_; //data real count
553  rc = ReadFile(handle, p_data, data_len, &data_len_, &overlap);
554  ni_log(NI_LOG_TRACE, "rc=%d,actlen=%d\n", rc, data_len_);
555  if (rc == FALSE)
556  {
557  rc = NI_ERRNO;
559  "%s() ReadFile handle=%" PRIx64 ", event_handle="
560  "%" PRIx64 ", lba=0x%lx, len=%d, rc=%d\n",
561  __func__, (int64_t)handle, (int64_t)event_handle, ((uint64_t)lba << 3),
562  data_len, rc);
563  ni_log(NI_LOG_ERROR, "ERROR %d: %s() failed\n", rc, __func__);
565  } else
566  {
567  rc = NI_RETCODE_SUCCESS;
568  }
569 #else
570  if (!handle || handle == NI_INVALID_DEVICE_HANDLE)
571  {
572  //if we can make sure that all handles are initialized to NI_INVALID_DEVICE_HANDLE
573  //we can remove the condition !handle
574  ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameters: handle=%" PRId32 "\n", __func__, handle);
576  }
577 
578  if (((uintptr_t)p_data) % NI_MEM_PAGE_ALIGNMENT)
579  {
581  "%s: Buffer not %d aligned = %p! Reading to aligned memory "
582  "and copying.\n",
583  __func__, NI_MEM_PAGE_ALIGNMENT, p_data);
584  void *p_buf = NULL;
585  if (ni_posix_memalign(&p_buf, sysconf(_SC_PAGESIZE), data_len))
586  {
588  "ERROR %d: %s() alloc data buffer failed\n", NI_ERRNO,
589  __func__);
591  }
592  else
593  {
594  rc = pread(handle, p_buf, data_len, offset);
595  if (rc >= 0)//copy only if anything has been read
596  {
597  memcpy(p_data, p_buf, data_len);
598  }
599  ni_aligned_free(p_buf);
600  }
601  } else
602  {
603  rc = pread(handle, p_data, data_len, offset);
604  }
606  "%s: handle=%" PRIx64
607  ", offset 0x%lx, lba=0x%lx, len=%d, rc=%d\n",
608  __func__, (int64_t)handle, offset, ((uint64_t)lba << 3), data_len, rc);
609  if (rc < 0 || rc != data_len)
610  {
612  "ERROR %d: %s failed, lba=0x%lx, len=%u, rc=%d, error=%d\n",
613  NI_ERRNO, __func__, ((uint64_t)lba << 3), data_len, rc, NI_ERRNO);
614  ni_parse_lba(lba);
616  } else
617  {
618  rc = NI_RETCODE_SUCCESS;
619  }
620 #endif
621  return rc;
622 }
623 
624 /*!******************************************************************************
625  * \brief Compose a io write command
626  *
627  * \param
628  *
629  * \return value < 0, failed, return failure code.
630  * value >= 0, success,
631  * windows return success code,
632  * linux return actural size
633  *******************************************************************************/
634 int32_t ni_nvme_send_write_cmd(ni_device_handle_t handle,
635  ni_event_handle_t event_handle, void *p_data,
636  uint32_t data_len, uint32_t lba)
637 {
638  int32_t rc;
639  uint64_t offset = (uint64_t)lba << LBA_BIT_OFFSET;
640 
641  if (!p_data)
642  {
643  ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameter: p_data=%p\n", __func__, p_data);
645  }
646 
647 #ifdef _WIN32
648  uint32_t offset_l = (uint32_t)(offset & 0xFFFFFFFF);
649  DWORD offset_h = (DWORD)(offset >> 32);
650  DWORD data_len_; //data real count
651  OVERLAPPED overlap;
652 
654  "%s: handle=%" PRIx64 ", lba=0x%lx, len=%d,offset:0x%x,0x%x\n",
655  __func__, (int64_t)handle, ((uint64_t)lba << 3), data_len, offset_l, offset_h);
656 
657  memset(&overlap, 0, sizeof(overlap));
658  overlap.Offset = offset_l;
659  overlap.OffsetHigh = offset_h;
660 
661  rc = WriteFile(handle, p_data, data_len, &data_len_, &overlap);
662  ni_log(NI_LOG_TRACE, "rc=%d,actlen=%d\n", rc, data_len_);
663  if (rc == FALSE)
664  {
665  rc = NI_ERRNO;
667  "%s() WriteFile handle=%" PRIx64 ", event_handle="
668  "%" PRIx64 ", lba=0x%lx, len=%d, rc=%d\n",
669  __func__, (int64_t)handle, (int64_t)event_handle, ((uint64_t)lba << 3),
670  data_len, rc);
671  ni_log(NI_LOG_ERROR, "ERROR %d: ni_nvme_send_write_cmd() failed\n", rc);
673  } else
674  {
675  rc = NI_RETCODE_SUCCESS;
676  }
677 #else
678  if (!handle || handle == NI_INVALID_DEVICE_HANDLE)
679  {
680  //if we can make sure that all handles are initialized to NI_INVALID_DEVICE_HANDLE
681  //we can remove the condition !handle
682  ni_log(NI_LOG_ERROR, "%s: ERROR: invalid parameters: handle=%" PRId32 "\n", __func__, handle);
684  }
685 
686  if (((uintptr_t)p_data) % NI_MEM_PAGE_ALIGNMENT)
687  {
689  "%s: Buffer not %d aligned = %p! Copying to aligned memory "
690  "and writing.\n",
691  __func__, NI_MEM_PAGE_ALIGNMENT, p_data);
692  void *p_buf = NULL;
693  if (ni_posix_memalign(&p_buf, sysconf(_SC_PAGESIZE), data_len))
694  {
696  "ERROR %d: %s() alloc data buffer failed\n", NI_ERRNO,
697  __func__);
699  }
700  else
701  {
702  memcpy(p_buf, p_data, data_len);
703  rc = pwrite(handle, p_buf, data_len, offset);
704  ni_aligned_free(p_buf);
705  }
706  }
707  else
708  {
709  rc = pwrite(handle, p_data, data_len, offset);
710  }
712  "%s: handle=%" PRIx64 ", lba=0x%lx, len=%d, rc=%d\n", __func__,
713  (int64_t)handle, ((uint64_t)lba << 3), data_len, rc);
714  if ((rc < 0) || (rc != data_len))
715  {
717  "ERROR %d: %s failed, lba=0x%lx, len=%u, rc=%d, error=%d\n",
718  NI_ERRNO, __func__, ((uint64_t)lba << 3), data_len, rc, NI_ERRNO);
719  ni_parse_lba(lba);
721  } else
722  {
723  rc = NI_RETCODE_SUCCESS;
724  }
725 #endif
726  return rc;
727 }
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:347
NI_OP_BIT_OFFSET
#define NI_OP_BIT_OFFSET
Definition: ni_nvme.h:630
NI_SUB_BIT_OFFSET
#define NI_SUB_BIT_OFFSET
Definition: ni_nvme.h:629
ni_nvme_opcode_t
enum _ni_nvme_opcode ni_nvme_opcode_t
LBA_BIT_OFFSET
#define LBA_BIT_OFFSET
Definition: ni_nvme.h:626
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:427
_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:639
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:324
_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:632
NI_RETCODE_ERROR_STREAM_ERROR
@ NI_RETCODE_ERROR_STREAM_ERROR
Definition: ni_defs.h:524
_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:429
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:431
ni_retcode_t
ni_retcode_t
Definition: ni_defs.h:425
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:634
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:643
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:461
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:349
NETINT_PCI_VENDOR_ID
#define NETINT_PCI_VENDOR_ID
Definition: ni_defs.h:126
NI_RETCODE_ERROR_NVME_CMD_FAILED
@ NI_RETCODE_ERROR_NVME_CMD_FAILED
Definition: ni_defs.h:432
_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:251
NI_LOG_TRACE
@ NI_LOG_TRACE
Definition: ni_log.h:63
NI_INSTANCE_TYPE_OFFSET
#define NI_INSTANCE_TYPE_OFFSET
Definition: ni_nvme.h:631
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:546
_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:217
NI_RETCODE_NVME_SC_STREAM_ERROR
@ NI_RETCODE_NVME_SC_STREAM_ERROR
Definition: ni_defs.h:545
NI_MAX_DEVICE_NAME_LEN
#define NI_MAX_DEVICE_NAME_LEN
Definition: ni_defs.h:224
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:528
WR_OFFSET_IN_4K
#define WR_OFFSET_IN_4K
Definition: ni_nvme.h:646
NI_RETCODE_NVME_SC_INVALID_PARAMETER
@ NI_RETCODE_NVME_SC_INVALID_PARAMETER
Definition: ni_defs.h:544
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:548
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:428
_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:371
GET_XCODER_DEVICE_TYPE_STR
#define GET_XCODER_DEVICE_TYPE_STR(t)
Definition: ni_defs.h:417
_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:434
IDENTIFY_DEVICE_R
#define IDENTIFY_DEVICE_R
Definition: ni_nvme.h:688