summaryrefslogtreecommitdiffstats
path: root/os_linux.h
blob: 0b9636eab12f2a2f092f2042962ec352508eff61 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
/* 
 *  os_linux.h
 * 
 * Home page of code is: http://www.smartmontools.org
 *
 * Copyright (C) 2003-8 Bruce Allen
 *
 * Derived from code that was
 *
 *  Written By: Adam Radford <linux@3ware.com>
 *  Modifications By: Joel Jacobson <linux@3ware.com>
 *                    Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *                    Brad Strand <linux@3ware.com>
 *
 *  Copyright (C) 1999-2003 3ware Inc.
 *
 *  Kernel compatibility By:    Andre Hedrick <andre@suse.com>
 *  Non-Copyright (C) 2000      Andre Hedrick <andre@suse.com>
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */


#ifndef OS_LINUX_H_
#define OS_LINUX_H_

#define OS_LINUX_H_CVSID "$Id: os_linux.h 4842 2018-12-02 16:07:26Z chrfranke $\n"

/* 
   The following definitions/macros/prototypes are used for three
   different interfaces, referred to as "the three cases" below.
   CONTROLLER_3WARE_678K      -- 6000, 7000, and 8000 controllers via /dev/sd?
   CONTROLLER_3WARE_678K_CHAR -- 6000, 7000, and 8000 controllers via /dev/twe?
   CONTROLLER_3WARE_9000_CHAR -- 9000 controllers via /dev/twa?
*/

// USED FOR ALL THREE CASES

#define u32 unsigned int
#define TW_OP_ATA_PASSTHRU 0x11
#define MAX(x,y) ( (x)>(y)?(x):(y) )

#pragma pack(1)
/* Scatter gather list entry */
typedef struct TAG_TW_SG_Entry {
  unsigned int address;
  unsigned int length;
} TW_SG_Entry;

/* Command header for ATA pass-thru.  Note that for different
   drivers/interfaces the length of sg_list (here TW_ATA_PASS_SGL_MAX)
   is different.  But it can be taken as same for all three cases
   because it's never used to define any other structures, and we
   never use anything in the sg_list or beyond! */

#define TW_ATA_PASS_SGL_MAX      60

typedef struct TAG_TW_Passthru {
  struct {
    unsigned char opcode:5;
    unsigned char sgloff:3;
  } byte0;
  unsigned char size;
  unsigned char request_id;
  unsigned char unit;
  unsigned char status;  // On return, contains 3ware STATUS register
  unsigned char flags;
  unsigned short param;
  unsigned short features;  // On return, contains ATA ERROR register
  unsigned short sector_count;
  unsigned short sector_num;
  unsigned short cylinder_lo;
  unsigned short cylinder_hi;
  unsigned char drive_head;
  unsigned char command; // On return, contains ATA STATUS register
  TW_SG_Entry sg_list[TW_ATA_PASS_SGL_MAX];
  unsigned char padding[12];
} TW_Passthru;

// the following are for the SCSI interface only 

// Ioctl buffer: Note that this defn has changed in kernel tree...
// Total size is 1041 bytes -- this is really weird

#define TW_IOCTL                 0x80
#define TW_ATA_PASSTHRU          0x1e

// Adam -- should this be #pramga packed? Otherwise table_id gets
// moved for byte alignment.  Without packing, input passthru for SCSI
// ioctl is 31 bytes in.  With packing it is 30 bytes in.
typedef struct TAG_TW_Ioctl { 
  int input_length;
  int output_length;
  unsigned char cdb[16];
  unsigned char opcode;
  // This one byte of padding is missing from the typedefs in the
  // kernel code, but it is indeed present.  We put it explicitly
  // here, so that the structure can be packed.  Adam agrees with
  // this.
  unsigned char packing;
  unsigned short table_id;
  unsigned char parameter_id;
  unsigned char parameter_size_bytes;
  unsigned char unit_index;
  // Size up to here is 30 bytes + 1 padding!
  unsigned char input_data[499];
  // Reserve lots of extra space for commands that set Sector Count
  // register to large values
  unsigned char output_data[512]; // starts 530 bytes in!
  // two more padding bytes here if structure NOT packed.
} TW_Ioctl;

/* Ioctl buffer output -- SCSI interface only! */
typedef struct TAG_TW_Output {
  int padding[2];
  char output_data[512];
} TW_Output; 

// What follows is needed for 9000 char interface only

#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108
#define TW_MAX_SGL_LENGTH_9000 61

typedef struct TAG_TW_Ioctl_Driver_Command_9000 {
  unsigned int control_code;
  unsigned int status;
  unsigned int unique_id;
  unsigned int sequence_id;
  unsigned int os_specific;
  unsigned int buffer_length;
} TW_Ioctl_Driver_Command_9000;

/* Command Packet */
typedef struct TW_Command_9000 {
  /* First DWORD */
  struct {
    unsigned char opcode:5;
    unsigned char sgl_offset:3;
  } byte0;
  unsigned char size;
  unsigned char request_id;
  struct {
    unsigned char unit:4;
    unsigned char host_id:4;
  } byte3;
  /* Second DWORD */
  unsigned char status;
  unsigned char flags;
  union {
    unsigned short block_count;
    unsigned short parameter_count;
    unsigned short message_credits;
  } byte6;
  union {
    struct {
      u32 lba;
      TW_SG_Entry sgl[TW_MAX_SGL_LENGTH_9000];
      u32 padding;
    } io;
    struct {
      TW_SG_Entry sgl[TW_MAX_SGL_LENGTH_9000];
      u32 padding[2];
    } param;
    struct {
      u32 response_queue_pointer;
      u32 padding[125]; /* pad entire structure to 512 bytes */
    } init_connection;
    struct {
      char version[504];
    } ioctl_miniport_version;
  } byte8;
} TW_Command_9000;

/* Command Packet for 9000+ controllers */
typedef struct TAG_TW_Command_Apache {
  struct {
    unsigned char opcode:5;
    unsigned char reserved:3;
  } command;
  unsigned char   unit;
  unsigned short  request_id;
  unsigned char   sense_length;
  unsigned char   sgl_offset;
  unsigned short  sgl_entries;
  unsigned char   cdb[16];
  TW_SG_Entry     sg_list[TW_MAX_SGL_LENGTH_9000];
} TW_Command_Apache;

/* New command packet header */
typedef struct TAG_TW_Command_Apache_Header {
  unsigned char sense_data[18];
  struct {
    char reserved[4];
    unsigned short error;
    unsigned char status;
    struct {
      unsigned char severity:3;
      unsigned char reserved:5;
    } substatus_block;
  } status_block;
  unsigned char err_specific_desc[102];
} TW_Command_Apache_Header;

/* This struct is a union of the 2 command packets */
typedef struct TAG_TW_Command_Full_9000 {
  TW_Command_Apache_Header header;
  union {
    TW_Command_9000   oldcommand;
    TW_Command_Apache newcommand;
  } command;
  unsigned char padding[384]; /* Pad to 1024 bytes */
} TW_Command_Full_9000;

typedef struct TAG_TW_Ioctl_Apache {
  TW_Ioctl_Driver_Command_9000 driver_command;
  char                         padding[488];
  TW_Command_Full_9000         firmware_command;
  char                         data_buffer[1];
  // three bytes of padding here if structure not packed!
} TW_Ioctl_Buf_Apache;



// START OF DEFINITIONS FOR THE CHARACTER INTERFACE TO THE
// 6000/7000/8000 drivers

#define TW_MAX_SGL_LENGTH        62
#define TW_CMD_PACKET_WITH_DATA 0x1f

/* Command Packet */
typedef struct TW_Command {
  /* First DWORD */
  struct {
    unsigned char opcode:5;
    unsigned char sgl_offset:3;
  } byte0;
  unsigned char size;
  unsigned char request_id;
  struct {
    unsigned char unit:4;
    unsigned char host_id:4;
  } byte3;
  /* Second DWORD */
  unsigned char status;
  unsigned char flags;
  union {
    unsigned short block_count;
    unsigned short parameter_count;
    unsigned short message_credits;
  } byte6;
  union {
    struct {
      u32 lba;
      TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
      u32 padding;	/* pad to 512 bytes */
    } io;
    struct {
      TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
      u32 padding[2];
    } param;
    struct {
      u32 response_queue_pointer;
      u32 padding[125];
    } init_connection;
    struct {
      char version[504];
    } ioctl_miniport_version;
  } byte8;
} TW_Command;

typedef struct TAG_TW_New_Ioctl {
  unsigned int  data_buffer_length;
  unsigned char padding [508];
  TW_Command    firmware_command;
  char          data_buffer[1];
  // three bytes of padding here
} TW_New_Ioctl;
#pragma pack()

#if 0
// Useful for checking/understanding packing of 3ware data structures
// above.
void my(int x, char *y){
  printf("The size of %30s is: %5d\n",y, x);
  return;
}

int main() {
  TW_Ioctl tmp;
  my(sizeof(TW_SG_Entry),"TW_SG_Entry");
  my(sizeof(TW_Passthru),"TW_Passthru");
  my(sizeof(TW_Ioctl),"TW_Ioctl");
  my(sizeof(TW_Output),"TW_Output");
  my(sizeof(TW_Ioctl_Driver_Command_9000),"TW_Ioctl_Driver_Command_9000");
  my(sizeof(TW_Command_9000),"TW_Command_9000");
  my(sizeof(TW_Command_Apache),"TW_Command_Apache");
  my(sizeof(TW_Command_Apache_Header),"TW_Command_Apache_Header");
  my(sizeof(TW_Command_Full_9000),"TW_Command_Full_9000");
  my(sizeof(TW_Ioctl_Buf_Apache),"TW_Ioctl_Buf_Apache");
  my(sizeof(TW_Command),"TW_Command");
  my(sizeof(TW_New_Ioctl),"TW_New_Ioctl");                                                                
  printf("TW_Ioctl.table_id - start = %d (irrelevant)\n",
         (void *)&tmp.table_id - (void *)&tmp);
  printf("TW_Ioctl.input_data - start = %d (input passthru location)\n",
         (void *)&tmp.input_data - (void *)&tmp);
  printf("TW_Ioctl.output_data - start = %d (irrelevant)\n",
         (void *)&tmp.output_data - (void *)&tmp);
  return 0;
}
#endif

// The following definitions are from hdreg.h in the kernel source
// tree.  They don't carry any Copyright statements, but I think they
// are primarily from Mark Lord and Andre Hedrick.
typedef unsigned char task_ioreg_t;

typedef struct hd_drive_task_hdr {
  task_ioreg_t data;
  task_ioreg_t feature;
  task_ioreg_t sector_count;
  task_ioreg_t sector_number;
  task_ioreg_t low_cylinder;
  task_ioreg_t high_cylinder;
  task_ioreg_t device_head;
  task_ioreg_t command;
} task_struct_t;

typedef union ide_reg_valid_s {
  unsigned all			: 16;
  struct {
    unsigned data		: 1;
    unsigned error_feature	: 1;
    unsigned sector		: 1;
    unsigned nsector		: 1;
    unsigned lcyl		: 1;
    unsigned hcyl		: 1;
    unsigned select		: 1;
    unsigned status_command	: 1;
    unsigned data_hob		: 1;
    unsigned error_feature_hob	: 1;
    unsigned sector_hob		: 1;
    unsigned nsector_hob	: 1;
    unsigned lcyl_hob		: 1;
    unsigned hcyl_hob		: 1;
    unsigned select_hob		: 1;
    unsigned control_hob	: 1;
  } b;
} ide_reg_valid_t;

typedef struct ide_task_request_s {
  task_ioreg_t	   io_ports[8];
  task_ioreg_t	   hob_ports[8];
  ide_reg_valid_t  out_flags;
  ide_reg_valid_t  in_flags;
  int		   data_phase;
  int		   req_cmd;
  unsigned long	   out_size;
  unsigned long	   in_size;
} ide_task_request_t;

#define TASKFILE_NO_DATA	  0x0000
#define TASKFILE_IN		  0x0001
#define TASKFILE_OUT		  0x0004
#define HDIO_DRIVE_TASK_HDR_SIZE  8*sizeof(task_ioreg_t)
#define IDE_DRIVE_TASK_NO_DATA	       0
#define IDE_DRIVE_TASK_IN	       2
#define IDE_DRIVE_TASK_OUT	       3
#define HDIO_DRIVE_CMD            0x031f
#define HDIO_DRIVE_TASK           0x031e
#define HDIO_DRIVE_TASKFILE       0x031d
#define HDIO_GET_IDENTITY         0x030d

#define HPTIO_CTL                       0x03ff // ioctl interface for HighPoint raid device

#endif /* OS_LINUX_H_ */