source: trunk/src/os2ahci/os2ahci.c@ 207

Last change on this file since 207 was 207, checked in by David Azarewicz, 4 years ago

Add 64/48 bit LBA support.

File size: 50.8 KB
Line 
1/**
2 * os2ahci.c - main file for os2ahci driver
3 *
4 * Copyright (c) 2011 thi.guten Software Development
5 * Copyright (c) 2011 Mensys B.V.
6 * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
7 *
8 * Authors: Christian Mueller, Markus Thielen
9 *
10 * Parts copied from/inspired by the Linux AHCI driver;
11 * those parts are (c) Linux AHCI/ATA maintainers
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28#include "os2ahci.h"
29#include "ioctl.h"
30#include "version.h"
31#include "devhdr.h"
32
33/* set two-dimensional array of port options */
34#define set_port_option(opt, val) \
35 if (adapter_index == -1) { \
36 /* set option for all adapters and ports */ \
37 memset(opt, val, sizeof(opt)); \
38 } else if (port_index == -1) { \
39 /* set option for all ports on current adapter */ \
40 memset(opt[adapter_index], val, sizeof(*opt)); \
41 } else { \
42 /* set option for specific port */ \
43 opt[adapter_index][port_index] = val; \
44 }
45
46#define FLAG_KRNL_EXIT_ADD 0x1000
47#define FLAG_KRNL_EXIT_REMOVE 0x2000
48
49#define TYPE_KRNL_EXIT_NMI 0x0000 /* non masked interrupts */
50#define TYPE_KRNL_EXIT_SFF 0x0001 /* system fatal faults */
51#define TYPE_KRNL_EXIT_PROCDUMP 0x0002
52#define TYPE_KRNL_EXIT_DYN 0x0003
53#define TYPE_KRNL_EXIT_INT13 0x0004 /* enable int13 IO */
54
55extern int SetPsdPutc(void);
56static int add_unit_info(IORB_CONFIGURATION *iorb_conf, int dt_ai, int a, int p, int d, int scsi_id);
57
58int thorough_scan = 1; /* if != 0, perform thorough PCI scan */
59int init_reset = 1; /* if != 0, reset ports during init */
60int force_write_cache; /* if != 0, force write cache */
61int verbosity = 0; /* default is quiet. 1=show sign on banner, >1=show adapter info during boot */
62int use_mbr_test = 1;
63
64HDRIVER rm_drvh; /* resource manager driver handle */
65USHORT add_handle; /* driver handle (RegisterDeviceClass) */
66char drv_name[] = "OS2AHCI"; /* driver name as string */
67
68/* resource manager driver information structure */
69static DRIVERSTRUCT rm_drvinfo =
70{
71 NULL, /* We cannot do Flat to Far16 conversion at compile time */
72 NULL, /* so we put NULLs in all the Far16 fields and then fill */
73 NULL, /* them in at run time */
74 DMAJOR,
75 DMINOR,
76 BLD_YEAR, BLD_MONTH, BLD_DAY,
77 0,
78 DRT_ADDDM,
79 DRS_ADD,
80 NULL
81};
82
83SpinLock_t drv_lock; /* driver-level spinlock */
84IORB_QUEUE driver_queue; /* driver-level IORB queue */
85AD_INFO ad_infos[MAX_AD]; /* adapter information list */
86int ad_info_cnt; /* number of entries in ad_infos[] */
87u16 ad_ignore; /* bitmap with adapter indexes to ignore */
88int init_complete; /* if != 0, initialization has completed */
89int suspended;
90int resume_sleep_flag;
91AHCISTATS AhciStats;
92
93/* apapter/port-specific options saved when parsing the command line */
94u8 emulate_scsi[MAX_AD][AHCI_MAX_PORTS];
95u8 enable_ncq[MAX_AD][AHCI_MAX_PORTS];
96u8 link_speed[MAX_AD][AHCI_MAX_PORTS];
97u8 link_power[MAX_AD][AHCI_MAX_PORTS];
98u8 track_size[MAX_AD][AHCI_MAX_PORTS];
99u8 port_ignore[MAX_AD][AHCI_MAX_PORTS];
100
101char BldLevel[] = BLDLEVEL;
102
103/******************************************************************************
104 * OS/2 device driver main strategy function.
105 *
106 * NOTE: this is also used as the IDC entry point. We expect an IOCTL request
107 * packet for IDC calls, so they can be handled by gen_ioctl.
108 */
109void StrategyHandler(REQPACKET *prp)
110{
111 u16 rc;
112
113 switch (prp->bCommand)
114 {
115 case STRATEGY_BASEDEVINIT:
116 rc = init_drv(prp);
117 break;
118
119 case STRATEGY_SHUTDOWN:
120 rc = exit_drv(prp->save_restore.Function);
121 break;
122
123 case STRATEGY_GENIOCTL:
124 rc = gen_ioctl(prp);
125 break;
126
127 case STRATEGY_OPEN:
128 build_user_info();
129 rc = RPDONE;
130 break;
131
132 case STRATEGY_READ:
133 rc = char_dev_input(prp);
134 break;
135
136 case STRATEGY_SAVERESTORE:
137 rc = sr_drv(prp->save_restore.Function);
138 break;
139
140 case STRATEGY_INITCOMPLETE:
141 case STRATEGY_CLOSE:
142 case STRATEGY_INPUTSTATUS:
143 case STRATEGY_FLUSHINPUT:
144 /* noop */
145 rc = RPDONE;
146 break;
147
148 default:
149 rc = RPDONE | RPERR_BADCOMMAND;
150 break;
151 }
152
153 prp->usStatus = rc;
154}
155
156void IdcHandler(REQPACKET *prp)
157{
158 StrategyHandler(prp);
159}
160
161/******************************************************************************
162 * Intialize the os2ahci driver. This includes command line parsing, scanning
163 * the PCI bus for supported AHCI adapters, etc.
164 */
165USHORT init_drv(REQPACKET *req)
166{
167 static int init_drv_called;
168 static int init_drv_failed;
169 APIRET rmrc;
170 const char *pszCmdLine, *cmd_line;
171 int adapter_index = -1;
172 int port_index = -1;
173 int iInvertOption;
174 int iStatus;
175
176 if (init_drv_called)
177 {
178 /* This is the init call for the second (IBMS506$) character
179 * device driver. If the main driver failed initialization, fail this
180 * one as well.
181 */
182 return(RPDONE | ((init_drv_failed) ? RPERR_INITFAIL : 0));
183 }
184 D32g_DbgLevel = 0;
185 init_drv_called = 1;
186 suspended = 0;
187 resume_sleep_flag = 0;
188 memset(ad_infos, 0, sizeof(ad_infos));
189 memset(emulate_scsi, 1, sizeof(emulate_scsi)); /* set default enabled */
190 UtSetDriverName("OS2AHCI$");
191 Header.ulCaps |= DEV_ADAPTER_DD; /* DAZ This flag is not really needed. */
192 memset(&AhciStats, 0, sizeof(AhciStats));
193 AhciStats.ulSize = sizeof(AhciStats);
194 AhciStats.ulVersion = 0x101;
195
196 /* create driver-level spinlock */
197 KernAllocSpinLock(&drv_lock);
198
199 /* register driver with resource manager */
200 rm_drvinfo.DrvrName = drv_name;
201 rm_drvinfo.DrvrDescript = "AHCI SATA Driver";
202 rm_drvinfo.VendorName = DVENDOR;
203 if ((rmrc = RMCreateDriver(&rm_drvinfo, &rm_drvh)) != RMRC_SUCCESS)
204 {
205 iprintf("%s: failed to register driver with resource manager (rc = %d)", drv_name, rmrc);
206 goto init_fail;
207 }
208
209 pszCmdLine = cmd_line = req->init_in.szArgs;
210 iStatus = 0;
211 while (*pszCmdLine)
212 {
213 if (*pszCmdLine++ != '/') continue; /* Ignore anything that doesn't start with '/' */
214 /* pszCmdLine now points to first char of argument */
215
216 if ((iInvertOption = (*pszCmdLine == '!')) != 0) pszCmdLine++;
217
218 if (ArgCmp(pszCmdLine, "B:"))
219 {
220 pszCmdLine += 2;
221 InitComPort(strtol(pszCmdLine, &pszCmdLine, 0));
222 continue;
223 }
224
225 if (ArgCmp(pszCmdLine, "COM:"))
226 {
227 pszCmdLine += 4;
228 /* set COM port base address for debug messages */
229 D32g_ComBase = strtol(pszCmdLine, &pszCmdLine, 0);
230 #ifdef TESTVER
231 if (D32g_ComBase == 0) SetPsdPutc();
232 #endif
233 if (D32g_ComBase == 1) D32g_ComBase = 0x3f8;
234 if (D32g_ComBase == 2) D32g_ComBase = 0x2f8;
235 continue;
236 }
237
238 if (ArgCmp(pszCmdLine, "D"))
239 {
240 pszCmdLine++;
241 if (*pszCmdLine == ':')
242 {
243 pszCmdLine++;
244 D32g_DbgLevel = strtol(pszCmdLine, &pszCmdLine, 0);
245 }
246 else D32g_DbgLevel++; /* increase debug level */
247 continue;
248 }
249
250 if (ArgCmp(pszCmdLine, "G:"))
251 {
252 u16 usVendor;
253 u16 usDevice;
254
255 pszCmdLine += 2;
256 /* add specfied PCI ID as a supported generic AHCI adapter */
257 usVendor = strtol(pszCmdLine, &pszCmdLine, 16);
258 if (*pszCmdLine != ':') break;
259 pszCmdLine++;
260 usDevice = strtol(pszCmdLine, &pszCmdLine, 16);
261 if (add_pci_id(usVendor, usDevice))
262 {
263 iprintf("%s: failed to add PCI ID %04x:%04x", drv_name, usVendor, usDevice);
264 iStatus = 1;
265 }
266 thorough_scan = 1;
267 continue;
268 }
269
270 if (ArgCmp(pszCmdLine, "T"))
271 {
272 pszCmdLine++;
273 /* perform thorough PCI scan (i.e. look for individual supported PCI IDs) */
274 thorough_scan = !iInvertOption;
275 continue;
276 }
277
278 if (ArgCmp(pszCmdLine, "R"))
279 {
280 pszCmdLine++;
281 /* reset ports during initialization */
282 init_reset = !iInvertOption;
283 continue;
284 }
285
286 if (ArgCmp(pszCmdLine, "F"))
287 {
288 pszCmdLine++;
289 /* force write cache regardless of IORB flags */
290 force_write_cache = 1;
291 continue;
292 }
293
294 if (ArgCmp(pszCmdLine, "A:"))
295 {
296 pszCmdLine += 2;
297 /* set adapter index for adapter and port-related options */
298 adapter_index = strtol(pszCmdLine, &pszCmdLine, 0);
299 if (adapter_index < 0 || adapter_index >= MAX_AD)
300 {
301 iprintf("%s: invalid adapter index (%d)", drv_name, adapter_index);
302 iStatus = 1;
303 }
304 continue;
305 }
306
307 if (ArgCmp(pszCmdLine, "P:"))
308 {
309 pszCmdLine += 2;
310 /* set port index for port-related options */
311 port_index = strtol(pszCmdLine, &pszCmdLine, 0);
312 if (port_index < 0 || port_index >= AHCI_MAX_PORTS)
313 {
314 iprintf("%s: invalid port index (%d)", drv_name, port_index);
315 iStatus = 1;
316 }
317 continue;
318 }
319
320 if (ArgCmp(pszCmdLine, "I"))
321 {
322 pszCmdLine++;
323 /* ignore current adapter index */
324 if (adapter_index >= 0)
325 {
326 if (port_index >= 0) port_ignore[adapter_index][port_index] = !iInvertOption;
327 else ad_ignore |= 1U << adapter_index;
328 }
329 continue;
330 }
331
332 if (ArgCmp(pszCmdLine, "S"))
333 {
334 pszCmdLine++;
335 /* enable SCSI emulation for ATAPI devices */
336 set_port_option(emulate_scsi, !iInvertOption);
337 continue;
338 }
339
340 if (ArgCmp(pszCmdLine, "N"))
341 {
342 pszCmdLine++;
343 /* enable NCQ */
344 set_port_option(enable_ncq, !iInvertOption);
345 continue;
346 }
347
348 if (ArgCmp(pszCmdLine, "LS:"))
349 {
350 int optval;
351
352 pszCmdLine += 3;
353 /* set link speed */
354 optval = strtol(pszCmdLine, &pszCmdLine, 0);
355 set_port_option(link_speed, optval);
356 /* need to reset the port in order to establish link settings */
357 init_reset = 1;
358 continue;
359 }
360
361 if (ArgCmp(pszCmdLine, "LP:"))
362 {
363 int optval;
364
365 pszCmdLine += 3;
366 /* set power management */
367 optval = strtol(pszCmdLine, &pszCmdLine, 0);
368 set_port_option(link_power, optval);
369 /* need to reset the port in order to establish link settings */
370 init_reset = 1;
371 continue;
372 }
373
374 if (ArgCmp(pszCmdLine, "4"))
375 {
376 pszCmdLine++;
377 /* enable 4K sector geometry enhancement (track size = 56) */
378 if (!iInvertOption) set_port_option(track_size, 56);
379 continue;
380 }
381
382 if (ArgCmp(pszCmdLine, "U"))
383 {
384 pszCmdLine++;
385 /* Specify to use the MBR test to ignore non-MBR disks.
386 * Default is on.
387 */
388 use_mbr_test = !iInvertOption;
389 continue;
390 }
391
392 if (ArgCmp(pszCmdLine, "V"))
393 {
394 pszCmdLine++;
395 if (*pszCmdLine == ':')
396 {
397 pszCmdLine++;
398 verbosity = strtol(pszCmdLine, &pszCmdLine, 0);
399 }
400 else verbosity++; /* increase verbosity level */
401 continue;
402 }
403
404 if (ArgCmp(pszCmdLine, "W"))
405 {
406 pszCmdLine++;
407 /* Specify to allow the trace buffer to wrap when full. */
408 D32g_DbgBufWrap = !iInvertOption;
409 continue;
410 }
411
412 iprintf("Unrecognized switch: %s", pszCmdLine-1);
413 iStatus = 1; /* unrecognized argument */
414 }
415
416 if (iStatus) goto init_fail;
417
418 dprintf(0,"BldLevel: %s\n", BldLevel);
419 dprintf(0,"CmdLine: %s\n", cmd_line);
420 /*
421 if (sizeof(ADD_WORKSPACE) > ADD_WORKSPACE_SIZE)
422 {
423 dprintf(0,"ADD_WORKSPACE size is too big! %d>16\n", sizeof(ADD_WORKSPACE));
424 goto init_fail;
425 }
426 */
427
428 /* print initialization message */
429 ciprintf("%s driver version %d.%02d", drv_name, DMAJOR, DMINOR);
430
431 #ifdef TESTVER
432 #include "testver.c"
433 #endif
434
435 /* scan PCI bus for supported devices */
436 scan_pci_bus();
437
438 if (ad_info_cnt > 0)
439 {
440 /* initialization succeeded and we found at least one AHCI adapter */
441
442 if (Dev32Help_RegisterDeviceClass(drv_name, add_entry, 0, 1, &add_handle))
443 {
444 iprintf("%s: couldn't register device class", drv_name);
445 goto init_fail;
446 }
447
448 Timer_InitTimer(TIMER_COUNT);
449
450 /* allocate context hooks */
451 KernAllocateContextHook(restart_ctxhook, 0, &restart_ctxhook_h);
452 KernAllocateContextHook(reset_ctxhook, 0, &reset_ctxhook_h);
453 KernAllocateContextHook(engine_ctxhook, 0, &engine_ctxhook_h);
454
455 /* register kernel exit routine for trap dumps */
456 Dev32Help_RegisterKrnlExit(shutdown_driver, FLAG_KRNL_EXIT_ADD, TYPE_KRNL_EXIT_INT13);
457
458 return(RPDONE);
459 }
460 else
461 {
462 /* no adapters found */
463 ciprintf("%s: No adapters found.", drv_name);
464 }
465
466init_fail:
467 /* initialization failed; set segment sizes to 0 and return error */
468 init_drv_failed = 1;
469
470 if (rm_drvh != 0)
471 {
472 /* remove driver from resource manager */
473 RMDestroyDriver(rm_drvh);
474 }
475
476 ciprintf("%s driver *not* installed", drv_name);
477 return(RPDONE | RPERR_INITFAIL);
478}
479
480/******************************************************************************
481 * Generic IOCTL via character device driver. IOCTLs are used to control the
482 * driver operation and to execute native ATA and ATAPI (SCSI) commands from
483 * ring 3 applications. On top of that, some predefined IOCTLs (e.g. SMART
484 * commands for ATA disks) are implemented here.
485 */
486USHORT gen_ioctl(REQPACKET *ioctl)
487{
488 DPRINTF(2,"IOCTL 0x%x/0x%x\n", ioctl->ioctl.bCategory, ioctl->ioctl.bFunction);
489 AhciStats.ulTestCount2++;
490
491 switch (ioctl->ioctl.bCategory)
492 {
493 case OS2AHCI_IOCTL_CATEGORY:
494 switch (ioctl->ioctl.bFunction)
495 {
496 case OS2AHCI_IOCTL_GET_DEVLIST:
497 return(ioctl_get_devlist(ioctl));
498
499 case OS2AHCI_IOCTL_PASSTHROUGH:
500 return(ioctl_passthrough(ioctl));
501 }
502 break;
503
504 case DSKSP_CAT_GENERIC:
505 return(ioctl_gen_dsk(ioctl));
506
507 case DSKSP_CAT_SMART:
508 return(ioctl_smart(ioctl));
509 }
510
511 return(RPDONE | RPERR_BADCOMMAND);
512}
513
514/******************************************************************************
515 * Read from character device. If tracing is on (internal ring buffer trace),
516 * we return data from the trace buffer; if not, we might return a device
517 * dump similar to IBM1S506.ADD/DANIS506.ADD (TODO).
518 */
519USHORT char_dev_input(REQPACKET *pPacket)
520{
521 void *LinAdr;
522
523 if (Dev32Help_PhysToLin(pPacket->io.ulAddress, pPacket->io.usCount, &LinAdr))
524 {
525 pPacket->io.usCount = 0;
526 return RPDONE | RPERR_GENERAL;
527 }
528
529 pPacket->io.usCount = dCopyToUser(LinAdr, pPacket->io.usCount);
530
531 return RPDONE;
532}
533
534/******************************************************************************
535 * Device driver exit handler. This handler is called when OS/2 shuts down and
536 * flushes the write caches of all attached devices. Since this is effectively
537 * the same we do when suspending, we'll call out to the corresponding suspend
538 * function.
539 *
540 * NOTE: Errors are ignored because there's no way we could stop the shutdown
541 * or do something about the error, unless retrying endlessly is
542 * considered an option.
543 */
544USHORT exit_drv(int func)
545{
546 DPRINTF(2,"exit_drv(%d) called\n", func);
547
548 if (func == 0)
549 {
550 /* we're only interested in the second phase of the shutdown */
551 return(RPDONE);
552 }
553
554 suspend();
555 return(RPDONE);
556}
557
558/******************************************************************************
559 * Device driver suspend/resume handler. This handler is called when ACPI is
560 * executing a suspend or resume.
561 */
562USHORT sr_drv(int func)
563{
564 DPRINTF(2,"sr_drv(%d) called\n", func);
565
566 if (func) resume();
567 else suspend();
568
569 return(RPDONE);
570}
571
572/******************************************************************************
573 * ADD entry point. This is the main entry point for all ADD requests. Due to
574 * the asynchronous nature of ADD drivers, this function primarily queues the
575 * IORB(s) to the corresponding adapter or port queues, then triggers the
576 * state machine to initiate processing queued IORBs.
577 *
578 * NOTE: In order to prevent race conditions or engine stalls, certain rules
579 * around locking, unlocking and IORB handling in general have been
580 * established. Refer to the comments in "trigger_engine()" for
581 * details.
582 */
583void add_entry(IORBH FAR16DATA *vFirstIorb)
584{
585 IORBH FAR16DATA *vIorb;
586 IORBH FAR16DATA *vNext = FAR16NULL;
587
588 spin_lock(drv_lock);
589
590 for (vIorb=vFirstIorb; vIorb!=FAR16NULL; vIorb=vNext)
591 {
592 IORBH *pIorb = Far16ToFlat(vIorb);
593
594 /* Queue this IORB. Queues primarily exist on port level but there are
595 * some requests which affect the whole driver, most notably
596 * IOCC_CONFIGURATION. In either case, adding the IORB to the driver or
597 * port queue will change the links, thus we need to save the original
598 * link in 'vNext'.
599 */
600 if (pIorb->RequestControl & IORB_CHAIN) vNext = pIorb->f16NxtIORB;
601 else vNext = (IORBH FAR16DATA *)0;
602
603 pIorb->Status = 0;
604 pIorb->ErrorCode = 0;
605 memset(&pIorb->ADDWorkSpace, 0x00, sizeof(ADD_WORKSPACE));
606
607 #ifdef DEBUG
608 DumpIorb(pIorb); /* DAZ TESTING */
609 #endif
610
611 if (iorb_driver_level(pIorb))
612 {
613 /* driver-level IORB */
614 pIorb->UnitHandle = 0;
615 iorb_queue_add(&driver_queue, vIorb, pIorb);
616 }
617 else
618 {
619 /* port-level IORB */
620 int a = iorb_unit_adapter(pIorb);
621 int p = iorb_unit_port(pIorb);
622 int d = iorb_unit_device(pIorb);
623
624 if (a >= ad_info_cnt ||
625 p > ad_infos[a].port_max ||
626 d > ad_infos[a].ports[p].dev_max ||
627 (ad_infos[a].port_map & (1UL << p)) == 0)
628 {
629 /* unit handle outside of the allowed range */
630 dprintf(0,"warning: IORB for %d.%d.%d out of range\n", a, p, d);
631 pIorb->Status = IORB_ERROR;
632 pIorb->ErrorCode = IOERR_CMD_SYNTAX;
633 iorb_complete(vIorb, pIorb);
634 continue;
635 }
636
637 iorb_queue_add(&ad_infos[a].ports[p].iorb_queue, vIorb, pIorb);
638 }
639 }
640
641 /* trigger state machine */
642 trigger_engine();
643
644 spin_unlock(drv_lock);
645}
646
647/******************************************************************************
648 * Trigger IORB queue engine. This is a wrapper function for trigger_engine_1()
649 * which will try to get all IORBs sent on their way a couple of times. If
650 * there are still IORBs ready for processing after this, this function will
651 * hand off to a context hook which will continue to trigger the engine until
652 * all IORBs have been sent.
653 *
654 * NOTE: While initialization has not completed (or during suspend/resume
655 * operations), this function will loop indefinitely because we can't
656 * rely on interrupt handlers or context hooks and complex IORBs
657 * requiring multiple requeues would eventually hang and time out if
658 * we stopped triggering here.
659 */
660void trigger_engine(void)
661{
662 int i;
663
664 for (i = 0; i < 3 || !init_complete; i++)
665 {
666 if (trigger_engine_1() == 0)
667 {
668 /* done -- all IORBs have been sent on their way */
669 return;
670 }
671 }
672
673 /* Something keeps bouncing; hand off to the engine context hook which will
674 * keep trying in the background.
675 */
676 KernArmHook(engine_ctxhook_h, 0, 0);
677}
678
679/******************************************************************************
680 * Trigger IORB queue engine in order to send commands in the driver/port IORB
681 * queues to the AHCI hardware. This function will return the number of IORBs
682 * sent. Keep in mind that IORBs might "bounce" if the adapter/port is not in
683 * a state to accept the command, thus it might take quite a few calls to get
684 * all IORBs on their way. This is why there's a wrapper function which tries
685 * it a few times, then hands off to a context hook which will keep trying in
686 * the background.
687 *
688 * IORBs might complete before send_iorb() has returned, at any time during
689 * interrupt processing or on another CPU on SMP systems. IORB completion
690 * means modifications to the corresponding IORB queue (the completed IORB
691 * is removed from the queue) thus we need to protect the IORB queues from
692 * race conditions. The safest approach short of keeping the driver-level
693 * spinlock aquired permanently is to keep it throughout this function and
694 * release it temporarily in send_iorb().
695 *
696 * This implies that the handler functions are fully responsible for aquiring
697 * the driver-level spinlock when they need it, and for releasing it again.
698 *
699 * As a rule of thumb, get the driver-level spinlock whenever accessing
700 * volatile variables (IORB queues, values in ad_info[], ...).
701 *
702 * Additional Notes:
703 *
704 * - This function is expected to be called with the spinlock aquired
705 *
706 * - Adapters can be flagged as 'busy' which means no new IORBs are sent (they
707 * just remain in the queue). This can be used to release the driver-level
708 * spinlock while making sure no new IORBs are going to hit the hardware.
709 * In order to prevent engine stalls, all handlers using this functionality
710 * need to invoke trigger_engine() after resetting the busy flag.
711 *
712 * - Driver-level IORBs are not synchronized by adapter-level 'busy' flags.
713 * However, the driver-level queue is worked "one entry at a time" which
714 * means that no new IORBs will be queued on the driver-level queue until
715 * the head element has completed processing. This means that driver-
716 * level IORB handlers don't need to protect against each other. But they
717 * they do need to keep in mind interference with port-level IORBs:
718 *
719 * - Driver-level IORB handlers must obtain the spinlock and/or flag all
720 * adapters as 'busy' which are affected by the driver-level IORB
721 *
722 * - Driver-level IORB handlers must not access the hardware of a
723 * particular adapter if it's flagged as 'busy' by another IORB.
724 */
725int trigger_engine_1(void)
726{
727 IORBH FAR16DATA *vIorb;
728 IORBH *pIorb;
729 IORBH FAR16DATA *vNext;
730 int iorbs_sent = 0;
731 int a;
732 int p;
733
734 iorbs_sent = 0;
735
736 /* process driver-level IORBs */
737 if ((vIorb = driver_queue.vRoot) != FAR16NULL)
738 {
739 pIorb = Far16ToFlat(vIorb);
740
741 if (!add_workspace(pIorb)->processing)
742 {
743 send_iorb(vIorb, pIorb);
744 iorbs_sent++;
745 }
746 }
747
748 /* process port-level IORBs */
749 for (a = 0; a < ad_info_cnt; a++)
750 {
751 AD_INFO *ai = ad_infos + a;
752 if (ai->busy)
753 {
754 /* adapter is busy; don't process any IORBs */
755 continue;
756 }
757 for (p = 0; p <= ai->port_max; p++)
758 {
759 /* send all queued IORBs on this port */
760 vNext = FAR16NULL;
761 for (vIorb = ai->ports[p].iorb_queue.vRoot; vIorb != FAR16NULL; vIorb = vNext)
762 {
763 pIorb = Far16ToFlat(vIorb);
764
765 vNext = pIorb->f16NxtIORB;
766 if (!add_workspace(pIorb)->processing)
767 {
768 send_iorb(vIorb, pIorb);
769 iorbs_sent++;
770 }
771 }
772 }
773 }
774
775 return(iorbs_sent);
776}
777
778/******************************************************************************
779 * Send a single IORB to the corresponding AHCI adapter/port. This is just a
780 * switch board for calling the corresponding iocc_*() handler function.
781 *
782 * NOTE: This function is expected to be called with the driver-level spinlock
783 * aquired. It will release it before calling any of the handler
784 * functions and re-aquire it when done.
785 */
786void send_iorb(IORBH FAR16DATA *vIorb, IORBH *pIorb)
787{
788 /* Mark IORB as "processing" before doing anything else. Once the IORB is
789 * marked as "processing", we can release the spinlock because subsequent
790 * invocations of trigger_engine() (e.g. at interrupt time) will ignore this
791 * IORB.
792 */
793 add_workspace(pIorb)->processing = 1;
794 spin_unlock(drv_lock);
795
796 switch (pIorb->CommandCode)
797 {
798 case IOCC_CONFIGURATION:
799 iocc_configuration(vIorb, pIorb);
800 break;
801
802 case IOCC_DEVICE_CONTROL:
803 iocc_device_control(vIorb, pIorb);
804 break;
805
806 case IOCC_UNIT_CONTROL:
807 iocc_unit_control(vIorb, pIorb);
808 break;
809
810 case IOCC_GEOMETRY_64:
811 add_workspace(pIorb)->fIs64bit = 1;
812 /* fall thru */
813 case IOCC_GEOMETRY:
814 iocc_geometry(vIorb, pIorb);
815 break;
816
817 case IOCC_EXECUTE_IO_64:
818 add_workspace(pIorb)->fIs64bit = 1;
819 /* fall thru */
820 case IOCC_EXECUTE_IO:
821 iocc_execute_io(vIorb, pIorb);
822 break;
823
824 case IOCC_UNIT_STATUS:
825 iocc_unit_status(vIorb, pIorb);
826 break;
827
828 case IOCC_ADAPTER_PASSTHRU:
829 AhciStats.ulTestCount1++;
830 iocc_adapter_passthru(vIorb, pIorb);
831 break;
832
833 default:
834 /* unsupported call */
835 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
836 iorb_done(vIorb, pIorb);
837 break;
838 }
839
840 /* re-aquire spinlock before returning to trigger_engine() */
841 spin_lock(drv_lock);
842}
843
844/******************************************************************************
845 * Handle IOCC_CONFIGURATION requests.
846 */
847void iocc_configuration(IORBH FAR16DATA *vIorb, IORBH *pIorb)
848{
849 int a;
850
851 switch (pIorb->CommandModifier)
852 {
853
854 case IOCM_COMPLETE_INIT:
855 /* Complete initialization. From now on, we won't have to restore the BIOS
856 * configuration after each command and we're fully operational (i.e. will
857 * use interrupts, timers and context hooks instead of polling).
858 */
859 if (!init_complete)
860 {
861 DPRINTF(1,"leaving initialization mode\n");
862 for (a = 0; a < ad_info_cnt; a++)
863 {
864 lock_adapter(ad_infos + a);
865 ahci_complete_init(ad_infos + a);
866 }
867 init_complete = 1;
868
869 /* release all adapters */
870 for (a = 0; a < ad_info_cnt; a++)
871 {
872 unlock_adapter(ad_infos + a);
873 }
874 DPRINTF(1,"leaving initialization mode 2\n");
875
876 #ifdef LEGACY_APM
877 /* register APM hook */
878 apm_init();
879 #endif
880 }
881 iorb_done(vIorb, pIorb);
882 break;
883
884 case IOCM_GET_DEVICE_TABLE:
885 /* construct a device table */
886 iocm_device_table(vIorb, pIorb);
887 break;
888
889 default:
890 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
891 iorb_done(vIorb, pIorb);
892 break;
893 }
894}
895
896/******************************************************************************
897 * Handle IOCC_DEVICE_CONTROL requests.
898 */
899void iocc_device_control(IORBH FAR16DATA *vIorb, IORBH *pIorb)
900{
901 AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb);
902 IORBH FAR16DATA *vPtr;
903 IORBH FAR16DATA *vNext = FAR16NULL;
904 int p = iorb_unit_port(pIorb);
905 int d = iorb_unit_device(pIorb);
906
907 switch (pIorb->CommandModifier)
908 {
909 case IOCM_ABORT:
910 /* abort all pending commands on specified port and device */
911 spin_lock(drv_lock);
912 for (vPtr = ai->ports[p].iorb_queue.vRoot; vPtr != FAR16NULL; vPtr = vNext)
913 {
914 IORBH *pPtr = Far16ToFlat(vPtr);
915
916 vNext = pPtr->f16NxtIORB;
917 /* move all matching IORBs to the abort queue */
918 if (vPtr != vIorb && iorb_unit_device(pPtr) == d)
919 {
920 iorb_queue_del(&ai->ports[p].iorb_queue, vPtr);
921 iorb_queue_add(&abort_queue, vPtr, pPtr);
922 pPtr->ErrorCode = IOERR_CMD_ABORTED;
923 }
924 }
925 spin_unlock(drv_lock);
926
927 /* trigger reset context hook which will finish the abort processing */
928 KernArmHook(reset_ctxhook_h, 0, 0);
929 break;
930
931 case IOCM_SUSPEND:
932 case IOCM_RESUME:
933 case IOCM_GET_QUEUE_STATUS:
934 /* Suspend/resume operations allow access to the hardware for other
935 * entities such as IBMIDECD.FLT. Since os2ahci implements both ATA
936 * and ATAPI in the same driver, this won't be required.
937 */
938 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
939 break;
940
941 case IOCM_LOCK_MEDIA:
942 case IOCM_UNLOCK_MEDIA:
943 case IOCM_EJECT_MEDIA:
944 /* unit control commands to lock, unlock and eject media */
945 /* will be supported later... */
946 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
947 break;
948
949 default:
950 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
951 break;
952 }
953
954 iorb_done(vIorb, pIorb);
955}
956
957/******************************************************************************
958 * Handle IOCC_UNIT_CONTROL requests.
959 */
960void iocc_unit_control(IORBH FAR16DATA *vIorb, IORBH *pIorb)
961{
962 IORB_UNIT_CONTROL *pIorb_uc = (IORB_UNIT_CONTROL *)pIorb;
963 int a = iorb_unit_adapter(pIorb);
964 int p = iorb_unit_port(pIorb);
965 int d = iorb_unit_device(pIorb);
966
967 spin_lock(drv_lock);
968 switch (pIorb->CommandModifier)
969 {
970 case IOCM_ALLOCATE_UNIT:
971 /* allocate unit for exclusive access */
972 if (ad_infos[a].ports[p].devs[d].allocated)
973 {
974 iorb_seterr(pIorb, IOERR_UNIT_ALLOCATED);
975 }
976 else
977 {
978 ad_infos[a].ports[p].devs[d].allocated = 1;
979 }
980 break;
981
982 case IOCM_DEALLOCATE_UNIT:
983 /* deallocate exclusive access to unit */
984 if (!ad_infos[a].ports[p].devs[d].allocated)
985 {
986 iorb_seterr(pIorb, IOERR_UNIT_NOT_ALLOCATED);
987 }
988 else
989 {
990 ad_infos[a].ports[p].devs[d].allocated = 0;
991 }
992 break;
993
994 case IOCM_CHANGE_UNITINFO:
995 /* Change unit (device) information. One reason for this IOCM is the
996 * interface for filter device drivers: a filter device driver can
997 * either change existing UNITINFOs or permanently allocate units
998 * and fabricate new [logical] units; the former is the reason why we
999 * must store the pointer to the updated UNITNIFO for subsequent
1000 * IOCC_CONFIGURATION/IOCM_GET_DEVICE_TABLE calls.
1001 */
1002 if (!ad_infos[a].ports[p].devs[d].allocated)
1003 {
1004 iorb_seterr(pIorb, IOERR_UNIT_NOT_ALLOCATED);
1005 break;
1006 }
1007 ad_infos[a].ports[p].devs[d].unit_info = pIorb_uc->f16UnitInfo;
1008 break;
1009
1010 default:
1011 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
1012 break;
1013 }
1014
1015 spin_unlock(drv_lock);
1016 iorb_done(vIorb, pIorb);
1017}
1018
1019/******************************************************************************
1020 * Scan all ports for AHCI devices and construct a DASD device table.
1021 *
1022 * NOTES: This function may be called multiple times. Only the first
1023 * invocation will actually scan for devices; all subsequent calls will
1024 * merely return the results of the initial scan, potentially augmented
1025 * by modified unit infos after IOCC_CONFIGURATION/IOCM_CHANGE_UNITINFO
1026 * requests.
1027 *
1028 * In order to support applications that can't deal with ATAPI devices
1029 * (i.e. need a SCSI adapter) os2ahci will optionally report ATAPI
1030 * dvices as SCSI devices. The corresponding SCSI adapter doesn't
1031 * really exist and is only reported here for the IOCM_GET_DEVICETABLE
1032 * request. The units attached to this adapter will use the real HW
1033 * unit IDs, thus we'll never receive a command specific to the
1034 * emulated SCSI adapter and won't need to set up any sort of entity
1035 * for it; the only purpose of the emulated SCSI adapter is to pass the
1036 * bus type "AI_DEVBUS_SCSI_2" upstream, and the emulated units, of
1037 * course. The emulated SCSI target IDs are allocated as follows:
1038 *
1039 * 0 the virtual adapter
1040 * 1..n emulated devices; SCSI target ID increments sequentially
1041 */
1042void iocm_device_table(IORBH FAR16DATA *vIorb, IORBH *pIorb)
1043{
1044 IORB_CONFIGURATION *pIorb_conf;
1045 DEVICETABLE FAR16DATA *vDt;
1046 DEVICETABLE *pDt;
1047 char *pPos;
1048 int scsi_units = 0;
1049 int scsi_id = 1;
1050 int rc;
1051 int dta;
1052 int a;
1053 int p;
1054 int d;
1055
1056 pIorb_conf = (IORB_CONFIGURATION *)pIorb;
1057 vDt = pIorb_conf->f16DeviceTable;
1058 pDt = Far16ToFlat(vDt);
1059
1060 spin_lock(drv_lock);
1061
1062 /* initialize device table header */
1063 pDt->ADDLevelMajor = ADD_LEVEL_MAJOR;
1064 pDt->ADDLevelMinor = ADD_LEVEL_MINOR;
1065 pDt->ADDHandle = add_handle;
1066 pDt->TotalAdapters = ad_info_cnt + 1;
1067
1068 /* set start of adapter and device information tables */
1069 pPos = (char*)&pDt->pAdapter[pDt->TotalAdapters];
1070
1071 /* go through all adapters, including the virtual SCSI adapter */
1072 for (dta = 0; dta < pDt->TotalAdapters; dta++)
1073 {
1074 ADAPTERINFO *pPtr = (ADAPTERINFO *)pPos;
1075
1076 /* sanity check for sufficient space in device table */
1077 if ((u32)(pPtr + 1) - (u32)pDt > pIorb_conf->DeviceTableLen)
1078 {
1079 dprintf(0,"error: device table provided by DASD too small\n");
1080 iorb_seterr(pIorb, IOERR_CMD_SW_RESOURCE);
1081 goto iocm_device_table_done;
1082 }
1083
1084 pDt->pAdapter[dta] = MakeNear16PtrFromDiff(pIorb_conf->f16DeviceTable, pDt, pPtr);
1085
1086 //DPRINTF(2,"iocm_device_table: ptr=%x dta=%x pAdapter[dta]=%x pDeviceTable=%x\n",
1087 // ptr, dta, dt->pAdapter[dta], iorb_conf->pDeviceTable);
1088 memset(pPtr, 0x00, sizeof(*pPtr));
1089
1090 pPtr->AdapterIOAccess = AI_IOACCESS_BUS_MASTER;
1091 pPtr->AdapterHostBus = AI_HOSTBUS_OTHER | AI_BUSWIDTH_32BIT;
1092 pPtr->AdapterFlags = AF_16M | AF_HW_SCATGAT;
1093 pPtr->MaxHWSGList = AHCI_MAX_SG / 2; /* AHCI S/G elements are 22 bits */
1094
1095 if (dta < ad_info_cnt)
1096 {
1097 /* this is a physical AHCI adapter */
1098 AD_INFO *ad_info = ad_infos + dta;
1099
1100 pPtr->AdapterDevBus = AI_DEVBUS_ST506 | AI_DEVBUS_32BIT;
1101 snprintf(pPtr->AdapterName, sizeof(pPtr->AdapterName), "AHCI_%d", dta);
1102
1103 if (!ad_info->port_scan_done)
1104 {
1105 /* first call; need to scan AHCI hardware for devices */
1106 if (ad_info->busy)
1107 {
1108 dprintf(0,"error: port scan requested while adapter was busy\n");
1109 iorb_seterr(pIorb, IOERR_CMD_SW_RESOURCE);
1110 goto iocm_device_table_done;
1111 }
1112 ad_info->busy = 1;
1113 spin_unlock(drv_lock);
1114 rc = ahci_scan_ports(ad_info);
1115 spin_lock(drv_lock);
1116 ad_info->busy = 0;
1117
1118 if (rc != 0)
1119 {
1120 dprintf(0,"error: port scan failed on adapter #%d\n", dta);
1121 iorb_seterr(pIorb, IOERR_CMD_SW_RESOURCE);
1122 goto iocm_device_table_done;
1123 }
1124 ad_info->port_scan_done = 1;
1125 }
1126
1127 /* insert physical (i.e. AHCI) devices into the device table */
1128 for (p = 0; p <= ad_info->port_max; p++)
1129 {
1130 for (d = 0; d <= ad_info->ports[p].dev_max; d++)
1131 {
1132 if (ad_info->ports[p].devs[d].present)
1133 {
1134 if (ad_info->ports[p].devs[d].atapi && emulate_scsi[dta][p])
1135 {
1136 /* report this unit as SCSI unit */
1137 scsi_units++;
1138 //continue;
1139 }
1140 if (add_unit_info(pIorb_conf, dta, dta, p, d, 0))
1141 {
1142 goto iocm_device_table_done;
1143 }
1144 }
1145 }
1146 }
1147 }
1148 else
1149 {
1150 /* this is the virtual SCSI adapter */
1151 if (scsi_units == 0)
1152 {
1153 /* not a single unit to be emulated via SCSI */
1154 pDt->TotalAdapters--;
1155 break;
1156 }
1157
1158 /* set adapter name and bus type to mimic a SCSI controller */
1159 pPtr->AdapterDevBus = AI_DEVBUS_SCSI_2 | AI_DEVBUS_16BIT;
1160 snprintf(pPtr->AdapterName, sizeof(pPtr->AdapterName), "AHCI_SCSI_0");
1161
1162 /* add all ATAPI units to be emulated by this virtual adaper */
1163 for (a = 0; a < ad_info_cnt; a++)
1164 {
1165 AD_INFO *ad_info = ad_infos + a;
1166
1167 for (p = 0; p <= ad_info->port_max; p++)
1168 {
1169 for (d = 0; d <= ad_info->ports[p].dev_max; d++)
1170 {
1171 if (ad_info->ports[p].devs[d].present && ad_info->ports[p].devs[d].atapi && emulate_scsi[a][p])
1172 {
1173 if (add_unit_info(pIorb_conf, dta, a, p, d, scsi_id++))
1174 {
1175 goto iocm_device_table_done;
1176 }
1177 }
1178 }
1179 }
1180 }
1181 }
1182
1183 /* calculate offset for next adapter */
1184 pPos = (char *)(pPtr->UnitInfo + pPtr->AdapterUnits);
1185 }
1186
1187iocm_device_table_done:
1188 spin_unlock(drv_lock);
1189 iorb_done(vIorb, pIorb);
1190}
1191
1192/******************************************************************************
1193 * Handle IOCC_GEOMETRY requests.
1194 */
1195void iocc_geometry(IORBH FAR16DATA *vIorb, IORBH *pIorb)
1196{
1197 switch (pIorb->CommandModifier)
1198 {
1199 case IOCM_GET_MEDIA_GEOMETRY:
1200 case IOCM_GET_DEVICE_GEOMETRY:
1201 add_workspace(pIorb)->idempotent = 1;
1202 ahci_get_geometry(vIorb, pIorb);
1203 break;
1204
1205 default:
1206 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
1207 iorb_done(vIorb, pIorb);
1208 }
1209}
1210
1211/******************************************************************************
1212 * Handle IOCC_EXECUTE_IO requests.
1213 */
1214void iocc_execute_io(IORBH FAR16DATA *vIorb, IORBH *pIorb)
1215{
1216 switch (pIorb->CommandModifier)
1217 {
1218 case IOCM_READ:
1219 add_workspace(pIorb)->idempotent = 1;
1220 ahci_read(vIorb, pIorb);
1221 break;
1222
1223 case IOCM_READ_VERIFY:
1224 add_workspace(pIorb)->idempotent = 1;
1225 ahci_verify(vIorb, pIorb);
1226 break;
1227
1228 case IOCM_WRITE:
1229 case IOCM_WRITE_VERIFY:
1230 add_workspace(pIorb)->idempotent = 1;
1231 ahci_write(vIorb, pIorb);
1232 break;
1233
1234 default:
1235 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
1236 iorb_done(vIorb, pIorb);
1237 }
1238}
1239
1240/******************************************************************************
1241 * Handle IOCC_UNIT_STATUS requests.
1242 */
1243void iocc_unit_status(IORBH FAR16DATA *vIorb, IORBH *pIorb)
1244{
1245 switch (pIorb->CommandModifier)
1246 {
1247 case IOCM_GET_UNIT_STATUS:
1248 add_workspace(pIorb)->idempotent = 1;
1249 ahci_unit_ready(vIorb, pIorb);
1250 break;
1251
1252 default:
1253 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
1254 iorb_done(vIorb, pIorb);
1255 }
1256}
1257
1258/******************************************************************************
1259 * Handle IOCC_ADAPTER_PASSTHROUGH requests.
1260 */
1261void iocc_adapter_passthru(IORBH FAR16DATA *vIorb, IORBH *pIorb)
1262{
1263 switch (pIorb->CommandModifier)
1264 {
1265 case IOCM_EXECUTE_CDB:
1266 add_workspace(pIorb)->idempotent = 0;
1267 ahci_execute_cdb(vIorb, pIorb);
1268 break;
1269
1270 case IOCM_EXECUTE_ATA:
1271 add_workspace(pIorb)->idempotent = 0;
1272 ahci_execute_ata(vIorb, pIorb);
1273 break;
1274
1275 default:
1276 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
1277 iorb_done(vIorb, pIorb);
1278 }
1279}
1280
1281/******************************************************************************
1282 * Add an IORB to the specified queue. This function must be called with the
1283 * adapter-level spinlock aquired.
1284 */
1285void iorb_queue_add(IORB_QUEUE *queue, IORBH FAR16DATA *vIorb, IORBH *pIorb)
1286{
1287 if (iorb_priority(pIorb)
1288 {
1289 /* priority IORB; insert at first position */
1290 pIorb->f16NxtIORB = queue->vRoot;
1291 queue->vRoot = vIorb;
1292 }
1293 else
1294 {
1295 /* append IORB to end of queue */
1296 pIorb->f16NxtIORB = FAR16NULL;
1297
1298 if (queue->vRoot == FAR16NULL)
1299 {
1300 queue->vRoot = vIorb;
1301 }
1302 else
1303 {
1304 ((IORBH *)Far16ToFlat(queue->vTail))->f16NxtIORB = vIorb;
1305 }
1306 queue->vTail = vIorb;
1307 }
1308
1309 #ifdef DEBUG
1310 if (D32g_DbgLevel)
1311 {
1312 /* determine queue type (local, driver, abort or port) and minimum debug
1313 * level; otherwise, queue debug prints can become really confusing.
1314 */
1315 char *queue_type;
1316 int min_debug = 7;
1317
1318 if ((u32)queue >> 16 == (u32)&queue >> 16) /* DAZ this is bogus */
1319 {
1320 /* this queue is on the stack */
1321 queue_type = "local";
1322 min_debug = 8;
1323 }
1324 else if (queue == &driver_queue)
1325 {
1326 queue_type = "driver";
1327 }
1328 else if (queue == &abort_queue)
1329 {
1330 queue_type = "abort";
1331 min_debug = 8;
1332 }
1333 else
1334 {
1335 queue_type = "port";
1336 }
1337
1338 DPRINTF(min_debug,"IORB %x queued (cmd=%d/%d queue=%x [%s], timeout=%d)\n",
1339 vIorb, pIorb->CommandCode, pIorb->CommandModifier, queue, queue_type,
1340 pIorb->Timeout);
1341 }
1342 #endif
1343}
1344
1345/******************************************************************************
1346 * Remove an IORB from the specified queue. This function must be called with
1347 * the adapter-level spinlock aquired.
1348 */
1349int iorb_queue_del(IORB_QUEUE *queue, IORBH FAR16DATA *vIorb)
1350{
1351 IORBH FAR16DATA *_vIorb;
1352 IORBH FAR16DATA *_vPrev = FAR16NULL;
1353 int found = 0;
1354
1355 for (_vIorb = queue->vRoot; _vIorb != FAR16NULL; )
1356 {
1357 IORBH *_pIorb = Far16ToFlat(_vIorb);
1358 if (_vIorb == vIorb)
1359 {
1360 /* found the IORB to be removed */
1361 if (_vPrev != FAR16NULL)
1362 {
1363 ((IORBH*)Far16ToFlat(_vPrev))->f16NxtIORB = _pIorb->f16NxtIORB;
1364 }
1365 else
1366 {
1367 queue->vRoot = _pIorb->f16NxtIORB;
1368 }
1369 if (_vIorb == queue->vTail)
1370 {
1371 queue->vTail = _vPrev;
1372 }
1373 found = 1;
1374 break;
1375 }
1376 _vPrev = _vIorb;
1377 _vIorb = _pIorb->f16NxtIORB;
1378 }
1379
1380 #ifdef DEBUG
1381 if (found)
1382 {
1383 DPRINTF(8,"IORB %x removed (queue = %x)\n", vIorb, queue);
1384 }
1385 else
1386 {
1387 DPRINTF(2,"IORB %x not found in queue %x\n", vIorb, queue);
1388 }
1389 #endif
1390
1391 return(!found);
1392}
1393
1394/******************************************************************************
1395 * Set the error code in the specified IORB
1396 *
1397 * NOTE: This function does *not* call iorb_done(). It merely sets the IORB
1398 * status to the specified error code.
1399 */
1400void iorb_seterr(IORBH *pIorb, USHORT error_code)
1401{
1402 pIorb->ErrorCode = error_code;
1403 pIorb->Status |= IORB_ERROR;
1404}
1405
1406/******************************************************************************
1407 * Mark the specified IORB as done and notify the asynchronous post function,
1408 * if any. The IORB is also removed from the corresponding IORB queue.
1409 *
1410 * NOTES: This function does not clear the Status field; it merely adds the
1411 * IORB_DONE flag.
1412 *
1413 * This function is expected to be called *without* the corresponding
1414 * driver-level drv_lock aquired. It will aquire the spinlock before
1415 * updating the IORB queue and release it before notifying the upstream
1416 * code in order to prevent deadlocks.
1417 *
1418 * Due to this logic, this function is only good for simple task-time
1419 * completions. Functions working on lists of IORBs (such as interrupt
1420 * handlers or context hooks) should call iorb_complete() directly and
1421 * implement their own logic for removing the IORB from the port queue.
1422 * See abort_ctxhook() for an example.
1423 */
1424void iorb_done(IORBH FAR16DATA *vIorb, IORBH *pIorb)
1425{
1426 int a = iorb_unit_adapter(pIorb);
1427 int p = iorb_unit_port(pIorb);
1428
1429 /* remove IORB from corresponding queue */
1430 spin_lock(drv_lock);
1431 if (iorb_driver_level(pIorb))
1432 {
1433 iorb_queue_del(&driver_queue, vIorb);
1434 }
1435 else
1436 {
1437 iorb_queue_del(&ad_infos[a].ports[p].iorb_queue, vIorb);
1438 }
1439 aws_free(add_workspace(pIorb));
1440 spin_unlock(drv_lock);
1441
1442 iorb_complete(vIorb, pIorb);
1443}
1444
1445/******************************************************************************
1446 * Complete an IORB. This should be called without the adapter-level spinlock
1447 * to allow the IORB completion routine to perform whatever processing it
1448 * requires. This implies that the IORB should no longer be in any global
1449 * queue because the IORB completion routine may well reuse the IORB and send
1450 * the next request to us before even returning from this function.
1451 */
1452void iorb_complete(IORBH FAR16DATA *vIorb, IORBH *pIorb)
1453{
1454 pIorb->Status |= IORB_DONE;
1455
1456 DPRINTF(7,"IORB %x complete status=0x%04x error=0x%04x\n",
1457 vIorb, pIorb->Status, pIorb->ErrorCode);
1458
1459 if (pIorb->RequestControl & IORB_ASYNC_POST)
1460 {
1461 Dev32Help_CallFar16((PFNFAR16)pIorb->f16NotifyAddress, vIorb);
1462 }
1463}
1464
1465/******************************************************************************
1466 * Requeue the specified IORB such that it will be sent downstream for
1467 * processing again. This includes freeing all resources currently allocated
1468 * (timer, buffer, ...) and resetting the flags to 0. The driver-level
1469 * spinlock must be aquired when calling this function.
1470 *
1471 * The following flags are preserved:
1472 * - no_ncq
1473 */
1474void iorb_requeue(IORBH *pIorb)
1475{
1476 ADD_WORKSPACE *aws = add_workspace(pIorb);
1477 u16 no_ncq = aws->no_ncq;
1478 u16 unaligned = aws->unaligned;
1479 u16 retries = aws->retries;
1480
1481 aws_free(aws);
1482 memset(aws, 0x00, sizeof(*aws));
1483
1484 aws->no_ncq = no_ncq;
1485 aws->unaligned = unaligned;
1486 aws->retries = retries;
1487}
1488
1489/******************************************************************************
1490 * Free resources in ADD workspace (timer, buffer, ...). This function should
1491 * be called with the spinlock held to prevent race conditions.
1492 */
1493void aws_free(ADD_WORKSPACE *aws)
1494{
1495 if (aws->timer != 0)
1496 {
1497 Timer_CancelTimer(aws->timer);
1498 aws->timer = 0;
1499 }
1500
1501 if (aws->buf != NULL)
1502 {
1503 MemFree(aws->buf);
1504 aws->buf = NULL;
1505 }
1506}
1507
1508/******************************************************************************
1509 * Lock the adapter, waiting for availability if necessary. This is expected
1510 * to be called at task/request time without the driver-level spinlock
1511 * aquired. Don't call at interrupt time.
1512 */
1513void lock_adapter(AD_INFO *ai)
1514{
1515 TIMER Timer;
1516
1517 spin_lock(drv_lock);
1518 while (ai->busy)
1519 {
1520 spin_unlock(drv_lock);
1521 TimerInit(&Timer, 250);
1522 while (!TimerCheckAndBlock(&Timer));
1523 spin_lock(drv_lock);
1524 }
1525 ai->busy = 1;
1526 spin_unlock(drv_lock);
1527}
1528
1529/******************************************************************************
1530 * Unlock adapter (i.e. reset busy flag)
1531 */
1532void unlock_adapter(AD_INFO *ai)
1533{
1534 ai->busy = 0;
1535}
1536
1537/******************************************************************************
1538 * Timeout handler for I/O commands. Since timeout handling can involve
1539 * lengthy operations like port resets, the main code is located in a
1540 * separate function which is invoked via a context hook.
1541 */
1542void __syscall timeout_callback(ULONG timer_handle, ULONG p1)
1543{
1544 IORBH FAR16DATA *vIorb = (IORBH FAR16DATA *)CastULONGToFar16(p1);
1545 IORBH *pIorb = Far16ToFlat(vIorb);
1546 int a = iorb_unit_adapter(pIorb);
1547 int p = iorb_unit_port(pIorb);
1548
1549 Timer_CancelTimer(timer_handle);
1550 dprintf(0,"timeout for IORB %x port=%x\n", vIorb, p);
1551
1552 /* Move the timed-out IORB to the abort queue. Since it's possible that the
1553 * IORB has completed after the timeout has expired but before we got to
1554 * this line of code, we'll check the return code of iorb_queue_del(): If it
1555 * returns an error, the IORB must have completed a few microseconds ago and
1556 * there is no timeout.
1557 */
1558 spin_lock(drv_lock);
1559 if (iorb_queue_del(&ad_infos[a].ports[p].iorb_queue, vIorb) == 0)
1560 {
1561 iorb_queue_add(&abort_queue, vIorb, pIorb);
1562 pIorb->ErrorCode = IOERR_ADAPTER_TIMEOUT;
1563 }
1564 spin_unlock(drv_lock);
1565
1566 /* Trigger abort processing function. We don't really care whether this
1567 * succeeds because the only reason why it would fail should be multiple
1568 * calls to DevHelp_ArmCtxHook() before the context hook had a chance to
1569 * start executing, which leaves two scenarios:
1570 *
1571 * - We succeded in arming the context hook. Fine.
1572 *
1573 * - We armed the context hook a second time before it had a chance to
1574 * start executing. In this case, the already scheduled context hook
1575 * will process our IORB as well.
1576 */
1577 KernArmHook(reset_ctxhook_h, 0, 0);
1578
1579 /* Set up a watchdog timer which calls the context hook manually in case
1580 * some kernel thread is looping around the IORB_COMPLETE status bit
1581 * without yielding the CPU (kernel threads don't preempt). This shouldn't
1582 * happen per design because kernel threads are supposed to yield but it
1583 * does in the early boot phase.
1584 */
1585 Timer_StartTimerMS(&th_reset_watchdog, 5000, reset_watchdog, 0);
1586}
1587
1588/******************************************************************************
1589 * Reset handler watchdog. If a timeout occurs, a context hook is armed which
1590 * will execute as soon as a kernel thread yields the CPU. However, some
1591 * kernel components won't yield the CPU during the early boot phase and the
1592 * only way to kick some sense into those components is to run the context
1593 * hook right inside this timer callback. Not exactly pretty, especially
1594 * considering the fact that context hooks were implemented to prevent running
1595 * lengthy operations like a port reset at interrupt time, but without this
1596 * watchdog mechanism we run the risk of getting completely stalled by device
1597 * problems during the early boot phase.
1598 */
1599void __syscall reset_watchdog(ULONG timer_handle, ULONG p1)
1600{
1601 /* reset watchdog timer */
1602 Timer_CancelTimer(timer_handle);
1603 th_reset_watchdog = 0;
1604 dprintf(0,"reset watchdog invoked\n");
1605
1606 /* You cannot call the reset_ctxhook directly because it does things
1607 * that are illegal in an interrupt handler.
1608 */
1609
1610 KernArmHook(reset_ctxhook_h, 0, 0);
1611
1612 /* call context hook manually */
1613 //reset_ctxhook(0);
1614}
1615
1616/******************************************************************************
1617 * Add unit info to ADAPTERINFO array (IOCC_GET_DEVICE_TABLE requests). The
1618 * adapter info array in the device table, dt->pAdapter[], is expected to be
1619 * initialized for the specified index (dt_ai).
1620 *
1621 * Please note that the device table adapter index, dta, is not always equal
1622 * to the physical adapter index, a: if SCSI emulation has been activated, the
1623 * last reported adapter is a virtual SCSI adapter and the physical adapter
1624 * indexes for those units are, of course, different from the device table
1625 * index of the virtual SCSI adapter.
1626 */
1627static int add_unit_info(IORB_CONFIGURATION *pIorb_conf, int dta,
1628 int a, int p, int d, int scsi_id)
1629{
1630 DEVICETABLE *pDt = Far16ToFlat(pIorb_conf->f16DeviceTable);
1631 ADAPTERINFO *pPtr;
1632 UNITINFO *pUi;
1633 AD_INFO *ai = ad_infos + a;
1634
1635 pPtr = (ADAPTERINFO *)MakeFlatFromNear16(pIorb_conf->f16DeviceTable, pDt->pAdapter[dta]);
1636 //DPRINTF(2,"add_unit_info: ptr=%x dta=%x pAdapter[dta]=%x pDeviceTable=%x\n",
1637 // ptr, dta, dt->pAdapter[dta], iorb_conf->pDeviceTable);
1638
1639 pUi = &pPtr->UnitInfo[pPtr->AdapterUnits];
1640
1641 if ((u32)(pUi + 1) - (u32)pDt > pIorb_conf->DeviceTableLen)
1642 {
1643 dprintf(0,"error: device table provided by DASD too small\n");
1644 iorb_seterr(&pIorb_conf->iorbh, IOERR_CMD_SW_RESOURCE);
1645 return(-1);
1646 }
1647
1648 if (ai->ports[p].devs[d].unit_info == NULL)
1649 {
1650 /* provide original information about this device (unit) */
1651 memset(pUi, 0x00, sizeof(*pUi));
1652 pUi->AdapterIndex = dta; /* device table adapter index */
1653 pUi->UnitHandle = iorb_unit(a, p, d); /* physical adapter index */
1654 pUi->UnitIndex = pPtr->AdapterUnits;
1655 pUi->UnitType = ai->ports[p].devs[d].dev_type;
1656 pUi->QueuingCount = ai->ports[p].devs[d].ncq_max;
1657 if (ai->ports[p].devs[d].removable) pUi->UnitFlags |= UF_REMOVABLE;
1658 if (ai->ports[p].devs[d].ignored) pUi->UnitFlags |= UF_NODASD_SUPT;
1659 if (scsi_id > 0) pUi->UnitSCSITargetID = scsi_id; /* set fake SCSI ID for this unit */
1660 }
1661 else
1662 {
1663 /* copy updated device (unit) information (IOCM_CHANGE_UNITINFO) */
1664 memcpy(pUi, ai->ports[p].devs[d].unit_info, sizeof(*pUi));
1665 }
1666
1667 pPtr->AdapterUnits++;
1668 return(0);
1669}
1670
Note: See TracBrowser for help on using the repository browser.