How to use the ARM PMU in GEM5? - arm

I had a problem initializing the PMU in gem5 for an arm full system with the starter_fs.py in --cpu hpi.
i followed the instructions of this post Using perf_event with the ARM PMU inside gem5 and i managed to solve my problem. I added the patch and configure the system. I am not using perf. I try to access directly the registers and read them. As i see GEM5 has only some register events implemented. Can we add the others as well as :
for example EXC_TAKEN is not implemented. Is the following the way to add them?
self.addEvent(ProbeEvent(self,0x09, cpu, "EXC_TAKEN"))
#0x09: EXC_TAKEN ???
Also, reading the pmu event registers i manage to read them and extract the events but the pmccntr cycle register always returns zero? How gem5 increments this register? What are the steps to read the cycle reggister?
a code that i use to read using perf is the following:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/perf_event.h>
#define NUM_NODES 100
#define NONE 9999
struct _NODE
{
int iDist;
int iPrev;
};
typedef struct _NODE NODE;
struct _QITEM
{
int iNode;
int iDist;
int iPrev;
struct _QITEM *qNext;
};
typedef struct _QITEM QITEM;
QITEM *qHead = NULL;
int AdjMatrix[NUM_NODES][NUM_NODES];
int g_qCount = 0;
NODE rgnNodes[NUM_NODES];
int ch;
int iPrev, iNode;
int i, iCost, iDist;
void print_path (NODE *rgnNodes, int chNode)
{
if (rgnNodes[chNode].iPrev != NONE)
{
//print_path(rgnNodes, rgnNodes[chNode].iPrev);
}
//printf (" %d", chNode);
fflush(stdout);
}
void enqueue (int iNode, int iDist, int iPrev)
{
QITEM *qNew = (QITEM *) malloc(sizeof(QITEM));
QITEM *qLast = qHead;
if (!qNew)
{
//fprintf(stderr, "Out of memory.\n");
exit(1);
}
qNew->iNode = iNode;
qNew->iDist = iDist;
qNew->iPrev = iPrev;
qNew->qNext = NULL;
if (!qLast)
{
qHead = qNew;
}
else
{
while (qLast->qNext) qLast = qLast->qNext;
qLast->qNext = qNew;
}
g_qCount++;
// ASSERT(g_qCount);
}
void dequeue (int *piNode, int *piDist, int *piPrev)
{
QITEM *qKill = qHead;
if (qHead)
{
// ASSERT(g_qCount);
*piNode = qHead->iNode;
*piDist = qHead->iDist;
*piPrev = qHead->iPrev;
qHead = qHead->qNext;
free(qKill);
g_qCount--;
}
}
int qcount (void)
{
return(g_qCount);
}
int dijkstra(int chStart, int chEnd)
{
for (ch = 0; ch < NUM_NODES; ch++)
{
rgnNodes[ch].iDist = NONE;
rgnNodes[ch].iPrev = NONE;
}
if (chStart == chEnd)
{
//printf("Shortest path is 0 in cost. Just stay where you are.\n");
}
else
{
rgnNodes[chStart].iDist = 0;
rgnNodes[chStart].iPrev = NONE;
enqueue (chStart, 0, NONE);
while (qcount() > 0)
{
dequeue (&iNode, &iDist, &iPrev);
for (i = 0; i < NUM_NODES; i++)
{
if ((iCost = AdjMatrix[iNode][i]) != NONE)
{
if ((NONE == rgnNodes[i].iDist) ||
(rgnNodes[i].iDist > (iCost + iDist)))
{
rgnNodes[i].iDist = iDist + iCost;
rgnNodes[i].iPrev = iNode;
enqueue (i, iDist + iCost, iNode);
}
}
}
}
//printf("Shortest path is %d in cost. ", rgnNodes[chEnd].iDist);
//printf("Path is: ");
//print_path(rgnNodes, chEnd);
//printf("\n");
}
}
int main(int argc, char *argv[]) {
int diff = 0;
uint64_t num_cycles_nominal=0;
uint64_t num_cycles_attack=0;
uint64_t counter_cpu_cycles = 0;
//system("./load-module");
int i,j,k;
FILE *fp;
static int perf_fd_cpu_cycles;
static struct perf_event_attr attr_cpu_cycles;
attr_cpu_cycles.size = sizeof(attr_cpu_cycles);
attr_cpu_cycles.exclude_kernel = 1;
attr_cpu_cycles.exclude_hv = 1;
attr_cpu_cycles.exclude_callchain_kernel = 1;
attr_cpu_cycles.type = PERF_TYPE_RAW;
attr_cpu_cycles.config = 0x11;
/* Open the file descriptor corresponding to this counter. The counter
should start at this moment. */
if ((perf_fd_cpu_cycles = syscall(__NR_perf_event_open, &attr_cpu_cycles, 0, -1, -1, 0)) == -1)
fprintf(stderr, "perf_event_open fail %d %d: %s\n", perf_fd_cpu_cycles, errno, strerror(errno));
if (argc<2) {
//fprintf(stderr, "Usage: dijkstra <filename>\n");
//fprintf(stderr, "Only supports matrix size is #define'd.\n");
}
/* open the adjacency matrix file */
fp = fopen (argv[1],"r");
/* make a fully connected matrix */
for (i=0;i<NUM_NODES;i++) {
for (j=0;j<NUM_NODES;j++) {
/* make it more sparce */
fscanf(fp,"%d",&k);
AdjMatrix[i][j]= k;
}
}
/* Get and close the performance counters. */
read(perf_fd_cpu_cycles, &counter_cpu_cycles, sizeof(counter_cpu_cycles));
//close(perf_fd_cpu_cycles);
printf("Number of cpu_cycles before: %d\n", counter_cpu_cycles);
num_cycles_nominal = counter_cpu_cycles;
/* Get and close the performance counters. */
read(perf_fd_cpu_cycles, &counter_cpu_cycles, sizeof(counter_cpu_cycles));
//close(perf_fd_cpu_cycles);
printf("Number of cpu_cycles after attack: %d\n", counter_cpu_cycles);
num_cycles_attack = counter_cpu_cycles - num_cycles_nominal;
/* finds 10 shortest paths between nodes */
for (i=0,j=NUM_NODES/2;i<100;i++,j++) {
j=j%NUM_NODES;
dijkstra(i,j);
}
read(perf_fd_cpu_cycles, &counter_cpu_cycles, sizeof(counter_cpu_cycles));
close(perf_fd_cpu_cycles);
printf("Number of cpu_cycles end: %d\n", counter_cpu_cycles);
num_cycles_nominal = counter_cpu_cycles - num_cycles_attack;
printf("Number of cpu_cycles nominal: %d\n", num_cycles_nominal);
printf("Number of cpu_cycles attack: %d\n", num_cycles_attack);
exit(0);
}
the problem is that i can read the branch misses with perf having 0x10 instead 0f 0x11 (cycle counters RAW EVENT in GEM5) but using 0x11 for reading the cycles i get zero. When i try to reverse engineer the increment of cycle counter i do the following comments:
when simple/atomic or simple/timing i see that updateCycleCounter is called from the base.hh, also for the 03 cpu model. When HPI and considering that hpi is a MinorCPU model i see that updateCycleCounter is called only in POWER_STATE_ON, but i didnt find in the code a POWER_STATE_ON reference updateCycleCounter(CPU_STATE_ON) which will update the cycle counter. Please help me verify this assumption.
*****The problem was that in the MinorCPU the updateCycleCounter wasnt called for the CPU_STATE_ON which updates the ActiveCycles. It was fixed by the following patch https://gem5-review.googlesource.com/c/public/gem5/+/38095 .

Related

not all PWMs are generated in Pi4 wiringPI language C

I am working on a project where I have to use multi-threading to generate multiple pwms. I am working on raspberry and I use WiringPI to generate softPWMs.
The problems is my raspberry does not want to generate 5 PWMs. Each time a run the code, the PWMs are generated randomly on 3 of the five pins I have setted. I do not know if it is the OS putting some threads on sleep or not.
I have no idea where the problem might be from. In fact, I tries using the same code to send periodically send many variable and it did work. But when I try using the same code with PWM it does not work. The code I am using is right below. If any of you has any idea please help
#include <wiringPi.h>
#include <stdio.h>
#include <softPwm.h>
#include <stdlib.h>
#include <pthread.h>
#define THREAD_NUM 1
struct thArg{
int PWM_pin1;
int rapportCyclique1;
int PWM_pin2;
int rapportCyclique2;
int PWM_pin3;
int rapportCyclique3;
int PWM_pin4;
int rapportCyclique4;
};
struct thArg data = {
22,20,
23,40,
24,80,
25,60
};
void* routine(void* args){
//int PWM_pin = *(int*)args->PWM_pin;
//int intensity = *(int*)args->rapportCyclique;
//pthread_mutex_lock(&mutexBuffer);
struct thArg *arrgs = (struct thArg *) args;
int PWM_pin1 = arrgs->PWM_pin1;
int rapportCyclique1 = arrgs->rapportCyclique1;
int PWM_pin2 = arrgs->PWM_pin2;
int rapportCyclique2 = arrgs->rapportCyclique2;
int PWM_pin3 = arrgs->PWM_pin3;
int rapportCyclique3 = arrgs->rapportCyclique3;
int PWM_pin4 = arrgs->PWM_pin4;
int rapportCyclique4 = arrgs->rapportCyclique4;
pinMode(PWM_pin1, OUTPUT);
softPwmCreate(PWM_pin1, 1, 100);
pinMode(PWM_pin2, OUTPUT);
softPwmCreate(PWM_pin1, 1, 100);
pinMode(PWM_pin3, OUTPUT);
softPwmCreate(PWM_pin1, 1, 100);
pinMode(PWM_pin4, OUTPUT);
softPwmCreate(PWM_pin1, 1, 100);
softPwmWrite(PWM_pin1, rapportCyclique1);
softPwmWrite(PWM_pin2, rapportCyclique2);
softPwmWrite(PWM_pin3, rapportCyclique3);
softPwmWrite(PWM_pin4, rapportCyclique4);
//pthread_mutex_unlock(&mutexBuffer);
}
void* routine(void*);
int main(int argc, char** argv)
{
wiringPiSetup();
pthread_t th[THREAD_NUM];
for(int i=0; i<THREAD_NUM; i++)
{
struct thArg *a = malloc(sizeof(struct thArg));
*a = data;
if(pthread_create(&th[i], NULL, &routine, a) != 0)
{
perror("failed to create thread\n");
exit( EXIT_FAILURE );
}
}
for(int i = 0; i<THREAD_NUM; i++){
if(pthread_join(th[i], NULL)!= 0)
{
perror("Failed to join thread\n");
exit( EXIT_FAILURE );
}
}
//pthread_mutex_destroy(&mutexBuffer);
return EXIT_SUCCESS;
}

C language how to make a timeout function using in gethostname()?

This program reads the domain from a file to a string, truncates the string with "\n" as a key, and then executes the getostbyname() function for each domain to enter the resulting information into the file.
When I use gethostbyname, I want to create a function to enter fail if there is no response for a certain period of time. I tried to implement and process the timeout function, but the function did not work.
The logic that I thought of is calling gethostbyname() and entering fail in the file if there is no response for two seconds, then proceed to the next string and call gethostbyname().
The amount of files is about 150 million domains, so I took only a part of them and made them an example.
Please help me create the functions I want.
This is input.txt
www.naver.com
kbphonemall.com
kbplant.com
k-bplus.com
kbpointreestore.com
kbprint.com
kbprism.com
kbprivatebanking.com
kbpstore.com
kbr9rtudaf5ppy.com
kbrafting.com
kbraille.com
kbrainbank.com
kbrainbow.com
kbrainc.com
kbrainglocal.com
kbrandexpo.com
kbrandingschool.com
kbrandmall.com
kbrandmuseum.com
kbranking.com
k-bread.com
k-breadshop.com
kbreaknews.com
kbreasy.com
kbr-easy.com
kb-rent.com
kbrentacar.com
kb-rentcar.com
kbreport.com
k-brew.com
kbrewtec.com
kbrick.com
kbridge21.com
kbrno.com
k-broad.com
kbrockstar.com
kbrosbeauty.com
kbrosis.com
kbrworks.com
kbs1004.com
kbs123.com
kbs20.com
kbs220.com
kbs3.com
kbs31.com
kbs336.com
kbs358.com
kbs40.com
kbs556.com
kbs5678.com
kbs69.com
kbs7.com
kbs700.com
kbs79.com
kbs87.com
kbs9003.com
kbs911.com
kbs97.com
kbsarchive.com
kbsavers.com
kbsavings.com
kbsavingstar.com
kbsba.com
kbsbaechoo.com
kbsbook.com
kbsc1.com
kbscarf.com
kbsccoding.com
kbscert.com
kbschoolbanking.com
kbscyerrutb.com
kbsec.com
kbsec-greeting.com
kbsecuritynews.com
kbseschool.com
kbsestudy.com
kbsfn.com
kbsgmp.com
kbsgreen.com
kbsgulbee.com
kbs-hip.com
kbsholdings.com
kbshsg.com
kbsisa.com
kbsjeju.com
kbskadt.com
kbskiotmall.com
kbsklt.com
kbskorea.com
kbskorean.com
kbskovo.com
kbsktw.com
kbsktwidea.com
kbslogos.com
kbslove.com
kbs-lse.com
kbsmc-ibd.com
kbsmcob.com
kbsmedi.com
kbsmetal.com
kbsmol.com
kbs-mt.com
kbsmt-academy.com
kbsnd.com
kbsnews.com
kbsnnews.com
kbsonbocns.com
kbsonbodirect.com
kbsonsa.com
kbspetdoc.com
kbsplus.com
kbspro.com
kbsq.com
kbssky.com
kbssomgr.com
kbssports.com
kbsstudy.com
kbstar.com
kbstar2020.com
kbstar21.com
kbstar24.com
kbstarb.com
kbstarcard.com
kbstarclub.com
kbstardirect.com
kbstarebank.com
kbstarfg.com
kbstarfinance.com
kbstarflower.com
kbstarfx.com
kbstarg.com
kbstarir.com
kbstarland.com
kbstarmail.com
kbstarmall.com
kbstarmbank.com
kbstarmoney.com
kbstarpb.com
kbstarsvc.com
kbstarworld.com
kbstarzone.com
kbstbt.com
kbsteel.com
kbstock1.com
kbstock5.com
kbs-travel.com
kbstructure.com
kbstv.com
kbstve.com
kbsuf.com
kbsupercard.com
kbsupporters.com
kbsv.com
kbsvoice.com
kbtac.com
kbtchain.com
kbtechgate.com
kbtechone.com
kbtechpos.com
kbtechshop.com
kbtilbo.com
kb-truck.com
kbtups.com
kbtva.com
kbubi.com
kbuddhism.com
k-buddhism.com
k-buddy.com
kbujejucall.com
kbulgyonews.com
k-bulls.com
kbumall.com
kbund.com
kb-uniform.com
kbusinessnews.com
kbusinfo.com
kbusking.com
kbuvd.com
kbvalve.com
kbvipstock.com
kbweb.com
kbweddingfair.com
kbwel.com
kbwith.com
kbwlab.com
kbwnet.com
kb-world.com
kbworldwide.com
kb-world-wide.com
kby8992.com
kbynews.com
kc005.com
kc04.com
kc0522.com
kc1004.com
kc114.com
kc1357.com
kc1895.com
kc1904.com
kc22.com
kc25.com
kc712.com
kc9479.com
kc97bkyg3tvzgdws.com
kca2009.com
kca21.com
kca7.com
kcaa1.com
kcaa12.com
kcaa21.com
kca-academy.com
kcaawelfare.com
kcabiz.com
kca-charcoal.com
kcadcom.com
k-caddie.com
k-cae.com
kcafrp.com
kcagcf.com
kcagolf.com
kcagym.com
kcahub.com
kcairfiltertech.com
kcakca.com
kcakn.com
kcakorea.com
kcakyrgyz.com
kcallica.com
kcaltrip.com
kcangle.com
kcar.com
k-car.com
kcar2.com
kcaratpay.com
kcarauction.com
kcaraudio.com
kcarb2b.com
kcarcapital.com
kcar-capital.com
kcard.com
kcardirect.com
kcar-direct.com
k-cardirect.com
k-careeraptitude.com
kcarfriends.com
kcarlogis.com
kcarmall.com
kcarnet.com
kcarschool.com
kcarz.com
k-cata.com
kcateam.com
kcatfree.com
kca-therapy.com
kcb4u.com
kcb5.com
kcbc-acc.com
kcbcard.com
kcbec.com
kcbend.com
kcbetrade.com
kcbexchange.com
kcbiea.com
kc-biz.com
kcboltec.com
kcbs119.com
kcbtec.com
kcbtv.com
kcbunion.com
kcc000.com
kcc001.com
kcc002.com
kcc003.com
kcc007.com
kcc1004.com
kcc1122.com
kcc114.com
kcc2.com
kcc21.com
kcc258.com
kcc339.com
kcc5858.com
kcc775.com
kcc7777.com
kcc7979.com
kcc8282.com
kccaedu.com
kccardpos.com
kccarr.com
kccaster.com
kccasters.com
kccauto.com
kccce.com
kccchem.com
kccckorea.com
kcccolorndesign.com
kcccontainer.com
kccdeco.com
kccdepot.com
kccea.com
kccegis.com
kccei.com
kcceleader.com
kccenc.com
kccepost.com
kcceramice.com
kcceye.com
kccf2012.com
kccfilm.com
kccflooring.com
kccgift.com
kccglass.com
kccgroup.com
kcchain.com
kccheavyduty.com
kccholdings.com
kcchomecc.com
kcchomeccinterior.com
kcchwarang.com
kccia.com
kccichem.com
kccinsight.com
kccinterior.com
kccjewelry.com
kcckdong.com
kccks.com
kccmarine.com
kccmaul.com
kccnara.com
kccofficial.com
kccold.com
kccomang.com
kccond.com
kcconveyor.com
kc-coop.com
kc-cottrell.com
kccpaint114.com
kccpaintmall.com
kccplant.com
kccplus.com
kccpr.com
kccrefinish.com
kccrose.com
kccsa.com
kccscleaning.com
kccseoul.com
kccsilicon.com
kccsilicone.com
kccsmms.com
kccssafe.com
kccswitzen-patio.com
kcctm.com
kcctour.com
kccultural.com
kccview.com
kccvma.com
kccwelltztower.com
kccwindow.com
kccwindows.com
kccworld.com
kccycasters.com
kccyes.com
kcdc2020.com
kcdc21.com
kcdcode.com
kcdeaf.com
kcdfarm.com
kcdic.com
kcdkorea.com
kcdoll.com
kcdoor.com
k-cea.com
kcea98.com
kceasw.com
kceautodoor.com
kceccenter.com
kcecctv.com
kcecoin.com
kcecrs.com
and this is code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#define IPATH "example.txt"
#define OPATH "result/output.txt"
struct hostent *host;
int whatthe = 0;
void sig_handler(int signum){
host = NULL;
}
void dnslookup(char temp1[]){
host = gethostbyname(temp1);
}
int main(int argc, char *argv[]){
struct timeval tv;
double begin, end;
gettimeofday(&tv, NULL);
begin = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ;
char *ListBuffer;
int ListSize;
FILE *InputFile = fopen(IPATH, "r");
FILE *OutputFile = fopen(OPATH, "w");
fseek(InputFile, 0, SEEK_END);
ListSize = ftell(InputFile); //길이를 재고
ListSize ++; //NULL 문자가 들어갈 자리까지 해줌. 문자열의 끝을 알기 위해서
ListBuffer = malloc(ListSize); //잰 길이만큼 동적할당
memset(ListBuffer, 0, ListSize); //할당한 메모리 초기화
ListBuffer[ListSize] = '\0';
fseek(InputFile, 0, SEEK_SET);
fread(ListBuffer, ListSize, 1, InputFile); //읽어와서 동적할당한 배열에 넣기
char temp[] = {0, };
char *temp2;
int count = 0;
int h_count = 0;
char *str1 = NULL;
char *temp1 = strtok_r(ListBuffer, "\n", &str1);
while (temp1 != NULL){
dnslookup(temp1);
signal(SIGALRM,sig_handler);
alarm(2);
if (host != NULL){
fprintf(OutputFile, "%s / %s\n", temp1, inet_ntoa(*(struct in_addr *)host->h_addr_list[0]));
}
else{
fprintf(OutputFile, "%s / %s\n",temp1, "FAIL");
}
temp1 = strtok_r(NULL, "\n", &str1);
}
fclose(InputFile); //파일 포인터 닫기
fclose(OutputFile); //파일 포인터 닫기
free(ListBuffer); // 동적 메모리 해제
ListBuffer = NULL;
gettimeofday(&tv, NULL);
end = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ;
// 출력
printf("Execution time %f\n", (end - begin) / 1000);
}
what is problem?
If you need more explanation, I'll answer it quickly.
Thank you for reading my question. Have a nice day.
Use setjmp() & longjmp() pair with alarm().
#include <setjmp.h>
#define DNS_TIMEOUT 2 // timeout you need
static jmp_buf env;
void sig_handler (int signum) {
//host = NULL;
longjmp (env, 1); // jump to setjmp() location with value 1
}
int dnslookup (const char* domain) {
#define STATUS_TIMEOUT 128 // custom: timeout occurred
int status = 0;
signal (SIGALRM, sig_handler);
if (0 == setjmp(env)) { // to return here after timeout with return value 1
alarm (DNS_TIMEOUT); // setting timeout
host = gethostbyname (domain);
signal (SIGALRM, SIG_DFL);
alarm (0); // cancel alarm
} else { // after timeout-alarm we're here
// you may want to record TIMEOUT instead of FAIL
status = STATUS_TIMEOUT;
host = NULL;
//printf ("\nTimeout for %s", domain);
}
return status;
}
Also:
ListBuffer = malloc(ListSize); //잰 길이만큼 동적할당
memset(ListBuffer, 0, ListSize); //할당한 메모리 초기화 // not necessary
//ListBuffer[ListSize] = '\0'; // BUFFER-OVERFLOW
...
char *rmdList = NULL;
char *domain = strtok_r (ListBuffer, "\n", &rmdList);
while (domain != NULL) {
int status = dnslookup (domain);
// signal (SIGALRM, sig_handler);
// alarm (2);
if (host)
fprintf (OutputFile, "%s / %s\n", domain, inet_ntoa (* (struct in_addr *) host->h_addr_list[0]));
else if (STATUS_TIMEOUT == status)
fprintf (OutputFile, "%s / %s\n", domain, "TIMEOUT");
else
fprintf (OutputFile, "%s / %s\n", domain, "FAIL");
domain = strtok_r (NULL, "\n", &rmdList);
}
That said :
The gethostbyname*(), gethostbyaddr*(), herror(), and hstrerror()
functions are obsolete. Applications should use getaddrinfo(3),
getnameinfo(3), and gai_strerror(3) instead.

Commands to execute functions in C

I'm using the LXLE 14.04 distribution of Linux.
I want to write a C program to read commands, interpret and perform them. I'd like the program to be efficient, and I do not want to use
a linked list.
The commands are operations on sets.
Each set can contain any of the values from 0 through 127 inclusive.
I decided to represent a set as an array of characters, containing 128 bits.
If bit at position pos is turned on then the number pos is in the set and if the bit at position pos is turned off then the number pos is
not present in the set. For example, if the bit at position 4 is 1, then the number 4 is present in the set, if the bit at position 11 is 1 then the number
11 is present in the set.
The program should read commands and interpret them in a certain way.
There are a few commands: read_set, print_set, union_set, intersect_set, sub_set and halt.
For example, the command read_set A,1,2,14,-1 in the terminal will cause the reading of values of the list into the specified set in the command.
In this case the specified set in the command is A. The end of the list is represented by -1. So after writing this command, the set A will contain the elements 1,2,14.
This is what I have so far.
Below is the file set.h
#include <stdio.h>
typedef struct
{
char array[16]; /*Takes 128 bits of storage*/
}set;
extern set A , B , C , D , E , F;
This is the file main.c
#include <stdio.h>
#include "set.h"
#include <string.h>
#include <stdlib.h>
set A , B , C , D , E , F; /*Variable definition*/
void read_set(set s,char command[])
{
int i, number = 0 , pos;
char* str_num = strtok(NULL,"A, ");
unsigned int flag = 1;
printf("I am in the function read_set right now\n");
while(str_num != NULL) /*without str_num != NULL get segmentation fault*/
{
number = atoi(str_num);
if(number == -1)
return;
printf("number%d ",number);
printf("str_num %c\n",*str_num);
i = number/8; /*Array index*/
pos = number%8; /*bit position*/
flag = flag << pos;
s.array[i] = s.array[i] | flag;
str_num = strtok(NULL, ", ");
if(s.array[i] & flag)
printf("Bit at position %d is turned on\n",pos);
else
printf("Bit at position %d is turned off\n",pos);
flag = 1;
}
}
void print_set(set s)
{
unsigned int flag = 1; int in_set = 0;
int i = 0;
while(s.array[i] != -1)
{
if(s.array[i] & flag)
{
in_set = s.array[i];
printf("%d,",in_set );
}
i++;
flag = 1;
}
}
int main()
{
#define CMD_LENGTH 256
char command[CMD_LENGTH]; char* letter;
printf("Please enter a command");
gets(command);
letter = strtok(command,"read_set ,");
switch(*letter)
{
case 'A':
{
read_set(A,command);
break;
}
case 'B':
{
read_set(B,command);
break;
}
case 'C':
{
read_set(C,command);
break;
}
case 'D':
{
read_set(D,command);
break;
}
case 'E':
{
read_set(E,command);
break;
}
case 'F':
{
read_set(F,command);
break;
}
}
return 0;
}
Clearly, it is not a good practice to write a bunch of switch statements and using strtok for each command, and repeating the code written in the main function for each command in order to call the different functions. I thought about using a pointer to a generic function, but since each function receives different parameters,
I do not think this is going to work.
Is there a better way of doing this?
Thanks in advance!
Update #1:
Here's the code. I've made some changes to it.
#include <stdio.h>
#include "set.h"
#include <string.h>
#include <stdlib.h>
set A , B , C , D , E , F; /*Variable definition*/
set sets[6];
/*Below I want to initialize sets so that set[0] = A set[1] = B etc*/
sets[0].array = A.array;
sets[1].array = B.array;
sets[2].array = C.array;
sets[3].array = D.array;
sets[4].array = E.array;
sets[5].array = F.array;
void read_set(set s,char all_command[])
{
int i, number = 0 , pos;
char* str_num = strtok(NULL,"A, ");
unsigned int flag = 1;
printf("I am in the function read_set right now\n");
while(str_num != NULL) /*without str_num != NULL get segmentation fault*/
{
number = atoi(str_num);
if(number == -1)
return;
printf("number%d ",number);
printf("str_num %c\n",*str_num);
i = number/8; /*Array index*/
pos = number%8; /*bit position*/
flag = flag << pos;
s.array[i] = s.array[i] | flag;
str_num = strtok(NULL, ", ");
if(s.array[i] & flag)
printf("Bit at position %d is turned on\n",pos);
else
printf("Bit at position %d is turned off\n",pos);
flag = 1;
}
}
typedef struct
{
char *command;
void (*func)(set,char*);
} entry;
entry chart[] = { {"read_set",&read_set} };
void (*getFunc(char *comm) ) (set,char*)
{
int i;
for(i=0; i<2; i++)
{
if( strcmp(chart[i].command,comm) == 0)
return chart[i].func;
}
return NULL;
}
int main()
{
#define PER_CMD 256
char all_comm[PER_CMD]; void (*ptr_one)(set,char*) = NULL; char* comm; char* letter;
while( (strcmp(all_comm,"halt") != 0 ) & (all_comm != NULL))
{
printf("Please enter a command");
gets(all_comm);
comm = strtok(all_comm,", ");
ptr_one = getFunc(comm);
letter = strtok(NULL,",");
ptr_one(A,all_comm);
all_comm[0] = '\0';
letter[0] = '\0';
}
return 0;
}
I get the following compile error:
main.c:9:8: error: expected ���=���, ���,���, ���;���, ���asm��� or ���attribute��� before ���.��� token
What's my mistake? How can I fix this?
Thanks a lot! #Claim Yang
However,in your case, using switch is almost the best solution to this.
Another way without switch is using a simple way to get an index. Here is a simple solution.
set sets[6];
read_set(sets[*letter - 'A'], command);
Then if you need to read a command, another array of pointers to functions is needed. Like below:
void (*functions[3])(set,char[]);
functions[0] = read_set;
And so on.
The point is coverting your string to an int, so it can be seen as an index of an array.
Then call functions like functions[string_to_int(string)](set,char[]);

Linux DMA: Using the DMAengine for scatter-gather transactions

I try to use the DMAengine API from a custom kernel driver to perform a scatter-gather operation. I have a contiguous memory region as source and I want to copy its data in several distributed buffers through a scatterlist structure. The DMA controller is the PL330 one that supports the DMAengine API (see PL330 DMA controller).
My test code is the following:
In my driver header file (test_driver.h):
#ifndef __TEST_DRIVER_H__
#define __TEST_DRIVER_H__
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/of_dma.h>
#define SG_ENTRIES 3
#define BUF_SIZE 16
#define DEV_BUF 0x10000000
struct dma_block {
void * data;
int size;
};
struct dma_private_info {
struct sg_table sgt;
struct dma_block * blocks;
int nblocks;
int dma_started;
struct dma_chan * dma_chan;
struct dma_slave_config dma_config;
struct dma_async_tx_descriptor * dma_desc;
dma_cookie_t cookie;
};
struct test_platform_device {
struct platform_device * pdev;
struct dma_private_info dma_priv;
};
#define _get_devp(tdev) (&((tdev)->pdev->dev))
#define _get_dmapip(tdev) (&((tdev)->dma_priv))
int dma_stop(struct test_platform_device * tdev);
int dma_start(struct test_platform_device * tdev);
int dma_start_block(struct test_platform_device * tdev);
int dma_init(struct test_platform_device * tdev);
int dma_exit(struct test_platform_device * tdev);
#endif
In my source that contains the dma functions (dma_functions.c):
#include <linux/slab.h>
#include "test_driver.h"
#define BARE_RAM_BASE 0x10000000
#define BARE_RAM_SIZE 0x10000000
struct ram_bare {
uint32_t * __iomem map;
uint32_t base;
uint32_t size;
};
static void dma_sg_check(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
uint32_t * buf;
unsigned int bufsize;
int nwords;
int nbytes_word = sizeof(uint32_t);
int nblocks;
struct ram_bare ramb;
uint32_t * p;
int i;
int j;
ramb.map = ioremap(BARE_RAM_BASE,BARE_RAM_SIZE);
ramb.base = BARE_RAM_BASE;
ramb.size = BARE_RAM_SIZE;
dev_info(dev,"nblocks: %d \n",dma_priv->nblocks);
p = ramb.map;
nblocks = dma_priv->nblocks;
for( i = 0 ; i < nblocks ; i++ ) {
buf = (uint32_t *) dma_priv->blocks[i].data;
bufsize = dma_priv->blocks[i].size;
nwords = dma_priv->blocks[i].size/nbytes_word;
dev_info(dev,"block[%d],size %d: ",i,bufsize);
for ( j = 0 ; j < nwords; j++, p++) {
dev_info(dev,"DMA: 0x%x, RAM: 0x%x",buf[j],ioread32(p));
}
}
iounmap(ramb.map);
}
static int dma_sg_exit(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
int ret = 0;
int i;
for( i = 0 ; i < dma_priv->nblocks ; i++ ) {
kfree(dma_priv->blocks[i].data);
}
kfree(dma_priv->blocks);
sg_free_table(&(dma_priv->sgt));
return ret;
}
int dma_stop(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
int ret = 0;
dma_unmap_sg(dev,dma_priv->sgt.sgl,\
dma_priv->sgt.nents, DMA_FROM_DEVICE);
dma_sg_exit(tdev);
dma_priv->dma_started = 0;
return ret;
}
static void dma_callback(void * param)
{
enum dma_status dma_stat;
struct test_platform_device * tdev = (struct test_platform_device *) param;
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
dev_info(dev,"Checking the DMA state....\n");
dma_stat = dma_async_is_tx_complete(dma_priv->dma_chan,\
dma_priv->cookie, NULL, NULL);
if(dma_stat == DMA_COMPLETE) {
dev_info(dev,"DMA complete! \n");
dma_sg_check(tdev);
dma_stop(tdev);
} else if (unlikely(dma_stat == DMA_ERROR)) {
dev_info(dev,"DMA error! \n");
dma_stop(tdev);
}
}
static void dma_busy_loop(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
enum dma_status status;
int status_change = -1;
do {
status = dma_async_is_tx_complete(dma_priv->dma_chan, dma_priv->cookie, NULL, NULL);
switch(status) {
case DMA_COMPLETE:
if(status_change != 0)
dev_info(dev,"DMA status: COMPLETE\n");
status_change = 0;
break;
case DMA_PAUSED:
if (status_change != 1)
dev_info(dev,"DMA status: PAUSED\n");
status_change = 1;
break;
case DMA_IN_PROGRESS:
if(status_change != 2)
dev_info(dev,"DMA status: IN PROGRESS\n");
status_change = 2;
break;
case DMA_ERROR:
if (status_change != 3)
dev_info(dev,"DMA status: ERROR\n");
status_change = 3;
break;
default:
dev_info(dev,"DMA status: UNKNOWN\n");
status_change = -1;
break;
}
} while(status != DMA_COMPLETE);
dev_info(dev,"DMA transaction completed! \n");
}
static int dma_sg_init(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct scatterlist *sg;
int ret = 0;
int i;
ret = sg_alloc_table(&(dma_priv->sgt), SG_ENTRIES, GFP_ATOMIC);
if(ret)
goto out_mem2;
dma_priv->nblocks = SG_ENTRIES;
dma_priv->blocks = (struct dma_block *) kmalloc(dma_priv->nblocks\
*sizeof(struct dma_block), GFP_ATOMIC);
if(dma_priv->blocks == NULL)
goto out_mem1;
for( i = 0 ; i < dma_priv->nblocks ; i++ ) {
dma_priv->blocks[i].size = BUF_SIZE;
dma_priv->blocks[i].data = kmalloc(dma_priv->blocks[i].size, GFP_ATOMIC);
if(dma_priv->blocks[i].data == NULL)
goto out_mem3;
}
for_each_sg(dma_priv->sgt.sgl, sg, dma_priv->sgt.nents, i)
sg_set_buf(sg,dma_priv->blocks[i].data,dma_priv->blocks[i].size);
return ret;
out_mem3:
i--;
while(i >= 0)
kfree(dma_priv->blocks[i].data);
kfree(dma_priv->blocks);
out_mem2:
sg_free_table(&(dma_priv->sgt));
out_mem1:
ret = -ENOMEM;
return ret;
}
static int _dma_start(struct test_platform_device * tdev,int block)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
int ret = 0;
int sglen;
/* Step 1: Allocate and initialize the SG list */
dma_sg_init(tdev);
/* Step 2: Map the SG list */
sglen = dma_map_sg(dev,dma_priv->sgt.sgl,\
dma_priv->sgt.nents, DMA_FROM_DEVICE);
if(! sglen)
goto out2;
/* Step 3: Configure the DMA */
(dma_priv->dma_config).direction = DMA_DEV_TO_MEM;
(dma_priv->dma_config).src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
(dma_priv->dma_config).src_maxburst = 1;
(dma_priv->dma_config).src_addr = (dma_addr_t) DEV_BUF;
dmaengine_slave_config(dma_priv->dma_chan, \
&(dma_priv->dma_config));
/* Step 4: Prepare the SG descriptor */
dma_priv->dma_desc = dmaengine_prep_slave_sg(dma_priv->dma_chan, \
dma_priv->sgt.sgl, dma_priv->sgt.nents, DMA_DEV_TO_MEM, \
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (dma_priv->dma_desc == NULL) {
dev_err(dev,"DMA could not assign a descriptor! \n");
goto out1;
}
/* Step 5: Set the callback method */
(dma_priv->dma_desc)->callback = dma_callback;
(dma_priv->dma_desc)->callback_param = (void *) tdev;
/* Step 6: Put the DMA descriptor in the queue */
dma_priv->cookie = dmaengine_submit(dma_priv->dma_desc);
/* Step 7: Fires the DMA transaction */
dma_async_issue_pending(dma_priv->dma_chan);
dma_priv->dma_started = 1;
if(block)
dma_busy_loop(tdev);
return ret;
out1:
dma_stop(tdev);
out2:
ret = -1;
return ret;
}
int dma_start(struct test_platform_device * tdev) {
return _dma_start(tdev,0);
}
int dma_start_block(struct test_platform_device * tdev) {
return _dma_start(tdev,1);
}
int dma_init(struct test_platform_device * tdev)
{
int ret = 0;
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
dma_priv->dma_chan = dma_request_slave_channel(dev, \
"dma_chan0");
if (dma_priv->dma_chan == NULL) {
dev_err(dev,"DMA channel busy! \n");
ret = -1;
}
dma_priv->dma_started = 0;
return ret;
}
int dma_exit(struct test_platform_device * tdev)
{
int ret = 0;
struct dma_private_info * dma_priv = _get_dmapip(tdev);
if(dma_priv->dma_started) {
dmaengine_terminate_all(dma_priv->dma_chan);
dma_stop(tdev);
dma_priv->dma_started = 0;
}
if(dma_priv->dma_chan != NULL)
dma_release_channel(dma_priv->dma_chan);
return ret;
}
In my driver source file (test_driver.c):
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include "test_driver.h"
static int dma_block=0;
module_param_named(dma_block, dma_block, int, 0444);
static struct test_platform_device tdev;
static struct of_device_id test_of_match[] = {
{ .compatible = "custom,test-driver-1.0", },
{}
};
static int test_probe(struct platform_device *op)
{
int ret = 0;
struct device * dev = &(op->dev);
const struct of_device_id *match = of_match_device(test_of_match, &op->dev);
if (!match)
return -EINVAL;
tdev.pdev = op;
dma_init(&tdev);
if(dma_block)
ret = dma_start_block(&tdev);
else
ret = dma_start(&tdev);
if(ret) {
dev_err(dev,"Error to start DMA transaction! \n");
} else {
dev_info(dev,"DMA OK! \n");
}
return ret;
}
static int test_remove(struct platform_device *op)
{
dma_exit(&tdev);
return 0;
}
static struct platform_driver test_platform_driver = {
.probe = test_probe,
.remove = test_remove,
.driver = {
.name = "test-driver",
.owner = THIS_MODULE,
.of_match_table = test_of_match,
},
};
static int test_init(void)
{
platform_driver_register(&test_platform_driver);
return 0;
}
static void test_exit(void)
{
platform_driver_unregister(&test_platform_driver);
}
module_init(test_init);
module_exit(test_exit);
MODULE_AUTHOR("klyone");
MODULE_DESCRIPTION("DMA SG test module");
MODULE_LICENSE("GPL");
However, the DMA never calls my callback function and I do not have any idea why it happens. Maybe, I am misunderstanding something...
Could anyone help me?
Thanks in advance.
Caveat: I don't have a definitive solution for you, but merely some observations and suggestions on how to debug this [based on many years of experience writing/debugging linux device drivers].
I presume you believe the callback is not being done because you don't get any printk messages. But, the callback is the only place that has them. But, is the printk level set high enough to see the messages? I'd add a dev_info to your module init, to prove it prints as expected.
Also, you [probably] won't get a callback if dma_start doesn't work as expected, so I'd add some dev_info calls there, too (e.g. before and after the call in step 7). I also notice that not all calls in dma_start check error returns [may be fine or void return, just mentioning in case you missed one]
At this point, it should be noted that there are really two questions here: (1) Did your DMA request start successfully [and complete]? (2) Did you get a callback?
So, I'd split off some code from dma_complete into (e.g.) dma_test_done. The latter does the same checking but only prints the "complete" message. You can call this in a poll mode to verify DMA completion.
So, if you [eventually] get a completion, then the problem reduces to why you didn't get the callback. If, however, you don't [even] get a completion, that's an even more fundamental problem.
This reminds me. You didn't show any code that calls dma_start or how you wait for the completion. I presume that if your callback were working, it would issue a wakeup of some sort that the base level would wait on. Or, the callback would do the request deallocate/cleanup (i.e. more code you'd write)
At step 7, you're calling dma_async_issue_pending, which should call pl330_issue_pending. pl330_issue_pending will call pl330_tasklet.
pl330_tasklet is a tasklet function, but it can also be called directly [to kick off DMA when there are no active requests].
pl330_tasklet will loop on its "work" queue and move any completed items to its "completed" queue. It then tries to start new requests. It then loops on its completed queue and issues the callbacks.
pl330_tasklet grabs the callback pointer, but if it's null it is silently ignored. You've set a callback, but it might be good to verify that where you set the callback is the same place [or propagates to] the place where pl330_tasklet will fetch it from.
When you make the call, everything may be busy, so there are no completed requests, no room to start a new request, so nothing to complete. In that case, pl330_tasklet will be called again later.
So, when dma_async_issue_pending returns, nothing may have happened yet. This is quite probable for your case.
pl330_tasklet tries to start new DMA by calling fill_queue. It will check that a descriptor is not [already] busy by looking at status != BUSY. So, you may wish to verify that yours has the correct value. Otherwise, you'd never get a callback [or even any DMA start].
Then, fill_queue will try to start the request via pl330_submit_req. But, that can return an error (e.g. queue already full), so, again, things are deferred.
For reference, notice the following comment at the top of pl330_submit_req:
Submit a list of xfers after which the client wants notification.
Client is not notified after each xfer unit, just once after all
xfer units are done or some error occurs.
What I'd do is start hacking up pl330.c and add debug messages and cross-checking. If your system is such that pl330 is servicing many other requests, you might limit the debug messages by checking that the device's private data pointer matches yours.
In particular, you'd like to get a message when your request actually gets started, so you could add a debug message to the end of pl330_submit_req
Then, adding messages within pl330_tasklet for requests will help, too.
Those are two good starting points. But, don't be afraid to add more printk calls as needed. You may be surprised by what gets called [or doesn't get called] or in what order.
UPDATE:
If I install the kernel module with the blocking behaviour, everything is initialized well. However, the dma_busy_loop function shows that the DMA descriptor is always IN PROGESS and the DMA transaction never completes. For this reason, the callback function is not executed. What could be happening?
Did a little more research. Cookies are just sequence numbers that increment. For example, if you issue a request that gets broken up into [say] 10 separate scatter/gather operations [descriptors], each one gets a unique cookie value. The cookie return value is the latest/last of the bunch (e.g. 10).
When you're calling (1) dma_async_is_tx_complete, (2) it calls chan->device->device_tx_status, (3) which is pl330_tx_status, (4) which calls dma_cookie_status
Side note/tip: When I was tracking this down, I just kept flipping back and forth between dmaengine.h and pl330.c. It was like: Look at (1), it calls (2). Where is that set? In pl330.c, I presume. So, I grepped for the string and got the name of pl330's function (i.e. (3)). So, I go there, and see that it does (4). So ... Back to dmaengine.h ...
However, when you make the outer call, you're ignoring [setting to NULL] the last two arguments. These can be useful because they return the "last" and "used" cookies. So, even if you don't get full completion, these values could change and show partial progress.
One of them should eventually be >= to the "return" cookie value. (i.e.) The entire operation should be complete. So, this will help differentiate what may be happening.
Also, note that in dmaengine.h, right below dma_async_is_tx_complete, there is dma_async_is_complete. This function is what decides whether to return DMA_COMPLETE or DMA_IN_PROGRESS, based on the cookie value you pass and the "last" and "used" cookie values. It's passive, and not used in the code path [AFAICT], but it does show how to calculate completion yourself.

sending various scsi commands through a single function

I have been playing around with scsi command and I can send some basic commands like different inquirys and such.
I have been using this example to to generate my inquiry. I am working on making this example work with different scsi commands.
http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/pexample.html
I have changed to function to accept different scsi commands through a struct and it also returns a struct based on the output. This works with an inquiry flawlessly. However if I send a READ CAPACITY(16) command the function triggers on the if statement:
(io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)
I am new to scsi programming so I might be doing something totally wrong...
my READ CAPACITY(16) command is just this:
scsi_read_capacity.cmdblk[0]=0x9e;
scsi_read_capacity.cmdblk[13]=32;
the rest of the CDB are 0!
here is the code:
#include <stdio.h>
#include <sys/ioctl.h>
#include <scsi/sg.h>
/* global struct to store return data from a scsi cmd*/
typedef struct SCSI_data {
unsigned char data[1024];
unsigned char raw_sens[252];
unsigned char sense_key;
unsigned char additional_sense_code;
unsigned char additional_sense_qualifier;
unsigned char additional_sense_length;
unsigned char sense_data_descriptors[10][244];
int result;
} SCSI_data;
/* global struct to store return data from a scsi cmd*/
typedef struct SCSI_cmd {
int sg_fd;
unsigned char cmdblk[32];
int cmdblklength;
int allocation_length;
int xfer;
int timeout;
} SCSI_cmd;
SCSI_data send_scsicmd(SCSI_cmd cmdobject) {
int k;;
unsigned char inqBuff[cmdobject.allocation_length];
unsigned char sense_buffer[252];
SCSI_data output_data;
sg_io_hdr_t io_hdr;
/* Prepare INQUIRY command */
memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = cmdobject.cmdblklength;
io_hdr.mx_sb_len = sizeof(sense_buffer);
io_hdr.dxfer_direction = cmdobject.xfer;
io_hdr.dxfer_len = cmdobject.allocation_length;
io_hdr.dxferp = inqBuff;
io_hdr.cmdp = cmdobject.cmdblk;
io_hdr.sbp = sense_buffer;
io_hdr.timeout = cmdobject.timeout;
if (ioctl(cmdobject.sg_fd, SG_IO, &io_hdr) < 0) {
output_data.result=2;
return output_data;
}
/* now for the error processing */
if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
output_data.result=1;
if (io_hdr.sb_len_wr > 0) {
printf("INQUIRY sense data: ");
for (k = 0; k < io_hdr.sb_len_wr; ++k) {
if ((k > 0) && (0 == (k % 10)))
printf("\n ");
printf("0x%02x ", sense_buffer[k]);
}
printf("\n");
}
if (io_hdr.masked_status)
printf("INQUIRY SCSI status=0x%x\n", io_hdr.status);
if (io_hdr.host_status)
printf("INQUIRY host_status=0x%x\n", io_hdr.host_status);
if (io_hdr.driver_status)
printf("INQUIRY driver_status=0x%x\n", io_hdr.driver_status);
}
else { /* assume INQUIRY response is present */
output_data.result=0;
for (k=0;k<cmdobject.allocation_length;k++) {
output_data.data[k]=inqBuff[k];
}
}
return output_data;
}
int main(int argc, char * argv[]) {
FILE *driveptr=fopen(argv[1], "r");
int i;
SCSI_data scsi_data_read_capacity;
SCSI_cmd scsi_read_capacity;
scsi_read_capacity.sg_fd=fileno(driveptr);
scsi_read_capacity.cmdblk[0]=0x9e;
scsi_read_capacity.cmdblk[13]=32;
scsi_read_capacity.cmdblklength=16;
scsi_read_capacity.xfer=SG_DXFER_FROM_DEV;
scsi_read_capacity.allocation_length=32;
scsi_read_capacity.timeout=1000;
scsi_data_read_capacity=send_scsicmd(scsi_read_capacity);
if (scsi_data_read_capacity.result==0) {
printf(" capacity in blocks: %02x%02x%02x%02x%02x%02x%02x%02x\n",
scsi_data_read_capacity.data[0],
scsi_data_read_capacity.data[1],
scsi_data_read_capacity.data[2],
scsi_data_read_capacity.data[3],
scsi_data_read_capacity.data[4],
scsi_data_read_capacity.data[5],
scsi_data_read_capacity.data[6],
scsi_data_read_capacity.data[7]);
printf(" blocksize: %02x%02x%02x%02x\n",
scsi_data_read_capacity.data[8],
scsi_data_read_capacity.data[9],
scsi_data_read_capacity.data[10],
scsi_data_read_capacity.data[11]);
}
fclose(driveptr);
return 0;
}
I had just a small problem. My CDB was wrong!
I had to use this:
scsi_read_capacity.cmdblk[0]=0x9E;
scsi_read_capacity.cmdblk[1]=0x10;
scsi_read_capacity.cmdblk[13]=32;
the second byte had to be equal to 0x10, this is because the scsi cmd 0x9E is a service action command which accepts an argument in the second byte which defines its behavior!

Resources