source: trunk/src/os2ahci.c@ 9

Last change on this file since 9 was 9, checked in by root, 15 years ago

fixes for Watcom compiler

File size: 32.6 KB
Line 
1/******************************************************************************
2 * os2ahci.c - main file for os2ahci driver
3 *
4 * Copyright (c) 2010 Christian Mueller. Parts copied from/inspired by the
5 * Linux AHCI driver; those parts are (c) Linux AHCI/ATA maintainers
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include "os2ahci.h"
23
24/* -------------------------- macros and constants ------------------------- */
25
26/* parse integer command line parameter */
27#define drv_parm_int(s, value, type, radix) \
28 { \
29 char _far *_ep; \
30 if ((s)[1] != ':') { \
31 cprintf("missing colon (:) after /%c\n", *(s)); \
32 goto init_fail; \
33 } \
34 value = (type) strtol((s) + 2, \
35 (const char _far* _far*) &_ep, \
36 radix); \
37 s = _ep; \
38 }
39
40
41/* MT: got to fix include paths... */
42#ifndef IOCM_EXECUTE_ATA
43#define IOCM_EXECUTE_ATA 0x0003
44#endif
45
46/* ------------------------ typedefs and structures ------------------------ */
47
48/* -------------------------- function prototypes -------------------------- */
49
50/* ------------------------ global/static variables ------------------------ */
51
52int debug = 0; /* if > 0, print debug messages to COM1 */
53int thorough_scan; /* if != 0, perform thorough PCI scan */
54int init_reset; /* if != 0, reset ports during init */
55
56PFN Device_Help = 0; /* pointer to device helper entry point */
57ULONG RMFlags = 0; /* required by resource manager library */
58PFN RM_Help0 = NULL; /* required by resource manager library */
59PFN RM_Help3 = NULL; /* required by resource manager library */
60HDRIVER rm_drvh; /* resource manager driver handle */
61char rm_drvname[80]; /* driver name as returned by RM */
62USHORT add_handle; /* driver handle (RegisterDeviceClass) */
63UCHAR timer_pool[TIMER_POOL_SIZE]; /* timer pool */
64
65/* resource manager driver information structure */
66DRIVERSTRUCT rm_drvinfo = {
67 "OS2AHCI", /* driver name */
68 "AHCI SATA Driver", /* driver description */
69 "GNU", /* vendor name */
70 CMVERSION_MAJOR, /* RM interface version major */
71 CMVERSION_MINOR, /* RM interface version minor */
72 2010, 4, 27, /* date */
73 0, /* driver flags */
74 DRT_ADDDM, /* driver type */
75 DRS_ADD, /* driver sub type */
76 NULL /* driver callback */
77};
78
79ULONG drv_lock; /* driver-level spinlock */
80IORB_QUEUE driver_queue; /* driver-level IORB queue */
81AD_INFO ad_infos[MAX_AD]; /* adapter information list */
82int ad_info_cnt; /* number of entries in ad_infos[] */
83int init_complete; /* if != 0, initialization has completed */
84
85/* apapter/port-specific options saved when parsing the command line */
86int link_speed[MAX_AD][AHCI_MAX_PORTS];
87
88static char init_msg[] = "OS2AHCI driver version %d.%02d\n";
89static char exit_msg[] = "OS2AHCI driver *not* installed\n";
90
91/* ----------------------------- start of code ----------------------------- */
92
93/******************************************************************************
94 * OS/2 device driver main strategy function. This function is only used
95 * for initialization purposes; all other calls go directly to the adapter
96 * device driver's strategy function.
97 */
98USHORT c_strat(RPH _far *req)
99{
100 u16 rc;
101
102 switch (req->Cmd) {
103
104 case CMDInitBase:
105 rc = init_drv((RPINITIN _far *) req);
106 break;
107
108 default:
109 rc = STDON | STATUS_ERR_UNKCMD;
110 break;
111 }
112
113 return(rc);
114}
115
116/******************************************************************************
117 * Intialize the os2ahci driver. This includes command line parsing, scanning
118 * the PCI bus for supported AHCI adapters, etc.
119 */
120USHORT init_drv(RPINITIN _far *req)
121{
122 RPINITOUT _far *rsp = (RPINITOUT _far *) req;
123 DDD_PARM_LIST _far *ddd_pl = (DDD_PARM_LIST _far *) req->InitArgs;
124 APIRET rmrc;
125 char _far *cmd_line;
126 char _far *s;
127 int adapter_index;
128 int port_index;
129 u16 vendor;
130 u16 device;
131
132 /* set device helper entry point */
133 Device_Help = req->DevHlpEP;
134
135 /* create driver-level spinlock */
136 DevHelp_CreateSpinLock(&drv_lock);
137
138 if (debug) {
139 /* initialize debug interface (COM1) */
140 init_com1();
141 }
142
143 /* print initialization message */
144 cprintf(init_msg, VERSION / 100, VERSION % 100);
145
146 /* register driver with resource manager */
147 if ((rmrc = RMCreateDriver(&rm_drvinfo, &rm_drvh)) != RMRC_SUCCESS) {
148 cprintf("failed to register driver with resource manager (rc = %d)\n", rmrc);
149 goto init_fail;
150 }
151
152 /* parse command line parameters */
153 cmd_line = (char _far *) ((u32) ddd_pl & 0xffff0000l) + ddd_pl->cmd_line_args;
154 adapter_index = 0;
155 port_index = 0;
156
157 for (s = cmd_line; *s != 0; s++) {
158 if (*s == '/' && s[1] != '\0') {
159 s++;
160 switch(tolower(*s)) {
161
162 case 'd':
163 /* increase debug level */
164 debug++;
165 break;
166
167 case 'i':
168 /* add specfied PCI ID as a supported generic AHCI adapter */
169 drv_parm_int(s, vendor, u16, 16);
170 drv_parm_int(s, device, u16, 16);
171 if (add_pci_id(vendor, device)) {
172 cprintf("failed to add PCI ID %04x:%04x\n", vendor, device);
173 goto init_fail;
174 }
175 thorough_scan = 1;
176 break;
177
178 case 't':
179 /* perform thorough PCI scan (i.e. look for individual supported PCI IDs) */
180 thorough_scan = 1;
181 break;
182
183 case 'r':
184 /* reset ports during initialization */
185 init_reset = 1;
186 break;
187
188 case 'a':
189 /* set adapter index for adapter and port-related options */
190 drv_parm_int(s, adapter_index, int, 10);
191 if (adapter_index < 0 || adapter_index >= MAX_AD) {
192 cprintf("invalid adapter index (%d)\n", adapter_index);
193 goto init_fail;
194 }
195 break;
196
197 case 'p':
198 /* set port index for port-related options */
199 drv_parm_int(s, port_index, int, 10);
200 if (port_index < 0 || port_index >= AHCI_MAX_PORTS) {
201 cprintf("invalid port index (%d)\n", port_index);
202 goto init_fail;
203 }
204 break;
205
206 case 's':
207 /* set link speed of current port on current adapter */
208 drv_parm_int(s, link_speed[adapter_index][port_index], u8, 10);
209 init_reset = 1;
210 break;
211
212 default:
213 cprintf("invalid option: /%c\n", *s);
214 goto init_fail;
215 }
216 }
217 }
218
219 /* scan PCI bus for supported devices */
220 scan_pci_bus();
221
222 if (ad_info_cnt > 0) {
223 /* initialization succeeded and we found at least one AHCI adapter */
224 ADD_InitTimer(timer_pool, sizeof(timer_pool));
225 mdelay_cal();
226
227 if (DevHelp_RegisterDeviceClass("OS2AHCI", (PFN) add_entry, 0, 1,
228 &add_handle)) {
229 cprintf("error: couldn't register device class\n");
230 goto init_fail;
231 }
232
233 /* allocate context hooks */
234 if (DevHelp_AllocateCtxHook(mk_NPFN(restart_hook), &restart_ctxhook_h) != 0 ||
235 DevHelp_AllocateCtxHook(mk_NPFN(reset_hook), &reset_ctxhook_h) != 0 ||
236 DevHelp_AllocateCtxHook(mk_NPFN(engine_hook), &engine_ctxhook_h)) {
237 cprintf("failed to allocate task-time context hooks\n");
238 goto init_fail;
239 }
240
241 rsp->CodeEnd = (u16) end_of_code;
242 rsp->DataEnd = (u16) &end_of_data;
243 return(STDON);
244 }
245
246init_fail:
247 /* initialization failed; set segment sizes to 0 and return error */
248 cprintf(exit_msg);
249 rsp->CodeEnd = 0;
250 rsp->DataEnd = 0;
251
252 /* free context hooks */
253 if (engine_ctxhook_h != 0) DevHelp_FreeCtxHook(engine_ctxhook_h);
254 if (reset_ctxhook_h != 0) DevHelp_FreeCtxHook(reset_ctxhook_h);
255 if (restart_ctxhook_h != 0) DevHelp_FreeCtxHook(restart_ctxhook_h);
256
257 if (rm_drvh != 0) {
258 /* remove driver from resource manager */
259 RMDestroyDriver(rm_drvh);
260 }
261
262 cprintf(exit_msg);
263 return(STDON | ERROR_I24_QUIET_INIT_FAIL);
264}
265
266/******************************************************************************
267 * ADD entry point. This is the main entry point for all ADD requests. Due to
268 * the asynchronous nature of ADD drivers, this function primarily queues the
269 * IORB(s) to the corresponding adapter or port queues, then triggers the
270 * state machine to initiate processing queued IORBs.
271 *
272 * NOTE: In order to prevent race conditions or engine stalls, certain rules
273 * around locking, unlocking and IORB handling in general have been
274 * established. Refer to the comments in "trigger_engine()" for
275 * details.
276 */
277void _far _loadds add_entry(IORBH _far *first_iorb)
278{
279 IORBH _far *iorb;
280 IORBH _far *next = NULL;
281
282 spin_lock(drv_lock);
283
284 for (iorb = first_iorb; iorb != NULL; iorb = next) {
285 /* Queue this IORB. Queues primarily exist on port level but there are
286 * some requests which affect the whole driver, most notably
287 * IOCC_CONFIGURATION. In either case, adding the IORB to the driver or
288 * port queue will change the links, thus we need to save the original
289 * link in 'next'.
290 */
291 next = (iorb->RequestControl | IORB_CHAIN) ? iorb->pNxtIORB : 0;
292
293 iorb->Status = 0;
294 iorb->ErrorCode = 0;
295 memset(&iorb->ADDWorkSpace, 0x00, sizeof(ADD_WORKSPACE));
296
297 if (iorb_driver_level(iorb)) {
298 /* adapter-level IORB */
299 iorb->UnitHandle = 0;
300 iorb_queue_add(&driver_queue, iorb);
301
302 } else {
303 /* port-level IORB */
304 int a = iorb_unit_adapter(iorb);
305 int p = iorb_unit_port(iorb);
306 int d = iorb_unit_device(iorb);
307
308 if (a >= ad_info_cnt ||
309 p > ad_infos[a].port_max ||
310 d > ad_infos[a].ports[p].dev_max ||
311 (ad_infos[a].port_map & (1UL << p)) == 0) {
312
313 /* unit handle outside of the allowed range */
314 dprintf("warning: IORB for %d.%d.%d out of range\n", a, p, d);
315 iorb->Status = IORB_ERROR | IORB_DONE;
316 iorb->ErrorCode = IOERR_CMD_SYNTAX;
317 if (iorb->RequestControl & IORB_ASYNC_POST) {
318 iorb->NotifyAddress(iorb);
319 }
320 continue;
321 }
322
323 iorb_queue_add(&ad_infos[a].ports[p].iorb_queue, iorb);
324 }
325 }
326
327 /* trigger state machine */
328 trigger_engine();
329
330 spin_unlock(drv_lock);
331}
332
333/******************************************************************************
334 * Trigger IORB queue engine. This is a wrapper function for trigger_engine_1()
335 * which will try to get all IORBs sent on their way a couple of times. If
336 * there are still IORBs ready for processing after this, this function will
337 * hand off to a context hook which will continue to trigger the engine until
338 * all IORBs have been sent.
339 */
340void trigger_engine(void)
341{
342 int i;
343
344 for (i = 0; i < 3; i++) {
345 if (trigger_engine_1() == 0) {
346 /* done -- all IORBs have been sent on their way */
347 return;
348 }
349 }
350
351 /* Something keeps bouncing; hand off to the engine context hook which will
352 * keep trying in the background.
353 */
354 DevHelp_ArmCtxHook(0, engine_ctxhook_h);
355}
356
357/******************************************************************************
358 * Trigger IORB queue engine in order to send commands in the driver/port IORB
359 * queues to the AHCI hardware. This function will return the number of IORBs
360 * sent. Keep in mind that IORBs might "bounce" if the adapter/port is not in
361 * a state to accept the command, thus it might take quite a few calls to get
362 * all IORBs on their way. This is why there's a wrapper function which tries
363 * it a few times, then hands off to a context hook which will keep trying in
364 * the background.
365 *
366 * IORBs might complete before send_iorb() has returned, at any time during
367 * interrupt processing or on another CPU on SMP systems. IORB completion
368 * means modifications to the corresponding IORB queue (the completed IORB
369 * is removed from the queue) thus we need to protect the IORB queues from
370 * race conditions. The safest approach short of keeping the driver-level
371 * spinlock aquired permanently is to keep it throughout this function and
372 * release it temporarily in send_iorb().
373 *
374 * This implies that the handler functions are fully responsible for aquiring
375 * the driver-level spinlock when they need it, and for releasing it again.
376 *
377 * As a rule of thumb, get the driver-level spinlock whenever accessing
378 * volatile variables (IORB queues, values in ad_info[], ...).
379 *
380 * Additional Notes:
381 *
382 * - This function is expected to be called with the spinlock aquired
383 *
384 * - The handler functions are free to process more than one IORB (i.e.
385 * command queuing). The idea is that the root IORB (and potential next
386 * IORBs) are marked as "processing" which keeps trigger_engine() from
387 * touching this IORB queue until all of those IORBs have completed
388 * processing and have been removed from the queue.
389 *
390 * - Adapters can be flagged as 'busy' which means no new IORBs are sent (they
391 * just remain in the queue). This can be used to release the driver-level
392 * spinlock while making sure no new IORBs are going to hit the hardware.
393 * In order to prevent engine stalls, all handlers using this functionality
394 * need to invoke trigger_engine() after resetting the busy flag.
395 *
396 * - Handlers that use the adapter 'busy' flag when processing driver-level
397 * IORBs don't need to protect themselves against new IORBs on the driver
398 * level because those will always be queued at the end of the driver-
399 * level queue (there are no driver-level priority IORBs).
400 */
401int trigger_engine_1(void)
402{
403 IORBH _far *iorb;
404 int iorbs_sent = 0;
405 int a;
406 int p;
407
408 iorbs_sent = 0;
409
410 /* process driver-level IORBs */
411 if ((iorb = driver_queue.root) != NULL && !add_workspace(iorb)->processing) {
412 send_iorb(iorb);
413 iorbs_sent++;
414 }
415
416 /* process port-level IORBs */
417 for (a = 0; a < ad_info_cnt; a++) {
418 AD_INFO *ai = ad_infos + a;
419 if (ai->busy) {
420 /* adapter is busy; don't process any IORBs */
421 continue;
422 }
423 for (p = 0; p <= ai->port_max; p++) {
424 if ((iorb = ai->ports[p].iorb_queue.root) != NULL &&
425 !add_workspace(iorb)->processing) {
426 send_iorb(iorb);
427 iorbs_sent++;
428 }
429 }
430 }
431
432 return(iorbs_sent);
433}
434
435/******************************************************************************
436 * Send a single IORB to the corresponding AHCI adapter/port. This is just a
437 * switch board for calling the corresponding iocc_*() handler function.
438 *
439 * NOTE: This function is expected to be called with the driver-level spinlock
440 * aquired. It will release it before calling any of the handler
441 * functions and re-aquire it when done.
442 */
443void send_iorb(IORBH _far *iorb)
444{
445 /* Mark IORB as "processing" before doing anything else. Once the IORB is
446 * marked as "processing", we can release the spinlock because subsequent
447 * invocations of trigger_engine() (e.g. at interrupt time) will ignore this
448 * IORB.
449 *
450 * NOTE: Handler functions are free to look at follow-up IORBs in order to
451 * queue them to the hardware (native command queueing). If they
452 * choose to do so, they must mark those IORBs as "processing" as
453 * well.
454 */
455 add_workspace(iorb)->processing = 1;
456 spin_unlock(drv_lock);
457
458 switch (iorb->CommandCode) {
459
460 case IOCC_CONFIGURATION:
461 iocc_configuration(iorb);
462 break;
463
464 case IOCC_DEVICE_CONTROL:
465 iocc_device_control(iorb);
466 break;
467
468 case IOCC_UNIT_CONTROL:
469 iocc_unit_control(iorb);
470 break;
471
472 case IOCC_GEOMETRY:
473 iocc_geometry(iorb);
474 break;
475
476 case IOCC_EXECUTE_IO:
477 iocc_execute_io(iorb);
478 break;
479
480 case IOCC_UNIT_STATUS:
481 iocc_unit_status(iorb);
482 break;
483
484 case IOCC_ADAPTER_PASSTHRU:
485 iocc_adapter_passthru(iorb);
486 break;
487
488 default:
489 /* unsupported call */
490 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
491 iorb_done(iorb);
492 break;
493 }
494
495 /* re-aquire spinlock before returning to trigger_engine() */
496 spin_lock(drv_lock);
497}
498
499/******************************************************************************
500 * Handle IOCC_CONFIGURATION requests.
501 */
502void iocc_configuration(IORBH _far *iorb)
503{
504 int a;
505
506 switch (iorb->CommandModifier) {
507
508 case IOCM_COMPLETE_INIT:
509 /* Complete initialization. From now on, we won't have to restore the BIOS
510 * configuration after each command and we're fully operational (i.e. will
511 * use interrupts, timers and context hooks instead of polling).
512 */
513 dprintf("leaving initialization mode\n");
514 spin_lock(drv_lock);
515 if (!init_complete) {
516 for (a = 0; a < ad_info_cnt; a++) {
517 ahci_complete_init(ad_infos + a);
518 }
519 init_complete = 1;
520 }
521 spin_unlock(drv_lock);
522 iorb_done(iorb);
523 break;
524
525 case IOCM_GET_DEVICE_TABLE:
526 /* construct a device table */
527 iocm_device_table(iorb);
528 break;
529
530 default:
531 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
532 iorb_done(iorb);
533 break;
534 }
535}
536
537/******************************************************************************
538 * Handle IOCC_DEVICE_CONTROL requests.
539 */
540void iocc_device_control(IORBH _far *iorb)
541{
542 AD_INFO *ai;
543 IORBH _far *ptr;
544 IORBH _far *next = NULL;
545 int a = iorb_unit_adapter(iorb);
546 int p = iorb_unit_port(iorb);
547 int d = iorb_unit_device(iorb);
548
549 switch (iorb->CommandModifier) {
550
551 case IOCM_ABORT:
552 /* abort all pending commands on specified port and device */
553 ai = ad_infos + a;
554 spin_lock(drv_lock);
555 for (ptr = ai->ports[p].iorb_queue.root; ptr != NULL; ptr = next) {
556 next = ptr->pNxtIORB;
557 /* move all matching IORBs to the abort queue */
558 if (ptr != iorb && iorb_unit_device(ptr) == d) {
559 iorb_queue_del(&ai->ports[p].iorb_queue, ptr);
560 iorb_queue_add(&abort_queue, ptr);
561 ptr->ErrorCode = IOERR_CMD_ABORTED;
562 }
563 }
564 spin_unlock(drv_lock);
565
566 /* trigger reset context hook which will finish the abort processing */
567 DevHelp_ArmCtxHook(0, reset_ctxhook_h);
568 break;
569
570 case IOCM_SUSPEND:
571 case IOCM_RESUME:
572 case IOCM_GET_QUEUE_STATUS:
573 /* Suspend/resume operations allow access to the hardware for other
574 * entities such as IBMIDECD.FLT. Since os2ahci implements both ATA
575 * and ATAPI in the same driver, this won't be required.
576 */
577 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
578 break;
579
580 case IOCM_LOCK_MEDIA:
581 case IOCM_UNLOCK_MEDIA:
582 case IOCM_EJECT_MEDIA:
583 /* unit control commands to lock, unlock and eject media */
584 /* will be supported later... */
585 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
586 break;
587
588 default:
589 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
590 break;
591 }
592
593 iorb_done(iorb);
594}
595
596/******************************************************************************
597 * Handle IOCC_UNIT_CONTROL requests.
598 */
599void iocc_unit_control(IORBH _far *iorb)
600{
601 IORB_UNIT_CONTROL _far *iorb_uc = (IORB_UNIT_CONTROL _far *) iorb;
602 int a = iorb_unit_adapter(iorb);
603 int p = iorb_unit_port(iorb);
604 int d = iorb_unit_device(iorb);
605
606 spin_lock(drv_lock);
607 switch (iorb->CommandModifier) {
608
609 case IOCM_ALLOCATE_UNIT:
610 /* allocate unit for exclusive access */
611 if (ad_infos[a].ports[p].devs[d].allocated) {
612 iorb_seterr(iorb, IOERR_UNIT_ALLOCATED);
613 } else {
614 ad_infos[a].ports[p].devs[d].allocated = 1;
615 }
616 break;
617
618 case IOCM_DEALLOCATE_UNIT:
619 /* deallocate exclusive access to unit */
620 if (!ad_infos[a].ports[p].devs[d].allocated) {
621 iorb_seterr(iorb, IOERR_UNIT_NOT_ALLOCATED);
622 } else {
623 ad_infos[a].ports[p].devs[d].allocated = 0;
624 }
625 break;
626
627 case IOCM_CHANGE_UNITINFO:
628 /* Change unit (device) information. One reason for this IOCM is the
629 * interface for filter device drivers: a filter device driver can
630 * either change existing UNITINFOs or permanently allocate units
631 * and fabricate new [logical] units; the former is the reason why we
632 * must store the pointer to the updated UNITNIFO for subsequent
633 * IOCC_CONFIGURATION/IOCM_GET_DEVICE_TABLE calls.
634 */
635 if (!ad_infos[a].ports[p].devs[d].allocated) {
636 iorb_seterr(iorb, IOERR_UNIT_NOT_ALLOCATED);
637 break;
638 }
639 ad_infos[a].ports[p].devs[d].unit_info = iorb_uc->pUnitInfo;
640 break;
641
642 default:
643 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
644 break;
645 }
646
647 spin_unlock(drv_lock);
648 iorb_done(iorb);
649}
650
651/******************************************************************************
652 * Scan all ports for AHCI devices and construct a DASD device table.
653 *
654 * NOTE: This function may be called multiple times. Only the first invocation
655 * will actually scan for devices; all subsequent calls will merely
656 * return the results of the initial scan, potentially augmented by
657 * modified unit infos after IOCC_CONFIGURATION/IOCM_CHANGE_UNITINFO
658 * requests.
659 */
660void iocm_device_table(IORBH _far *iorb)
661{
662 IORB_CONFIGURATION _far *iorb_conf;
663 DEVICETABLE _far *dt;
664 char _far *pos;
665 int rc;
666 int a;
667 int p;
668 int d;
669
670 iorb_conf = (IORB_CONFIGURATION _far *) iorb;
671 dt = iorb_conf->pDeviceTable;
672
673 spin_lock(drv_lock);
674
675 /* initialize device table header */
676 dt->ADDLevelMajor = ADD_LEVEL_MAJOR;
677 dt->ADDLevelMinor = ADD_LEVEL_MINOR;
678 dt->ADDHandle = add_handle;
679 dt->TotalAdapters = ad_info_cnt;
680
681 /* Initial position of dynamic portion of device table (i.e. behind the
682 * array of ADAPTERINFO pointers, pAdapter, in the device table)
683 */
684 pos = (char _far *) (dt->pAdapter + ad_info_cnt);
685
686 for (a = 0; a < ad_info_cnt; a++) {
687 ADAPTERINFO _far *ptr = (ADAPTERINFO _far *) pos;
688 AD_INFO *ad_info = ad_infos + a;
689 int units = 0;
690
691 /* sanity check for sufficient space in device table */
692 if ((u32) (ptr + 1) - (u32) dt > iorb_conf->DeviceTableLen) {
693 dprintf("error: device table provided by DASD too small\n");
694 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
695 goto iocm_device_table_done;
696 }
697
698 /* set ADAPTERINFO offset in device table */
699 dt->pAdapter[a] = (ADAPTERINFO _near *) ((u32) ptr & 0xffff);
700
701 /* fill in adapter information structure in device table */
702 memset(ptr, 0x00, sizeof(*ptr));
703 sprintf(ptr->AdapterName, "AHCI_%d", a);
704 ptr->AdapterDevBus = AI_DEVBUS_ST506 | AI_DEVBUS_32BIT;
705 ptr->AdapterIOAccess = AI_IOACCESS_BUS_MASTER;
706 ptr->AdapterHostBus = AI_HOSTBUS_OTHER | AI_BUSWIDTH_32BIT;
707 ptr->AdapterFlags = AF_16M | AF_HW_SCATGAT;
708
709 /* AHCI limits S/G elements to 22 bits, thus we'll report only half of
710 * our S/G list buffers to reduce complexity. The command preparation code
711 * will always try to map as many S/G elements as possible so the physical
712 * S/G list capacity is not really wasted except in rare conditions where
713 * we need to split commands with long S/G lists without any suitable split
714 * points except those at the reported MaxHWSGList.
715 */
716 ptr->MaxHWSGList = AHCI_MAX_SG / 2;
717
718 if (!ad_info->port_scan_done) {
719 /* First call; need to scan AHCI hardware for devices. Since this might
720 * be a lengthy operation, especially when init_reset is set, we'll mark
721 * the adapter as busy (new IORBs will only be queued but not executed)
722 * and release the spinlock while scanning the ports so interrupts will
723 * be processed.
724 */
725 if (ad_info->busy) {
726 dprintf("error: port scan requested while adapter was busy\n");
727 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
728 goto iocm_device_table_done;
729 }
730 ad_info->busy = 1;
731 spin_unlock(drv_lock);
732 rc = ahci_scan_ports(ad_info);
733 spin_lock(drv_lock);
734 ad_info->busy = 0;
735
736 if (rc != 0) {
737 dprintf("error: port scan failed on adapter #%d\n", a);
738 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
739 goto iocm_device_table_done;
740 }
741 ad_info->port_scan_done = 1;
742 }
743
744 /* insert devices (units) into the device table */
745 for (p = 0; p <= ad_info->port_max; p++) {
746 for (d = 0; d <= ad_info->ports[p].dev_max; d++) {
747 if (ad_info->ports[p].devs[d].present) {
748 UNITINFO _far *ui = ptr->UnitInfo + units;
749
750 /* sanity check for sufficient space in device table */
751 if ((u32) (ui + 1) - (u32) dt > iorb_conf->DeviceTableLen) {
752 dprintf("error: device table provided by DASD too small\n");
753 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
754 goto iocm_device_table_done;
755 }
756
757 if (ad_info->ports[p].devs[d].unit_info == NULL) {
758 /* provide initial information about this device (unit) */
759 memset(ui, 0x00, sizeof(*ui));
760 ui->AdapterIndex = a;
761 ui->UnitIndex = units;
762 ui->UnitHandle = iorb_unit(a, p, d);
763 ui->UnitType = ad_info->ports[p].devs[d].dev_type;
764 ui->QueuingCount = AHCI_MAX_CMDS;
765 if (ad_info->ports[p].devs[d].removable) {
766 ui->UnitFlags |= UF_REMOVABLE;
767 }
768 } else {
769 /* copy updated device (unit) information (IOCM_CHANGE_UNITINFO) */
770 memcpy(ui, ad_info->ports[p].devs[d].unit_info, sizeof(*ui));
771 }
772 units++;
773 }
774 }
775 }
776
777 /* set total device (unit) count for this adapter */
778 ptr->AdapterUnits = units;
779
780 /* calculate offset for next adapter */
781 pos = (char _far *) (ptr->UnitInfo + units);
782 }
783
784iocm_device_table_done:
785 spin_unlock(drv_lock);
786 iorb_done(iorb);
787}
788
789/******************************************************************************
790 * Handle IOCC_GEOMETRY requests.
791 */
792void iocc_geometry(IORBH _far *iorb)
793{
794 switch (iorb->CommandModifier) {
795
796 case IOCM_GET_MEDIA_GEOMETRY:
797 case IOCM_GET_DEVICE_GEOMETRY:
798 add_workspace(iorb)->idempotent = 1;
799 ahci_get_geometry(iorb);
800 break;
801
802 default:
803 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
804 iorb_done(iorb);
805 }
806}
807
808/******************************************************************************
809 * Handle IOCC_EXECUTE_IO requests.
810 */
811void iocc_execute_io(IORBH _far *iorb)
812{
813 switch (iorb->CommandModifier) {
814
815 case IOCM_READ:
816 add_workspace(iorb)->idempotent = 1;
817 ahci_read(iorb);
818 break;
819
820 case IOCM_READ_VERIFY:
821 add_workspace(iorb)->idempotent = 1;
822 ahci_verify(iorb);
823 break;
824
825 case IOCM_WRITE:
826 add_workspace(iorb)->idempotent = 1;
827 ahci_write(iorb);
828 break;
829
830 case IOCM_WRITE_VERIFY:
831 add_workspace(iorb)->idempotent = 1;
832 ahci_write(iorb);
833 break;
834
835 default:
836 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
837 iorb_done(iorb);
838 }
839}
840
841/******************************************************************************
842 * Handle IOCC_UNIT_STATUS requests.
843 */
844void iocc_unit_status(IORBH _far *iorb)
845{
846 switch (iorb->CommandModifier) {
847
848 case IOCM_GET_UNIT_STATUS:
849 add_workspace(iorb)->idempotent = 1;
850 ahci_unit_ready(iorb);
851 break;
852
853 default:
854 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
855 iorb_done(iorb);
856 }
857}
858
859/******************************************************************************
860 * Handle IOCC_ADAPTER_PASSTHROUGH requests.
861 */
862void iocc_adapter_passthru(IORBH _far *iorb)
863{
864 switch (iorb->CommandModifier) {
865
866 case IOCM_EXECUTE_CDB:
867 ahci_execute_cdb(iorb);
868 break;
869
870 case IOCM_EXECUTE_ATA:
871 ahci_execute_ata(iorb);
872 break;
873
874 default:
875 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
876 iorb_done(iorb);
877 }
878}
879
880/******************************************************************************
881 * Add an IORB to the specified queue.
882 */
883void iorb_queue_add(IORB_QUEUE _far *queue, IORBH _far *iorb)
884{
885 if (iorb_priority(iorb) {
886 /* priority IORB; insert at first position */
887 iorb->pNxtIORB = queue->root;
888 queue->root = iorb;
889
890 } else {
891 /* append IORB to end of queue */
892 iorb->pNxtIORB = NULL;
893
894 if (queue->root == NULL) {
895 queue->root = iorb;
896 } else {
897 queue->tail->pNxtIORB = iorb;
898 }
899 queue->tail = iorb;
900 }
901
902 ddprintf("IORB queued: %d/%d (queue = %Fp, IORB = %Fp)\n",
903 iorb->CommandCode, iorb->CommandModifier, queue, iorb);
904}
905
906/******************************************************************************
907 * Remove an IORB from the specified queue.
908 */
909int iorb_queue_del(IORB_QUEUE _far *queue, IORBH _far *iorb)
910{
911 IORBH _far *_iorb;
912 IORBH _far *_prev = NULL;
913 int found = 0;
914
915 for (_iorb = queue->root; _iorb != NULL; _iorb = _iorb->pNxtIORB) {
916 if (_iorb == iorb) {
917 /* found the IORB to be removed */
918 if (_prev != NULL) {
919 _prev->pNxtIORB = _iorb->pNxtIORB;
920 } else {
921 queue->root = _iorb->pNxtIORB;
922 }
923 if (_iorb == queue->tail) {
924 queue->tail = _prev;
925 }
926 found = 1;
927 break;
928 }
929 _prev = _iorb;
930 }
931
932 if (found) {
933 ddprintf("IORB removed: %d/%d (queue = %Fp, IORB = %Fp) - %04x/%04x\n",
934 iorb->CommandCode, iorb->CommandModifier, queue, iorb,
935 iorb->Status, iorb->ErrorCode);
936 } else {
937 ddprintf("IORB %Fp not found in queue %Fp\n", iorb, queue);
938 }
939
940 return(!found);
941}
942
943/******************************************************************************
944 * Set the error code in the specified IORB
945 *
946 * NOTE: This function does *not* call iorb_done(). It merely sets the IORB
947 * status to the specified error code.
948 */
949void iorb_seterr(IORBH _far *iorb, USHORT error_code)
950{
951 iorb->ErrorCode = error_code;
952 iorb->Status = IORB_ERROR;
953}
954
955/******************************************************************************
956 * Mark the specified IORB as done and notify the asynchronous post function,
957 * if any. The IORB is also removed from the corresponding IORB queue.
958 *
959 * NOTES: This function does not clear the Status field; it merely adds the
960 * IORB_DONE flag.
961 *
962 * This function is expected to be called *without* the corresponding
963 * driver-level drv_lock aquired. It will aquire the spinlock before
964 * updating the IORB queue and release it before notifying the upstream
965 * code in order to prevent deadlocks.
966 *
967 * Due to this logic, this function is only good for simple task-time
968 * completions. Functions working on lists of IORBs (such as interrupt
969 * handlers or context hooks) should implement their own logic. See
970 * abort_ctxhook() for an example.
971 */
972void iorb_done(IORBH _far *iorb)
973{
974 int a = iorb_unit_adapter(iorb);
975 int p = iorb_unit_port(iorb);
976
977 /* remove IORB from corresponding queue */
978 spin_lock(drv_lock);
979 if (iorb_driver_level(iorb)) {
980 iorb_queue_del(&driver_queue, iorb);
981 } else {
982 iorb_queue_del(&ad_infos[a].ports[p].iorb_queue, iorb);
983 }
984 aws_free(add_workspace(iorb));
985 spin_unlock(drv_lock);
986
987 /* notify caller, if requested */
988 iorb->Status |= IORB_DONE;
989 if (iorb->RequestControl & IORB_ASYNC_POST) {
990 iorb->NotifyAddress(iorb);
991 }
992}
993
994/******************************************************************************
995 * Requeue the specified IORB such that it will be sent downstream for
996 * processing again. This includes freeing all resources currently allocated
997 * (timer, buffer, ...) and resetting the flags to 0.
998 *
999 * The following flags are preserved:
1000 * - no_ncq
1001 */
1002void iorb_requeue(IORBH _far *iorb)
1003{
1004 ADD_WORKSPACE _far *aws = add_workspace(iorb);
1005 u16 no_ncq = aws->no_ncq;
1006
1007 aws_free(aws);
1008 memset(aws, 0x00, sizeof(*aws));
1009 aws->no_ncq = no_ncq;
1010}
1011
Note: See TracBrowser for help on using the repository browser.