source: trunk/src/os2ahci/ioctl.c@ 165

Last change on this file since 165 was 165, checked in by David Azarewicz, 12 years ago

code cleanup - debug messages
fixed defect in smart ioctl

File size: 20.0 KB
Line 
1/******************************************************************************
2 * ioctl.c - Generic IOCTL command processing
3 *
4 * Copyright (c) 2011 thi.guten Software Development
5 * Copyright (c) 2011 Mensys B.V.
6 *
7 * Authors: Christian Mueller, Markus Thielen
8 *
9 * Parts copied from/inspired by the Linux AHCI driver;
10 * those parts are (c) Linux AHCI/ATA maintainers
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#include "os2ahci.h"
28#include "atapi.h"
29#include "ata.h"
30#include "ioctl.h"
31
32#include <scsi.h>
33
34#pragma pack(1)
35
36/* -------------------------- macros and constants ------------------------- */
37
38/* ------------------------ typedefs and structures ------------------------ */
39
40/* Memory area for IOCTLs which send IORBs downstream; currently only
41 * OS2AHCI_IOCTL_PASSTHROUGH falls into this category, thus we're simply
42 * reusing the IORB_ADAPTER_PASSTHRU structure for now. If this ever changes,
43 * we'll need to define a union to cover all IORB types in question.
44 */
45#define CMDLEN sizeof(((OS2AHCI_PASSTHROUGH *) 0)->cmd)
46typedef struct {
47 IORB_ADAPTER_PASSTHRU iorb; /* IORB */
48 SCSI_STATUS_BLOCK ssb; /* SCSI status block */
49 UCHAR cmd[CMDLEN]; /* copy of passthrough cmd
50 * (need to fill ATA return
51 * registers at interrupt time)
52 */
53 UCHAR sense[ATAPI_SENSE_LEN]; /* sense buffer */
54 SCATGATENTRY sg_lst[AHCI_MAX_SG / 2]; /* scatter/gather list */
55 ULONG sg_cnt; /* number of S/G elements */
56 UCHAR lh[16]; /* lock handle for VMLock() */
57} IOCTL_CONTEXT;
58
59/* -------------------------- function prototypes -------------------------- */
60
61static USHORT do_smart (BYTE unit, BYTE sub_func, BYTE cnt, BYTE lba_l,
62 void _far *buf);
63static int map_unit (BYTE unit, USHORT _far *a, USHORT _far *p,
64 USHORT _far *d);
65static LIN lin (void _far *p);
66
67IORBH _far * _far _cdecl ioctl_wakeup(IORBH _far *iorb);
68
69/* ------------------------ global/static variables ------------------------ */
70
71/* ----------------------------- start of code ----------------------------- */
72
73/******************************************************************************
74 * Return device list to allow the ring 3 application to figure out which
75 * adapter/port/device combinations are available.
76 */
77USHORT ioctl_get_devlist(RP_GENIOCTL _far *ioctl)
78{
79 OS2AHCI_DEVLIST _far *devlst = (OS2AHCI_DEVLIST _far *) ioctl->DataPacket;
80 USHORT maxcnt = 0;
81 USHORT cnt = 0;
82 USHORT a;
83 USHORT p;
84 USHORT d;
85
86 /* verify addressability of parm buffer (number of devlst elements) */
87 if (DevHelp_VerifyAccess((SEL) ((ULONG) ioctl->ParmPacket >> 16),
88 sizeof(USHORT),
89 (USHORT) (ULONG) ioctl->ParmPacket,
90 VERIFY_READONLY) != 0) {
91 return(STDON | STERR | 0x05);
92 }
93
94 maxcnt = *((USHORT _far *) ioctl->ParmPacket);
95
96 /* verify addressability of return buffer (OS2AHCI_DEVLIST) */
97 if (DevHelp_VerifyAccess((SEL) ((ULONG) devlst >> 16),
98 offsetof(OS2AHCI_DEVLIST, devs) +
99 sizeof(devlst->devs) * maxcnt,
100 (USHORT) (ULONG) devlst,
101 VERIFY_READWRITE) != 0) {
102 return(STDON | STERR | 0x05);
103 }
104
105 /* fill-in device list */
106 for (a = 0; a < ad_info_cnt; a++) {
107 AD_INFO *ai = ad_infos + a;
108
109 for (p = 0; p <= ai->port_max; p++) {
110 P_INFO *pi = ai->ports + p;
111
112 for (d = 0; d <= pi->dev_max; d++) {
113 if (pi->devs[d].present) {
114 /* add this device to the device list */
115 if (cnt >= maxcnt) {
116 /* not enough room in devlst */
117 goto ioctl_get_device_done;
118 }
119
120 devlst->devs[cnt].adapter = a;
121 devlst->devs[cnt].port = p;
122 devlst->devs[cnt].device = d;
123 devlst->devs[cnt].type = pi->devs[d].dev_type;
124 devlst->devs[cnt].ncq_max = pi->devs[d].ncq_max;
125
126 if (pi->devs[d].lba48) devlst->devs[cnt].flags |= DF_LBA48;
127 if (pi->devs[d].atapi) devlst->devs[cnt].flags |= DF_ATAPI;
128 if (pi->devs[d].atapi_16) devlst->devs[cnt].flags |= DF_ATAPI_16;
129 if (pi->devs[d].removable) devlst->devs[cnt].flags |= DF_REMOVABLE;
130 cnt++;
131 }
132 }
133 }
134 }
135
136ioctl_get_device_done:
137 devlst->cnt = cnt;
138 return(STDON);
139}
140
141/******************************************************************************
142 * Adapter passthrough IOCTL. This IOCTL covers both ATA and ATAPI passthrough
143 * requests.
144 */
145USHORT ioctl_passthrough(RP_GENIOCTL _far *ioctl)
146{
147 OS2AHCI_PASSTHROUGH _far *req = (OS2AHCI_PASSTHROUGH _far *) ioctl->ParmPacket;
148 char _far *sense_buf = (char _far *) ioctl->DataPacket;
149 IOCTL_CONTEXT *ic;
150 USHORT ret;
151 USHORT a;
152 USHORT p;
153 USHORT d;
154
155 /* verify addressability of parm buffer (OS2AHCI_PASSTHROUGH) */
156 if (DevHelp_VerifyAccess((SEL) ((ULONG) req >> 16),
157 sizeof(OS2AHCI_PASSTHROUGH),
158 (USHORT) (ULONG) req,
159 VERIFY_READWRITE) != 0) {
160 return(STDON | STERR | 0x05);
161 }
162
163 /* verify addressability of data buffer (sense data) */
164 if (req->sense_len > 0) {
165 if (DevHelp_VerifyAccess((SEL) ((ULONG) sense_buf >> 16),
166 req->sense_len,
167 (USHORT) (ULONG) sense_buf,
168 VERIFY_READWRITE) != 0) {
169 return(STDON | STERR | 0x05);
170 }
171 }
172
173 /* Verify basic request parameters such as adapter/port/device, size of
174 * DMA buffer (the S/G list can't have more than AHCI_MAX_SG / 2 entries), ...
175 */
176 a = req->adapter;
177 p = req->port;
178 d = req->device;
179 if (a >= ad_info_cnt || p > ad_infos[a].port_max ||
180 d > ad_infos[a].ports[p].dev_max || !ad_infos[a].ports[p].devs[d].present) {
181 return(STDON | STERR | ERROR_I24_BAD_UNIT);
182 }
183 if ((req->buflen + 4095) / 4096 + 1 > AHCI_MAX_SG / 2 ||
184 req->cmdlen < 6 || req->cmdlen > sizeof(req->cmd)) {
185 return(STDON | STERR | ERROR_I24_INVALID_PARAMETER);
186 }
187
188 /* allocate IOCTL context data */
189 if ((ic = malloc(sizeof(*ic))) == NULL) {
190 return(STDON | STERR | ERROR_I24_GEN_FAILURE);
191 }
192 memset(ic, 0x00, sizeof(*ic));
193
194 /* lock DMA transfer buffer into memory and construct S/G list */
195 if (req->buflen > 0) {
196 if (DevHelp_VMLock(VMDHL_LONG | !((req->flags & PT_WRITE) ? VMDHL_WRITE : 0),
197 req->buf, req->buflen, lin(ic->sg_lst), lin(&ic->lh),
198 &ic->sg_cnt) != 0) {
199 /* couldn't lock buffer and/or produce a S/G list */
200 free(ic);
201 return(STDON | STERR | ERROR_I24_INVALID_PARAMETER);
202 }
203 }
204
205 /* fill in adapter passthrough fields */
206 ic->iorb.iorbh.Length = sizeof(ic->iorb);
207 ic->iorb.iorbh.UnitHandle = iorb_unit(a, p, d);
208 ic->iorb.iorbh.CommandCode = IOCC_ADAPTER_PASSTHRU;
209 ic->iorb.iorbh.CommandModifier = (req->flags & PT_ATAPI) ? IOCM_EXECUTE_CDB : IOCM_EXECUTE_ATA;
210 ic->iorb.iorbh.RequestControl = IORB_ASYNC_POST;
211 ic->iorb.iorbh.Timeout = req->timeout;
212 ic->iorb.iorbh.NotifyAddress = ioctl_wakeup;
213
214 ic->iorb.cSGList = ic->sg_cnt;
215 ic->iorb.pSGList = ic->sg_lst;
216 ic->iorb.ppSGLIST = virt_to_phys(ic->sg_lst);
217
218 memcpy(ic->cmd, req->cmd.cdb, sizeof(ic->cmd));
219 ic->iorb.ControllerCmdLen = req->cmdlen;
220 ic->iorb.pControllerCmd = ic->cmd;
221 ic->iorb.Flags = (req->flags & PT_WRITE) ? 0 : PT_DIRECTION_IN;
222
223 if (req->sense_len > 0) {
224 /* initialize SCSI status block to allow getting sense data */
225 ic->iorb.iorbh.pStatusBlock = (BYTE *) &ic->ssb;
226 ic->iorb.iorbh.StatusBlockLen = sizeof(ic->ssb);
227 ic->ssb.SenseData = (SCSI_REQSENSE_DATA _far *) ic->sense;
228 ic->ssb.ReqSenseLen = sizeof(ic->sense);
229 ic->iorb.iorbh.RequestControl |= IORB_REQ_STATUSBLOCK;
230 }
231
232 /* send IORB on its way */
233 add_entry(&ic->iorb.iorbh);
234
235 /* Wait for IORB completion. */
236 spin_lock(drv_lock);
237 while (!(ic->iorb.iorbh.Status & IORB_DONE)) {
238 DevHelp_ProcBlock((ULONG) (void _far *) &ic->iorb.iorbh, 30000, 1);
239 }
240 spin_unlock(drv_lock);
241
242 ret = STDON;
243
244 /* map IORB error codes to device driver error codes */
245 if (ic->iorb.iorbh.Status & IORB_ERROR) {
246 ret |= STERR;
247
248 switch (ic->iorb.iorbh.ErrorCode) {
249
250 case IOERR_UNIT_NOT_READY:
251 ret |= ERROR_I24_NOT_READY;
252 break;
253
254 case IOERR_MEDIA_CHANGED:
255 ret |= ERROR_I24_DISK_CHANGE;
256 break;
257
258 case IOERR_MEDIA:
259 case IOERR_MEDIA_NOT_FORMATTED:
260 ret |= ERROR_I24_CRC;
261 break;
262
263 case IOERR_CMD_SYNTAX:
264 case IOERR_CMD_NOT_SUPPORTED:
265 ret |= ERROR_I24_BAD_COMMAND;
266 break;
267
268 case IOERR_MEDIA_WRITE_PROTECT:
269 ret |= ERROR_I24_WRITE_PROTECT;
270 break;
271
272 case IOERR_CMD_ABORTED:
273 ret |= ERROR_I24_CHAR_CALL_INTERRUPTED;
274 break;
275
276 case IOERR_RBA_ADDRESSING_ERROR:
277 ret |= ERROR_I24_SEEK;
278 break;
279
280 case IOERR_RBA_LIMIT:
281 ret |= ERROR_I24_SECTOR_NOT_FOUND;
282 break;
283
284 case IOERR_CMD_SGLIST_BAD:
285 ret |= ERROR_I24_INVALID_PARAMETER;
286 break;
287
288 case IOERR_DEVICE_NONSPECIFIC:
289 case IOERR_ADAPTER_TIMEOUT:
290 case IOERR_ADAPTER_DEVICEBUSCHECK:
291 case IOERR_CMD_ADD_SOFTWARE_FAILURE:
292 case IOERR_CMD_SW_RESOURCE:
293 default:
294 ret |= ERROR_I24_GEN_FAILURE;
295 break;
296 }
297
298 /* copy sense information, if there is any */
299 if ((ic->iorb.iorbh.Status & IORB_STATUSBLOCK_AVAIL) &&
300 (ic->ssb.Flags | STATUS_SENSEDATA_VALID)) {
301 memcpy(sense_buf, ic->ssb.SenseData,
302 min(ic->ssb.ReqSenseLen, req->sense_len));
303 }
304
305 } else if ((req->flags & PT_ATAPI) == 0) {
306 /* Copy ATA cmd back to IOCTL request (ATA commands are effectively
307 * registers which are sometimes used to indicate return conditions,
308 * e.g. when requesting the smart status)
309 */
310 memcpy(&req->cmd.ata, ic->cmd, sizeof(req->cmd.ata));
311 }
312
313 free(ic);
314 if (req->buflen > 0) {
315 DevHelp_VMUnLock(lin(ic->lh));
316 }
317 return(ret);
318}
319
320/******************************************************************************
321 * Generic disk IOCTL handler; this IOCTL category has originally been defined
322 * in IBM1S506; the code has been more or less copied from DANIS506.
323 *
324 * NOTE: Only a subset of the IOCTL calls are implemented in OS2AHCI at this
325 * point, basically those calls required to get HDMON working.
326 */
327USHORT ioctl_gen_dsk(RP_GENIOCTL _far *ioctl)
328{
329 DSKSP_CommandParameters _far *cp = (DSKSP_CommandParameters _far *) ioctl->ParmPacket;
330 UnitInformationData _far *ui;
331 OS2AHCI_PASSTHROUGH pt;
332 RP_GENIOCTL tmp_ioctl;
333 USHORT size = 0;
334 USHORT ret;
335 USHORT a;
336 USHORT p;
337 USHORT d;
338 UCHAR unit;
339
340 /* verify addressability of parm buffer (DSKSP_CommandParameters) */
341 if (DevHelp_VerifyAccess((SEL) ((ULONG) cp >> 16),
342 sizeof(DSKSP_CommandParameters),
343 (USHORT) (ULONG) cp,
344 VERIFY_READONLY) != 0) {
345 return(STDON | STERR | 0x05);
346 }
347 unit = cp->byPhysicalUnit;
348
349 /* verify addressability of data buffer (depends on function code) */
350 switch (ioctl->Function) {
351
352 case DSKSP_GEN_GET_COUNTERS:
353 size = sizeof(DeviceCountersData);
354 break;
355
356 case DSKSP_GET_UNIT_INFORMATION:
357 size = sizeof(UnitInformationData);
358 break;
359
360 case DSKSP_GET_INQUIRY_DATA:
361 size = ATA_ID_WORDS * sizeof(u16);
362 break;
363 }
364
365 if (size > 0) {
366 if (DevHelp_VerifyAccess((SEL) ((ULONG) ioctl->DataPacket >> 16),
367 size, (USHORT) (ULONG) ioctl->DataPacket,
368 VERIFY_READWRITE) != 0) {
369 return(STDON | STERR | 0x05);
370 }
371 }
372
373 if (map_unit(unit, &a, &p, &d)) {
374 return(STDON | STERR | ERROR_I24_BAD_UNIT);
375 }
376
377 /* execute generic disk request */
378 switch (ioctl->Function) {
379
380 case DSKSP_GEN_GET_COUNTERS:
381 /* Not supported, yet; we would need dynamically allocated device
382 * structures to cope with the memory requirements of the corresponding
383 * statistics buffer. For the time being, we'll return an empty buffer.
384 */
385 memset(ioctl->DataPacket, 0x00, sizeof(DeviceCountersData));
386 ret = STDON;
387 break;
388
389 case DSKSP_GET_UNIT_INFORMATION:
390 /* get unit information; things like port addresses won't fit so we don't
391 * even bother returning those.
392 */
393 ui = (UnitInformationData _far *) ioctl->DataPacket;
394 memset(ui, 0x00, sizeof(*ui));
395
396 ui->wRevisionNumber = 1;
397 ui->wIRQ = ad_infos[a].irq;
398 ui->wFlags = UIF_VALID;
399 ui->wFlags |= UIF_RUNNING_BMDMA;
400 ui->wFlags |= (unit & 0x0001) ? UIF_SLAVE : 0;
401 ui->wFlags |= (ad_infos[a].ports[p].devs[d].atapi) ? UIF_ATAPI : 0;
402 ui->wFlags |= UIF_SATA;
403
404 ret = STDON;
405 break;
406
407 case DSKSP_GET_INQUIRY_DATA:
408 /* return ATA ID buffer */
409 memset(&tmp_ioctl, 0x00, sizeof(tmp_ioctl));
410 tmp_ioctl.Category = OS2AHCI_IOCTL_CATEGORY;
411 tmp_ioctl.Function = OS2AHCI_IOCTL_PASSTHROUGH;
412 tmp_ioctl.ParmPacket = (void _far *) &pt;
413
414 memset(&pt, 0x00, sizeof(pt));
415 pt.adapter = a;
416 pt.port = p;
417 pt.device = d;
418 pt.cmdlen = sizeof(pt.cmd.ata);
419 pt.cmd.ata.cmd = (ad_infos[a].ports[p].devs[d].atapi) ?
420 ATA_CMD_ID_ATAPI : ATA_CMD_ID_ATA;
421 pt.buflen = size;
422 pt.buf = lin(ioctl->DataPacket);
423
424 ret = gen_ioctl(&tmp_ioctl);
425 break;
426
427 default:
428 ret = STDON | STATUS_ERR_UNKCMD;
429 break;
430 }
431
432 return(ret);
433}
434
435/******************************************************************************
436 * SMART IOCTL handler; this IOCTL category has originally been defined in
437 * IBM1S506; the code has been more or less copied from DANIS506.
438 */
439USHORT ioctl_smart(RP_GENIOCTL _far *ioctl)
440{
441 DSKSP_CommandParameters _far *cp = (DSKSP_CommandParameters _far *) ioctl->ParmPacket;
442 USHORT size = 0;
443 USHORT ret;
444 UCHAR unit;
445 UCHAR parm;
446
447 /* verify addressability of parm buffer (DSKSP_CommandParameters) */
448 if (DevHelp_VerifyAccess((SEL) ((ULONG) cp >> 16),
449 sizeof(DSKSP_CommandParameters),
450 (USHORT) (ULONG) cp,
451 VERIFY_READONLY) != 0) {
452 return(STDON | STERR | 0x05);
453 }
454 unit = cp->byPhysicalUnit;
455
456 /* verify addressability of data buffer (depends on SMART function) */
457 switch (ioctl->Function) {
458
459 case DSKSP_SMART_GETSTATUS:
460 size = sizeof(ULONG);
461 break;
462
463 case DSKSP_SMART_GET_ATTRIBUTES:
464 case DSKSP_SMART_GET_THRESHOLDS:
465 case DSKSP_SMART_GET_LOG:
466 size = 512;
467 break;
468 }
469
470 if (size > 0) {
471 if (DevHelp_VerifyAccess((SEL) ((ULONG) ioctl->DataPacket >> 16),
472 size, (USHORT) (ULONG) ioctl->DataPacket,
473 VERIFY_READWRITE) != 0) {
474 return(STDON | STERR | 0x05);
475 }
476 parm = ioctl->DataPacket[0];
477 }
478
479 /* execute SMART request */
480 switch (ioctl->Function) {
481
482 case DSKSP_SMART_ONOFF:
483 ret = do_smart(unit, (BYTE) ((parm) ? ATA_SMART_ENABLE : ATA_SMART_DISABLE), 0, 0, NULL);
484 break;
485
486 case DSKSP_SMART_AUTOSAVE_ONOFF:
487 ret = do_smart(unit, ATA_SMART_AUTOSAVE, (BYTE) ((parm) ? (BYTE) 0xf1 : 0), 0, NULL);
488 break;
489
490 case DSKSP_SMART_AUTO_OFFLINE:
491 ret = do_smart(unit, ATA_SMART_AUTO_OFFLINE, parm, 0, NULL);
492 break;
493
494 case DSKSP_SMART_EXEC_OFFLINE:
495 ret = do_smart(unit, ATA_SMART_IMMEDIATE_OFFLINE, 0, parm, NULL);
496 break;
497
498 case DSKSP_SMART_SAVE:
499 ret = do_smart(unit, ATA_SMART_SAVE, 0, 0, NULL);
500 break;
501
502 case DSKSP_SMART_GETSTATUS:
503 ret = do_smart(unit, ATA_SMART_STATUS, 0, 0, ioctl->DataPacket);
504 break;
505
506 case DSKSP_SMART_GET_ATTRIBUTES:
507 ret = do_smart(unit, ATA_SMART_READ_VALUES, 0, 0, ioctl->DataPacket);
508 break;
509
510 case DSKSP_SMART_GET_THRESHOLDS:
511 ret = do_smart(unit, ATA_SMART_READ_THRESHOLDS, 0, 0, ioctl->DataPacket);
512 break;
513
514 case DSKSP_SMART_GET_LOG:
515 ret = do_smart(unit, ATA_SMART_READ_LOG, 1, parm, ioctl->DataPacket);
516 break;
517
518 default:
519 ret = STDON | STATUS_ERR_UNKCMD;
520 }
521
522 return(ret);
523}
524
525/******************************************************************************
526 * Perform SMART request. The code has been more or less copied from DANIS506.
527 */
528static USHORT do_smart(BYTE unit, BYTE sub_func, BYTE cnt, BYTE lba_l, void _far *buf)
529{
530 OS2AHCI_PASSTHROUGH pt;
531 RP_GENIOCTL ioctl;
532 USHORT ret;
533 USHORT a;
534 USHORT p;
535 USHORT d;
536
537 if (map_unit(unit, &a, &p, &d)) {
538 return(STDON | STERR | ERROR_I24_BAD_UNIT);
539 }
540
541 /* Perform SMART request using the existing OS2AHCI_IOTCL_PASSTHROUGH IOCTL
542 * interface which already takes care of allocating an IORB, s/g lists, etc.
543 */
544 memset(&ioctl, 0x00, sizeof(ioctl));
545 ioctl.Category = OS2AHCI_IOCTL_CATEGORY;
546 ioctl.Function = OS2AHCI_IOCTL_PASSTHROUGH;
547 ioctl.ParmPacket = (void _far *) &pt;
548
549 memset(&pt, 0x00, sizeof(pt));
550 pt.adapter = a;
551 pt.port = p;
552 pt.device = d;
553 pt.cmdlen = sizeof(pt.cmd.ata);
554 pt.cmd.ata.features = sub_func;
555 pt.cmd.ata.count = cnt;
556 pt.cmd.ata.lba_l = (0xc24fL << 8) | lba_l;
557 pt.cmd.ata.cmd = ATA_CMD_SMART;
558
559 if (buf != NULL && sub_func != ATA_SMART_STATUS) {
560 pt.buflen = 512;
561 pt.buf = lin(buf);
562 }
563
564 if (((ret = gen_ioctl(&ioctl)) & STERR) == 0 && sub_func == ATA_SMART_STATUS) {
565
566 /* ATA_SMART_STATUS doesn't transfer anything but instead relies on the
567 * returned D2H FIS, mapped to the ATA CMD, to have a certain value
568 * (0xf42c); the IOCTL result is expected to be returned as a ULONG in
569 * the data buffer.
570 */
571 if (((pt.cmd.ata.lba_l >> 8) & 0xffff) == 0xf42c) {
572 *((ULONG _far *) buf) = 1;
573 } else {
574 *((ULONG _far *) buf) = 0;
575 }
576 }
577
578 return(ret);
579}
580
581/******************************************************************************
582 * Map DSKSP unit number to corresponding adapter/port/device number. Units
583 * are identified by an 8-bit adapter/device number with the lowest bit
584 * selecting between master (0) and slave (1). This number is mapped to our
585 * ATA/ATAPI units sequentially.
586 */
587static int map_unit(BYTE unit, USHORT _far *a, USHORT _far *p, USHORT _far *d)
588{
589 USHORT _a;
590 USHORT _p;
591 USHORT _d;
592
593 /* map unit to adapter/port/device */
594 for (_a = 0; _a < ad_info_cnt; _a++) {
595 AD_INFO *ai = ad_infos + _a;
596
597 for (_p = 0; _p <= ai->port_max; _p++) {
598 P_INFO *pi = ai->ports + _p;
599
600 for (_d = 0; _d <= pi->dev_max; _d++) {
601 if (pi->devs[_d].present) {
602 if (unit-- == 0) {
603 /* found the device */
604 *a = _a;
605 *p = _p;
606 *d = _d;
607 return(0);
608 }
609 }
610 }
611 }
612 }
613
614 /* unit not found */
615 return(-1);
616}
617
618/******************************************************************************
619 * Get linear address for specified virtual address.
620 */
621static LIN lin(void _far *p)
622{
623 LIN l;
624
625 if (DevHelp_VirtToLin((SEL) ((ULONG) p >> 16), (USHORT) (ULONG) p, &l) != 0) {
626 return(0);
627 }
628
629 return(l);
630}
631
632/******************************************************************************
633 * IORB notification routine; used to wake up the sleeping application thread
634 * when the IOCTL IORB is complete.
635 */
636IORBH _far * _far _cdecl ioctl_wakeup(IORBH _far *iorb)
637{
638 USHORT awake_count;
639
640 DevHelp_ProcRun((ULONG) iorb, &awake_count);
641
642 return(NULL);
643}
644
Note: See TracBrowser for help on using the repository browser.